* [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL
@ 2009-09-28 19:39 Doug Evans
2009-09-28 19:46 ` Sérgio Durigan Júnior
2009-09-28 19:58 ` Pedro Alves
0 siblings, 2 replies; 6+ messages in thread
From: Doug Evans @ 2009-09-28 19:39 UTC (permalink / raw)
To: gdb-patches, sergiodj
Hi.
On one system I use (bi-arch ubuntu-hardy clone),
i386-disp-step.exp is failing because the wait status
value linux_nat_wait_1 gets when hitting a system call is 0857f
which gets passed to the upper layers which then get confused
by a signal of 0x85 (== 0x80 | SIGTRAP).
This patch fixes things by masking off the 0x80 bit before
passing the signal number to up the call chain.
Ok to check in?
2009-09-28 Doug Evans <dje@google.com>
* linux-nat.c (TRAP_REMOVE_SYSCALL_FLAG): New macro.
(linux_nat_wait_1): Mask off is-syscall bit in wait status for
TRAP_IS_SYSCALL before passing value to caller.
Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.148
diff -u -p -r1.148 linux-nat.c
--- linux-nat.c 28 Sep 2009 18:39:29 -0000 1.148
+++ linux-nat.c 28 Sep 2009 19:29:21 -0000
@@ -70,6 +70,7 @@
/* To be used when one needs to know wether a
WSTOPSIG (status) is a syscall */
#define TRAP_IS_SYSCALL (SIGTRAP | 0x80)
+#define TRAP_REMOVE_SYSCALL_FLAG(status) ((status) & ~(0x80 << 8))
/* This comment documents high-level logic of this file.
@@ -3012,6 +3013,12 @@ retry:
lp = linux_nat_filter_event (lwpid, status, options);
+ /* If this was a syscall trap, we no longer need or want
+ the 0x80 flag, remove it. */
+ if (WIFSTOPPED (status)
+ && WSTOPSIG (status) == TRAP_IS_SYSCALL)
+ status = TRAP_REMOVE_SYSCALL_FLAG (status);
+
if (lp
&& ptid_is_pid (ptid)
&& ptid_get_pid (lp->ptid) != ptid_get_pid (ptid))
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL
2009-09-28 19:39 [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL Doug Evans
@ 2009-09-28 19:46 ` Sérgio Durigan Júnior
2009-09-28 19:58 ` Pedro Alves
1 sibling, 0 replies; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2009-09-28 19:46 UTC (permalink / raw)
To: Doug Evans; +Cc: gdb-patches
On Monday 28 September 2009, Doug Evans wrote:
> This patch fixes things by masking off the 0x80 bit before
> passing the signal number to up the call chain.
>
> Ok to check in?
As we already discussed that on IRC, that's fine by me. Thank you for doing
this.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL
2009-09-28 19:39 [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL Doug Evans
2009-09-28 19:46 ` Sérgio Durigan Júnior
@ 2009-09-28 19:58 ` Pedro Alves
2009-09-28 23:27 ` Pedro Alves
1 sibling, 1 reply; 6+ messages in thread
From: Pedro Alves @ 2009-09-28 19:58 UTC (permalink / raw)
To: gdb-patches; +Cc: Doug Evans, sergiodj
On Monday 28 September 2009 20:39:05, Doug Evans wrote:
> Hi.
>
> On one system I use (bi-arch ubuntu-hardy clone),
> i386-disp-step.exp is failing because the wait status
> value linux_nat_wait_1 gets when hitting a system call is 0857f
> which gets passed to the upper layers which then get confused
> by a signal of 0x85 (== 0x80 | SIGTRAP).
>
> This patch fixes things by masking off the 0x80 bit before
> passing the signal number to up the call chain.
>
> Ok to check in?
This seems OK-is to me, although I see one extra case that
isn't handled correctly:
stop_wait_callback:
status = wait_lwp (lp);
...
if (WSTOPSIG (status) != SIGSTOP)
{
if (WSTOPSIG (status) == SIGTRAP)
{
...
}
else
{
/* If the lp->status field is still empty, use it to
hold this event. If not, then this event must be
returned to the event queue of the LWP. */
if (lp->status)
{
if (debug_linux_nat)
{
fprintf_unfiltered (gdb_stdlog,
"SWC: kill %s, %s\n",
target_pid_to_str (lp->ptid),
status_to_str ((int) status));
}
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status)); <<<<<<<<
}
It seems we can reach that <<< marked code with a TRAP_IS_SYSCALL, but,
I doubt that we want to requeue that signal in the kernel (?).
--
Pedro Alves
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL
2009-09-28 19:58 ` Pedro Alves
@ 2009-09-28 23:27 ` Pedro Alves
0 siblings, 0 replies; 6+ messages in thread
From: Pedro Alves @ 2009-09-28 23:27 UTC (permalink / raw)
To: gdb-patches; +Cc: Doug Evans, sergiodj
A Monday 28 September 2009 20:58:48, Pedro Alves escreveu:
> On Monday 28 September 2009 20:39:05, Doug Evans wrote:
> > Hi.
> >
> > On one system I use (bi-arch ubuntu-hardy clone),
> > i386-disp-step.exp is failing because the wait status
> > value linux_nat_wait_1 gets when hitting a system call is 0857f
> > which gets passed to the upper layers which then get confused
> > by a signal of 0x85 (== 0x80 | SIGTRAP).
> >
> > This patch fixes things by masking off the 0x80 bit before
> > passing the signal number to up the call chain.
> >
> > Ok to check in?
>
> This seems OK-is to me, although I see one extra case that
> isn't handled correctly:
>
> stop_wait_callback:
>
> status = wait_lwp (lp);
>
> ...
>
> if (WSTOPSIG (status) != SIGSTOP)
> {
> if (WSTOPSIG (status) == SIGTRAP)
> {
> ...
> }
> else
> {
> /* If the lp->status field is still empty, use it to
> hold this event. If not, then this event must be
> returned to the event queue of the LWP. */
> if (lp->status)
> {
> if (debug_linux_nat)
> {
> fprintf_unfiltered (gdb_stdlog,
> "SWC: kill %s, %s\n",
> target_pid_to_str (lp->ptid),
> status_to_str ((int) status));
> }
> kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status)); <<<<<<<<
> }
>
> It seems we can reach that <<< marked code with a TRAP_IS_SYSCALL, but,
> I doubt that we want to requeue that signal in the kernel (?).
>
In case I wasn't clear, I was alluding at the fact that I think
the filtering is done too late.. In fact, things are worse than I
imagined. See here for a simple failing example:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <pthread.h>
void *
thread_function (void *arg)
{
while (1)
{
usleep (1);
}
}
int
main ()
{
int res;
pthread_t thread;
long i = 0;
for (i = 0; i < 10; i++)
{
res = pthread_create(&thread,
NULL,
thread_function,
NULL);
}
thread_function (NULL);
}
(gdb) r
Starting program: /home/pedro/gdb/tests/trap_is_syscall
[New Thread 0x7fe7dee066e0 (LWP 9531)]
[Thread debugging using libthread_db enabled]
[New Thread 0x40800950 (LWP 9538)]
[New Thread 0x41001950 (LWP 9539)]
[New Thread 0x41802950 (LWP 9540)]
[New Thread 0x42003950 (LWP 9541)]
[New Thread 0x42804950 (LWP 9542)]
[New Thread 0x43005950 (LWP 9545)]
[New Thread 0x43806950 (LWP 9547)]
[New Thread 0x44007950 (LWP 9548)]
[New Thread 0x44808950 (LWP 9549)]
[New Thread 0x45009950 (LWP 9550)]
<ctrl-c>
Program received signal SIGINT, Interrupt.
0x00007ffff78ffb81 in nanosleep () from /lib/libc.so.6
(gdb) catch syscall
warning: Could not open "syscalls/amd64-linux.xml"
warning: Could not load the syscall XML file `syscalls/amd64-linux.xml'.
GDB will not be able to display syscall names.
Catchpoint 1 (any syscall)
(gdb) c
Continuing.
[Switching to Thread 0x45009950 (LWP 9550)]
Catchpoint 1 (call to syscall 35), 0x00007ffff78ffb81 in nanosleep () from /lib/libc.so.6
(gdb) c
Continuing.
Program received signal ?, Unknown signal.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[Switching to Thread 0x44808950 (LWP 9549)]
0x00007ffff78ffb81 in nanosleep () from /lib/libc.so.6
(gdb)
`?' is due to TRAP_IS_SYSCALL.
Same with "set debug lin-lwp 1":
linux_nat_wait: [process -1]
LLW: Using pending wait status Trace/breakpoint trap (stopped at syscall) for Thread 0x44808950 (LWP 10484).
LLW: Candidate event Trace/breakpoint trap (stopped at syscall) in Thread 0x44808950 (LWP 10484).
Program received signal ?, Unknown signal.
[Switching to Thread 0x44808950 (LWP 10484)]
0x00007ffff78ffb81 in nanosleep () from /lib/libc.so.6
I wouldn't be surprised if syscall events were inverted from here
on (entry/exit).
Playing with a patch like the below, it's easier to trigger the case
I was mentioning before:
---
gdb/linux-nat.c | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
Index: src/gdb/linux-nat.c
===================================================================
--- src.orig/gdb/linux-nat.c 2009-09-29 00:09:13.000000000 +0100
+++ src/gdb/linux-nat.c 2009-09-29 00:13:59.000000000 +0100
@@ -2400,6 +2400,13 @@ stop_wait_callback (struct lwp_info *lp,
target_pid_to_str (lp->ptid),
errno ? safe_strerror (errno) : "OK");
+ if (WSTOPSIG (status) == TRAP_IS_SYSCALL)
+ {
+ /* Simulate the case of a signal < SIGTRAP and
+ SIGSTOP being delivered before the SIGSTOP. */
+ // kill_lwp (GET_LWP (lp->ptid), SIGINT);
+ }
+
/* Hold this event/waitstatus while we check to see if
there are any more (we still want to get that SIGSTOP). */
stop_wait_callback (lp, NULL);
@@ -2416,7 +2423,9 @@ stop_wait_callback (struct lwp_info *lp,
target_pid_to_str (lp->ptid),
status_to_str ((int) status));
}
- kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status));
+
+ // gdb_assert (WSTOPSIG (status) != TRAP_IS_SYSCALL);
+ gdb_assert (kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (status)) == 0);
}
else
lp->status = status;
Uncommenting the first commented out kill_lwp the patchlet adds, makes
the last gdb_assert trigger (can't kill with signal 0x85), meaning, a syscall event
gets lost.
--
Pedro Alves
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL
2009-09-29 12:45 Doug Evans
@ 2009-09-29 14:32 ` Pedro Alves
0 siblings, 0 replies; 6+ messages in thread
From: Pedro Alves @ 2009-09-29 14:32 UTC (permalink / raw)
To: Doug Evans; +Cc: sergiodj, gdb-patches
(for those not reading the whole thread, catch syscall is
unfortunatly broken with trivial multi-threading.)
On Tuesday 29 September 2009 13:43:48, Doug Evans wrote:
> I'm not sure the filtering is done too late though.
> [One *could* do it earlier, but it seems like it could be done
> later too.]
I don't see this 0x8x signal that much different from
the extended waitstatuses, and I don't see anywhere else
other than linux_handle_extended_wait (or somewhere around it)
that would need to distinguish a syscall SIGTRAP from a regular
SIGTRAP, and yet differently from other ptrace SIGTRAPs. Take
cancel_breakpoint, for example, this seems to me that it should
already be ignoring any LWP that is stopped with a SIGTRAP due
to an ptrace event, like PTRACE_EVENT_VFORK|FORK|EXEC.
cancel_breakpoint:
- if (lp->status != 0
+ if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE
+ && lp->status != 0
&& WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP
stop_wait_callback only needs to care that there's a SIGTRAP,
doesn't need to know if that SIGTRAP is a PTRACE_EVENT_FORK event
pending, just like it doesn't look like it needs to care for
TRAP_IS_SIGCALL specially.
I do see other broken calls to the core with an unfiltered 0x85,
like, e.g.,:
get_pending_status:
signo = target_signal_from_host (WSTOPSIG (lp->status));
or cases of passing a 0x85 to ptrace/kernel, like detach_callback:
if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
WSTOPSIG (status)) < 0)
This one's quite concerning:
Catchpoint 1 (returned from syscall 202), 0x00007ffff7bd113e in __lll_lock_wait_private () from /lib/libpthread.so.0
(gdb) detach
Can't detach Thread 0x43806950 (LWP 20939): Input/output error
(gdb)
(gdb) c
Continuing.
../../src/gdb/linux-nat.c:1782: internal-error: linux_nat_resume: Assertion `lp != NULL' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
Irk!
It seems we'd want to handle syscall SIGTRAPs exactly like other
extended wait statuses --- they're all ptrace SIGTRAPs: don't ever
pass a ptrace SIGTRAP to the inferior.
Here's another somewhat related breakage:
Take the same simple multi-threaded app example as before, and do this:
(gdb) r
Starting program: /home/pedro/gdb/tests/trap_is_syscall
[Thread debugging using libthread_db enabled]
[New Thread 0x40800950 (LWP 18877)]
[New Thread 0x41001950 (LWP 18878)]
[New Thread 0x41802950 (LWP 18879)]
[New Thread 0x42003950 (LWP 18880)]
[New Thread 0x42804950 (LWP 18881)]
[New Thread 0x43005950 (LWP 18882)]
[New Thread 0x43806950 (LWP 18883)]
[New Thread 0x44007950 (LWP 18884)]
[New Thread 0x44808950 (LWP 18885)]
[New Thread 0x45009950 (LWP 18886)]
<ctrl-c>
Program received signal SIGINT, Interrupt.
0x00007ffff78ffb81 in nanosleep () from /lib/libc.so.6
(gdb) catch syscall
warning: Could not open "syscalls/amd64-linux.xml"
warning: Could not load the syscall XML file `syscalls/amd64-linux.xml'.
GDB will not be able to display syscall names.
Catchpoint 1 (any syscall)
(gdb) c
Continuing.
[Switching to Thread 0x45009950 (LWP 18886)]
Catchpoint 1 (call to syscall 35), 0x00007ffff78ffb81 in nanosleep () from /lib/libc.so.6
<a couple more continues>
Now, delete the catchpoint, while some LWPs have a pending syscall event to report:
(gdb) del 1
(gdb) c
Continuing.
Program received signal SIGTRAP, Trace/breakpoint trap.
[Switching to Thread 0x44808950 (LWP 18885)]
0x00007ffff78ffb81 in nanosleep () from /lib/libc.so.6
(gdb)
This case does need to be filtered later, it seems to me.
> btw, I'm seeing lots of "syscall 0" (presumably restarted system calls).
> I hacked another patch to save the the syscall number so that the user
> wouldn't see syscall 0, but maybe the thing to do is record the
> fact that the syscall got restarted and report that to the user?
> [I'm assuming the 0's I see are indeed restarted syscalls.]
Hmmm, haven't seen this one yet.
--
Pedro Alves
^ permalink raw reply [flat|nested] 6+ messages in thread
* [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL
@ 2009-09-29 12:45 Doug Evans
2009-09-29 14:32 ` Pedro Alves
0 siblings, 1 reply; 6+ messages in thread
From: Doug Evans @ 2009-09-29 12:45 UTC (permalink / raw)
To: pedro, sergiodj; +Cc: gdb-patches
Pedro wrote:
> In case I wasn't clear, I was alluding at the fact that I think
> the filtering is done too late..
Ya, it was clear.
There are (basically) two callers of my_waitpid that care:
wait_lwp and linux_nat_wait_1.
I was looking at linux_nat_wait_1, leaving wait_lwp for another pass.
But I see some problems alright.
I'm not sure the filtering is done too late though.
[One *could* do it earlier, but it seems like it could be done
later too.]
One could keep bit 0x80 with the recording pending status,
and process it immediately before linux_nat_wait_1 returns.
Something like the appended patch
(included for illustration's sake, it has a few hacks).
btw, I'm seeing lots of "syscall 0" (presumably restarted system calls).
I hacked another patch to save the the syscall number so that the user
wouldn't see syscall 0, but maybe the thing to do is record the
fact that the syscall got restarted and report that to the user?
[I'm assuming the 0's I see are indeed restarted syscalls.]
E.g.
(gdb)
Continuing.
[Switching to Thread 0xf6561b90 (LWP 23241)]
Catchpoint 1 (call to syscall 0), 0xffffe410 in __kernel_vsyscall ()
(gdb)
Continuing.
Catchpoint 1 (returned from syscall 0), 0xffffe410 in __kernel_vsyscall ()
(gdb)
---
Index: linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.c,v
retrieving revision 1.149
diff -u -p -r1.149 linux-nat.c
--- linux-nat.c 28 Sep 2009 21:09:15 -0000 1.149
+++ linux-nat.c 29 Sep 2009 12:39:06 -0000
@@ -1719,8 +1719,8 @@ resume_callback (struct lwp_info *lp, vo
memset (&lp->siginfo, 0, sizeof (lp->siginfo));
}
else if (lp->stopped && debug_linux_nat)
- fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (has pending)\n",
- target_pid_to_str (lp->ptid));
+ fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (has pending 0x%x)\n",
+ target_pid_to_str (lp->ptid), lp->status);
else if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog, "RC: Not resuming sibling %s (not stopped)\n",
target_pid_to_str (lp->ptid));
@@ -2070,47 +2070,6 @@ linux_handle_extended_wait (struct lwp_i
return 0;
}
- /* Used for 'catch syscall' feature. */
- if (WSTOPSIG (status) == TRAP_IS_SYSCALL)
- {
- if (catch_syscall_enabled () == 0)
- ourstatus->kind = TARGET_WAITKIND_IGNORE;
- else
- {
- struct regcache *regcache = get_thread_regcache (lp->ptid);
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
-
- ourstatus->value.syscall_number =
- (int) gdbarch_get_syscall_number (gdbarch, lp->ptid);
-
- /* If we are catching this specific syscall number, then we
- should update the target_status to reflect which event
- has occurred. But if this syscall is not to be caught,
- then we can safely mark the event as a SYSCALL_RETURN.
-
- This is particularly needed if:
-
- - We are catching any syscalls, or
- - We are catching the syscall "exit"
-
- In this case, as the syscall "exit" *doesn't* return,
- then GDB would be confused because it would mark the last
- syscall event as a SYSCALL_ENTRY. After that, if we re-ran the
- inferior GDB will think that the first syscall event is
- the opposite of a SYSCALL_ENTRY, which is the SYSCALL_RETURN.
- Therefore, GDB would report inverted syscall events. */
- if (catching_syscall_number (ourstatus->value.syscall_number))
- ourstatus->kind =
- (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ?
- TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY;
- else
- ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
-
- lp->syscall_state = ourstatus->kind;
- }
- return 0;
- }
-
internal_error (__FILE__, __LINE__,
_("unknown ptrace event %d"), event);
}
@@ -2326,7 +2285,8 @@ stop_wait_callback (struct lwp_info *lp,
if (WSTOPSIG (status) != SIGSTOP)
{
- if (WSTOPSIG (status) == SIGTRAP)
+ if (WSTOPSIG (status) == SIGTRAP
+ || WSTOPSIG (status) == TRAP_IS_SYSCALL)
{
/* If a LWP other than the LWP that we're reporting an
event for has hit a GDB breakpoint (as opposed to
@@ -2344,6 +2304,14 @@ stop_wait_callback (struct lwp_info *lp,
/* Save the trap's siginfo in case we need it later. */
save_siginfo (lp);
+ if (WSTOPSIG (status) == TRAP_IS_SYSCALL)
+ {
+ /* Simulate the case of a signal < SIGTRAP and
+ SIGSTOP being delivered before the SIGSTOP. */
+ //xxx
+ //kill_lwp (GET_LWP (lp->ptid), SIGINT);
+ }
+
/* Now resume this LWP and get the SIGSTOP event. */
errno = 0;
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
@@ -2367,11 +2335,12 @@ stop_wait_callback (struct lwp_info *lp,
queue. */
if (lp->status)
{
+ gdb_assert (WSTOPSIG (lp->status) != TRAP_IS_SYSCALL);
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
"SWC: kill %s, %s\n",
target_pid_to_str (lp->ptid),
- status_to_str ((int) status));
+ status_to_str ((int) lp->status));
kill_lwp (GET_LWP (lp->ptid), WSTOPSIG (lp->status));
}
@@ -2497,7 +2466,9 @@ select_event_lwp_callback (struct lwp_in
/* Select only resumed LWPs that have a SIGTRAP event pending. */
if (lp->status != 0 && lp->resumed
- && WIFSTOPPED (lp->status) && WSTOPSIG (lp->status) == SIGTRAP)
+ && WIFSTOPPED (lp->status)
+ && (WSTOPSIG (lp->status) == SIGTRAP
+ || WSTOPSIG (lp->status) == TRAP_IS_SYSCALL))
if ((*selector)-- == 0)
return 1;
@@ -2613,6 +2584,17 @@ select_event_lwp (ptid_t filter, struct
if (event_lp != NULL)
{
/* Switch the event LWP. */
+ if (debug_linux_nat && event_lp != *orig_lp)
+ {
+ /* This has to be done in two printf's.
+ target_pid_to_str can only have one in-use result. */
+ fprintf_unfiltered (gdb_stdlog,
+ "SEL: orig_lp = %s",
+ target_pid_to_str ((*orig_lp)->ptid));
+ fprintf_unfiltered (gdb_stdlog,
+ ", switching to %s\n",
+ target_pid_to_str (event_lp->ptid));
+ }
*orig_lp = event_lp;
*status = event_lp->status;
}
@@ -2713,12 +2695,8 @@ linux_nat_filter_event (int lwpid, int s
&& (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == TRAP_IS_SYSCALL))
save_siginfo (lp);
- /* Handle GNU/Linux's extended waitstatus for trace events.
- It is necessary to check if WSTOPSIG is signaling that
- the inferior is entering/exiting a system call. */
- if (WIFSTOPPED (status)
- && ((WSTOPSIG (status) == TRAP_IS_SYSCALL)
- || (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)))
+ /* Handle GNU/Linux's extended waitstatus for trace events. */
+ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
{
if (debug_linux_nat)
fprintf_unfiltered (gdb_stdlog,
@@ -2863,7 +2841,7 @@ linux_nat_wait_1 (struct target_ops *ops
int status = 0;
pid_t pid;
- if (debug_linux_nat_async)
+ if (debug_linux_nat || debug_linux_nat_async)
fprintf_unfiltered (gdb_stdlog, "LLW: enter\n");
/* The first time we get here after starting a new inferior, we may
@@ -3013,12 +2991,6 @@ retry:
lp = linux_nat_filter_event (lwpid, status, options);
- /* If this was a syscall trap, we no longer need or want
- the 0x80 flag, remove it. */
- if (WIFSTOPPED (status)
- && WSTOPSIG (status) == TRAP_IS_SYSCALL)
- status = TRAP_REMOVE_SYSCALL_FLAG (status);
-
if (lp
&& ptid_is_pid (ptid)
&& ptid_get_pid (lp->ptid) != ptid_get_pid (ptid))
@@ -3108,7 +3080,7 @@ retry:
/* No interesting event. */
ourstatus->kind = TARGET_WAITKIND_IGNORE;
- if (debug_linux_nat_async)
+ if (debug_linux_nat || debug_linux_nat_async)
fprintf_unfiltered (gdb_stdlog, "LLW: exit (ignore)\n");
restore_child_signals_mask (&prev_mask);
@@ -3137,7 +3109,10 @@ retry:
if (WIFSTOPPED (status))
{
- int signo = target_signal_from_host (WSTOPSIG (status));
+ int stopsig = (WSTOPSIG (status) == TRAP_IS_SYSCALL
+ ? WSTOPSIG (TRAP_REMOVE_SYSCALL_FLAG (status))
+ : WSTOPSIG (status));
+ int signo = target_signal_from_host (stopsig);
struct inferior *inf;
inf = find_inferior_pid (ptid_get_pid (lp->ptid));
@@ -3222,6 +3197,50 @@ retry:
the comment in cancel_breakpoints_callback to find out why. */
iterate_over_lwps (minus_one_ptid, cancel_breakpoints_callback, lp);
+ /* Check for caught syscalls (via "catch syscall"). */
+ if (WIFSTOPPED (status)
+ && WSTOPSIG (status) == TRAP_IS_SYSCALL)
+ {
+ if (catch_syscall_enabled () == 0)
+ lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
+ else
+ {
+ struct regcache *regcache = get_thread_regcache (lp->ptid);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+
+ lp->waitstatus.value.syscall_number =
+ (int) gdbarch_get_syscall_number (gdbarch, lp->ptid);
+
+ /* If we are catching this specific syscall number, then we
+ should update the target_status to reflect which event
+ has occurred. But if this syscall is not to be caught,
+ then we can safely mark the event as a SYSCALL_RETURN.
+
+ This is particularly needed if:
+
+ - We are catching any syscalls, or
+ - We are catching the syscall "exit"
+
+ In this case, as the syscall "exit" *doesn't* return,
+ then GDB would be confused because it would mark the last
+ syscall event as a SYSCALL_ENTRY. After that, if we re-ran the
+ inferior GDB will think that the first syscall event is
+ the opposite of a SYSCALL_ENTRY, which is the SYSCALL_RETURN.
+ Therefore, GDB would report inverted syscall events. */
+ if (catching_syscall_number (lp->waitstatus.value.syscall_number))
+ lp->waitstatus.kind =
+ (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ?
+ TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY;
+ else
+ lp->waitstatus.kind = TARGET_WAITKIND_SYSCALL_RETURN;
+
+ lp->syscall_state = lp->waitstatus.kind;
+ }
+
+ /* We no longer need or want the 0x80 flag, remove it. */
+ status = TRAP_REMOVE_SYSCALL_FLAG (status);
+ }
+
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
{
if (debug_linux_nat)
@@ -3238,7 +3257,7 @@ retry:
else
store_waitstatus (ourstatus, status);
- if (debug_linux_nat_async)
+ if (debug_linux_nat || debug_linux_nat_async)
fprintf_unfiltered (gdb_stdlog, "LLW: exit\n");
restore_child_signals_mask (&prev_mask);
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-09-29 14:32 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-09-28 19:39 [RFC] mask off is-syscall bit for TRAP_IS_SYSCALL Doug Evans
2009-09-28 19:46 ` Sérgio Durigan Júnior
2009-09-28 19:58 ` Pedro Alves
2009-09-28 23:27 ` Pedro Alves
2009-09-29 12:45 Doug Evans
2009-09-29 14:32 ` Pedro Alves
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox