[PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP

Pedro Alves palves@redhat.com
Wed Dec 2 14:01:00 GMT 2015


On 12/01/2015 08:17 PM, Josh Stone wrote:

> OK, I think I've got it, and it's a real regression from 7.10 even for
> other events like fork.  I'm not using --wrapper, so I'm not sure of the
> interaction there, but even gdbserver's simple fork+exec can show the
> problem.  Basically, on the very first stop we don't set flags yet, so
> the first resume from there continues without the right flags.
> 
> The sequence I was running into with syscalls goes like this:
> 
> - start_inferior calls create_inferior to fork, then calls mywait
>   - the forked process calls ptrace(PTRACE_TRACEME), then execs
> - linux_low_filter_event sees a raw SIGTRAP for the child after exec
>   - (we haven't set PTRACE_O_TRACEEXEC yet, so SIGTRAP is expected)
>   - arch setup is needed, so it hits the early return (new since 7.10)
>     ... thus child->must_set_ptrace_flags is not dealt with
> - start_inferior calls target_arch_setup
> - GDB sends QCatchSyscalls:1
> - linux_resume_one_lwp_throw calls ptrace(PTRACE_SYSCALL)
>   - but we still haven't set any flags, especially PTRACE_O_TRACESYSGOOD
> - linux_low_filter_event sees a raw SIGTRAP for the first syscall entry
>   - now we finally deal with child->must_set_ptrace_flags
> - linux_resume_one_lwp_throw calls ptrace(PTRACE_SYSCALL)
> - linux_low_filter_event sees SYSCALL_SIGTRAP for the return
>   - entry/return logic is confused now, thinks this is an entry
>   - (but if there's any other event, entry/return will get back in sync)
> 
> 
> But this problem isn't particular to my syscall patches.  Consider this
> simple forking program and use 'catch fork':
> 
>   #include <unistd.h>
>   int main() { fork(); return 0; }
> 
> Compiled normally, with dynamically-linked libc et al, you get:
> - SIGTRAP after exec, ignores child->must_set_ptrace_flags.
> - SIGTRAP for a swbreak, I guess some gdb setup, then it sets the
> necessary flags, especially PTRACE_O_TRACEFORK.
> - SIGTRAP for PTRACE_EVENT_FORK, hooray!
> 
> But compiled statically:
> - SIGTRAP after exec, ignores child->must_set_ptrace_flags.
> - CLD_EXITED, flags were never set!
> - if I add a breakpoint on main, flags will be set when that's reached,
> and then we do get the PTRACE_EVENT_FORK after all.

Ouch.  Thanks, I'm clear now.   It'd be super if one of these examples
got converted to a test case.

> 
> So, we need some point to get the right flags set before the program
> starts running for real.  If you don't like the way I moved the flags
> before that arch-setup early return, then when should we do it?
> 
> - Perhaps before the ptrace call in linux_resume_one_lwp_throw?  Then if
> any state changes while the thread is still stopped, triggering new
> must_set_ptrace_flags, we'll deal with it before resuming.  But I don't
> know if this would interact well with your wrapper concerns.
> 

Yeah, badly.

> - Perhaps at the end of linux_arch_setup?  AIUI this will be after
> everything you're worried about wrappers.

Something like that, yes.  gdb/linux-nat.c also does something like
that:

static void
linux_child_post_startup_inferior (struct target_ops *self, ptid_t ptid)
{
  linux_init_ptrace (ptid_get_pid (ptid), 0);
}

I think we should rename gdbserver's target_ops:target_arch_setup method/hook
to target_post_create_inferior along the way, and then linux-low.c's
implementation can both call linux_arch_setup and set the ptrace options.
Only Linux implements that target_ops method currently, so it should
be trivial.

Thanks,
Pedro Alves



More information about the Gdb-patches mailing list