This is the mail archive of the
mailing list for the GDB project.
Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver
- From: Josh Stone <jistone at redhat dot com>
- To: Pedro Alves <palves at redhat dot com>, gdb-patches at sourceware dot org
- Cc: philippe dot waroquiers at skynet dot be, sergiodj at redhat dot com, eliz at gnu dot org, xdje42 at gmail dot com
- Date: Tue, 8 Dec 2015 11:02:28 -0800
- Subject: Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver
- Authentication-results: sourceware.org; auth=none
- References: <1448506425-24691-1-git-send-email-jistone at redhat dot com> <1449196006-13759-1-git-send-email-jistone at redhat dot com> <1449196006-13759-2-git-send-email-jistone at redhat dot com> <5661929E dot 7020406 at redhat dot com> <566248F2 dot 5020908 at redhat dot com> <5666DBAC dot 5030401 at redhat dot com>
On 12/08/2015 05:31 AM, Pedro Alves wrote:
> On 12/05/2015 02:16 AM, Josh Stone wrote:
>> On a total tangent, is it ever possible that GDB/GDBserver might try to
>> read and modify registers from a PTRACE_EVENT stop?
> Do "catch fork", and you'll be given a prompt right inside a
> PTRACE_EVENT_FORK, where you can try to poke at registers at will.
>> If so, you should
>> beware that registers may actually be in flux. I ran into this with
>> Dyninst, which I fixed here though I can't find the discussion now.
>> The gist was that in a PTRACE_EVENT, the kernel may not have written the
>> return register yet. Dyninst wanted to save registers, resume in a bit
>> of instrumentation code, then restore registers and resume the normal
>> program. So the saved registers got an intermediate RAX, and when it
>> resumed into instrumentation the kernel finally wrote the good RAX
>> return value to complete the syscall (which the instrumentation
>> ignored). Then when dyninst restored registers the bad RAX was written
>> back, and thus the normal program code didn't get the correct value for
>> its fork return. My solution was to step out of the event with
>> PTRACE_SYSCALL before doing anything else.
> Just to be clear, doesn't $orig_rax help here? Are you saving/restoring that?
$orig_rax only keeps the value $rax had upon entry, which will be the
syscall number. The problem is the return value, which will eventually
go into $rax, but at the moment of a PTRACE_EVENT stop this value only
exists in kernel state. It's not visible in any user state at all.
Just now I had the thought that perhaps you could kludge the return $rax
by using the pid from PTRACE_GETEVENTMSG. (In the kernel, that comes
from the task_struct: child->ptrace_message.) However, this is subject
to pid namespace translation. So if gdb and the child are different,
say the latter is in a container, then PTRACE_GETEVENTMSG's pid will be
different than the return pid the child should see.
That said, the PTRACE_SYSCALL step isn't foolproof either. In theory
this should be fine, but arm and aarch64 kernels had bugs that they
wouldn't report the syscall return if you hadn't already caught the
entry. They would get on the syscall fast path and not check again for
tracing when they returned. Fixed in 4.1 for arm, 4.2 for aarch64.
PTRACE_SINGLESTEP may be a safer option to get out of the event syscall.
In a brief experiment with stepi on x86_64, this case doesn't even
advance the user $rip, but I can't be sure for all architectures. At
least we should expect it won't run away like a broken return
> Otherwise, it sounds like trying to run an inferior function
> call [(gdb) p foo_func()] when the program is stopped for "catch fork"
> may misbehave too.
OK, I'll play with it this way to see what happens... but I ought to
finish QCatchSyscalls before I tackle new problems. :)