This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] Add a 'starti' command.


On 09/01/2017 10:42 PM, John Baldwin wrote:
> On Thursday, August 31, 2017 11:51:33 PM Pedro Alves wrote:
>> Hi John,
>>
>> On 08/30/2017 12:54 AM, John Baldwin wrote:
>>> This works like 'start' but it stops at the first instruction rather than
>>> the first line in main().  This is useful if one wants to single step
>>> through runtime linker startup.
>>
>> I like the idea.  I actually once wrote a patch quite similar to this.
>> I had called the command "create", inspired by "target_create_inferior".
>> Is there a reason to actually set a breakpoint at the first instruction and
>> run to it, actually?  My old prototype just created the inferior and
>> didn't resume it all, see:
>>
>>  https://github.com/palves/gdb/commits/create_command
>>
>> though maybe going through normal_stop may be a good idea.

I should expand on this sentence above.  I was thinking of thinks like,
should a user-defined hook-stop run in this case?  Probably.  Going
via "normal_stop" makes sure that is handled.  My old prototype would
skip any hook-stop (and I don't recall whether I did that on purpose.)

This suggests to me that it'd be good to have a test making sure
we either run the hook-stop or not, whatever we decide should happen.

> 
> I tried this today and ended up with gdb hung in poll() but not printing a
> prompt or accepting commands still, so I've left it as a breakpoint.

Another option is still go via process/normal_stop, but make sure that
the thread won't really be run by queing a pending status.  Like so:

  if (/* starti mode*/)
    {
      // queue a pending event instead of setting a breakpoint at "*$pc".
      thread_info *thr = inferior_thread ();
      thr->suspend.waitstatus_pending_p = 1;
      thr->suspend.waitstatus.kind = TARGET_WAITKIND_STOPPED;
      thr->suspend.waitstatus.value.sig = GDB_SIGNAL_0;
    }

One difference this makes is that this way the inferior doesn't really
ever get a chance to run.  If a signal in nostop+pass state is queued
between creating the process and running to the breakpoint at "*$pc",
the signal handler (if any), runs.  With the pending event approach,
it won't.

> 
>> I agree with Keith - this should really have some tests.
>>
>> For example:
>>
>> - write a global constructor that sets a flag, and then check
>>   that the flag is still clear when we're still at the entry point.
>>   This can be either a C++ test or a C test using
>>   __attribute__ ((constructor))-
>>
>> - After creating the inferior, check that you can manually set
>>   a break on main, and continue to it.
> 
> I've created a test which does these two (will send a v2 in a minute).
> 
>> - Try backtrace, and check that only one frame comes
>>   out.  That may expose buggy unwinders that don't stop
>>   unwinding at the entry point currently, but then that
>>   should be fixed anyway, since users will run into that
>>   too.
> 
> This one didn't work out for me on either FreeBSD or a CentOS 7 VM.  I
> know for the FreeBSD case the initial entry point in the runtime linker
> doesn't have any CFI directives that would aid in unwinding, and that
> might be true for ld.so on Linux as well.
> 
> FreeBSD:
> 
> (gdb) starti
> Starting program: /bin/ls 
> Temporary breakpoint 1 at 0x800609650: file /usr/src/libexec/rtld-elf/amd64/rtld_start.S, line 33.
> 
> Temporary breakpoint 1, .rtld_start ()
>     at /usr/src/libexec/rtld-elf/amd64/rtld_start.S:33
> 33              xorq    %rbp,%rbp               # Clear frame pointer for good form
> (gdb) where
> #0  .rtld_start () at /usr/src/libexec/rtld-elf/amd64/rtld_start.S:33
> #1  0x0000000000000001 in ?? ()
> #2  0x00007fffffffe648 in ?? ()
> #3  0x0000000000000000 in ?? ()
> 
> CentOS 7:
> 
> (gdb) starti
> Starting program: /usr/bin/ls 
> Temporary breakpoint 1 at 0x7ffff7ddd170
> 
> Temporary breakpoint 1, 0x00007ffff7ddd170 in _start ()
>    from /lib64/ld-linux-x86-64.so.2
> (gdb) where
> #0  0x00007ffff7ddd170 in _start () from /lib64/ld-linux-x86-64.so.2
> #1  0x0000000000000001 in ?? ()
> #2  0x00007fffffffe6ac in ?? ()
> #3  0x0000000000000000 in ?? ()

Curious.  For the case of entry points that miss CFI, we have fallback code to
stop unwinding at the entry point's frame by default ("set backtrace past-entry",
frame.c:inside_entry_func), but in this case, we're still in the
dynamic loader, not at the program's entry point yet so that hack^Wsafety-net doesn't
kick in.

Thanks,
Pedro Alves


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]