* [PATCH] Implement 'catch syscall' for gdbserver @ 2015-10-30 11:02 Josh Stone 2015-10-30 13:26 ` Eli Zaretskii ` (3 more replies) 0 siblings, 4 replies; 49+ messages in thread From: Josh Stone @ 2015-10-30 11:02 UTC (permalink / raw) To: gdb-patches; +Cc: sergiodj, palves, philippe.waroquiers, Josh Stone This adds a new QCatchSyscalls packet to enable 'catch syscall', and new stop reasons "syscall_entry" and "syscall_return" for those events. It is currently only supported on Linux x86 and x86_64. Based on work from Philippe Waroquiers <philippe.waroquiers@skynet.be>. Beyond simple rebasing, I've also updated it to store the syscall catch lists uniquely to each target process, and updated entry/return logic from checking ENOSYS to now matching gdb's current Linux logic. gdb/ChangeLog: 2015-10-29 Josh Stone <jistone@redhat.com> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new GDBserver support for catch syscall. * remote.c (PACKET_QCatchSyscalls): New enum. (remote_set_syscall_catchpoint): New function. (remote_protocol_features): New element for QCatchSyscalls. (remote_parse_stop_reply): Parse syscall_entry/return stops. (init_remote_ops): Install remote_set_syscall_catchpoint. (_initialize_remote): Config QCatchSyscalls. gdb/doc/ChangeLog: 2015-10-29 Josh Stone <jistone@redhat.com> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. (Stop Reply Packets): List the syscall entry and return stop reasons. (General Query Packets): Describe QCatchSyscalls, and add it to the table and detailed list of stub features. gdb/gdbserver/ChangeLog: 2015-10-29 Josh Stone <jistone@redhat.com> * inferiors.h: Include "gdb_vecs.h". (struct process_info): Add syscalls_to_catch. * inferiors.c (remove_process): Free syscalls_to_catch. * remote-utils.c (prepare_resume_reply): Report syscall_entry and syscall_resume stops. * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. * server.c (handle_general_set): Handle QCatchSyscalls. (handle_query): Report support for QCatchSyscalls. * target.h (struct target_ops): Add supports_catch_syscall. (target_supports_catch_syscall): New macro. * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. (struct lwp_info): Add syscall_state. * linux-low.c (SYSCALL_SIGTRAP): Define. (handle_extended_wait): Mark syscall_state like an entry. (get_syscall_trapinfo): New function, proxy to the_low_target. (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. (linux_low_filter_event): Set ptrace options even before arch-specific setup. Either toggle syscall_state entry/return or set ignored. (gdb_catching_syscalls_p): New function. (gdb_catch_this_syscall_p): New function. (linux_wait_1): Handle SYSCALL_SIGTRAP. (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. (linux_supports_catch_syscall): New function. (linux_target_ops): Install it. * linux-x86-low.c (x86_get_syscall_trapinfo): New function. (the_low_target): Install it. * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. * spu-low.c (spu_target_ops): Likewise. * win32-low.c (win32_target_ops): Likewise. gdb/testsuite/ChangeLog: 2015-10-29 Josh Stone <jistone@redhat.com> * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux remote targets. (do_syscall_tests): Only test mid-vfork on local or extended-remote. --- gdb/NEWS | 10 ++ gdb/doc/gdb.texinfo | 56 +++++++++++ gdb/gdbserver/inferiors.c | 1 + gdb/gdbserver/inferiors.h | 5 + gdb/gdbserver/linux-low.c | 158 +++++++++++++++++++++++++++++-- gdb/gdbserver/linux-low.h | 13 +++ gdb/gdbserver/linux-x86-low.c | 31 ++++++ gdb/gdbserver/nto-low.c | 1 + gdb/gdbserver/remote-utils.c | 12 +++ gdb/gdbserver/server.c | 49 ++++++++++ gdb/gdbserver/server.h | 6 ++ gdb/gdbserver/spu-low.c | 1 + gdb/gdbserver/target.h | 8 ++ gdb/gdbserver/win32-low.c | 1 + gdb/remote.c | 116 +++++++++++++++++++++++ gdb/testsuite/gdb.base/catch-syscall.exp | 15 ++- 16 files changed, 472 insertions(+), 11 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index b2b1e99d58c6..9c9b4b04a146 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -77,6 +77,11 @@ exec-events feature in qSupported response can contain the corresponding 'stubfeature'. Set and show commands can be used to display whether these features are enabled. +QCatchSyscalls:1 [;SYSNO]... +QCatchSyscalls:0 + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") + catching syscalls from the inferior process. + * Extended-remote exec events ** GDB now has support for exec events on extended-remote Linux targets. @@ -87,6 +92,11 @@ set remote exec-event-feature-packet show remote exec-event-feature-packet Set/show the use of the remote exec event feature. +* New features in the GDB remote stub, GDBserver + + ** GDBserver now supports catch syscall. Currently enabled + on x86/x86_64 GNU/Linux targets. + *** Changes in GDB 7.10 * Support for process record-replay and reverse debugging on aarch64*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 3c1f7857393c..d8ed630da3fc 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20121,6 +20121,10 @@ are: @tab @code{qSupported} @tab Remote communications parameters +@item @code{catch-syscalls} +@tab @code{QCatchSyscalls} +@tab @code{catch syscall} + @item @code{pass-signals} @tab @code{QPassSignals} @tab @code{handle @var{signal}} @@ -35418,6 +35422,11 @@ The currently defined stop reasons are: The packet indicates a watchpoint hit, and @var{r} is the data address, in hex. +@item syscall_entry +@itemx syscall_return +The packet indicates a syscall entry or return, and @var{r} is the +syscall number, in hex. + @cindex shared library events, remote reply @item library The packet indicates that the loaded libraries have changed. @@ -35878,6 +35887,44 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). Use of this packet is controlled by the @code{set non-stop} command; @pxref{Non-Stop Mode}. +@item QCatchSyscalls:1 @r{[};@var{sysno}@r{]}@dots{} +@itemx QCatchSyscalls:0 +@cindex catch syscalls from inferior, remote request +@cindex @samp{QCatchSyscalls} packet +@anchor{QCatchSyscalls} +Enable (@samp{QCatchSyscalls:1}) or disable (@samp{QCatchSyscalls:0}) +catching syscalls from the inferior process. + +For @samp{QCatchSyscalls:1}, each listed syscall @var{sysno} (encoded +in hex) should be reported to @value{GDBN}. If no syscall @var{sysno} +is listed, every system call should be reported. + +Note that if a syscall not member of the list is reported, @value{GDBN} +will filter it if this syscall is not caught. It is however more efficient +to only report the needed syscalls. + +Multiple @samp{QCatchSyscalls:1} packets do not +combine; any earlier @samp{QCatchSyscalls:1} list is completely replaced by the +new list. + +Reply: +@table @samp +@item OK +The request succeeded. + +@item E @var{nn} +An error occurred. @var{nn} are hex digits. + +@item @w{} +An empty reply indicates that @samp{QCatchSyscalls} is not supported by +the stub. +@end table + +Use of this packet is controlled by the @code{set remote catch-syscalls} +command (@pxref{Remote Configuration, set remote catch-syscalls}). +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} @cindex pass signals to inferior, remote request @cindex @samp{QPassSignals} packet @@ -36296,6 +36343,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{QCatchSyscalls} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QPassSignals} @tab No @tab @samp{-} @@ -36489,6 +36541,10 @@ packet (@pxref{qXfer fdpic loadmap read}). The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). +@item QCatchSyscalls +The remote stub understands the @samp{QCatchSyscalls} packet +(@pxref{QCatchSyscalls}). + @item QPassSignals The remote stub understands the @samp{QPassSignals} packet (@pxref{QPassSignals}). diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 72a3ef1b1b61..a8263656a4af 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -316,6 +316,7 @@ remove_process (struct process_info *process) free_all_breakpoints (process); gdb_assert (find_thread_process (process) == NULL); remove_inferior (&all_processes, &process->entry); + VEC_free (int, process->syscalls_to_catch); free (process); } diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h index d7226163c0e8..43fc869f6612 100644 --- a/gdb/gdbserver/inferiors.h +++ b/gdb/gdbserver/inferiors.h @@ -19,6 +19,8 @@ #ifndef INFERIORS_H #define INFERIORS_H +#include "gdb_vecs.h" + /* Generic information for tracking a list of ``inferiors'' - threads, processes, etc. */ struct inferior_list @@ -67,6 +69,9 @@ struct process_info /* The list of installed fast tracepoints. */ struct fast_tracepoint_jump *fast_tracepoint_jumps; + /* The list of syscalls to report, or just ANY_SYSCALL. */ + VEC (int) *syscalls_to_catch; + const struct target_desc *tdesc; /* Private target data. */ diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 41ab510fa4ac..c2c513130997 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -70,6 +70,11 @@ #define O_LARGEFILE 0 #endif +/* Unlike other extended result codes, WSTOPSIG (status) on + PTRACE_O_TRACESYSGOOD syscall events doesn't return SIGTRAP, but + instead SIGTRAP with bit 7 set. */ +#define SYSCALL_SIGTRAP (SIGTRAP | 0x80) + /* Some targets did not define these ptrace constants from the start, so gdbserver defines them locally here. In the future, these may be removed after they are added to asm/ptrace.h. */ @@ -447,6 +452,11 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) struct thread_info *event_thr = get_lwp_thread (event_lwp); struct lwp_info *new_lwp; + /* All extended events we currently use are mid-syscall. Only + PTRACE_EVENT_STOP is delivered more like a signal-stop, but + you have to be using PTRACE_SEIZE to get that. */ + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) || (event == PTRACE_EVENT_CLONE)) { @@ -662,6 +672,40 @@ get_pc (struct lwp_info *lwp) return pc; } +/* This function should only be called if LWP got a SYSCALL_SIGTRAP. + Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. */ + +static void +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno, int *sysret) +{ + struct thread_info *saved_thread; + struct regcache *regcache; + + if (the_low_target.get_syscall_trapinfo == NULL) + { + /* If we cannot get the syscall trapinfo, report an unknown + system call number and -ENOSYS return value. */ + *sysno = UNKNOWN_SYSCALL; + *sysret = -ENOSYS; + return; + } + + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + + regcache = get_thread_regcache (current_thread, 1); + (*the_low_target.get_syscall_trapinfo) (regcache, sysno, sysret); + + if (debug_threads) + { + debug_printf ("get_syscall_trapinfo sysno %d sysret %d\n", + *sysno, *sysret); + } + + current_thread = saved_thread; +} + /* This function should only be called if LWP got a SIGTRAP. The SIGTRAP could mean several things. @@ -2154,6 +2198,8 @@ linux_low_ptrace_options (int attached) if (report_exec_events) options |= PTRACE_O_TRACEEXEC; + options |= PTRACE_O_TRACESYSGOOD; + return options; } @@ -2249,6 +2295,16 @@ linux_low_filter_event (int lwpid, int wstat) gdb_assert (WIFSTOPPED (wstat)); + /* Set ptrace flags ASAP, so no events can be missed. */ + if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) + { + struct process_info *proc = find_process_pid (pid_of (thread)); + int options = linux_low_ptrace_options (proc->attached); + + linux_enable_event_reporting (lwpid, options); + child->must_set_ptrace_flags = 0; + } + if (WIFSTOPPED (wstat)) { struct process_info *proc; @@ -2276,13 +2332,19 @@ linux_low_filter_event (int lwpid, int wstat) } } - if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) + /* Always update syscall_state, even if it will be filtered later. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) { - struct process_info *proc = find_process_pid (pid_of (thread)); - int options = linux_low_ptrace_options (proc->attached); - - linux_enable_event_reporting (lwpid, options); - child->must_set_ptrace_flags = 0; + child->syscall_state = + child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY + ? TARGET_WAITKIND_SYSCALL_RETURN + : TARGET_WAITKIND_SYSCALL_ENTRY; + } + else + { + /* Almost all other ptrace-stops are known to be outside of system + calls, with further exceptions in handle_extended_wait. */ + child->syscall_state = TARGET_WAITKIND_IGNORE; } /* Be careful to not overwrite stop_pc until @@ -2885,6 +2947,44 @@ ignore_event (struct target_waitstatus *ourstatus) return null_ptid; } +/* Returns 1 if GDB is interested in any event_child syscalls. */ + +static int +gdb_catching_syscalls_p (struct lwp_info *event_child) +{ + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + return !VEC_empty (int, proc->syscalls_to_catch); +} + +/* Returns 1 if GDB is interested in the event_child syscall. + Only to be called when stopped reason is SYSCALL_SIGTRAP. */ + +static int +gdb_catch_this_syscall_p (struct lwp_info *event_child) +{ + int i, iter; + int sysno, sysret; + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + if (VEC_empty (int, proc->syscalls_to_catch)) + return 0; + + if (VEC_index (int, proc->syscalls_to_catch, 0) == ANY_SYSCALL) + return 1; + + get_syscall_trapinfo (event_child, &sysno, &sysret); + for (i = 0; + VEC_iterate (int, proc->syscalls_to_catch, i, iter); + i++) + if (iter == sysno) + return 1; + + return 0; +} + /* Wait for process, returns status. */ static ptid_t @@ -3195,6 +3295,22 @@ linux_wait_1 (ptid_t ptid, /* Check whether GDB would be interested in this event. */ + /* Check if GDB is interested in this syscall. */ + if (WIFSTOPPED (w) + && WSTOPSIG (w) == SYSCALL_SIGTRAP + && !gdb_catch_this_syscall_p (event_child)) + { + if (debug_threads) + { + debug_printf ("Ignored syscall for LWP %ld.\n", + lwpid_of (current_thread)); + } + + linux_resume_one_lwp (event_child, event_child->stepping, + 0, NULL); + return ignore_event (ourstatus); + } + /* If GDB is not interested in this signal, don't stop other threads, and don't report it to GDB. Just resume the inferior right away. We do this for threading-related signals as well as @@ -3449,8 +3565,16 @@ linux_wait_1 (ptid_t ptid, } } - if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) == SIGSTOP) + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) + { + int sysret; + + get_syscall_trapinfo (event_child, + &ourstatus->value.syscall_number, &sysret); + ourstatus->kind = event_child->syscall_state; + } + else if (current_thread->last_resume_kind == resume_stop + && WSTOPSIG (w) == SIGSTOP) { /* A thread that has been requested to stop by GDB with vCont;t, and it stopped cleanly, so report as SIG0. The use of @@ -3867,6 +3991,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, struct thread_info *thread = get_lwp_thread (lwp); struct thread_info *saved_thread; int fast_tp_collecting; + int ptrace_request; struct process_info *proc = get_thread_process (thread); /* Note that target description may not be initialised @@ -4052,7 +4177,14 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, regcache_invalidate_thread (thread); errno = 0; lwp->stepping = step; - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread), + if (step) + ptrace_request = PTRACE_SINGLESTEP; + else if (gdb_catching_syscalls_p (lwp)) + ptrace_request = PTRACE_SYSCALL; + else + ptrace_request = PTRACE_CONT; + ptrace (ptrace_request, + lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, /* Coerce to a uintptr_t first to avoid potential gcc warning of coercing an 8 byte integer to a 4 byte pointer. */ @@ -6135,6 +6267,13 @@ linux_process_qsupported (const char *query) } static int +linux_supports_catch_syscall (void) +{ + return (the_low_target.get_syscall_trapinfo != NULL + && linux_supports_tracesysgood()); +} + +static int linux_supports_tracepoints (void) { if (*the_low_target.supports_tracepoints == NULL) @@ -7010,6 +7149,7 @@ static struct target_ops linux_target_ops = { linux_common_core_of_thread, linux_read_loadmap, linux_process_qsupported, + linux_supports_catch_syscall, linux_supports_tracepoints, linux_read_pc, linux_write_pc, diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index ccf4c9421d87..71d72f48ea3a 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -201,6 +201,12 @@ struct linux_target_ops /* Hook to support target specific qSupported. */ void (*process_qsupported) (const char *); + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. Only to be called when inferior is stopped + due to SYSCALL_SIGTRAP. */ + void (*get_syscall_trapinfo) (struct regcache *regcache, + int *sysno, int *sysret); + /* Returns true if the low target supports tracepoints. */ int (*supports_tracepoints) (void); @@ -271,6 +277,13 @@ struct lwp_info event already received in a wait()). */ int stopped; + /* Signal wether we are in a SYSCALL_ENTRY or + in a SYSCALL_RETURN event. + Values: + - TARGET_WAITKIND_SYSCALL_ENTRY + - TARGET_WAITKIND_SYSCALL_RETURN */ + enum target_waitkind syscall_state; + /* When stopped is set, the last wait status recorded for this lwp. */ int last_status; diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index 89ec4e54b3b8..6e3c589de8fb 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -1432,6 +1432,36 @@ x86_arch_setup (void) current_process ()->tdesc = x86_linux_read_description (); } +/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return + code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ + +static void +x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno, int *sysret) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + long l_sysno; + long l_sysret; + + collect_register_by_name (regcache, "orig_rax", &l_sysno); + collect_register_by_name (regcache, "rax", &l_sysret); + *sysno = (int) l_sysno; + *sysret = (int) l_sysret; + } + else + { + int l_sysno; + int l_sysret; + + collect_register_by_name (regcache, "orig_eax", &l_sysno); + collect_register_by_name (regcache, "eax", &l_sysret); + *sysno = (int) l_sysno; + *sysret = (int) l_sysret; + } +} + static int x86_supports_tracepoints (void) { @@ -3292,6 +3322,7 @@ struct linux_target_ops the_low_target = x86_linux_new_fork, x86_linux_prepare_to_resume, x86_linux_process_qsupported, + x86_get_syscall_trapinfo, x86_supports_tracepoints, x86_get_thread_area, x86_install_fast_tracepoint_jump_pad, diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index d72c46515d13..1301acea49b7 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -979,6 +979,7 @@ static struct target_ops nto_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index e36609176afa..19eed77d4874 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1119,6 +1119,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, case TARGET_WAITKIND_VFORKED: case TARGET_WAITKIND_VFORK_DONE: case TARGET_WAITKIND_EXECD: + case TARGET_WAITKIND_SYSCALL_ENTRY: + case TARGET_WAITKIND_SYSCALL_RETURN: { struct thread_info *saved_thread; const char **regp; @@ -1161,6 +1163,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, status->value.execd_pathname = NULL; buf += strlen (buf); } + else if ((status->kind == TARGET_WAITKIND_SYSCALL_ENTRY) + || (status->kind == TARGET_WAITKIND_SYSCALL_RETURN)) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + ? "syscall_entry" : "syscall_return"); + + sprintf (buf, "T%02x%s:%x;", signal, event, + status->value.syscall_number); + } else sprintf (buf, "T%02x", status->value.sig); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index fd2804beaa4e..72621f261dfa 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -592,6 +592,52 @@ handle_general_set (char *own_buf) return; } + if (startswith (own_buf, "QCatchSyscalls:1")) + { + const char *p; + CORE_ADDR sysno; + struct process_info *process; + + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + process = current_process (); + + VEC_truncate (int, process->syscalls_to_catch, 0); + + p = own_buf + strlen("QCatchSyscalls:1"); + if (*p == ';') + { + p += 1; + while (*p) + { + p = decode_address_to_semicolon (&sysno, p); + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); + } + } + else + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); + + write_ok (own_buf); + return; + } + + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) + { + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + VEC_free (int, current_process ()->syscalls_to_catch); + write_ok (own_buf); + return; + } + if (startswith (own_buf, "QProgramSignals:")) { int numsigs = (int) GDB_SIGNAL_LAST, i; @@ -2140,6 +2186,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) "PacketSize=%x;QPassSignals+;QProgramSignals+", PBUFSIZ - 1); + if (target_supports_catch_syscall ()) + strcat (own_buf, ";QCatchSyscalls+"); + if (the_target->qxfer_libraries_svr4 != NULL) strcat (own_buf, ";qXfer:libraries-svr4:read+" ";augmented-libraries-svr4-read+"); diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 96ad4fa58b7c..a8780ebfbc65 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -133,4 +133,10 @@ extern void discard_queued_stop_replies (ptid_t ptid); as large as the largest register set supported by gdbserver. */ #define PBUFSIZ 16384 +/* Definition for an unknown syscall, used basically in error-cases. */ +#define UNKNOWN_SYSCALL (-1) + +/* Definition for any syscall, used for unfiltered syscall reporting. */ +#define ANY_SYSCALL (-2) + #endif /* SERVER_H */ diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c index 89bed7a02dd1..55ec0caef296 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -699,6 +699,7 @@ static struct target_ops spu_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 769c876ede49..ef8a7680ccca 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -309,6 +309,10 @@ struct target_ops /* Target specific qSupported support. */ void (*process_qsupported) (const char *); + /* Return 1 if the target supports catch syscall, 0 (or leave the + callback NULL) otherwise. */ + int (*supports_catch_syscall) (void); + /* Return 1 if the target supports tracepoints, 0 (or leave the callback NULL) otherwise. */ int (*supports_tracepoints) (void); @@ -526,6 +530,10 @@ int kill_inferior (int); the_target->process_qsupported (query); \ } while (0) +#define target_supports_catch_syscall() \ + (the_target->supports_catch_syscall ? \ + (*the_target->supports_catch_syscall) () : 0) + #define target_supports_tracepoints() \ (the_target->supports_tracepoints \ ? (*the_target->supports_tracepoints) () : 0) diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index 6e33509c0b50..4314513876fa 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1844,6 +1844,7 @@ static struct target_ops win32_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/remote.c b/gdb/remote.c index fed397affeab..41751e9d93b1 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1388,6 +1388,7 @@ enum { PACKET_qSupported, PACKET_qTStatus, PACKET_QPassSignals, + PACKET_QCatchSyscalls, PACKET_QProgramSignals, PACKET_qCRC, PACKET_qSearch_memory, @@ -1973,6 +1974,99 @@ remote_pass_signals (struct target_ops *self, } } +/* If 'QCatchSyscalls' is supported, tell the remote stub + to report syscalls to GDB. */ + +static int +remote_set_syscall_catchpoint (struct target_ops *self, + int pid, int needed, int any_count, + int table_size, int *table) +{ + char *catch_packet, *p; + enum packet_result result; + int n_sysno = 0; + + if (remote_protocol_packets[PACKET_QCatchSyscalls].support == PACKET_DISABLE) + { + /* Not supported. */ + return 1; + } + + if (needed && !any_count) + { + int i; + + /* Count how many syscalls are to be caught (table[sysno] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i]) + n_sysno++; + } + } + + if (remote_debug) + { + fprintf_unfiltered (gdb_stdlog, + "remote_set_syscall_catchpoint " + "pid %d needed %d any_count %d n_sysno %d\n", + pid, needed, any_count, n_sysno); + } + + if (needed) + { + /* Prepare a packet with the sysno list, assuming max 8+1 + characters for a sysno. If the resulting packet size is too + big, fallback on the non selective packet. */ + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; + + catch_packet = xmalloc (maxpktsz); + strcpy (catch_packet, "QCatchSyscalls:1"); + if (!any_count) + { + int i; + char *p; + + p = catch_packet; + p += strlen (p); + + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i]) + { + xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); + p += strlen (p); + } + } + } + if (strlen (catch_packet) > get_remote_packet_size ()) + { + /* catch_packet too big. Fallback to less efficient + non selective mode, with GDB doing the filtering. */ + catch_packet[strlen ("QCatchSyscalls:1")] = 0; + } + } + else + { + catch_packet = xmalloc (strlen ("QCatchSyscalls:0") + 1); + strcpy (catch_packet, "QCatchSyscalls:0"); + } + + { + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + + putpkt (catch_packet); + getpkt (&rs->buf, &rs->buf_size, 0); + result = packet_ok (buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); + xfree (catch_packet); + if (result == PACKET_OK) + return 0; + else + return -1; + } +} + /* If 'QProgramSignals' is supported, tell the remote stub what signals it should pass through to the inferior when detaching. */ @@ -4328,6 +4422,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_traceframe_info }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, + { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet, + PACKET_QCatchSyscalls }, { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QProgramSignals }, { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, @@ -6159,6 +6255,22 @@ Packet: '%s'\n"), if (strprefix (p, p1, "thread")) event->ptid = read_ptid (++p1, &p); + else if (strprefix (p, p1, "syscall_entry")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } + else if (strprefix (p, p1, "syscall_return")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } else if (strprefix (p, p1, "watch") || strprefix (p, p1, "rwatch") || strprefix (p, p1, "awatch")) @@ -12734,6 +12846,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_load = remote_load; remote_ops.to_mourn_inferior = remote_mourn; remote_ops.to_pass_signals = remote_pass_signals; + remote_ops.to_set_syscall_catchpoint = remote_set_syscall_catchpoint; remote_ops.to_program_signals = remote_program_signals; remote_ops.to_thread_alive = remote_thread_alive; remote_ops.to_update_thread_list = remote_update_thread_list; @@ -13263,6 +13376,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], "QPassSignals", "pass-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QCatchSyscalls], + "QCatchSyscalls", "catch-syscalls", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], "QProgramSignals", "program-signals", 0); diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp index c1cfe23cdddb..0ba078db22ac 100644 --- a/gdb/testsuite/gdb.base/catch-syscall.exp +++ b/gdb/testsuite/gdb.base/catch-syscall.exp @@ -19,7 +19,15 @@ # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> # on September/2008. -if { [is_remote target] || ![isnative] } then { +if { ![isnative] } then { + continue +} + +# This shall be updated whenever QCatchSyscalls packet support is implemented +# on some gdbserver architecture. +if { [is_remote target] + && ![istarget "x86_64-*-linux*"] + && ![istarget "i\[34567\]86-*-linux*"] } { continue } @@ -390,7 +398,10 @@ proc do_syscall_tests {} { if [runto_main] then { test_catch_syscall_skipping_return } # Testing the 'catch syscall' command starting mid-vfork. - if [runto_main] then { test_catch_syscall_mid_vfork } + # (Only local or extended-remote can use "catch vfork".) + if { ![is_remote target] || [target_info gdb_protocol] == "extended-remote" } { + if [runto_main] then { test_catch_syscall_mid_vfork } + } # Testing if the 'catch syscall' command works when switching to # different architectures on-the-fly (PR gdb/10737). -- 2.4.3 ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH] Implement 'catch syscall' for gdbserver 2015-10-30 11:02 [PATCH] Implement 'catch syscall' for gdbserver Josh Stone @ 2015-10-30 13:26 ` Eli Zaretskii 2015-11-01 22:15 ` Doug Evans ` (2 subsequent siblings) 3 siblings, 0 replies; 49+ messages in thread From: Eli Zaretskii @ 2015-10-30 13:26 UTC (permalink / raw) To: Josh Stone; +Cc: gdb-patches, sergiodj, palves, philippe.waroquiers, jistone > From: Josh Stone <jistone@redhat.com> > Cc: sergiodj@redhat.com, palves@redhat.com, philippe.waroquiers@skynet.be, Josh Stone <jistone@redhat.com> > Date: Thu, 29 Oct 2015 18:52:26 -0700 > > gdb/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new > GDBserver support for catch syscall. > * remote.c (PACKET_QCatchSyscalls): New enum. > (remote_set_syscall_catchpoint): New function. > (remote_protocol_features): New element for QCatchSyscalls. > (remote_parse_stop_reply): Parse syscall_entry/return stops. > (init_remote_ops): Install remote_set_syscall_catchpoint. > (_initialize_remote): Config QCatchSyscalls. > > gdb/doc/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > (Stop Reply Packets): List the syscall entry and return stop reasons. > (General Query Packets): Describe QCatchSyscalls, and add it to the > table and detailed list of stub features. > > gdb/gdbserver/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * inferiors.h: Include "gdb_vecs.h". > (struct process_info): Add syscalls_to_catch. > * inferiors.c (remove_process): Free syscalls_to_catch. > * remote-utils.c (prepare_resume_reply): Report syscall_entry and > syscall_resume stops. > * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. > * server.c (handle_general_set): Handle QCatchSyscalls. > (handle_query): Report support for QCatchSyscalls. > * target.h (struct target_ops): Add supports_catch_syscall. > (target_supports_catch_syscall): New macro. > * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. > (struct lwp_info): Add syscall_state. > * linux-low.c (SYSCALL_SIGTRAP): Define. > (handle_extended_wait): Mark syscall_state like an entry. > (get_syscall_trapinfo): New function, proxy to the_low_target. > (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. > (linux_low_filter_event): Set ptrace options even before arch-specific > setup. Either toggle syscall_state entry/return or set ignored. > (gdb_catching_syscalls_p): New function. > (gdb_catch_this_syscall_p): New function. > (linux_wait_1): Handle SYSCALL_SIGTRAP. > (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. > (linux_supports_catch_syscall): New function. > (linux_target_ops): Install it. > * linux-x86-low.c (x86_get_syscall_trapinfo): New function. > (the_low_target): Install it. > * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. > * spu-low.c (spu_target_ops): Likewise. > * win32-low.c (win32_target_ops): Likewise. > > gdb/testsuite/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux > remote targets. > (do_syscall_tests): Only test mid-vfork on local or extended-remote. The documentation parts are OK, with this minor comment and one question. Here's the comment: > +Note that if a syscall not member of the list is reported, @value{GDBN} ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ "a syscall not in the list" sounds simpler and more clear, and doesn't change the meaning. > +will filter it if this syscall is not caught. It is however more efficient > +to only report the needed syscalls. The question is about the same sentence: maybe because I don't really use this stuff, I'm not sure I understand the distinction between "reported" and "caught" here: what does it mean for a syscall to be reported, but not caught? Perhaps this text should be clarified to not cause such confusion. Thanks. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH] Implement 'catch syscall' for gdbserver 2015-10-30 11:02 [PATCH] Implement 'catch syscall' for gdbserver Josh Stone 2015-10-30 13:26 ` Eli Zaretskii @ 2015-11-01 22:15 ` Doug Evans 2015-11-02 18:24 ` Josh Stone 2015-11-23 4:20 ` Doug Evans 2015-11-26 2:53 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Josh Stone 3 siblings, 1 reply; 49+ messages in thread From: Doug Evans @ 2015-11-01 22:15 UTC (permalink / raw) To: Josh Stone Cc: gdb-patches, Sergio Durigan Junior, Pedro Alves, Philippe Waroquiers On Thu, Oct 29, 2015 at 6:52 PM, Josh Stone <jistone@redhat.com> wrote: > This adds a new QCatchSyscalls packet to enable 'catch syscall', and new > stop reasons "syscall_entry" and "syscall_return" for those events. It > is currently only supported on Linux x86 and x86_64. > > Based on work from Philippe Waroquiers <philippe.waroquiers@skynet.be>. > > Beyond simple rebasing, I've also updated it to store the syscall catch > lists uniquely to each target process, and updated entry/return logic > from checking ENOSYS to now matching gdb's current Linux logic. > > gdb/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new > GDBserver support for catch syscall. > * remote.c (PACKET_QCatchSyscalls): New enum. > (remote_set_syscall_catchpoint): New function. > (remote_protocol_features): New element for QCatchSyscalls. > (remote_parse_stop_reply): Parse syscall_entry/return stops. > (init_remote_ops): Install remote_set_syscall_catchpoint. > (_initialize_remote): Config QCatchSyscalls. > > gdb/doc/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > (Stop Reply Packets): List the syscall entry and return stop reasons. > (General Query Packets): Describe QCatchSyscalls, and add it to the > table and detailed list of stub features. > > gdb/gdbserver/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * inferiors.h: Include "gdb_vecs.h". > (struct process_info): Add syscalls_to_catch. > * inferiors.c (remove_process): Free syscalls_to_catch. > * remote-utils.c (prepare_resume_reply): Report syscall_entry and > syscall_resume stops. > * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. > * server.c (handle_general_set): Handle QCatchSyscalls. > (handle_query): Report support for QCatchSyscalls. > * target.h (struct target_ops): Add supports_catch_syscall. > (target_supports_catch_syscall): New macro. > * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. > (struct lwp_info): Add syscall_state. > * linux-low.c (SYSCALL_SIGTRAP): Define. > (handle_extended_wait): Mark syscall_state like an entry. > (get_syscall_trapinfo): New function, proxy to the_low_target. > (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. > (linux_low_filter_event): Set ptrace options even before arch-specific > setup. Either toggle syscall_state entry/return or set ignored. > (gdb_catching_syscalls_p): New function. > (gdb_catch_this_syscall_p): New function. > (linux_wait_1): Handle SYSCALL_SIGTRAP. > (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. > (linux_supports_catch_syscall): New function. > (linux_target_ops): Install it. > * linux-x86-low.c (x86_get_syscall_trapinfo): New function. > (the_low_target): Install it. > * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. > * spu-low.c (spu_target_ops): Likewise. > * win32-low.c (win32_target_ops): Likewise. > > gdb/testsuite/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux > remote targets. > (do_syscall_tests): Only test mid-vfork on local or extended-remote. Hi. I haven't reviewed the patch completely yet, but one comment. We generally have a convention for recording all significant authors of a patch in the ChangeLog entry. If Philippe doesn't want his name in the c/l entry that's cool, but if there is a significant amount of his work here we should note it in the c/l entry. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH] Implement 'catch syscall' for gdbserver 2015-11-01 22:15 ` Doug Evans @ 2015-11-02 18:24 ` Josh Stone 2015-11-21 10:29 ` Philippe Waroquiers 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2015-11-02 18:24 UTC (permalink / raw) To: Doug Evans Cc: gdb-patches, Sergio Durigan Junior, Pedro Alves, Philippe Waroquiers On 11/01/2015 02:14 PM, Doug Evans wrote: > Hi. I haven't reviewed the patch completely yet, but one comment. > We generally have a convention for recording all significant authors > of a patch in the ChangeLog entry. > If Philippe doesn't want his name in the c/l entry that's cool, > but if there is a significant amount of his work here we should note > it in the c/l entry. Philippe doesn't seem to care much [1] but I am happy to credit him however the project deems proper. I see now that there are occasional entries in the ChangeLog with multiple names, so I'll definitely add Philippe that way here. [1] https://sourceware.org/ml/gdb-patches/2015-09/msg00362.html ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH] Implement 'catch syscall' for gdbserver 2015-11-02 18:24 ` Josh Stone @ 2015-11-21 10:29 ` Philippe Waroquiers 2015-11-23 4:20 ` Doug Evans 0 siblings, 1 reply; 49+ messages in thread From: Philippe Waroquiers @ 2015-11-21 10:29 UTC (permalink / raw) To: gdb-patches; +Cc: Doug Evans, Sergio Durigan Junior, Pedro Alves, Josh Stone On Mon, 2015-11-02 at 10:24 -0800, Josh Stone wrote: > On 11/01/2015 02:14 PM, Doug Evans wrote: > > Hi. I haven't reviewed the patch completely yet, but one comment. Any news about review ? It would be nice if the patch could go in the next gdb version. Thanks Philippe ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH] Implement 'catch syscall' for gdbserver 2015-11-21 10:29 ` Philippe Waroquiers @ 2015-11-23 4:20 ` Doug Evans 0 siblings, 0 replies; 49+ messages in thread From: Doug Evans @ 2015-11-23 4:20 UTC (permalink / raw) To: Philippe Waroquiers Cc: gdb-patches, Sergio Durigan Junior, Pedro Alves, Josh Stone Philippe Waroquiers <philippe.waroquiers@skynet.be> writes: > On Mon, 2015-11-02 at 10:24 -0800, Josh Stone wrote: >> On 11/01/2015 02:14 PM, Doug Evans wrote: >> > Hi. I haven't reviewed the patch completely yet, but one comment. > Any news about review ? > It would be nice if the patch could go in the next gdb version. Thanks for the ping. Done. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH] Implement 'catch syscall' for gdbserver 2015-10-30 11:02 [PATCH] Implement 'catch syscall' for gdbserver Josh Stone 2015-10-30 13:26 ` Eli Zaretskii 2015-11-01 22:15 ` Doug Evans @ 2015-11-23 4:20 ` Doug Evans 2015-11-25 2:37 ` Josh Stone 2015-11-26 2:53 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Josh Stone 3 siblings, 1 reply; 49+ messages in thread From: Doug Evans @ 2015-11-23 4:20 UTC (permalink / raw) To: Josh Stone; +Cc: gdb-patches, sergiodj, palves, philippe.waroquiers Josh Stone <jistone@redhat.com> writes: > This adds a new QCatchSyscalls packet to enable 'catch syscall', and new > stop reasons "syscall_entry" and "syscall_return" for those events. It > is currently only supported on Linux x86 and x86_64. > > Based on work from Philippe Waroquiers <philippe.waroquiers@skynet.be>. > > Beyond simple rebasing, I've also updated it to store the syscall catch > lists uniquely to each target process, and updated entry/return logic > from checking ENOSYS to now matching gdb's current Linux logic. > > gdb/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new > GDBserver support for catch syscall. > * remote.c (PACKET_QCatchSyscalls): New enum. > (remote_set_syscall_catchpoint): New function. > (remote_protocol_features): New element for QCatchSyscalls. > (remote_parse_stop_reply): Parse syscall_entry/return stops. > (init_remote_ops): Install remote_set_syscall_catchpoint. > (_initialize_remote): Config QCatchSyscalls. > > gdb/doc/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > (Stop Reply Packets): List the syscall entry and return stop reasons. > (General Query Packets): Describe QCatchSyscalls, and add it to the > table and detailed list of stub features. > > gdb/gdbserver/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * inferiors.h: Include "gdb_vecs.h". > (struct process_info): Add syscalls_to_catch. > * inferiors.c (remove_process): Free syscalls_to_catch. > * remote-utils.c (prepare_resume_reply): Report syscall_entry and > syscall_resume stops. > * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. > * server.c (handle_general_set): Handle QCatchSyscalls. > (handle_query): Report support for QCatchSyscalls. > * target.h (struct target_ops): Add supports_catch_syscall. > (target_supports_catch_syscall): New macro. > * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. > (struct lwp_info): Add syscall_state. > * linux-low.c (SYSCALL_SIGTRAP): Define. > (handle_extended_wait): Mark syscall_state like an entry. > (get_syscall_trapinfo): New function, proxy to the_low_target. > (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. > (linux_low_filter_event): Set ptrace options even before arch-specific > setup. Either toggle syscall_state entry/return or set ignored. > (gdb_catching_syscalls_p): New function. > (gdb_catch_this_syscall_p): New function. > (linux_wait_1): Handle SYSCALL_SIGTRAP. > (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. > (linux_supports_catch_syscall): New function. > (linux_target_ops): Install it. > * linux-x86-low.c (x86_get_syscall_trapinfo): New function. > (the_low_target): Install it. > * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. > * spu-low.c (spu_target_ops): Likewise. > * win32-low.c (win32_target_ops): Likewise. > > gdb/testsuite/ChangeLog: > > 2015-10-29 Josh Stone <jistone@redhat.com> > > * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux > remote targets. > (do_syscall_tests): Only test mid-vfork on local or extended-remote. > --- > gdb/NEWS | 10 ++ > gdb/doc/gdb.texinfo | 56 +++++++++++ > gdb/gdbserver/inferiors.c | 1 + > gdb/gdbserver/inferiors.h | 5 + > gdb/gdbserver/linux-low.c | 158 +++++++++++++++++++++++++++++-- > gdb/gdbserver/linux-low.h | 13 +++ > gdb/gdbserver/linux-x86-low.c | 31 ++++++ > gdb/gdbserver/nto-low.c | 1 + > gdb/gdbserver/remote-utils.c | 12 +++ > gdb/gdbserver/server.c | 49 ++++++++++ > gdb/gdbserver/server.h | 6 ++ > gdb/gdbserver/spu-low.c | 1 + > gdb/gdbserver/target.h | 8 ++ > gdb/gdbserver/win32-low.c | 1 + > gdb/remote.c | 116 +++++++++++++++++++++++ > gdb/testsuite/gdb.base/catch-syscall.exp | 15 ++- > 16 files changed, 472 insertions(+), 11 deletions(-) > > diff --git a/gdb/NEWS b/gdb/NEWS > index b2b1e99d58c6..9c9b4b04a146 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -77,6 +77,11 @@ exec-events feature in qSupported > response can contain the corresponding 'stubfeature'. Set and > show commands can be used to display whether these features are enabled. > > +QCatchSyscalls:1 [;SYSNO]... > +QCatchSyscalls:0 > + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") > + catching syscalls from the inferior process. > + > * Extended-remote exec events > > ** GDB now has support for exec events on extended-remote Linux targets. > @@ -87,6 +92,11 @@ set remote exec-event-feature-packet > show remote exec-event-feature-packet > Set/show the use of the remote exec event feature. > > +* New features in the GDB remote stub, GDBserver > + > + ** GDBserver now supports catch syscall. Currently enabled > + on x86/x86_64 GNU/Linux targets. > + > *** Changes in GDB 7.10 > > * Support for process record-replay and reverse debugging on aarch64*-linux* > diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo > index 3c1f7857393c..d8ed630da3fc 100644 > --- a/gdb/doc/gdb.texinfo > +++ b/gdb/doc/gdb.texinfo > @@ -20121,6 +20121,10 @@ are: > @tab @code{qSupported} > @tab Remote communications parameters > > +@item @code{catch-syscalls} > +@tab @code{QCatchSyscalls} > +@tab @code{catch syscall} > + > @item @code{pass-signals} > @tab @code{QPassSignals} > @tab @code{handle @var{signal}} > @@ -35418,6 +35422,11 @@ The currently defined stop reasons are: > The packet indicates a watchpoint hit, and @var{r} is the data address, in > hex. > > +@item syscall_entry > +@itemx syscall_return > +The packet indicates a syscall entry or return, and @var{r} is the > +syscall number, in hex. > + > @cindex shared library events, remote reply > @item library > The packet indicates that the loaded libraries have changed. > @@ -35878,6 +35887,44 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). > Use of this packet is controlled by the @code{set non-stop} command; > @pxref{Non-Stop Mode}. > > +@item QCatchSyscalls:1 @r{[};@var{sysno}@r{]}@dots{} > +@itemx QCatchSyscalls:0 > +@cindex catch syscalls from inferior, remote request > +@cindex @samp{QCatchSyscalls} packet > +@anchor{QCatchSyscalls} > +Enable (@samp{QCatchSyscalls:1}) or disable (@samp{QCatchSyscalls:0}) > +catching syscalls from the inferior process. > + > +For @samp{QCatchSyscalls:1}, each listed syscall @var{sysno} (encoded > +in hex) should be reported to @value{GDBN}. If no syscall @var{sysno} > +is listed, every system call should be reported. > + > +Note that if a syscall not member of the list is reported, @value{GDBN} > +will filter it if this syscall is not caught. It is however more efficient > +to only report the needed syscalls. > + > +Multiple @samp{QCatchSyscalls:1} packets do not > +combine; any earlier @samp{QCatchSyscalls:1} list is completely replaced by the > +new list. > + > +Reply: > +@table @samp > +@item OK > +The request succeeded. > + > +@item E @var{nn} > +An error occurred. @var{nn} are hex digits. > + > +@item @w{} > +An empty reply indicates that @samp{QCatchSyscalls} is not supported by > +the stub. > +@end table > + > +Use of this packet is controlled by the @code{set remote catch-syscalls} > +command (@pxref{Remote Configuration, set remote catch-syscalls}). > +This packet is not probed by default; the remote stub must request it, > +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). > + > @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} > @cindex pass signals to inferior, remote request > @cindex @samp{QPassSignals} packet > @@ -36296,6 +36343,11 @@ These are the currently defined stub features and their properties: > @tab @samp{-} > @tab Yes > > +@item @samp{QCatchSyscalls} > +@tab No > +@tab @samp{-} > +@tab Yes > + > @item @samp{QPassSignals} > @tab No > @tab @samp{-} > @@ -36489,6 +36541,10 @@ packet (@pxref{qXfer fdpic loadmap read}). > The remote stub understands the @samp{QNonStop} packet > (@pxref{QNonStop}). > > +@item QCatchSyscalls > +The remote stub understands the @samp{QCatchSyscalls} packet > +(@pxref{QCatchSyscalls}). > + > @item QPassSignals > The remote stub understands the @samp{QPassSignals} packet > (@pxref{QPassSignals}). > diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c > index 72a3ef1b1b61..a8263656a4af 100644 > --- a/gdb/gdbserver/inferiors.c > +++ b/gdb/gdbserver/inferiors.c > @@ -316,6 +316,7 @@ remove_process (struct process_info *process) > free_all_breakpoints (process); > gdb_assert (find_thread_process (process) == NULL); > remove_inferior (&all_processes, &process->entry); > + VEC_free (int, process->syscalls_to_catch); > free (process); > } > > diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h > index d7226163c0e8..43fc869f6612 100644 > --- a/gdb/gdbserver/inferiors.h > +++ b/gdb/gdbserver/inferiors.h > @@ -19,6 +19,8 @@ > #ifndef INFERIORS_H > #define INFERIORS_H > > +#include "gdb_vecs.h" > + > /* Generic information for tracking a list of ``inferiors'' - threads, > processes, etc. */ > struct inferior_list > @@ -67,6 +69,9 @@ struct process_info > /* The list of installed fast tracepoints. */ > struct fast_tracepoint_jump *fast_tracepoint_jumps; > > + /* The list of syscalls to report, or just ANY_SYSCALL. */ > + VEC (int) *syscalls_to_catch; > + > const struct target_desc *tdesc; > > /* Private target data. */ > diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c > index 41ab510fa4ac..c2c513130997 100644 > --- a/gdb/gdbserver/linux-low.c > +++ b/gdb/gdbserver/linux-low.c > @@ -70,6 +70,11 @@ > #define O_LARGEFILE 0 > #endif > > +/* Unlike other extended result codes, WSTOPSIG (status) on > + PTRACE_O_TRACESYSGOOD syscall events doesn't return SIGTRAP, but > + instead SIGTRAP with bit 7 set. */ > +#define SYSCALL_SIGTRAP (SIGTRAP | 0x80) > + This is already defined in nat/linux-nat.h. > /* Some targets did not define these ptrace constants from the start, > so gdbserver defines them locally here. In the future, these may > be removed after they are added to asm/ptrace.h. */ > @@ -447,6 +452,11 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) > struct thread_info *event_thr = get_lwp_thread (event_lwp); > struct lwp_info *new_lwp; > > + /* All extended events we currently use are mid-syscall. Only > + PTRACE_EVENT_STOP is delivered more like a signal-stop, but > + you have to be using PTRACE_SEIZE to get that. */ > + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; > + > if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) > || (event == PTRACE_EVENT_CLONE)) > { > @@ -662,6 +672,40 @@ get_pc (struct lwp_info *lwp) > return pc; > } > > +/* This function should only be called if LWP got a SYSCALL_SIGTRAP. > + Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the > + return code. */ > + > +static void > +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno, int *sysret) > +{ > + struct thread_info *saved_thread; > + struct regcache *regcache; > + > + if (the_low_target.get_syscall_trapinfo == NULL) > + { > + /* If we cannot get the syscall trapinfo, report an unknown > + system call number and -ENOSYS return value. */ > + *sysno = UNKNOWN_SYSCALL; > + *sysret = -ENOSYS; > + return; > + } > + > + saved_thread = current_thread; > + current_thread = get_lwp_thread (lwp); > + > + regcache = get_thread_regcache (current_thread, 1); > + (*the_low_target.get_syscall_trapinfo) (regcache, sysno, sysret); > + > + if (debug_threads) > + { > + debug_printf ("get_syscall_trapinfo sysno %d sysret %d\n", > + *sysno, *sysret); > + } > + > + current_thread = saved_thread; > +} > + > /* This function should only be called if LWP got a SIGTRAP. > The SIGTRAP could mean several things. > > @@ -2154,6 +2198,8 @@ linux_low_ptrace_options (int attached) > if (report_exec_events) > options |= PTRACE_O_TRACEEXEC; > > + options |= PTRACE_O_TRACESYSGOOD; > + > return options; > } > > @@ -2249,6 +2295,16 @@ linux_low_filter_event (int lwpid, int wstat) > > gdb_assert (WIFSTOPPED (wstat)); > > + /* Set ptrace flags ASAP, so no events can be missed. */ > + if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) It's a bit weird to check WIFSTOPPED after we just asserted it's true, but I realize all the subsequent "if"s checks WIFSTOPPED too. > + { > + struct process_info *proc = find_process_pid (pid_of (thread)); > + int options = linux_low_ptrace_options (proc->attached); > + > + linux_enable_event_reporting (lwpid, options); > + child->must_set_ptrace_flags = 0; > + } > + Is moving the must_set_ptrace_flags check up to here good in general, or is it only necessary for this patch? I see that gdb/linux-nat.c does the must_set_ptrace_flags check early. [ref: gdb/linux.c line 2312: if (lp->must_set_ptrace_flags)] If this part of patch can be separated out, I think that'd be helpful. > if (WIFSTOPPED (wstat)) > { > struct process_info *proc; > @@ -2276,13 +2332,19 @@ linux_low_filter_event (int lwpid, int wstat) > } > } > > - if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) > + /* Always update syscall_state, even if it will be filtered later. */ > + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) > { > - struct process_info *proc = find_process_pid (pid_of (thread)); > - int options = linux_low_ptrace_options (proc->attached); > - > - linux_enable_event_reporting (lwpid, options); > - child->must_set_ptrace_flags = 0; > + child->syscall_state = > + child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY > + ? TARGET_WAITKIND_SYSCALL_RETURN > + : TARGET_WAITKIND_SYSCALL_ENTRY; Our convention when wrapping on "=" is to put the "=" on the next line. Also, I'd put the expression in parens like this: child->syscall_state = (child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY ? TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY); > + } > + else > + { > + /* Almost all other ptrace-stops are known to be outside of system > + calls, with further exceptions in handle_extended_wait. */ > + child->syscall_state = TARGET_WAITKIND_IGNORE; > } > > /* Be careful to not overwrite stop_pc until > @@ -2885,6 +2947,44 @@ ignore_event (struct target_waitstatus *ourstatus) > return null_ptid; > } > > +/* Returns 1 if GDB is interested in any event_child syscalls. */ > + > +static int > +gdb_catching_syscalls_p (struct lwp_info *event_child) > +{ > + struct thread_info *thread = get_lwp_thread (event_child); > + struct process_info *proc = get_thread_process (thread); > + > + return !VEC_empty (int, proc->syscalls_to_catch); > +} > + > +/* Returns 1 if GDB is interested in the event_child syscall. > + Only to be called when stopped reason is SYSCALL_SIGTRAP. */ > + > +static int > +gdb_catch_this_syscall_p (struct lwp_info *event_child) > +{ > + int i, iter; > + int sysno, sysret; > + struct thread_info *thread = get_lwp_thread (event_child); > + struct process_info *proc = get_thread_process (thread); > + > + if (VEC_empty (int, proc->syscalls_to_catch)) > + return 0; > + > + if (VEC_index (int, proc->syscalls_to_catch, 0) == ANY_SYSCALL) > + return 1; > + > + get_syscall_trapinfo (event_child, &sysno, &sysret); > + for (i = 0; > + VEC_iterate (int, proc->syscalls_to_catch, i, iter); > + i++) > + if (iter == sysno) > + return 1; > + > + return 0; > +} > + > /* Wait for process, returns status. */ > > static ptid_t > @@ -3195,6 +3295,22 @@ linux_wait_1 (ptid_t ptid, > > /* Check whether GDB would be interested in this event. */ > > + /* Check if GDB is interested in this syscall. */ > + if (WIFSTOPPED (w) > + && WSTOPSIG (w) == SYSCALL_SIGTRAP > + && !gdb_catch_this_syscall_p (event_child)) > + { > + if (debug_threads) > + { > + debug_printf ("Ignored syscall for LWP %ld.\n", > + lwpid_of (current_thread)); > + } > + > + linux_resume_one_lwp (event_child, event_child->stepping, > + 0, NULL); > + return ignore_event (ourstatus); > + } > + > /* If GDB is not interested in this signal, don't stop other > threads, and don't report it to GDB. Just resume the inferior > right away. We do this for threading-related signals as well as > @@ -3449,8 +3565,16 @@ linux_wait_1 (ptid_t ptid, > } > } > > - if (current_thread->last_resume_kind == resume_stop > - && WSTOPSIG (w) == SIGSTOP) > + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) > + { > + int sysret; > + > + get_syscall_trapinfo (event_child, > + &ourstatus->value.syscall_number, &sysret); > + ourstatus->kind = event_child->syscall_state; > + } > + else if (current_thread->last_resume_kind == resume_stop > + && WSTOPSIG (w) == SIGSTOP) > { > /* A thread that has been requested to stop by GDB with vCont;t, > and it stopped cleanly, so report as SIG0. The use of > @@ -3867,6 +3991,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, > struct thread_info *thread = get_lwp_thread (lwp); > struct thread_info *saved_thread; > int fast_tp_collecting; > + int ptrace_request; > struct process_info *proc = get_thread_process (thread); > > /* Note that target description may not be initialised > @@ -4052,7 +4177,14 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, > regcache_invalidate_thread (thread); > errno = 0; > lwp->stepping = step; > - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread), > + if (step) > + ptrace_request = PTRACE_SINGLESTEP; > + else if (gdb_catching_syscalls_p (lwp)) > + ptrace_request = PTRACE_SYSCALL; Unnecessary extra space after =. > + else > + ptrace_request = PTRACE_CONT; Ditto. > + ptrace (ptrace_request, > + lwpid_of (thread), > (PTRACE_TYPE_ARG3) 0, > /* Coerce to a uintptr_t first to avoid potential gcc warning > of coercing an 8 byte integer to a 4 byte pointer. */ > @@ -6135,6 +6267,13 @@ linux_process_qsupported (const char *query) > } > > static int > +linux_supports_catch_syscall (void) > +{ > + return (the_low_target.get_syscall_trapinfo != NULL > + && linux_supports_tracesysgood()); > +} > + > +static int > linux_supports_tracepoints (void) > { > if (*the_low_target.supports_tracepoints == NULL) > @@ -7010,6 +7149,7 @@ static struct target_ops linux_target_ops = { > linux_common_core_of_thread, > linux_read_loadmap, > linux_process_qsupported, > + linux_supports_catch_syscall, > linux_supports_tracepoints, > linux_read_pc, > linux_write_pc, > diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h > index ccf4c9421d87..71d72f48ea3a 100644 > --- a/gdb/gdbserver/linux-low.h > +++ b/gdb/gdbserver/linux-low.h > @@ -201,6 +201,12 @@ struct linux_target_ops > /* Hook to support target specific qSupported. */ > void (*process_qsupported) (const char *); > > + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the > + return code. Only to be called when inferior is stopped > + due to SYSCALL_SIGTRAP. */ > + void (*get_syscall_trapinfo) (struct regcache *regcache, > + int *sysno, int *sysret); > + > /* Returns true if the low target supports tracepoints. */ > int (*supports_tracepoints) (void); > > @@ -271,6 +277,13 @@ struct lwp_info > event already received in a wait()). */ > int stopped; > > + /* Signal wether we are in a SYSCALL_ENTRY or > + in a SYSCALL_RETURN event. > + Values: > + - TARGET_WAITKIND_SYSCALL_ENTRY > + - TARGET_WAITKIND_SYSCALL_RETURN */ > + enum target_waitkind syscall_state; > + > /* When stopped is set, the last wait status recorded for this lwp. */ > int last_status; > > diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c > index 89ec4e54b3b8..6e3c589de8fb 100644 > --- a/gdb/gdbserver/linux-x86-low.c > +++ b/gdb/gdbserver/linux-x86-low.c > @@ -1432,6 +1432,36 @@ x86_arch_setup (void) > current_process ()->tdesc = x86_linux_read_description (); > } > > +/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return > + code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ > + > +static void > +x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno, int *sysret) > +{ > + int use_64bit = register_size (regcache->tdesc, 0) == 8; > + > + if (use_64bit) > + { > + long l_sysno; > + long l_sysret; > + > + collect_register_by_name (regcache, "orig_rax", &l_sysno); > + collect_register_by_name (regcache, "rax", &l_sysret); > + *sysno = (int) l_sysno; > + *sysret = (int) l_sysret; > + } > + else > + { > + int l_sysno; > + int l_sysret; > + > + collect_register_by_name (regcache, "orig_eax", &l_sysno); > + collect_register_by_name (regcache, "eax", &l_sysret); > + *sysno = (int) l_sysno; > + *sysret = (int) l_sysret; These casts are confusing, especially when coupled with the l_ prefix ("l" for "long" is the first thing that comes to mind, but these are ints). I can appreciate them when casting from long to int, but here we already have ints. How about changing the parameters to sysno_ptr, sysret_ptr, and change l_sysno,l_sysret to sysno,sysret? Or some such. > + } > +} > + > static int > x86_supports_tracepoints (void) > { > @@ -3292,6 +3322,7 @@ struct linux_target_ops the_low_target = > x86_linux_new_fork, > x86_linux_prepare_to_resume, > x86_linux_process_qsupported, > + x86_get_syscall_trapinfo, > x86_supports_tracepoints, > x86_get_thread_area, > x86_install_fast_tracepoint_jump_pad, > diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c > index d72c46515d13..1301acea49b7 100644 > --- a/gdb/gdbserver/nto-low.c > +++ b/gdb/gdbserver/nto-low.c > @@ -979,6 +979,7 @@ static struct target_ops nto_target_ops = { > NULL, /* core_of_thread */ > NULL, /* read_loadmap */ > NULL, /* process_qsupported */ > + NULL, /* supports_catch_syscall */ > NULL, /* supports_tracepoints */ > NULL, /* read_pc */ > NULL, /* write_pc */ > diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c > index e36609176afa..19eed77d4874 100644 > --- a/gdb/gdbserver/remote-utils.c > +++ b/gdb/gdbserver/remote-utils.c > @@ -1119,6 +1119,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, > case TARGET_WAITKIND_VFORKED: > case TARGET_WAITKIND_VFORK_DONE: > case TARGET_WAITKIND_EXECD: > + case TARGET_WAITKIND_SYSCALL_ENTRY: > + case TARGET_WAITKIND_SYSCALL_RETURN: > { > struct thread_info *saved_thread; > const char **regp; > @@ -1161,6 +1163,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, > status->value.execd_pathname = NULL; > buf += strlen (buf); > } > + else if ((status->kind == TARGET_WAITKIND_SYSCALL_ENTRY) > + || (status->kind == TARGET_WAITKIND_SYSCALL_RETURN)) > + { > + enum gdb_signal signal = GDB_SIGNAL_TRAP; > + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY > + ? "syscall_entry" : "syscall_return"); > + > + sprintf (buf, "T%02x%s:%x;", signal, event, > + status->value.syscall_number); > + } > else > sprintf (buf, "T%02x", status->value.sig); > > diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c > index fd2804beaa4e..72621f261dfa 100644 > --- a/gdb/gdbserver/server.c > +++ b/gdb/gdbserver/server.c > @@ -592,6 +592,52 @@ handle_general_set (char *own_buf) > return; > } > > + if (startswith (own_buf, "QCatchSyscalls:1")) > + { > + const char *p; > + CORE_ADDR sysno; > + struct process_info *process; > + > + if (!target_running () || !target_supports_catch_syscall ()) > + { > + write_enn (own_buf); > + return; > + } > + > + process = current_process (); > + > + VEC_truncate (int, process->syscalls_to_catch, 0); > + > + p = own_buf + strlen("QCatchSyscalls:1"); > + if (*p == ';') > + { > + p += 1; > + while (*p) > + { > + p = decode_address_to_semicolon (&sysno, p); > + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); > + } > + } > + else > + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); > + > + write_ok (own_buf); > + return; > + } > + > + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) > + { > + if (!target_running () || !target_supports_catch_syscall ()) > + { > + write_enn (own_buf); > + return; > + } > + > + VEC_free (int, current_process ()->syscalls_to_catch); > + write_ok (own_buf); > + return; > + } > + > if (startswith (own_buf, "QProgramSignals:")) > { > int numsigs = (int) GDB_SIGNAL_LAST, i; > @@ -2140,6 +2186,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) > "PacketSize=%x;QPassSignals+;QProgramSignals+", > PBUFSIZ - 1); > > + if (target_supports_catch_syscall ()) > + strcat (own_buf, ";QCatchSyscalls+"); > + > if (the_target->qxfer_libraries_svr4 != NULL) > strcat (own_buf, ";qXfer:libraries-svr4:read+" > ";augmented-libraries-svr4-read+"); > diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h > index 96ad4fa58b7c..a8780ebfbc65 100644 > --- a/gdb/gdbserver/server.h > +++ b/gdb/gdbserver/server.h > @@ -133,4 +133,10 @@ extern void discard_queued_stop_replies (ptid_t ptid); > as large as the largest register set supported by gdbserver. */ > #define PBUFSIZ 16384 > > +/* Definition for an unknown syscall, used basically in error-cases. */ > +#define UNKNOWN_SYSCALL (-1) > + > +/* Definition for any syscall, used for unfiltered syscall reporting. */ > +#define ANY_SYSCALL (-2) > + > #endif /* SERVER_H */ > diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c > index 89bed7a02dd1..55ec0caef296 100644 > --- a/gdb/gdbserver/spu-low.c > +++ b/gdb/gdbserver/spu-low.c > @@ -699,6 +699,7 @@ static struct target_ops spu_target_ops = { > NULL, /* core_of_thread */ > NULL, /* read_loadmap */ > NULL, /* process_qsupported */ > + NULL, /* supports_catch_syscall */ > NULL, /* supports_tracepoints */ > NULL, /* read_pc */ > NULL, /* write_pc */ > diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h > index 769c876ede49..ef8a7680ccca 100644 > --- a/gdb/gdbserver/target.h > +++ b/gdb/gdbserver/target.h > @@ -309,6 +309,10 @@ struct target_ops > /* Target specific qSupported support. */ > void (*process_qsupported) (const char *); > > + /* Return 1 if the target supports catch syscall, 0 (or leave the > + callback NULL) otherwise. */ > + int (*supports_catch_syscall) (void); > + > /* Return 1 if the target supports tracepoints, 0 (or leave the > callback NULL) otherwise. */ > int (*supports_tracepoints) (void); > @@ -526,6 +530,10 @@ int kill_inferior (int); > the_target->process_qsupported (query); \ > } while (0) > > +#define target_supports_catch_syscall() \ > + (the_target->supports_catch_syscall ? \ > + (*the_target->supports_catch_syscall) () : 0) > + > #define target_supports_tracepoints() \ > (the_target->supports_tracepoints \ > ? (*the_target->supports_tracepoints) () : 0) > diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c > index 6e33509c0b50..4314513876fa 100644 > --- a/gdb/gdbserver/win32-low.c > +++ b/gdb/gdbserver/win32-low.c > @@ -1844,6 +1844,7 @@ static struct target_ops win32_target_ops = { > NULL, /* core_of_thread */ > NULL, /* read_loadmap */ > NULL, /* process_qsupported */ > + NULL, /* supports_catch_syscall */ > NULL, /* supports_tracepoints */ > NULL, /* read_pc */ > NULL, /* write_pc */ > diff --git a/gdb/remote.c b/gdb/remote.c > index fed397affeab..41751e9d93b1 100644 > --- a/gdb/remote.c > +++ b/gdb/remote.c > @@ -1388,6 +1388,7 @@ enum { > PACKET_qSupported, > PACKET_qTStatus, > PACKET_QPassSignals, > + PACKET_QCatchSyscalls, > PACKET_QProgramSignals, > PACKET_qCRC, > PACKET_qSearch_memory, > @@ -1973,6 +1974,99 @@ remote_pass_signals (struct target_ops *self, > } > } > > +/* If 'QCatchSyscalls' is supported, tell the remote stub > + to report syscalls to GDB. */ > + > +static int > +remote_set_syscall_catchpoint (struct target_ops *self, > + int pid, int needed, int any_count, > + int table_size, int *table) > +{ > + char *catch_packet, *p; > + enum packet_result result; > + int n_sysno = 0; > + > + if (remote_protocol_packets[PACKET_QCatchSyscalls].support == PACKET_DISABLE) > + { > + /* Not supported. */ > + return 1; > + } > + > + if (needed && !any_count) > + { > + int i; > + > + /* Count how many syscalls are to be caught (table[sysno] != 0). */ > + for (i = 0; i < table_size; i++) > + { > + if (table[i]) > + n_sysno++; > + } > + } > + > + if (remote_debug) > + { > + fprintf_unfiltered (gdb_stdlog, > + "remote_set_syscall_catchpoint " > + "pid %d needed %d any_count %d n_sysno %d\n", > + pid, needed, any_count, n_sysno); > + } > + > + if (needed) > + { > + /* Prepare a packet with the sysno list, assuming max 8+1 > + characters for a sysno. If the resulting packet size is too > + big, fallback on the non selective packet. */ > + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; > + > + catch_packet = xmalloc (maxpktsz); > + strcpy (catch_packet, "QCatchSyscalls:1"); > + if (!any_count) > + { > + int i; > + char *p; > + > + p = catch_packet; > + p += strlen (p); > + > + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ > + for (i = 0; i < table_size; i++) > + { > + if (table[i]) > + { > + xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); > + p += strlen (p); > + } > + } > + } > + if (strlen (catch_packet) > get_remote_packet_size ()) > + { > + /* catch_packet too big. Fallback to less efficient > + non selective mode, with GDB doing the filtering. */ > + catch_packet[strlen ("QCatchSyscalls:1")] = 0; > + } > + } > + else > + { > + catch_packet = xmalloc (strlen ("QCatchSyscalls:0") + 1); > + strcpy (catch_packet, "QCatchSyscalls:0"); > + } > + > + { > + struct remote_state *rs = get_remote_state (); > + char *buf = rs->buf; > + > + putpkt (catch_packet); > + getpkt (&rs->buf, &rs->buf_size, 0); > + result = packet_ok (buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); > + xfree (catch_packet); > + if (result == PACKET_OK) > + return 0; > + else > + return -1; > + } > +} > + > /* If 'QProgramSignals' is supported, tell the remote stub what > signals it should pass through to the inferior when detaching. */ > > @@ -4328,6 +4422,8 @@ static const struct protocol_feature remote_protocol_features[] = { > PACKET_qXfer_traceframe_info }, > { "QPassSignals", PACKET_DISABLE, remote_supported_packet, > PACKET_QPassSignals }, > + { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet, > + PACKET_QCatchSyscalls }, > { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, > PACKET_QProgramSignals }, > { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, > @@ -6159,6 +6255,22 @@ Packet: '%s'\n"), > > if (strprefix (p, p1, "thread")) > event->ptid = read_ptid (++p1, &p); > + else if (strprefix (p, p1, "syscall_entry")) > + { > + ULONGEST sysno; > + > + event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; > + p = unpack_varlen_hex (++p1, &sysno); > + event->ws.value.syscall_number = (int) sysno; > + } > + else if (strprefix (p, p1, "syscall_return")) > + { > + ULONGEST sysno; > + > + event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; > + p = unpack_varlen_hex (++p1, &sysno); > + event->ws.value.syscall_number = (int) sysno; > + } > else if (strprefix (p, p1, "watch") > || strprefix (p, p1, "rwatch") > || strprefix (p, p1, "awatch")) > @@ -12734,6 +12846,7 @@ Specify the serial device it is connected to\n\ > remote_ops.to_load = remote_load; > remote_ops.to_mourn_inferior = remote_mourn; > remote_ops.to_pass_signals = remote_pass_signals; > + remote_ops.to_set_syscall_catchpoint = remote_set_syscall_catchpoint; > remote_ops.to_program_signals = remote_program_signals; > remote_ops.to_thread_alive = remote_thread_alive; > remote_ops.to_update_thread_list = remote_update_thread_list; > @@ -13263,6 +13376,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, > add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], > "QPassSignals", "pass-signals", 0); > > + add_packet_config_cmd (&remote_protocol_packets[PACKET_QCatchSyscalls], > + "QCatchSyscalls", "catch-syscalls", 0); > + > add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], > "QProgramSignals", "program-signals", 0); > > diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp > index c1cfe23cdddb..0ba078db22ac 100644 > --- a/gdb/testsuite/gdb.base/catch-syscall.exp > +++ b/gdb/testsuite/gdb.base/catch-syscall.exp > @@ -19,7 +19,15 @@ > # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> > # on September/2008. > > -if { [is_remote target] || ![isnative] } then { > +if { ![isnative] } then { > + continue > +} > + > +# This shall be updated whenever QCatchSyscalls packet support is implemented > +# on some gdbserver architecture. > +if { [is_remote target] > + && ![istarget "x86_64-*-linux*"] > + && ![istarget "i\[34567\]86-*-linux*"] } { > continue > } > > @@ -390,7 +398,10 @@ proc do_syscall_tests {} { > if [runto_main] then { test_catch_syscall_skipping_return } > > # Testing the 'catch syscall' command starting mid-vfork. > - if [runto_main] then { test_catch_syscall_mid_vfork } > + # (Only local or extended-remote can use "catch vfork".) > + if { ![is_remote target] || [target_info gdb_protocol] == "extended-remote" } { > + if [runto_main] then { test_catch_syscall_mid_vfork } > + } > > # Testing if the 'catch syscall' command works when switching to > # different architectures on-the-fly (PR gdb/10737). ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH] Implement 'catch syscall' for gdbserver 2015-11-23 4:20 ` Doug Evans @ 2015-11-25 2:37 ` Josh Stone 0 siblings, 0 replies; 49+ messages in thread From: Josh Stone @ 2015-11-25 2:37 UTC (permalink / raw) To: Doug Evans; +Cc: gdb-patches, sergiodj, palves, philippe.waroquiers Thanks for the review! I'll go ahead and correct the style issues without further comment. Other replies are inline. I'll try to rebase and send updates tomorrow. On 11/22/2015 08:18 PM, Doug Evans wrote: > Josh Stone <jistone@redhat.com> writes: >> This adds a new QCatchSyscalls packet to enable 'catch syscall', and new >> stop reasons "syscall_entry" and "syscall_return" for those events. It >> is currently only supported on Linux x86 and x86_64. >> >> Based on work from Philippe Waroquiers <philippe.waroquiers@skynet.be>. >> >> Beyond simple rebasing, I've also updated it to store the syscall catch >> lists uniquely to each target process, and updated entry/return logic >> from checking ENOSYS to now matching gdb's current Linux logic. >> >> gdb/ChangeLog: >> >> 2015-10-29 Josh Stone <jistone@redhat.com> >> >> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new >> GDBserver support for catch syscall. >> * remote.c (PACKET_QCatchSyscalls): New enum. >> (remote_set_syscall_catchpoint): New function. >> (remote_protocol_features): New element for QCatchSyscalls. >> (remote_parse_stop_reply): Parse syscall_entry/return stops. >> (init_remote_ops): Install remote_set_syscall_catchpoint. >> (_initialize_remote): Config QCatchSyscalls. >> >> gdb/doc/ChangeLog: >> >> 2015-10-29 Josh Stone <jistone@redhat.com> >> >> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. >> (Stop Reply Packets): List the syscall entry and return stop reasons. >> (General Query Packets): Describe QCatchSyscalls, and add it to the >> table and detailed list of stub features. >> >> gdb/gdbserver/ChangeLog: >> >> 2015-10-29 Josh Stone <jistone@redhat.com> >> >> * inferiors.h: Include "gdb_vecs.h". >> (struct process_info): Add syscalls_to_catch. >> * inferiors.c (remove_process): Free syscalls_to_catch. >> * remote-utils.c (prepare_resume_reply): Report syscall_entry and >> syscall_resume stops. >> * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. >> * server.c (handle_general_set): Handle QCatchSyscalls. >> (handle_query): Report support for QCatchSyscalls. >> * target.h (struct target_ops): Add supports_catch_syscall. >> (target_supports_catch_syscall): New macro. >> * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. >> (struct lwp_info): Add syscall_state. >> * linux-low.c (SYSCALL_SIGTRAP): Define. >> (handle_extended_wait): Mark syscall_state like an entry. >> (get_syscall_trapinfo): New function, proxy to the_low_target. >> (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. >> (linux_low_filter_event): Set ptrace options even before arch-specific >> setup. Either toggle syscall_state entry/return or set ignored. >> (gdb_catching_syscalls_p): New function. >> (gdb_catch_this_syscall_p): New function. >> (linux_wait_1): Handle SYSCALL_SIGTRAP. >> (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. >> (linux_supports_catch_syscall): New function. >> (linux_target_ops): Install it. >> * linux-x86-low.c (x86_get_syscall_trapinfo): New function. >> (the_low_target): Install it. >> * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. >> * spu-low.c (spu_target_ops): Likewise. >> * win32-low.c (win32_target_ops): Likewise. >> >> gdb/testsuite/ChangeLog: >> >> 2015-10-29 Josh Stone <jistone@redhat.com> >> >> * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux >> remote targets. >> (do_syscall_tests): Only test mid-vfork on local or extended-remote. >> --- >> gdb/NEWS | 10 ++ >> gdb/doc/gdb.texinfo | 56 +++++++++++ >> gdb/gdbserver/inferiors.c | 1 + >> gdb/gdbserver/inferiors.h | 5 + >> gdb/gdbserver/linux-low.c | 158 +++++++++++++++++++++++++++++-- >> gdb/gdbserver/linux-low.h | 13 +++ >> gdb/gdbserver/linux-x86-low.c | 31 ++++++ >> gdb/gdbserver/nto-low.c | 1 + >> gdb/gdbserver/remote-utils.c | 12 +++ >> gdb/gdbserver/server.c | 49 ++++++++++ >> gdb/gdbserver/server.h | 6 ++ >> gdb/gdbserver/spu-low.c | 1 + >> gdb/gdbserver/target.h | 8 ++ >> gdb/gdbserver/win32-low.c | 1 + >> gdb/remote.c | 116 +++++++++++++++++++++++ >> gdb/testsuite/gdb.base/catch-syscall.exp | 15 ++- >> 16 files changed, 472 insertions(+), 11 deletions(-) >> >> diff --git a/gdb/NEWS b/gdb/NEWS >> index b2b1e99d58c6..9c9b4b04a146 100644 >> --- a/gdb/NEWS >> +++ b/gdb/NEWS >> @@ -77,6 +77,11 @@ exec-events feature in qSupported >> response can contain the corresponding 'stubfeature'. Set and >> show commands can be used to display whether these features are enabled. >> >> +QCatchSyscalls:1 [;SYSNO]... >> +QCatchSyscalls:0 >> + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") >> + catching syscalls from the inferior process. >> + >> * Extended-remote exec events >> >> ** GDB now has support for exec events on extended-remote Linux targets. >> @@ -87,6 +92,11 @@ set remote exec-event-feature-packet >> show remote exec-event-feature-packet >> Set/show the use of the remote exec event feature. >> >> +* New features in the GDB remote stub, GDBserver >> + >> + ** GDBserver now supports catch syscall. Currently enabled >> + on x86/x86_64 GNU/Linux targets. >> + >> *** Changes in GDB 7.10 >> >> * Support for process record-replay and reverse debugging on aarch64*-linux* >> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo >> index 3c1f7857393c..d8ed630da3fc 100644 >> --- a/gdb/doc/gdb.texinfo >> +++ b/gdb/doc/gdb.texinfo >> @@ -20121,6 +20121,10 @@ are: >> @tab @code{qSupported} >> @tab Remote communications parameters >> >> +@item @code{catch-syscalls} >> +@tab @code{QCatchSyscalls} >> +@tab @code{catch syscall} >> + >> @item @code{pass-signals} >> @tab @code{QPassSignals} >> @tab @code{handle @var{signal}} >> @@ -35418,6 +35422,11 @@ The currently defined stop reasons are: >> The packet indicates a watchpoint hit, and @var{r} is the data address, in >> hex. >> >> +@item syscall_entry >> +@itemx syscall_return >> +The packet indicates a syscall entry or return, and @var{r} is the >> +syscall number, in hex. >> + >> @cindex shared library events, remote reply >> @item library >> The packet indicates that the loaded libraries have changed. >> @@ -35878,6 +35887,44 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). >> Use of this packet is controlled by the @code{set non-stop} command; >> @pxref{Non-Stop Mode}. >> >> +@item QCatchSyscalls:1 @r{[};@var{sysno}@r{]}@dots{} >> +@itemx QCatchSyscalls:0 >> +@cindex catch syscalls from inferior, remote request >> +@cindex @samp{QCatchSyscalls} packet >> +@anchor{QCatchSyscalls} >> +Enable (@samp{QCatchSyscalls:1}) or disable (@samp{QCatchSyscalls:0}) >> +catching syscalls from the inferior process. >> + >> +For @samp{QCatchSyscalls:1}, each listed syscall @var{sysno} (encoded >> +in hex) should be reported to @value{GDBN}. If no syscall @var{sysno} >> +is listed, every system call should be reported. >> + >> +Note that if a syscall not member of the list is reported, @value{GDBN} >> +will filter it if this syscall is not caught. It is however more efficient >> +to only report the needed syscalls. >> + >> +Multiple @samp{QCatchSyscalls:1} packets do not >> +combine; any earlier @samp{QCatchSyscalls:1} list is completely replaced by the >> +new list. >> + >> +Reply: >> +@table @samp >> +@item OK >> +The request succeeded. >> + >> +@item E @var{nn} >> +An error occurred. @var{nn} are hex digits. >> + >> +@item @w{} >> +An empty reply indicates that @samp{QCatchSyscalls} is not supported by >> +the stub. >> +@end table >> + >> +Use of this packet is controlled by the @code{set remote catch-syscalls} >> +command (@pxref{Remote Configuration, set remote catch-syscalls}). >> +This packet is not probed by default; the remote stub must request it, >> +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). >> + >> @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} >> @cindex pass signals to inferior, remote request >> @cindex @samp{QPassSignals} packet >> @@ -36296,6 +36343,11 @@ These are the currently defined stub features and their properties: >> @tab @samp{-} >> @tab Yes >> >> +@item @samp{QCatchSyscalls} >> +@tab No >> +@tab @samp{-} >> +@tab Yes >> + >> @item @samp{QPassSignals} >> @tab No >> @tab @samp{-} >> @@ -36489,6 +36541,10 @@ packet (@pxref{qXfer fdpic loadmap read}). >> The remote stub understands the @samp{QNonStop} packet >> (@pxref{QNonStop}). >> >> +@item QCatchSyscalls >> +The remote stub understands the @samp{QCatchSyscalls} packet >> +(@pxref{QCatchSyscalls}). >> + >> @item QPassSignals >> The remote stub understands the @samp{QPassSignals} packet >> (@pxref{QPassSignals}). >> diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c >> index 72a3ef1b1b61..a8263656a4af 100644 >> --- a/gdb/gdbserver/inferiors.c >> +++ b/gdb/gdbserver/inferiors.c >> @@ -316,6 +316,7 @@ remove_process (struct process_info *process) >> free_all_breakpoints (process); >> gdb_assert (find_thread_process (process) == NULL); >> remove_inferior (&all_processes, &process->entry); >> + VEC_free (int, process->syscalls_to_catch); >> free (process); >> } >> >> diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h >> index d7226163c0e8..43fc869f6612 100644 >> --- a/gdb/gdbserver/inferiors.h >> +++ b/gdb/gdbserver/inferiors.h >> @@ -19,6 +19,8 @@ >> #ifndef INFERIORS_H >> #define INFERIORS_H >> >> +#include "gdb_vecs.h" >> + >> /* Generic information for tracking a list of ``inferiors'' - threads, >> processes, etc. */ >> struct inferior_list >> @@ -67,6 +69,9 @@ struct process_info >> /* The list of installed fast tracepoints. */ >> struct fast_tracepoint_jump *fast_tracepoint_jumps; >> >> + /* The list of syscalls to report, or just ANY_SYSCALL. */ >> + VEC (int) *syscalls_to_catch; >> + >> const struct target_desc *tdesc; >> >> /* Private target data. */ >> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c >> index 41ab510fa4ac..c2c513130997 100644 >> --- a/gdb/gdbserver/linux-low.c >> +++ b/gdb/gdbserver/linux-low.c >> @@ -70,6 +70,11 @@ >> #define O_LARGEFILE 0 >> #endif >> >> +/* Unlike other extended result codes, WSTOPSIG (status) on >> + PTRACE_O_TRACESYSGOOD syscall events doesn't return SIGTRAP, but >> + instead SIGTRAP with bit 7 set. */ >> +#define SYSCALL_SIGTRAP (SIGTRAP | 0x80) >> + > > This is already defined in nat/linux-nat.h. Ah, indeed, and that's already included too. I'll nuke this. >> /* Some targets did not define these ptrace constants from the start, >> so gdbserver defines them locally here. In the future, these may >> be removed after they are added to asm/ptrace.h. */ >> @@ -447,6 +452,11 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) >> struct thread_info *event_thr = get_lwp_thread (event_lwp); >> struct lwp_info *new_lwp; >> >> + /* All extended events we currently use are mid-syscall. Only >> + PTRACE_EVENT_STOP is delivered more like a signal-stop, but >> + you have to be using PTRACE_SEIZE to get that. */ >> + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; >> + >> if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) >> || (event == PTRACE_EVENT_CLONE)) >> { >> @@ -662,6 +672,40 @@ get_pc (struct lwp_info *lwp) >> return pc; >> } >> >> +/* This function should only be called if LWP got a SYSCALL_SIGTRAP. >> + Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the >> + return code. */ >> + >> +static void >> +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno, int *sysret) >> +{ >> + struct thread_info *saved_thread; >> + struct regcache *regcache; >> + >> + if (the_low_target.get_syscall_trapinfo == NULL) >> + { >> + /* If we cannot get the syscall trapinfo, report an unknown >> + system call number and -ENOSYS return value. */ >> + *sysno = UNKNOWN_SYSCALL; >> + *sysret = -ENOSYS; >> + return; >> + } >> + >> + saved_thread = current_thread; >> + current_thread = get_lwp_thread (lwp); >> + >> + regcache = get_thread_regcache (current_thread, 1); >> + (*the_low_target.get_syscall_trapinfo) (regcache, sysno, sysret); >> + >> + if (debug_threads) >> + { >> + debug_printf ("get_syscall_trapinfo sysno %d sysret %d\n", >> + *sysno, *sysret); >> + } >> + >> + current_thread = saved_thread; >> +} >> + >> /* This function should only be called if LWP got a SIGTRAP. >> The SIGTRAP could mean several things. >> >> @@ -2154,6 +2198,8 @@ linux_low_ptrace_options (int attached) >> if (report_exec_events) >> options |= PTRACE_O_TRACEEXEC; >> >> + options |= PTRACE_O_TRACESYSGOOD; >> + >> return options; >> } >> >> @@ -2249,6 +2295,16 @@ linux_low_filter_event (int lwpid, int wstat) >> >> gdb_assert (WIFSTOPPED (wstat)); >> >> + /* Set ptrace flags ASAP, so no events can be missed. */ >> + if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) > > It's a bit weird to check WIFSTOPPED after we just asserted it's true, > but I realize all the subsequent "if"s checks WIFSTOPPED too. I agree it's weird, but as you say it's the local pattern. >> + { >> + struct process_info *proc = find_process_pid (pid_of (thread)); >> + int options = linux_low_ptrace_options (proc->attached); >> + >> + linux_enable_event_reporting (lwpid, options); >> + child->must_set_ptrace_flags = 0; >> + } >> + > > Is moving the must_set_ptrace_flags check up to here good in general, > or is it only necessary for this patch? > I see that gdb/linux-nat.c does the must_set_ptrace_flags check early. > [ref: gdb/linux.c line 2312: if (lp->must_set_ptrace_flags)] > If this part of patch can be separated out, I think that'd be helpful. Before I moved this, I was getting my first syscall trap as a plain SIGTRAP, indicating PTRACE_O_TRACESYSGOOD wasn't set as desired. I finally figured out that the following block with child->status_pending was returning early, so must_set_ptrace_flags wasn't even checked. It might even by my own peculiar setup though, as I was also testing this with my own strace-over-gdbserver hack. I'm sure there are ways that doesn't behave like a normal gdb client. Anyway, I think it's probably a good change in general, especially to mirror gdb's own behavior. In practice it may only matter for syscalls or the weird way I was using it, but that's ok. It'll be easy to make this piece a patch preceding the rest. >> if (WIFSTOPPED (wstat)) >> { >> struct process_info *proc; >> @@ -2276,13 +2332,19 @@ linux_low_filter_event (int lwpid, int wstat) >> } >> } >> >> - if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) >> + /* Always update syscall_state, even if it will be filtered later. */ >> + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) >> { >> - struct process_info *proc = find_process_pid (pid_of (thread)); >> - int options = linux_low_ptrace_options (proc->attached); >> - >> - linux_enable_event_reporting (lwpid, options); >> - child->must_set_ptrace_flags = 0; >> + child->syscall_state = >> + child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY >> + ? TARGET_WAITKIND_SYSCALL_RETURN >> + : TARGET_WAITKIND_SYSCALL_ENTRY; > > Our convention when wrapping on "=" is to put the "=" on the next line. > Also, I'd put the expression in parens like this: > > child->syscall_state > = (child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY > ? TARGET_WAITKIND_SYSCALL_RETURN > : TARGET_WAITKIND_SYSCALL_ENTRY); > >> + } >> + else >> + { >> + /* Almost all other ptrace-stops are known to be outside of system >> + calls, with further exceptions in handle_extended_wait. */ >> + child->syscall_state = TARGET_WAITKIND_IGNORE; >> } >> >> /* Be careful to not overwrite stop_pc until >> @@ -2885,6 +2947,44 @@ ignore_event (struct target_waitstatus *ourstatus) >> return null_ptid; >> } >> >> +/* Returns 1 if GDB is interested in any event_child syscalls. */ >> + >> +static int >> +gdb_catching_syscalls_p (struct lwp_info *event_child) >> +{ >> + struct thread_info *thread = get_lwp_thread (event_child); >> + struct process_info *proc = get_thread_process (thread); >> + >> + return !VEC_empty (int, proc->syscalls_to_catch); >> +} >> + >> +/* Returns 1 if GDB is interested in the event_child syscall. >> + Only to be called when stopped reason is SYSCALL_SIGTRAP. */ >> + >> +static int >> +gdb_catch_this_syscall_p (struct lwp_info *event_child) >> +{ >> + int i, iter; >> + int sysno, sysret; >> + struct thread_info *thread = get_lwp_thread (event_child); >> + struct process_info *proc = get_thread_process (thread); >> + >> + if (VEC_empty (int, proc->syscalls_to_catch)) >> + return 0; >> + >> + if (VEC_index (int, proc->syscalls_to_catch, 0) == ANY_SYSCALL) >> + return 1; >> + >> + get_syscall_trapinfo (event_child, &sysno, &sysret); >> + for (i = 0; >> + VEC_iterate (int, proc->syscalls_to_catch, i, iter); >> + i++) >> + if (iter == sysno) >> + return 1; >> + >> + return 0; >> +} >> + >> /* Wait for process, returns status. */ >> >> static ptid_t >> @@ -3195,6 +3295,22 @@ linux_wait_1 (ptid_t ptid, >> >> /* Check whether GDB would be interested in this event. */ >> >> + /* Check if GDB is interested in this syscall. */ >> + if (WIFSTOPPED (w) >> + && WSTOPSIG (w) == SYSCALL_SIGTRAP >> + && !gdb_catch_this_syscall_p (event_child)) >> + { >> + if (debug_threads) >> + { >> + debug_printf ("Ignored syscall for LWP %ld.\n", >> + lwpid_of (current_thread)); >> + } >> + >> + linux_resume_one_lwp (event_child, event_child->stepping, >> + 0, NULL); >> + return ignore_event (ourstatus); >> + } >> + >> /* If GDB is not interested in this signal, don't stop other >> threads, and don't report it to GDB. Just resume the inferior >> right away. We do this for threading-related signals as well as >> @@ -3449,8 +3565,16 @@ linux_wait_1 (ptid_t ptid, >> } >> } >> >> - if (current_thread->last_resume_kind == resume_stop >> - && WSTOPSIG (w) == SIGSTOP) >> + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) >> + { >> + int sysret; >> + >> + get_syscall_trapinfo (event_child, >> + &ourstatus->value.syscall_number, &sysret); >> + ourstatus->kind = event_child->syscall_state; >> + } >> + else if (current_thread->last_resume_kind == resume_stop >> + && WSTOPSIG (w) == SIGSTOP) >> { >> /* A thread that has been requested to stop by GDB with vCont;t, >> and it stopped cleanly, so report as SIG0. The use of >> @@ -3867,6 +3991,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, >> struct thread_info *thread = get_lwp_thread (lwp); >> struct thread_info *saved_thread; >> int fast_tp_collecting; >> + int ptrace_request; >> struct process_info *proc = get_thread_process (thread); >> >> /* Note that target description may not be initialised >> @@ -4052,7 +4177,14 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, >> regcache_invalidate_thread (thread); >> errno = 0; >> lwp->stepping = step; >> - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread), >> + if (step) >> + ptrace_request = PTRACE_SINGLESTEP; >> + else if (gdb_catching_syscalls_p (lwp)) >> + ptrace_request = PTRACE_SYSCALL; > > Unnecessary extra space after =. > >> + else >> + ptrace_request = PTRACE_CONT; > > Ditto. > >> + ptrace (ptrace_request, >> + lwpid_of (thread), >> (PTRACE_TYPE_ARG3) 0, >> /* Coerce to a uintptr_t first to avoid potential gcc warning >> of coercing an 8 byte integer to a 4 byte pointer. */ >> @@ -6135,6 +6267,13 @@ linux_process_qsupported (const char *query) >> } >> >> static int >> +linux_supports_catch_syscall (void) >> +{ >> + return (the_low_target.get_syscall_trapinfo != NULL >> + && linux_supports_tracesysgood()); >> +} >> + >> +static int >> linux_supports_tracepoints (void) >> { >> if (*the_low_target.supports_tracepoints == NULL) >> @@ -7010,6 +7149,7 @@ static struct target_ops linux_target_ops = { >> linux_common_core_of_thread, >> linux_read_loadmap, >> linux_process_qsupported, >> + linux_supports_catch_syscall, >> linux_supports_tracepoints, >> linux_read_pc, >> linux_write_pc, >> diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h >> index ccf4c9421d87..71d72f48ea3a 100644 >> --- a/gdb/gdbserver/linux-low.h >> +++ b/gdb/gdbserver/linux-low.h >> @@ -201,6 +201,12 @@ struct linux_target_ops >> /* Hook to support target specific qSupported. */ >> void (*process_qsupported) (const char *); >> >> + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the >> + return code. Only to be called when inferior is stopped >> + due to SYSCALL_SIGTRAP. */ >> + void (*get_syscall_trapinfo) (struct regcache *regcache, >> + int *sysno, int *sysret); >> + >> /* Returns true if the low target supports tracepoints. */ >> int (*supports_tracepoints) (void); >> >> @@ -271,6 +277,13 @@ struct lwp_info >> event already received in a wait()). */ >> int stopped; >> >> + /* Signal wether we are in a SYSCALL_ENTRY or >> + in a SYSCALL_RETURN event. >> + Values: >> + - TARGET_WAITKIND_SYSCALL_ENTRY >> + - TARGET_WAITKIND_SYSCALL_RETURN */ >> + enum target_waitkind syscall_state; >> + >> /* When stopped is set, the last wait status recorded for this lwp. */ >> int last_status; >> >> diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c >> index 89ec4e54b3b8..6e3c589de8fb 100644 >> --- a/gdb/gdbserver/linux-x86-low.c >> +++ b/gdb/gdbserver/linux-x86-low.c >> @@ -1432,6 +1432,36 @@ x86_arch_setup (void) >> current_process ()->tdesc = x86_linux_read_description (); >> } >> >> +/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return >> + code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ >> + >> +static void >> +x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno, int *sysret) >> +{ >> + int use_64bit = register_size (regcache->tdesc, 0) == 8; >> + >> + if (use_64bit) >> + { >> + long l_sysno; >> + long l_sysret; >> + >> + collect_register_by_name (regcache, "orig_rax", &l_sysno); >> + collect_register_by_name (regcache, "rax", &l_sysret); >> + *sysno = (int) l_sysno; >> + *sysret = (int) l_sysret; >> + } >> + else >> + { >> + int l_sysno; >> + int l_sysret; >> + >> + collect_register_by_name (regcache, "orig_eax", &l_sysno); >> + collect_register_by_name (regcache, "eax", &l_sysret); >> + *sysno = (int) l_sysno; >> + *sysret = (int) l_sysret; > > These casts are confusing, especially when coupled with the l_ prefix > ("l" for "long" is the first thing that comes to mind, but these are ints). > I can appreciate them when casting from long to int, but here we > already have ints. Ah, yeah, I think this is simply duped from the 64bit block. > How about changing the parameters to sysno_ptr, sysret_ptr, > and change l_sysno,l_sysret to sysno,sysret? > Or some such. I think we can just drop the locals entirely for this block and just collect the registers directly into the sysno/sysret parameters. >> + } >> +} >> + >> static int >> x86_supports_tracepoints (void) >> { >> @@ -3292,6 +3322,7 @@ struct linux_target_ops the_low_target = >> x86_linux_new_fork, >> x86_linux_prepare_to_resume, >> x86_linux_process_qsupported, >> + x86_get_syscall_trapinfo, >> x86_supports_tracepoints, >> x86_get_thread_area, >> x86_install_fast_tracepoint_jump_pad, >> diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c >> index d72c46515d13..1301acea49b7 100644 >> --- a/gdb/gdbserver/nto-low.c >> +++ b/gdb/gdbserver/nto-low.c >> @@ -979,6 +979,7 @@ static struct target_ops nto_target_ops = { >> NULL, /* core_of_thread */ >> NULL, /* read_loadmap */ >> NULL, /* process_qsupported */ >> + NULL, /* supports_catch_syscall */ >> NULL, /* supports_tracepoints */ >> NULL, /* read_pc */ >> NULL, /* write_pc */ >> diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c >> index e36609176afa..19eed77d4874 100644 >> --- a/gdb/gdbserver/remote-utils.c >> +++ b/gdb/gdbserver/remote-utils.c >> @@ -1119,6 +1119,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, >> case TARGET_WAITKIND_VFORKED: >> case TARGET_WAITKIND_VFORK_DONE: >> case TARGET_WAITKIND_EXECD: >> + case TARGET_WAITKIND_SYSCALL_ENTRY: >> + case TARGET_WAITKIND_SYSCALL_RETURN: >> { >> struct thread_info *saved_thread; >> const char **regp; >> @@ -1161,6 +1163,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, >> status->value.execd_pathname = NULL; >> buf += strlen (buf); >> } >> + else if ((status->kind == TARGET_WAITKIND_SYSCALL_ENTRY) >> + || (status->kind == TARGET_WAITKIND_SYSCALL_RETURN)) >> + { >> + enum gdb_signal signal = GDB_SIGNAL_TRAP; >> + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY >> + ? "syscall_entry" : "syscall_return"); >> + >> + sprintf (buf, "T%02x%s:%x;", signal, event, >> + status->value.syscall_number); >> + } >> else >> sprintf (buf, "T%02x", status->value.sig); >> >> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c >> index fd2804beaa4e..72621f261dfa 100644 >> --- a/gdb/gdbserver/server.c >> +++ b/gdb/gdbserver/server.c >> @@ -592,6 +592,52 @@ handle_general_set (char *own_buf) >> return; >> } >> >> + if (startswith (own_buf, "QCatchSyscalls:1")) >> + { >> + const char *p; >> + CORE_ADDR sysno; >> + struct process_info *process; >> + >> + if (!target_running () || !target_supports_catch_syscall ()) >> + { >> + write_enn (own_buf); >> + return; >> + } >> + >> + process = current_process (); >> + >> + VEC_truncate (int, process->syscalls_to_catch, 0); >> + >> + p = own_buf + strlen("QCatchSyscalls:1"); >> + if (*p == ';') >> + { >> + p += 1; >> + while (*p) >> + { >> + p = decode_address_to_semicolon (&sysno, p); >> + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); >> + } >> + } >> + else >> + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); >> + >> + write_ok (own_buf); >> + return; >> + } >> + >> + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) >> + { >> + if (!target_running () || !target_supports_catch_syscall ()) >> + { >> + write_enn (own_buf); >> + return; >> + } >> + >> + VEC_free (int, current_process ()->syscalls_to_catch); >> + write_ok (own_buf); >> + return; >> + } >> + >> if (startswith (own_buf, "QProgramSignals:")) >> { >> int numsigs = (int) GDB_SIGNAL_LAST, i; >> @@ -2140,6 +2186,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) >> "PacketSize=%x;QPassSignals+;QProgramSignals+", >> PBUFSIZ - 1); >> >> + if (target_supports_catch_syscall ()) >> + strcat (own_buf, ";QCatchSyscalls+"); >> + >> if (the_target->qxfer_libraries_svr4 != NULL) >> strcat (own_buf, ";qXfer:libraries-svr4:read+" >> ";augmented-libraries-svr4-read+"); >> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h >> index 96ad4fa58b7c..a8780ebfbc65 100644 >> --- a/gdb/gdbserver/server.h >> +++ b/gdb/gdbserver/server.h >> @@ -133,4 +133,10 @@ extern void discard_queued_stop_replies (ptid_t ptid); >> as large as the largest register set supported by gdbserver. */ >> #define PBUFSIZ 16384 >> >> +/* Definition for an unknown syscall, used basically in error-cases. */ >> +#define UNKNOWN_SYSCALL (-1) >> + >> +/* Definition for any syscall, used for unfiltered syscall reporting. */ >> +#define ANY_SYSCALL (-2) >> + >> #endif /* SERVER_H */ >> diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c >> index 89bed7a02dd1..55ec0caef296 100644 >> --- a/gdb/gdbserver/spu-low.c >> +++ b/gdb/gdbserver/spu-low.c >> @@ -699,6 +699,7 @@ static struct target_ops spu_target_ops = { >> NULL, /* core_of_thread */ >> NULL, /* read_loadmap */ >> NULL, /* process_qsupported */ >> + NULL, /* supports_catch_syscall */ >> NULL, /* supports_tracepoints */ >> NULL, /* read_pc */ >> NULL, /* write_pc */ >> diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h >> index 769c876ede49..ef8a7680ccca 100644 >> --- a/gdb/gdbserver/target.h >> +++ b/gdb/gdbserver/target.h >> @@ -309,6 +309,10 @@ struct target_ops >> /* Target specific qSupported support. */ >> void (*process_qsupported) (const char *); >> >> + /* Return 1 if the target supports catch syscall, 0 (or leave the >> + callback NULL) otherwise. */ >> + int (*supports_catch_syscall) (void); >> + >> /* Return 1 if the target supports tracepoints, 0 (or leave the >> callback NULL) otherwise. */ >> int (*supports_tracepoints) (void); >> @@ -526,6 +530,10 @@ int kill_inferior (int); >> the_target->process_qsupported (query); \ >> } while (0) >> >> +#define target_supports_catch_syscall() \ >> + (the_target->supports_catch_syscall ? \ >> + (*the_target->supports_catch_syscall) () : 0) >> + >> #define target_supports_tracepoints() \ >> (the_target->supports_tracepoints \ >> ? (*the_target->supports_tracepoints) () : 0) >> diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c >> index 6e33509c0b50..4314513876fa 100644 >> --- a/gdb/gdbserver/win32-low.c >> +++ b/gdb/gdbserver/win32-low.c >> @@ -1844,6 +1844,7 @@ static struct target_ops win32_target_ops = { >> NULL, /* core_of_thread */ >> NULL, /* read_loadmap */ >> NULL, /* process_qsupported */ >> + NULL, /* supports_catch_syscall */ >> NULL, /* supports_tracepoints */ >> NULL, /* read_pc */ >> NULL, /* write_pc */ >> diff --git a/gdb/remote.c b/gdb/remote.c >> index fed397affeab..41751e9d93b1 100644 >> --- a/gdb/remote.c >> +++ b/gdb/remote.c >> @@ -1388,6 +1388,7 @@ enum { >> PACKET_qSupported, >> PACKET_qTStatus, >> PACKET_QPassSignals, >> + PACKET_QCatchSyscalls, >> PACKET_QProgramSignals, >> PACKET_qCRC, >> PACKET_qSearch_memory, >> @@ -1973,6 +1974,99 @@ remote_pass_signals (struct target_ops *self, >> } >> } >> >> +/* If 'QCatchSyscalls' is supported, tell the remote stub >> + to report syscalls to GDB. */ >> + >> +static int >> +remote_set_syscall_catchpoint (struct target_ops *self, >> + int pid, int needed, int any_count, >> + int table_size, int *table) >> +{ >> + char *catch_packet, *p; >> + enum packet_result result; >> + int n_sysno = 0; >> + >> + if (remote_protocol_packets[PACKET_QCatchSyscalls].support == PACKET_DISABLE) >> + { >> + /* Not supported. */ >> + return 1; >> + } >> + >> + if (needed && !any_count) >> + { >> + int i; >> + >> + /* Count how many syscalls are to be caught (table[sysno] != 0). */ >> + for (i = 0; i < table_size; i++) >> + { >> + if (table[i]) >> + n_sysno++; >> + } >> + } >> + >> + if (remote_debug) >> + { >> + fprintf_unfiltered (gdb_stdlog, >> + "remote_set_syscall_catchpoint " >> + "pid %d needed %d any_count %d n_sysno %d\n", >> + pid, needed, any_count, n_sysno); >> + } >> + >> + if (needed) >> + { >> + /* Prepare a packet with the sysno list, assuming max 8+1 >> + characters for a sysno. If the resulting packet size is too >> + big, fallback on the non selective packet. */ >> + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; >> + >> + catch_packet = xmalloc (maxpktsz); >> + strcpy (catch_packet, "QCatchSyscalls:1"); >> + if (!any_count) >> + { >> + int i; >> + char *p; >> + >> + p = catch_packet; >> + p += strlen (p); >> + >> + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ >> + for (i = 0; i < table_size; i++) >> + { >> + if (table[i]) >> + { >> + xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); >> + p += strlen (p); >> + } >> + } >> + } >> + if (strlen (catch_packet) > get_remote_packet_size ()) >> + { >> + /* catch_packet too big. Fallback to less efficient >> + non selective mode, with GDB doing the filtering. */ >> + catch_packet[strlen ("QCatchSyscalls:1")] = 0; >> + } >> + } >> + else >> + { >> + catch_packet = xmalloc (strlen ("QCatchSyscalls:0") + 1); >> + strcpy (catch_packet, "QCatchSyscalls:0"); >> + } >> + >> + { >> + struct remote_state *rs = get_remote_state (); >> + char *buf = rs->buf; >> + >> + putpkt (catch_packet); >> + getpkt (&rs->buf, &rs->buf_size, 0); >> + result = packet_ok (buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); >> + xfree (catch_packet); >> + if (result == PACKET_OK) >> + return 0; >> + else >> + return -1; >> + } >> +} >> + >> /* If 'QProgramSignals' is supported, tell the remote stub what >> signals it should pass through to the inferior when detaching. */ >> >> @@ -4328,6 +4422,8 @@ static const struct protocol_feature remote_protocol_features[] = { >> PACKET_qXfer_traceframe_info }, >> { "QPassSignals", PACKET_DISABLE, remote_supported_packet, >> PACKET_QPassSignals }, >> + { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet, >> + PACKET_QCatchSyscalls }, >> { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, >> PACKET_QProgramSignals }, >> { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, >> @@ -6159,6 +6255,22 @@ Packet: '%s'\n"), >> >> if (strprefix (p, p1, "thread")) >> event->ptid = read_ptid (++p1, &p); >> + else if (strprefix (p, p1, "syscall_entry")) >> + { >> + ULONGEST sysno; >> + >> + event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; >> + p = unpack_varlen_hex (++p1, &sysno); >> + event->ws.value.syscall_number = (int) sysno; >> + } >> + else if (strprefix (p, p1, "syscall_return")) >> + { >> + ULONGEST sysno; >> + >> + event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; >> + p = unpack_varlen_hex (++p1, &sysno); >> + event->ws.value.syscall_number = (int) sysno; >> + } >> else if (strprefix (p, p1, "watch") >> || strprefix (p, p1, "rwatch") >> || strprefix (p, p1, "awatch")) >> @@ -12734,6 +12846,7 @@ Specify the serial device it is connected to\n\ >> remote_ops.to_load = remote_load; >> remote_ops.to_mourn_inferior = remote_mourn; >> remote_ops.to_pass_signals = remote_pass_signals; >> + remote_ops.to_set_syscall_catchpoint = remote_set_syscall_catchpoint; >> remote_ops.to_program_signals = remote_program_signals; >> remote_ops.to_thread_alive = remote_thread_alive; >> remote_ops.to_update_thread_list = remote_update_thread_list; >> @@ -13263,6 +13376,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, >> add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], >> "QPassSignals", "pass-signals", 0); >> >> + add_packet_config_cmd (&remote_protocol_packets[PACKET_QCatchSyscalls], >> + "QCatchSyscalls", "catch-syscalls", 0); >> + >> add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], >> "QProgramSignals", "program-signals", 0); >> >> diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp >> index c1cfe23cdddb..0ba078db22ac 100644 >> --- a/gdb/testsuite/gdb.base/catch-syscall.exp >> +++ b/gdb/testsuite/gdb.base/catch-syscall.exp >> @@ -19,7 +19,15 @@ >> # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> >> # on September/2008. >> >> -if { [is_remote target] || ![isnative] } then { >> +if { ![isnative] } then { >> + continue >> +} >> + >> +# This shall be updated whenever QCatchSyscalls packet support is implemented >> +# on some gdbserver architecture. >> +if { [is_remote target] >> + && ![istarget "x86_64-*-linux*"] >> + && ![istarget "i\[34567\]86-*-linux*"] } { >> continue >> } >> >> @@ -390,7 +398,10 @@ proc do_syscall_tests {} { >> if [runto_main] then { test_catch_syscall_skipping_return } >> >> # Testing the 'catch syscall' command starting mid-vfork. >> - if [runto_main] then { test_catch_syscall_mid_vfork } >> + # (Only local or extended-remote can use "catch vfork".) >> + if { ![is_remote target] || [target_info gdb_protocol] == "extended-remote" } { >> + if [runto_main] then { test_catch_syscall_mid_vfork } >> + } >> >> # Testing if the 'catch syscall' command works when switching to >> # different architectures on-the-fly (PR gdb/10737). ^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP 2015-10-30 11:02 [PATCH] Implement 'catch syscall' for gdbserver Josh Stone ` (2 preceding siblings ...) 2015-11-23 4:20 ` Doug Evans @ 2015-11-26 2:53 ` Josh Stone 2015-11-26 2:54 ` [PATCH v2 2/2] Implement 'catch syscall' for gdbserver Josh Stone ` (2 more replies) 3 siblings, 3 replies; 49+ messages in thread From: Josh Stone @ 2015-11-26 2:53 UTC (permalink / raw) To: gdb-patches Cc: philippe.waroquiers, sergiodj, palves, eliz, xdje42, Josh Stone The ptrace options should be set as soon as we know a thread is stopped, so no events can be missed. There's an arch-setup early return that was effectively delaying this update before, and I found for instance that the first syscall event wouldn't be properly reported with TRACESYSGOOD. It's now more similar to the way that gdb/linux-nat.c handles it. gdb/gdbserver/ChangeLog: 2015-11-25 Josh Stone <jistone@redhat.com> * linux-low.c (linux_low_filter_event): Set ptrace options as soon as each thread is stopped, even before arch-specific setup. --- gdb/gdbserver/linux-low.c | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index e3a56a7c1690..9f577aefee1b 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -2249,6 +2249,16 @@ linux_low_filter_event (int lwpid, int wstat) gdb_assert (WIFSTOPPED (wstat)); + /* Set ptrace flags ASAP, so no events can be missed. */ + if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) + { + struct process_info *proc = find_process_pid (pid_of (thread)); + int options = linux_low_ptrace_options (proc->attached); + + linux_enable_event_reporting (lwpid, options); + child->must_set_ptrace_flags = 0; + } + if (WIFSTOPPED (wstat)) { struct process_info *proc; @@ -2276,15 +2286,6 @@ linux_low_filter_event (int lwpid, int wstat) } } - if (WIFSTOPPED (wstat) && child->must_set_ptrace_flags) - { - struct process_info *proc = find_process_pid (pid_of (thread)); - int options = linux_low_ptrace_options (proc->attached); - - linux_enable_event_reporting (lwpid, options); - child->must_set_ptrace_flags = 0; - } - /* Be careful to not overwrite stop_pc until check_stopped_by_breakpoint is called. */ if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP -- 2.5.0 ^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH v2 2/2] Implement 'catch syscall' for gdbserver 2015-11-26 2:53 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Josh Stone @ 2015-11-26 2:54 ` Josh Stone 2015-11-26 10:34 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Pedro Alves 2015-12-04 2:26 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Josh Stone 2 siblings, 0 replies; 49+ messages in thread From: Josh Stone @ 2015-11-26 2:54 UTC (permalink / raw) To: gdb-patches Cc: philippe.waroquiers, sergiodj, palves, eliz, xdje42, Josh Stone This adds a new QCatchSyscalls packet to enable 'catch syscall', and new stop reasons "syscall_entry" and "syscall_return" for those events. It is currently only supported on Linux x86 and x86_64. gdb/ChangeLog: 2015-11-25 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new GDBserver support for catch syscall. * remote.c (PACKET_QCatchSyscalls): New enum. (remote_set_syscall_catchpoint): New function. (remote_protocol_features): New element for QCatchSyscalls. (remote_parse_stop_reply): Parse syscall_entry/return stops. (init_remote_ops): Install remote_set_syscall_catchpoint. (_initialize_remote): Config QCatchSyscalls. gdb/doc/ChangeLog: 2015-11-25 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. (Stop Reply Packets): List the syscall entry and return stop reasons. (General Query Packets): Describe QCatchSyscalls, and add it to the table and detailed list of stub features. gdb/gdbserver/ChangeLog: 2015-11-25 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * inferiors.h: Include "gdb_vecs.h". (struct process_info): Add syscalls_to_catch. * inferiors.c (remove_process): Free syscalls_to_catch. * remote-utils.c (prepare_resume_reply): Report syscall_entry and syscall_resume stops. * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. * server.c (handle_general_set): Handle QCatchSyscalls. (handle_query): Report support for QCatchSyscalls. * target.h (struct target_ops): Add supports_catch_syscall. (target_supports_catch_syscall): New macro. * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. (struct lwp_info): Add syscall_state. * linux-low.c (handle_extended_wait): Mark syscall_state as an entry. (get_syscall_trapinfo): New function, proxy to the_low_target. (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. (linux_low_filter_event): Toggle syscall_state entry/return for syscall traps, and set it ignored for all others. (gdb_catching_syscalls_p): New function. (gdb_catch_this_syscall_p): New function. (linux_wait_1): Handle SYSCALL_SIGTRAP. (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. (linux_supports_catch_syscall): New function. (linux_target_ops): Install it. * linux-x86-low.c (x86_get_syscall_trapinfo): New function. (the_low_target): Install it. * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. * spu-low.c (spu_target_ops): Likewise. * win32-low.c (win32_target_ops): Likewise. gdb/testsuite/ChangeLog: 2015-11-25 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux remote targets. (do_syscall_tests): Only test mid-vfork on local or extended-remote. --- gdb/NEWS | 10 +++ gdb/doc/gdb.texinfo | 56 +++++++++++++ gdb/gdbserver/inferiors.c | 1 + gdb/gdbserver/inferiors.h | 5 ++ gdb/gdbserver/linux-low.c | 140 ++++++++++++++++++++++++++++++- gdb/gdbserver/linux-low.h | 13 +++ gdb/gdbserver/linux-x86-low.c | 26 ++++++ gdb/gdbserver/nto-low.c | 1 + gdb/gdbserver/remote-utils.c | 12 +++ gdb/gdbserver/server.c | 49 +++++++++++ gdb/gdbserver/server.h | 6 ++ gdb/gdbserver/spu-low.c | 1 + gdb/gdbserver/target.h | 8 ++ gdb/gdbserver/win32-low.c | 1 + gdb/remote.c | 116 +++++++++++++++++++++++++ gdb/testsuite/gdb.base/catch-syscall.exp | 15 +++- 16 files changed, 455 insertions(+), 5 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 31072b7fd3ed..24ea91fdeea5 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -84,6 +84,11 @@ exec-events feature in qSupported response can contain the corresponding 'stubfeature'. Set and show commands can be used to display whether these features are enabled. +QCatchSyscalls:1 [;SYSNO]... +QCatchSyscalls:0 + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") + catching syscalls from the inferior process. + * Extended-remote exec events ** GDB now has support for exec events on extended-remote Linux targets. @@ -94,6 +99,11 @@ set remote exec-event-feature-packet show remote exec-event-feature-packet Set/show the use of the remote exec event feature. +* New features in the GDB remote stub, GDBserver + + ** GDBserver now supports catch syscall. Currently enabled + on x86/x86_64 GNU/Linux targets. + *** Changes in GDB 7.10 * Support for process record-replay and reverse debugging on aarch64*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 1917008adee4..4830440e436a 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20135,6 +20135,10 @@ are: @tab @code{qSupported} @tab Remote communications parameters +@item @code{catch-syscalls} +@tab @code{QCatchSyscalls} +@tab @code{catch syscall} + @item @code{pass-signals} @tab @code{QPassSignals} @tab @code{handle @var{signal}} @@ -35432,6 +35436,11 @@ The currently defined stop reasons are: The packet indicates a watchpoint hit, and @var{r} is the data address, in hex. +@item syscall_entry +@itemx syscall_return +The packet indicates a syscall entry or return, and @var{r} is the +syscall number, in hex. + @cindex shared library events, remote reply @item library The packet indicates that the loaded libraries have changed. @@ -35892,6 +35901,44 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). Use of this packet is controlled by the @code{set non-stop} command; @pxref{Non-Stop Mode}. +@item QCatchSyscalls:1 @r{[};@var{sysno}@r{]}@dots{} +@itemx QCatchSyscalls:0 +@cindex catch syscalls from inferior, remote request +@cindex @samp{QCatchSyscalls} packet +@anchor{QCatchSyscalls} +Enable (@samp{QCatchSyscalls:1}) or disable (@samp{QCatchSyscalls:0}) +catching syscalls from the inferior process. + +For @samp{QCatchSyscalls:1}, each listed syscall @var{sysno} (encoded +in hex) should be reported to @value{GDBN}. If no syscall @var{sysno} +is listed, every system call should be reported. + +Note that if a syscall not in the list is reported, @value{GDBN} will +still filter the event according to its own list from all corresponding +@code{catch syscall} commands. However, it is more efficient to only +report the requested syscalls. + +Multiple @samp{QCatchSyscalls:1} packets do not combine; any earlier +@samp{QCatchSyscalls:1} list is completely replaced by the new list. + +Reply: +@table @samp +@item OK +The request succeeded. + +@item E @var{nn} +An error occurred. @var{nn} are hex digits. + +@item @w{} +An empty reply indicates that @samp{QCatchSyscalls} is not supported by +the stub. +@end table + +Use of this packet is controlled by the @code{set remote catch-syscalls} +command (@pxref{Remote Configuration, set remote catch-syscalls}). +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} @cindex pass signals to inferior, remote request @cindex @samp{QPassSignals} packet @@ -36310,6 +36357,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{QCatchSyscalls} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QPassSignals} @tab No @tab @samp{-} @@ -36503,6 +36555,10 @@ packet (@pxref{qXfer fdpic loadmap read}). The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). +@item QCatchSyscalls +The remote stub understands the @samp{QCatchSyscalls} packet +(@pxref{QCatchSyscalls}). + @item QPassSignals The remote stub understands the @samp{QPassSignals} packet (@pxref{QPassSignals}). diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 72a3ef1b1b61..a8263656a4af 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -316,6 +316,7 @@ remove_process (struct process_info *process) free_all_breakpoints (process); gdb_assert (find_thread_process (process) == NULL); remove_inferior (&all_processes, &process->entry); + VEC_free (int, process->syscalls_to_catch); free (process); } diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h index d7226163c0e8..43fc869f6612 100644 --- a/gdb/gdbserver/inferiors.h +++ b/gdb/gdbserver/inferiors.h @@ -19,6 +19,8 @@ #ifndef INFERIORS_H #define INFERIORS_H +#include "gdb_vecs.h" + /* Generic information for tracking a list of ``inferiors'' - threads, processes, etc. */ struct inferior_list @@ -67,6 +69,9 @@ struct process_info /* The list of installed fast tracepoints. */ struct fast_tracepoint_jump *fast_tracepoint_jumps; + /* The list of syscalls to report, or just ANY_SYSCALL. */ + VEC (int) *syscalls_to_catch; + const struct target_desc *tdesc; /* Private target data. */ diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 9f577aefee1b..f74feb81f753 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -447,6 +447,11 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) struct thread_info *event_thr = get_lwp_thread (event_lwp); struct lwp_info *new_lwp; + /* All extended events we currently use are mid-syscall. Only + PTRACE_EVENT_STOP is delivered more like a signal-stop, but + you have to be using PTRACE_SEIZE to get that. */ + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) || (event == PTRACE_EVENT_CLONE)) { @@ -662,6 +667,40 @@ get_pc (struct lwp_info *lwp) return pc; } +/* This function should only be called if LWP got a SYSCALL_SIGTRAP. + Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. */ + +static void +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno, int *sysret) +{ + struct thread_info *saved_thread; + struct regcache *regcache; + + if (the_low_target.get_syscall_trapinfo == NULL) + { + /* If we cannot get the syscall trapinfo, report an unknown + system call number and -ENOSYS return value. */ + *sysno = UNKNOWN_SYSCALL; + *sysret = -ENOSYS; + return; + } + + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + + regcache = get_thread_regcache (current_thread, 1); + (*the_low_target.get_syscall_trapinfo) (regcache, sysno, sysret); + + if (debug_threads) + { + debug_printf ("get_syscall_trapinfo sysno %d sysret %d\n", + *sysno, *sysret); + } + + current_thread = saved_thread; +} + /* This function should only be called if LWP got a SIGTRAP. The SIGTRAP could mean several things. @@ -2154,6 +2193,8 @@ linux_low_ptrace_options (int attached) if (report_exec_events) options |= PTRACE_O_TRACEEXEC; + options |= PTRACE_O_TRACESYSGOOD; + return options; } @@ -2286,6 +2327,21 @@ linux_low_filter_event (int lwpid, int wstat) } } + /* Always update syscall_state, even if it will be filtered later. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) + { + child->syscall_state + = (child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY + ? TARGET_WAITKIND_SYSCALL_RETURN + : TARGET_WAITKIND_SYSCALL_ENTRY); + } + else + { + /* Almost all other ptrace-stops are known to be outside of system + calls, with further exceptions in handle_extended_wait. */ + child->syscall_state = TARGET_WAITKIND_IGNORE; + } + /* Be careful to not overwrite stop_pc until check_stopped_by_breakpoint is called. */ if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP @@ -2886,6 +2942,44 @@ ignore_event (struct target_waitstatus *ourstatus) return null_ptid; } +/* Returns 1 if GDB is interested in any event_child syscalls. */ + +static int +gdb_catching_syscalls_p (struct lwp_info *event_child) +{ + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + return !VEC_empty (int, proc->syscalls_to_catch); +} + +/* Returns 1 if GDB is interested in the event_child syscall. + Only to be called when stopped reason is SYSCALL_SIGTRAP. */ + +static int +gdb_catch_this_syscall_p (struct lwp_info *event_child) +{ + int i, iter; + int sysno, sysret; + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + if (VEC_empty (int, proc->syscalls_to_catch)) + return 0; + + if (VEC_index (int, proc->syscalls_to_catch, 0) == ANY_SYSCALL) + return 1; + + get_syscall_trapinfo (event_child, &sysno, &sysret); + for (i = 0; + VEC_iterate (int, proc->syscalls_to_catch, i, iter); + i++) + if (iter == sysno) + return 1; + + return 0; +} + /* Wait for process, returns status. */ static ptid_t @@ -3196,6 +3290,22 @@ linux_wait_1 (ptid_t ptid, /* Check whether GDB would be interested in this event. */ + /* Check if GDB is interested in this syscall. */ + if (WIFSTOPPED (w) + && WSTOPSIG (w) == SYSCALL_SIGTRAP + && !gdb_catch_this_syscall_p (event_child)) + { + if (debug_threads) + { + debug_printf ("Ignored syscall for LWP %ld.\n", + lwpid_of (current_thread)); + } + + linux_resume_one_lwp (event_child, event_child->stepping, + 0, NULL); + return ignore_event (ourstatus); + } + /* If GDB is not interested in this signal, don't stop other threads, and don't report it to GDB. Just resume the inferior right away. We do this for threading-related signals as well as @@ -3450,8 +3560,16 @@ linux_wait_1 (ptid_t ptid, } } - if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) == SIGSTOP) + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) + { + int sysret; + + get_syscall_trapinfo (event_child, + &ourstatus->value.syscall_number, &sysret); + ourstatus->kind = event_child->syscall_state; + } + else if (current_thread->last_resume_kind == resume_stop + && WSTOPSIG (w) == SIGSTOP) { /* A thread that has been requested to stop by GDB with vCont;t, and it stopped cleanly, so report as SIG0. The use of @@ -3868,6 +3986,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, struct thread_info *thread = get_lwp_thread (lwp); struct thread_info *saved_thread; int fast_tp_collecting; + int ptrace_request; struct process_info *proc = get_thread_process (thread); /* Note that target description may not be initialised @@ -4053,7 +4172,14 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, regcache_invalidate_thread (thread); errno = 0; lwp->stepping = step; - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread), + if (step) + ptrace_request = PTRACE_SINGLESTEP; + else if (gdb_catching_syscalls_p (lwp)) + ptrace_request = PTRACE_SYSCALL; + else + ptrace_request = PTRACE_CONT; + ptrace (ptrace_request, + lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, /* Coerce to a uintptr_t first to avoid potential gcc warning of coercing an 8 byte integer to a 4 byte pointer. */ @@ -6136,6 +6262,13 @@ linux_process_qsupported (char **features, int count) } static int +linux_supports_catch_syscall (void) +{ + return (the_low_target.get_syscall_trapinfo != NULL + && linux_supports_tracesysgood()); +} + +static int linux_supports_tracepoints (void) { if (*the_low_target.supports_tracepoints == NULL) @@ -7011,6 +7144,7 @@ static struct target_ops linux_target_ops = { linux_common_core_of_thread, linux_read_loadmap, linux_process_qsupported, + linux_supports_catch_syscall, linux_supports_tracepoints, linux_read_pc, linux_write_pc, diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index f1d4f0f5a462..f5c219d2c821 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -201,6 +201,12 @@ struct linux_target_ops /* Hook to support target specific qSupported. */ void (*process_qsupported) (char **, int count); + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. Only to be called when inferior is stopped + due to SYSCALL_SIGTRAP. */ + void (*get_syscall_trapinfo) (struct regcache *regcache, + int *sysno, int *sysret); + /* Returns true if the low target supports tracepoints. */ int (*supports_tracepoints) (void); @@ -271,6 +277,13 @@ struct lwp_info event already received in a wait()). */ int stopped; + /* Signal wether we are in a SYSCALL_ENTRY or + in a SYSCALL_RETURN event. + Values: + - TARGET_WAITKIND_SYSCALL_ENTRY + - TARGET_WAITKIND_SYSCALL_RETURN */ + enum target_waitkind syscall_state; + /* When stopped is set, the last wait status recorded for this lwp. */ int last_status; diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index 7f0719401a52..2acadd1700c3 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -1438,6 +1438,31 @@ x86_arch_setup (void) current_process ()->tdesc = x86_linux_read_description (); } +/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return + code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ + +static void +x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno, int *sysret) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + long l_sysno; + long l_sysret; + + collect_register_by_name (regcache, "orig_rax", &l_sysno); + collect_register_by_name (regcache, "rax", &l_sysret); + *sysno = (int) l_sysno; + *sysret = (int) l_sysret; + } + else + { + collect_register_by_name (regcache, "orig_eax", sysno); + collect_register_by_name (regcache, "eax", sysret); + } +} + static int x86_supports_tracepoints (void) { @@ -3298,6 +3323,7 @@ struct linux_target_ops the_low_target = x86_linux_new_fork, x86_linux_prepare_to_resume, x86_linux_process_qsupported, + x86_get_syscall_trapinfo, x86_supports_tracepoints, x86_get_thread_area, x86_install_fast_tracepoint_jump_pad, diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index d72c46515d13..1301acea49b7 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -979,6 +979,7 @@ static struct target_ops nto_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index e36609176afa..19eed77d4874 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1119,6 +1119,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, case TARGET_WAITKIND_VFORKED: case TARGET_WAITKIND_VFORK_DONE: case TARGET_WAITKIND_EXECD: + case TARGET_WAITKIND_SYSCALL_ENTRY: + case TARGET_WAITKIND_SYSCALL_RETURN: { struct thread_info *saved_thread; const char **regp; @@ -1161,6 +1163,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, status->value.execd_pathname = NULL; buf += strlen (buf); } + else if ((status->kind == TARGET_WAITKIND_SYSCALL_ENTRY) + || (status->kind == TARGET_WAITKIND_SYSCALL_RETURN)) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + ? "syscall_entry" : "syscall_return"); + + sprintf (buf, "T%02x%s:%x;", signal, event, + status->value.syscall_number); + } else sprintf (buf, "T%02x", status->value.sig); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 7d6c9cc47a25..7c5f033ce0a4 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -592,6 +592,52 @@ handle_general_set (char *own_buf) return; } + if (startswith (own_buf, "QCatchSyscalls:1")) + { + const char *p; + CORE_ADDR sysno; + struct process_info *process; + + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + process = current_process (); + + VEC_truncate (int, process->syscalls_to_catch, 0); + + p = own_buf + strlen("QCatchSyscalls:1"); + if (*p == ';') + { + p += 1; + while (*p) + { + p = decode_address_to_semicolon (&sysno, p); + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); + } + } + else + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); + + write_ok (own_buf); + return; + } + + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) + { + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + VEC_free (int, current_process ()->syscalls_to_catch); + write_ok (own_buf); + return; + } + if (startswith (own_buf, "QProgramSignals:")) { int numsigs = (int) GDB_SIGNAL_LAST, i; @@ -2147,6 +2193,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) "PacketSize=%x;QPassSignals+;QProgramSignals+", PBUFSIZ - 1); + if (target_supports_catch_syscall ()) + strcat (own_buf, ";QCatchSyscalls+"); + if (the_target->qxfer_libraries_svr4 != NULL) strcat (own_buf, ";qXfer:libraries-svr4:read+" ";augmented-libraries-svr4-read+"); diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 96ad4fa58b7c..a8780ebfbc65 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -133,4 +133,10 @@ extern void discard_queued_stop_replies (ptid_t ptid); as large as the largest register set supported by gdbserver. */ #define PBUFSIZ 16384 +/* Definition for an unknown syscall, used basically in error-cases. */ +#define UNKNOWN_SYSCALL (-1) + +/* Definition for any syscall, used for unfiltered syscall reporting. */ +#define ANY_SYSCALL (-2) + #endif /* SERVER_H */ diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c index 89bed7a02dd1..55ec0caef296 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -699,6 +699,7 @@ static struct target_ops spu_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 358a8ab77a83..b2ef96850420 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -311,6 +311,10 @@ struct target_ops features with COUNT elements. */ void (*process_qsupported) (char **features, int count); + /* Return 1 if the target supports catch syscall, 0 (or leave the + callback NULL) otherwise. */ + int (*supports_catch_syscall) (void); + /* Return 1 if the target supports tracepoints, 0 (or leave the callback NULL) otherwise. */ int (*supports_tracepoints) (void); @@ -528,6 +532,10 @@ int kill_inferior (int); the_target->process_qsupported (features, count); \ } while (0) +#define target_supports_catch_syscall() \ + (the_target->supports_catch_syscall ? \ + (*the_target->supports_catch_syscall) () : 0) + #define target_supports_tracepoints() \ (the_target->supports_tracepoints \ ? (*the_target->supports_tracepoints) () : 0) diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index b1de139cac70..678a5cecf1e9 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1844,6 +1844,7 @@ static struct target_ops win32_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/remote.c b/gdb/remote.c index 2bbab624b25d..b979c909618b 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1388,6 +1388,7 @@ enum { PACKET_qSupported, PACKET_qTStatus, PACKET_QPassSignals, + PACKET_QCatchSyscalls, PACKET_QProgramSignals, PACKET_qCRC, PACKET_qSearch_memory, @@ -1973,6 +1974,99 @@ remote_pass_signals (struct target_ops *self, } } +/* If 'QCatchSyscalls' is supported, tell the remote stub + to report syscalls to GDB. */ + +static int +remote_set_syscall_catchpoint (struct target_ops *self, + int pid, int needed, int any_count, + int table_size, int *table) +{ + char *catch_packet, *p; + enum packet_result result; + int n_sysno = 0; + + if (remote_protocol_packets[PACKET_QCatchSyscalls].support == PACKET_DISABLE) + { + /* Not supported. */ + return 1; + } + + if (needed && !any_count) + { + int i; + + /* Count how many syscalls are to be caught (table[sysno] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i]) + n_sysno++; + } + } + + if (remote_debug) + { + fprintf_unfiltered (gdb_stdlog, + "remote_set_syscall_catchpoint " + "pid %d needed %d any_count %d n_sysno %d\n", + pid, needed, any_count, n_sysno); + } + + if (needed) + { + /* Prepare a packet with the sysno list, assuming max 8+1 + characters for a sysno. If the resulting packet size is too + big, fallback on the non selective packet. */ + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; + + catch_packet = xmalloc (maxpktsz); + strcpy (catch_packet, "QCatchSyscalls:1"); + if (!any_count) + { + int i; + char *p; + + p = catch_packet; + p += strlen (p); + + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i]) + { + xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); + p += strlen (p); + } + } + } + if (strlen (catch_packet) > get_remote_packet_size ()) + { + /* catch_packet too big. Fallback to less efficient + non selective mode, with GDB doing the filtering. */ + catch_packet[strlen ("QCatchSyscalls:1")] = 0; + } + } + else + { + catch_packet = xmalloc (strlen ("QCatchSyscalls:0") + 1); + strcpy (catch_packet, "QCatchSyscalls:0"); + } + + { + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + + putpkt (catch_packet); + getpkt (&rs->buf, &rs->buf_size, 0); + result = packet_ok (buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); + xfree (catch_packet); + if (result == PACKET_OK) + return 0; + else + return -1; + } +} + /* If 'QProgramSignals' is supported, tell the remote stub what signals it should pass through to the inferior when detaching. */ @@ -4328,6 +4422,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_traceframe_info }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, + { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet, + PACKET_QCatchSyscalls }, { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QProgramSignals }, { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, @@ -6161,6 +6257,22 @@ Packet: '%s'\n"), if (strprefix (p, p1, "thread")) event->ptid = read_ptid (++p1, &p); + else if (strprefix (p, p1, "syscall_entry")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } + else if (strprefix (p, p1, "syscall_return")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } else if (strprefix (p, p1, "watch") || strprefix (p, p1, "rwatch") || strprefix (p, p1, "awatch")) @@ -12736,6 +12848,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_load = remote_load; remote_ops.to_mourn_inferior = remote_mourn; remote_ops.to_pass_signals = remote_pass_signals; + remote_ops.to_set_syscall_catchpoint = remote_set_syscall_catchpoint; remote_ops.to_program_signals = remote_program_signals; remote_ops.to_thread_alive = remote_thread_alive; remote_ops.to_update_thread_list = remote_update_thread_list; @@ -13265,6 +13378,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], "QPassSignals", "pass-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QCatchSyscalls], + "QCatchSyscalls", "catch-syscalls", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], "QProgramSignals", "program-signals", 0); diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp index c1cfe23cdddb..0ba078db22ac 100644 --- a/gdb/testsuite/gdb.base/catch-syscall.exp +++ b/gdb/testsuite/gdb.base/catch-syscall.exp @@ -19,7 +19,15 @@ # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> # on September/2008. -if { [is_remote target] || ![isnative] } then { +if { ![isnative] } then { + continue +} + +# This shall be updated whenever QCatchSyscalls packet support is implemented +# on some gdbserver architecture. +if { [is_remote target] + && ![istarget "x86_64-*-linux*"] + && ![istarget "i\[34567\]86-*-linux*"] } { continue } @@ -390,7 +398,10 @@ proc do_syscall_tests {} { if [runto_main] then { test_catch_syscall_skipping_return } # Testing the 'catch syscall' command starting mid-vfork. - if [runto_main] then { test_catch_syscall_mid_vfork } + # (Only local or extended-remote can use "catch vfork".) + if { ![is_remote target] || [target_info gdb_protocol] == "extended-remote" } { + if [runto_main] then { test_catch_syscall_mid_vfork } + } # Testing if the 'catch syscall' command works when switching to # different architectures on-the-fly (PR gdb/10737). -- 2.5.0 ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP 2015-11-26 2:53 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Josh Stone 2015-11-26 2:54 ` [PATCH v2 2/2] Implement 'catch syscall' for gdbserver Josh Stone @ 2015-11-26 10:34 ` Pedro Alves 2015-11-30 18:50 ` Josh Stone 2015-12-04 2:26 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Josh Stone 2 siblings, 1 reply; 49+ messages in thread From: Pedro Alves @ 2015-11-26 10:34 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 On 11/26/2015 02:53 AM, Josh Stone wrote: > The ptrace options should be set as soon as we know a thread is stopped, > so no events can be missed. There's an arch-setup early return that was > effectively delaying this update before, and I found for instance that > the first syscall event wouldn't be properly reported with TRACESYSGOOD. > It's now more similar to the way that gdb/linux-nat.c handles it. Hmm, I'm confused on how this resulted in the first syscall being misssed. That early return happens when we're not executing the real inferior yet -- the process is still running the "gdbserver --wrapper WRAPPER" binary. It's pedantically good, though not crucial, to set PTRACE_O_TRACEEXEC early for that scenario, to get a real PTRACE_EVENT_EXEC event instead of a bare SIGTRAP when the exec wrapper (or in the future, the shell, when we start inferiors with the shell, like gdb does, for arg expansion and globbing) actually execs. If the shell/wrapper forks, enabling fork events while still executing the wrapper/shell breaks startup -- server.c:start_inferior. The gdb version (fork-child.c:startup_inferior) does handle TARGET_WAITKIND_FORKED, but AFAICS forgets detaching/resuming the child... We _must_ not catch syscall events while running the exec wrapper (or the shell), otherwise server.c:start_inferior would get confused for seeing unexpected syscall stops. If the backend treats syscall catchpoints, it's OK, since gdb won't insert catchpoints in the process until after vRun returns, indicating the process is stopped at the entry point. IIRC, gdb actually does NOT handle catchpoint locations per-inferior today, but as long as the backend side thinks of catchpoints per-inferior, we can fix the GDB side. So all in all, I'm not sure this actually buys us anything other than need to fix the wrapper/shell-forks case. > > gdb/gdbserver/ChangeLog: > > 2015-11-25 Josh Stone <jistone@redhat.com> > > * linux-low.c (linux_low_filter_event): Set ptrace options as soon as > each thread is stopped, even before arch-specific setup. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP 2015-11-26 10:34 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Pedro Alves @ 2015-11-30 18:50 ` Josh Stone 2015-12-01 20:17 ` Josh Stone 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2015-11-30 18:50 UTC (permalink / raw) To: Pedro Alves, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 On 11/26/2015 02:34 AM, Pedro Alves wrote: > On 11/26/2015 02:53 AM, Josh Stone wrote: >> The ptrace options should be set as soon as we know a thread is stopped, >> so no events can be missed. There's an arch-setup early return that was >> effectively delaying this update before, and I found for instance that >> the first syscall event wouldn't be properly reported with TRACESYSGOOD. >> It's now more similar to the way that gdb/linux-nat.c handles it. > > Hmm, I'm confused on how this resulted in the first syscall being misssed. > That early return happens when we're not executing the real inferior > yet -- the process is still running the "gdbserver --wrapper WRAPPER" > binary. My memory of this is admittedly hazy by now. IIRC the first syscall wasn't *completely* missed, just reported without TRACESYSGOOD in effect, so it looked like a plain SIGTRAP. I will try to dig in and characterize the problem I had better, especially with your explanation of exec startup at hand. Thanks! > It's pedantically good, though not crucial, to set PTRACE_O_TRACEEXEC early for > that scenario, to get a real PTRACE_EVENT_EXEC event instead of a bare SIGTRAP > when the exec wrapper (or in the future, the shell, when we start inferiors > with the shell, like gdb does, for arg expansion and globbing) actually execs. > > If the shell/wrapper forks, enabling fork events while still executing the > wrapper/shell breaks startup -- server.c:start_inferior. The gdb > version (fork-child.c:startup_inferior) does handle TARGET_WAITKIND_FORKED, > but AFAICS forgets detaching/resuming the child... > > We _must_ not catch syscall events while running the exec wrapper (or > the shell), otherwise server.c:start_inferior would get confused for seeing > unexpected syscall stops. If the backend treats syscall catchpoints, it's OK, > since gdb won't insert catchpoints in the process until after vRun returns, > indicating the process is stopped at the entry point. IIRC, gdb actually > does NOT handle catchpoint locations per-inferior today, but as long as > the backend side thinks of catchpoints per-inferior, we can fix the GDB side. > > So all in all, I'm not sure this actually buys us anything other than need > to fix the wrapper/shell-forks case. > >> >> gdb/gdbserver/ChangeLog: >> >> 2015-11-25 Josh Stone <jistone@redhat.com> >> >> * linux-low.c (linux_low_filter_event): Set ptrace options as soon as >> each thread is stopped, even before arch-specific setup. > > Thanks, > Pedro Alves > ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP 2015-11-30 18:50 ` Josh Stone @ 2015-12-01 20:17 ` Josh Stone 2015-12-02 14:01 ` Pedro Alves 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2015-12-01 20:17 UTC (permalink / raw) To: Pedro Alves, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 On 11/30/2015 10:50 AM, Josh Stone wrote: > On 11/26/2015 02:34 AM, Pedro Alves wrote: >> On 11/26/2015 02:53 AM, Josh Stone wrote: >>> The ptrace options should be set as soon as we know a thread is stopped, >>> so no events can be missed. There's an arch-setup early return that was >>> effectively delaying this update before, and I found for instance that >>> the first syscall event wouldn't be properly reported with TRACESYSGOOD. >>> It's now more similar to the way that gdb/linux-nat.c handles it. >> >> Hmm, I'm confused on how this resulted in the first syscall being misssed. >> That early return happens when we're not executing the real inferior >> yet -- the process is still running the "gdbserver --wrapper WRAPPER" >> binary. > > My memory of this is admittedly hazy by now. IIRC the first syscall > wasn't *completely* missed, just reported without TRACESYSGOOD in > effect, so it looked like a plain SIGTRAP. > > I will try to dig in and characterize the problem I had better, > especially with your explanation of exec startup at hand. Thanks! 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. 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. - Perhaps at the end of linux_arch_setup? AIUI this will be after everything you're worried about wrappers. >> It's pedantically good, though not crucial, to set PTRACE_O_TRACEEXEC early for >> that scenario, to get a real PTRACE_EVENT_EXEC event instead of a bare SIGTRAP >> when the exec wrapper (or in the future, the shell, when we start inferiors >> with the shell, like gdb does, for arg expansion and globbing) actually execs. >> >> If the shell/wrapper forks, enabling fork events while still executing the >> wrapper/shell breaks startup -- server.c:start_inferior. The gdb >> version (fork-child.c:startup_inferior) does handle TARGET_WAITKIND_FORKED, >> but AFAICS forgets detaching/resuming the child... >> >> We _must_ not catch syscall events while running the exec wrapper (or >> the shell), otherwise server.c:start_inferior would get confused for seeing >> unexpected syscall stops. If the backend treats syscall catchpoints, it's OK, >> since gdb won't insert catchpoints in the process until after vRun returns, >> indicating the process is stopped at the entry point. IIRC, gdb actually >> does NOT handle catchpoint locations per-inferior today, but as long as >> the backend side thinks of catchpoints per-inferior, we can fix the GDB side. >> >> So all in all, I'm not sure this actually buys us anything other than need >> to fix the wrapper/shell-forks case. >> >>> >>> gdb/gdbserver/ChangeLog: >>> >>> 2015-11-25 Josh Stone <jistone@redhat.com> >>> >>> * linux-low.c (linux_low_filter_event): Set ptrace options as soon as >>> each thread is stopped, even before arch-specific setup. >> >> Thanks, >> Pedro Alves >> > ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP 2015-12-01 20:17 ` Josh Stone @ 2015-12-02 14:01 ` Pedro Alves 0 siblings, 0 replies; 49+ messages in thread From: Pedro Alves @ 2015-12-02 14:01 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 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 ^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors 2015-11-26 2:53 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Josh Stone 2015-11-26 2:54 ` [PATCH v2 2/2] Implement 'catch syscall' for gdbserver Josh Stone 2015-11-26 10:34 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Pedro Alves @ 2015-12-04 2:26 ` Josh Stone 2015-12-04 2:27 ` [PATCH v3 2/2] Implement 'catch syscall' for gdbserver Josh Stone 2015-12-04 12:16 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Pedro Alves 2 siblings, 2 replies; 49+ messages in thread From: Josh Stone @ 2015-12-04 2:26 UTC (permalink / raw) To: gdb-patches Cc: philippe.waroquiers, sergiodj, palves, eliz, xdje42, Josh Stone Rename target_ops.arch_setup to .post_create_inferior. In the Linux hook, continue calling the low arch setup, then also set ptrace flags. This corrects the possibility of running without flags, demonstrated by a new test that would fail to catch a fork before. gdb/gdbserver/ChangeLog: 2015-12-03 Josh Stone <jistone@redhat.com> * target.h (struct target_ops) <arch_setup>: Rename to ... (struct target_ops) <post_create_inferior>: ... this. (target_arch_setup): Rename to ... (target_post_create_inferior): ... this, calling post_create_inferior. * server.c (start_inferior): Update target_arch_setup calls to target_post_create_inferior. * linux-low.c (linux_low_ptrace_options): Forward declare. (linux_arch_setup): Update its comment for general use. (linux_post_create_inferior): New, run arch_setup and setup ptrace. (struct linux_target_ops): Use linux_post_create_inferior. * lynx-low.c (struct lynx_target_ops): Update arch_setup stub comment to post_create_inferior. * nto-low.c (struct nto_target_ops): Likewise. * spu-low.c (struct spu_target_ops): Likewise. * win32-low.c (struct win32_target_ops): Likewise. gdb/testsuite/ChangeLog: 2015-12-03 Josh Stone <jistone@redhat.com> * gdb.base/catch-static-fork.exp: New. --- gdb/gdbserver/linux-low.c | 24 +++++++++++++-- gdb/gdbserver/lynx-low.c | 2 +- gdb/gdbserver/nto-low.c | 2 +- gdb/gdbserver/server.c | 4 +-- gdb/gdbserver/spu-low.c | 2 +- gdb/gdbserver/target.h | 15 ++++----- gdb/gdbserver/win32-low.c | 2 +- gdb/testsuite/gdb.base/catch-static-fork.exp | 46 ++++++++++++++++++++++++++++ 8 files changed, 82 insertions(+), 15 deletions(-) create mode 100644 gdb/testsuite/gdb.base/catch-static-fork.exp diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index ec5337ae418b..5e2dc5857a8d 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -264,6 +264,7 @@ static int finish_step_over (struct lwp_info *lwp); static int kill_lwp (unsigned long lwpid, int signo); static void enqueue_pending_signal (struct lwp_info *lwp, int signal, siginfo_t *info); static void complete_ongoing_step_over (void); +static int linux_low_ptrace_options (int attached); /* When the event-loop is doing a step-over, this points at the thread being stepped. */ @@ -421,7 +422,7 @@ linux_add_process (int pid, int attached) static CORE_ADDR get_pc (struct lwp_info *lwp); -/* Implement the arch_setup target_ops method. */ +/* Call the target arch_setup function on the current thread. */ static void linux_arch_setup (void) @@ -919,6 +920,25 @@ linux_create_inferior (char *program, char **allargs) return pid; } +/* Implement the post_create_inferior target_ops method. */ + +static void +linux_post_create_inferior (void) +{ + struct lwp_info *lwp = get_thread_lwp (current_thread); + + linux_arch_setup (); + + if (lwp->must_set_ptrace_flags) + { + struct process_info *proc = current_process (); + int options = linux_low_ptrace_options (proc->attached); + + linux_enable_event_reporting (lwpid_of (current_thread), options); + lwp->must_set_ptrace_flags = 0; + } +} + /* Attach to an inferior process. Returns 0 on success, ERRNO on error. */ @@ -7077,7 +7097,7 @@ linux_breakpoint_kind_from_current_state (CORE_ADDR *pcptr) static struct target_ops linux_target_ops = { linux_create_inferior, - linux_arch_setup, + linux_post_create_inferior, linux_attach, linux_kill, linux_detach, diff --git a/gdb/gdbserver/lynx-low.c b/gdb/gdbserver/lynx-low.c index 36ab0a3b2d8e..2940ce516ad6 100644 --- a/gdb/gdbserver/lynx-low.c +++ b/gdb/gdbserver/lynx-low.c @@ -722,7 +722,7 @@ lynx_request_interrupt (void) static struct target_ops lynx_target_ops = { lynx_create_inferior, - NULL, /* arch_setup */ + NULL, /* post_create_inferior */ lynx_attach, lynx_kill, lynx_detach, diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index d72c46515d13..ee043b120830 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -933,7 +933,7 @@ nto_sw_breakpoint_from_kind (int kind, int *size) static struct target_ops nto_target_ops = { nto_create_inferior, - NULL, /* arch_setup */ + NULL, /* post_create_inferior */ nto_attach, nto_kill, nto_detach, diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 5e053b39b10b..6d151ee35d39 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -282,7 +282,7 @@ start_inferior (char **argv) } while (last_status.value.sig != GDB_SIGNAL_TRAP); } - target_arch_setup (); + target_post_create_inferior (); return signal_pid; } @@ -290,7 +290,7 @@ start_inferior (char **argv) (assuming success). */ last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0); - target_arch_setup (); + target_post_create_inferior (); if (last_status.kind != TARGET_WAITKIND_EXITED && last_status.kind != TARGET_WAITKIND_SIGNALLED) diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c index 89bed7a02dd1..64a440cf7ea2 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -653,7 +653,7 @@ spu_sw_breakpoint_from_kind (int kind, int *size) static struct target_ops spu_target_ops = { spu_create_inferior, - NULL, /* arch_setup */ + NULL, /* post_create_inferior */ spu_attach, spu_kill, spu_detach, diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 9cd07bc2d945..1a38b2052c2c 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -75,8 +75,9 @@ struct target_ops int (*create_inferior) (char *program, char **args); - /* Architecture-specific setup. */ - void (*arch_setup) (void); + /* Do additional setup after a new process is created, including + exec-wrapper completion. */ + void (*post_create_inferior) (void); /* Attach to a running process. @@ -475,11 +476,11 @@ void set_target_ops (struct target_ops *); #define create_inferior(program, args) \ (*the_target->create_inferior) (program, args) -#define target_arch_setup() \ - do \ - { \ - if (the_target->arch_setup != NULL) \ - (*the_target->arch_setup) (); \ +#define target_post_create_inferior() \ + do \ + { \ + if (the_target->post_create_inferior != NULL) \ + (*the_target->post_create_inferior) (); \ } while (0) #define myattach(pid) \ diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index b1de139cac70..ba20aea35a71 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1794,7 +1794,7 @@ win32_sw_breakpoint_from_kind (int kind, int *size) static struct target_ops win32_target_ops = { win32_create_inferior, - NULL, /* arch_setup */ + NULL, /* post_create_inferior */ win32_attach, win32_kill, win32_detach, diff --git a/gdb/testsuite/gdb.base/catch-static-fork.exp b/gdb/testsuite/gdb.base/catch-static-fork.exp new file mode 100644 index 000000000000..6961346b0204 --- /dev/null +++ b/gdb/testsuite/gdb.base/catch-static-fork.exp @@ -0,0 +1,46 @@ +# Copyright (C) 2015 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + +# Test that "catch fork" works on static executables. + +# For instance, on Linux we need PTRACE_O_TRACEFORK set before the program +# reaches the fork. GDBserver was only setting flags when it reached the first +# stop *after* arch_setup. In a dynamic executable there is often a swbreak in +# ld.so probes before reaching main, and ptrace flags were set then. But a +# static executable would just keep running and never catch the fork. + +if { [is_remote target] || ![isnative] } then { + continue +} + +# Until "catch fork" is implemented on other targets... +# +if { ![istarget "hppa*-hp-hpux*"] && ![istarget "*-*-linux*"] + && ![istarget "*-*-openbsd*"] } then { + continue +} + +# Reusing foll-fork.c since it's a simple forking program. +standard_testfile foll-fork.c + +if { [prepare_for_testing ${testfile}.exp ${testfile} $srcfile \ + {additional_flags=-static}] } { + return -1 +} + +gdb_test "catch fork" "Catchpoint \[0-9\]* \\(fork\\)" + +gdb_test "run" "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \ + "run to fork" -- 2.5.0 ^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-04 2:26 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Josh Stone @ 2015-12-04 2:27 ` Josh Stone 2015-12-04 8:45 ` Eli Zaretskii ` (2 more replies) 2015-12-04 12:16 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Pedro Alves 1 sibling, 3 replies; 49+ messages in thread From: Josh Stone @ 2015-12-04 2:27 UTC (permalink / raw) To: gdb-patches Cc: philippe.waroquiers, sergiodj, palves, eliz, xdje42, Josh Stone This adds a new QCatchSyscalls packet to enable 'catch syscall', and new stop reasons "syscall_entry" and "syscall_return" for those events. It is currently only supported on Linux x86 and x86_64. gdb/ChangeLog: 2015-12-03 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new GDBserver support for catch syscall. * remote.c (PACKET_QCatchSyscalls): New enum. (remote_set_syscall_catchpoint): New function. (remote_protocol_features): New element for QCatchSyscalls. (remote_parse_stop_reply): Parse syscall_entry/return stops. (init_remote_ops): Install remote_set_syscall_catchpoint. (_initialize_remote): Config QCatchSyscalls. * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. gdb/doc/ChangeLog: 2015-12-03 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. (Stop Reply Packets): List the syscall entry and return stop reasons. (General Query Packets): Describe QCatchSyscalls, and add it to the table and detailed list of stub features. gdb/gdbserver/ChangeLog: 2015-12-03 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * inferiors.h: Include "gdb_vecs.h". (struct process_info): Add syscalls_to_catch. * inferiors.c (remove_process): Free syscalls_to_catch. * remote-utils.c (prepare_resume_reply): Report syscall_entry and syscall_return stops. * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. * server.c (handle_general_set): Handle QCatchSyscalls. (handle_query): Report support for QCatchSyscalls. * target.h (struct target_ops): Add supports_catch_syscall. (target_supports_catch_syscall): New macro. * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. (struct lwp_info): Add syscall_state. * linux-low.c (handle_extended_wait): Mark syscall_state as an entry. (get_syscall_trapinfo): New function, proxy to the_low_target. (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. (linux_low_filter_event): Toggle syscall_state entry/return for syscall traps, and set it ignored for all others. (gdb_catching_syscalls_p): New function. (gdb_catch_this_syscall_p): New function. (linux_wait_1): Handle SYSCALL_SIGTRAP. (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. (linux_supports_catch_syscall): New function. (linux_target_ops): Install it. * linux-x86-low.c (x86_get_syscall_trapinfo): New function. (the_low_target): Install it. * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. * spu-low.c (spu_target_ops): Likewise. * win32-low.c (win32_target_ops): Likewise. gdb/testsuite/ChangeLog: 2015-12-03 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux remote targets. (do_syscall_tests): Only test mid-vfork on local or extended-remote. --- gdb/NEWS | 10 +++ gdb/doc/gdb.texinfo | 56 +++++++++++++ gdb/gdbserver/inferiors.c | 1 + gdb/gdbserver/inferiors.h | 5 ++ gdb/gdbserver/linux-low.c | 140 ++++++++++++++++++++++++++++++- gdb/gdbserver/linux-low.h | 13 +++ gdb/gdbserver/linux-x86-low.c | 26 ++++++ gdb/gdbserver/nto-low.c | 1 + gdb/gdbserver/remote-utils.c | 12 +++ gdb/gdbserver/server.c | 49 +++++++++++ gdb/gdbserver/server.h | 6 ++ gdb/gdbserver/spu-low.c | 1 + gdb/gdbserver/target.h | 8 ++ gdb/gdbserver/win32-low.c | 1 + gdb/linux-nat.h | 2 +- gdb/remote.c | 116 +++++++++++++++++++++++++ gdb/testsuite/gdb.base/catch-syscall.exp | 15 +++- 17 files changed, 456 insertions(+), 6 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index a222dfb491f0..1917523d8249 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -112,6 +112,11 @@ N stop reply threads are stopped). The remote stub reports support for this stop reply to GDB's qSupported query. +QCatchSyscalls:1 [;SYSNO]... +QCatchSyscalls:0 + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") + catching syscalls from the inferior process. + * Extended-remote exec events ** GDB now has support for exec events on extended-remote Linux targets. @@ -127,6 +132,11 @@ show remote exec-event-feature-packet The reply to qXfer:threads:read may now include a name attribute for each thread. +* New features in the GDB remote stub, GDBserver + + ** GDBserver now supports catch syscall. Currently enabled + on x86/x86_64 GNU/Linux targets. + *** Changes in GDB 7.10 * Support for process record-replay and reverse debugging on aarch64*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index b82f3c67a8a6..99865d9cef98 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20135,6 +20135,10 @@ are: @tab @code{qSupported} @tab Remote communications parameters +@item @code{catch-syscalls} +@tab @code{QCatchSyscalls} +@tab @code{catch syscall} + @item @code{pass-signals} @tab @code{QPassSignals} @tab @code{handle @var{signal}} @@ -35458,6 +35462,11 @@ The currently defined stop reasons are: The packet indicates a watchpoint hit, and @var{r} is the data address, in hex. +@item syscall_entry +@itemx syscall_return +The packet indicates a syscall entry or return, and @var{r} is the +syscall number, in hex. + @cindex shared library events, remote reply @item library The packet indicates that the loaded libraries have changed. @@ -35950,6 +35959,44 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). Use of this packet is controlled by the @code{set non-stop} command; @pxref{Non-Stop Mode}. +@item QCatchSyscalls:1 @r{[};@var{sysno}@r{]}@dots{} +@itemx QCatchSyscalls:0 +@cindex catch syscalls from inferior, remote request +@cindex @samp{QCatchSyscalls} packet +@anchor{QCatchSyscalls} +Enable (@samp{QCatchSyscalls:1}) or disable (@samp{QCatchSyscalls:0}) +catching syscalls from the inferior process. + +For @samp{QCatchSyscalls:1}, each listed syscall @var{sysno} (encoded +in hex) should be reported to @value{GDBN}. If no syscall @var{sysno} +is listed, every system call should be reported. + +Note that if a syscall not in the list is reported, @value{GDBN} will +still filter the event according to its own list from all corresponding +@code{catch syscall} commands. However, it is more efficient to only +report the requested syscalls. + +Multiple @samp{QCatchSyscalls:1} packets do not combine; any earlier +@samp{QCatchSyscalls:1} list is completely replaced by the new list. + +Reply: +@table @samp +@item OK +The request succeeded. + +@item E @var{nn} +An error occurred. @var{nn} are hex digits. + +@item @w{} +An empty reply indicates that @samp{QCatchSyscalls} is not supported by +the stub. +@end table + +Use of this packet is controlled by the @code{set remote catch-syscalls} +command (@pxref{Remote Configuration, set remote catch-syscalls}). +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} @cindex pass signals to inferior, remote request @cindex @samp{QPassSignals} packet @@ -36401,6 +36448,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{QCatchSyscalls} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QPassSignals} @tab No @tab @samp{-} @@ -36604,6 +36656,10 @@ packet (@pxref{qXfer fdpic loadmap read}). The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). +@item QCatchSyscalls +The remote stub understands the @samp{QCatchSyscalls} packet +(@pxref{QCatchSyscalls}). + @item QPassSignals The remote stub understands the @samp{QPassSignals} packet (@pxref{QPassSignals}). diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index 95f3ad03ab08..1c736b62650a 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -339,6 +339,7 @@ remove_process (struct process_info *process) free_all_breakpoints (process); gdb_assert (find_thread_process (process) == NULL); remove_inferior (&all_processes, &process->entry); + VEC_free (int, process->syscalls_to_catch); free (process); } diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h index d7226163c0e8..43fc869f6612 100644 --- a/gdb/gdbserver/inferiors.h +++ b/gdb/gdbserver/inferiors.h @@ -19,6 +19,8 @@ #ifndef INFERIORS_H #define INFERIORS_H +#include "gdb_vecs.h" + /* Generic information for tracking a list of ``inferiors'' - threads, processes, etc. */ struct inferior_list @@ -67,6 +69,9 @@ struct process_info /* The list of installed fast tracepoints. */ struct fast_tracepoint_jump *fast_tracepoint_jumps; + /* The list of syscalls to report, or just ANY_SYSCALL. */ + VEC (int) *syscalls_to_catch; + const struct target_desc *tdesc; /* Private target data. */ diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 5e2dc5857a8d..cceede6fe408 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -461,6 +461,11 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) gdb_assert (event_lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + /* All extended events we currently use are mid-syscall. Only + PTRACE_EVENT_STOP is delivered more like a signal-stop, but + you have to be using PTRACE_SEIZE to get that. */ + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) || (event == PTRACE_EVENT_CLONE)) { @@ -682,6 +687,40 @@ get_pc (struct lwp_info *lwp) return pc; } +/* This function should only be called if LWP got a SYSCALL_SIGTRAP. + Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. */ + +static void +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno, int *sysret) +{ + struct thread_info *saved_thread; + struct regcache *regcache; + + if (the_low_target.get_syscall_trapinfo == NULL) + { + /* If we cannot get the syscall trapinfo, report an unknown + system call number and -ENOSYS return value. */ + *sysno = UNKNOWN_SYSCALL; + *sysret = -ENOSYS; + return; + } + + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + + regcache = get_thread_regcache (current_thread, 1); + (*the_low_target.get_syscall_trapinfo) (regcache, sysno, sysret); + + if (debug_threads) + { + debug_printf ("get_syscall_trapinfo sysno %d sysret %d\n", + *sysno, *sysret); + } + + current_thread = saved_thread; +} + /* This function should only be called if LWP got a SIGTRAP. The SIGTRAP could mean several things. @@ -2241,6 +2280,8 @@ linux_low_ptrace_options (int attached) if (report_exec_events) options |= PTRACE_O_TRACEEXEC; + options |= PTRACE_O_TRACESYSGOOD; + return options; } @@ -2369,6 +2410,21 @@ linux_low_filter_event (int lwpid, int wstat) child->must_set_ptrace_flags = 0; } + /* Always update syscall_state, even if it will be filtered later. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) + { + child->syscall_state + = (child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY + ? TARGET_WAITKIND_SYSCALL_RETURN + : TARGET_WAITKIND_SYSCALL_ENTRY); + } + else + { + /* Almost all other ptrace-stops are known to be outside of system + calls, with further exceptions in handle_extended_wait. */ + child->syscall_state = TARGET_WAITKIND_IGNORE; + } + /* Be careful to not overwrite stop_pc until check_stopped_by_breakpoint is called. */ if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP @@ -2978,6 +3034,44 @@ filter_exit_event (struct lwp_info *event_child, return ptid; } +/* Returns 1 if GDB is interested in any event_child syscalls. */ + +static int +gdb_catching_syscalls_p (struct lwp_info *event_child) +{ + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + return !VEC_empty (int, proc->syscalls_to_catch); +} + +/* Returns 1 if GDB is interested in the event_child syscall. + Only to be called when stopped reason is SYSCALL_SIGTRAP. */ + +static int +gdb_catch_this_syscall_p (struct lwp_info *event_child) +{ + int i, iter; + int sysno, sysret; + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + if (VEC_empty (int, proc->syscalls_to_catch)) + return 0; + + if (VEC_index (int, proc->syscalls_to_catch, 0) == ANY_SYSCALL) + return 1; + + get_syscall_trapinfo (event_child, &sysno, &sysret); + for (i = 0; + VEC_iterate (int, proc->syscalls_to_catch, i, iter); + i++) + if (iter == sysno) + return 1; + + return 0; +} + /* Wait for process, returns status. */ static ptid_t @@ -3312,6 +3406,22 @@ linux_wait_1 (ptid_t ptid, /* Check whether GDB would be interested in this event. */ + /* Check if GDB is interested in this syscall. */ + if (WIFSTOPPED (w) + && WSTOPSIG (w) == SYSCALL_SIGTRAP + && !gdb_catch_this_syscall_p (event_child)) + { + if (debug_threads) + { + debug_printf ("Ignored syscall for LWP %ld.\n", + lwpid_of (current_thread)); + } + + linux_resume_one_lwp (event_child, event_child->stepping, + 0, NULL); + return ignore_event (ourstatus); + } + /* If GDB is not interested in this signal, don't stop other threads, and don't report it to GDB. Just resume the inferior right away. We do this for threading-related signals as well as @@ -3566,8 +3676,16 @@ linux_wait_1 (ptid_t ptid, } } - if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) == SIGSTOP) + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) + { + int sysret; + + get_syscall_trapinfo (event_child, + &ourstatus->value.syscall_number, &sysret); + ourstatus->kind = event_child->syscall_state; + } + else if (current_thread->last_resume_kind == resume_stop + && WSTOPSIG (w) == SIGSTOP) { /* A thread that has been requested to stop by GDB with vCont;t, and it stopped cleanly, so report as SIG0. The use of @@ -3987,6 +4105,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, struct thread_info *thread = get_lwp_thread (lwp); struct thread_info *saved_thread; int fast_tp_collecting; + int ptrace_request; struct process_info *proc = get_thread_process (thread); /* Note that target description may not be initialised @@ -4174,7 +4293,14 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, regcache_invalidate_thread (thread); errno = 0; lwp->stepping = step; - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread), + if (step) + ptrace_request = PTRACE_SINGLESTEP; + else if (gdb_catching_syscalls_p (lwp)) + ptrace_request = PTRACE_SYSCALL; + else + ptrace_request = PTRACE_CONT; + ptrace (ptrace_request, + lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, /* Coerce to a uintptr_t first to avoid potential gcc warning of coercing an 8 byte integer to a 4 byte pointer. */ @@ -6270,6 +6396,13 @@ linux_process_qsupported (char **features, int count) } static int +linux_supports_catch_syscall (void) +{ + return (the_low_target.get_syscall_trapinfo != NULL + && linux_supports_tracesysgood()); +} + +static int linux_supports_tracepoints (void) { if (*the_low_target.supports_tracepoints == NULL) @@ -7157,6 +7290,7 @@ static struct target_ops linux_target_ops = { linux_common_core_of_thread, linux_read_loadmap, linux_process_qsupported, + linux_supports_catch_syscall, linux_supports_tracepoints, linux_read_pc, linux_write_pc, diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index c211a37d280a..45fffcd3208c 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -201,6 +201,12 @@ struct linux_target_ops /* Hook to support target specific qSupported. */ void (*process_qsupported) (char **, int count); + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. Only to be called when inferior is stopped + due to SYSCALL_SIGTRAP. */ + void (*get_syscall_trapinfo) (struct regcache *regcache, + int *sysno, int *sysret); + /* Returns true if the low target supports tracepoints. */ int (*supports_tracepoints) (void); @@ -277,6 +283,13 @@ struct lwp_info event already received in a wait()). */ int stopped; + /* Signal whether we are in a SYSCALL_ENTRY or + in a SYSCALL_RETURN event. + Values: + - TARGET_WAITKIND_SYSCALL_ENTRY + - TARGET_WAITKIND_SYSCALL_RETURN */ + enum target_waitkind syscall_state; + /* When stopped is set, the last wait status recorded for this lwp. */ int last_status; diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index 18adf5ee7d17..1caf71edf485 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -1438,6 +1438,31 @@ x86_arch_setup (void) current_process ()->tdesc = x86_linux_read_description (); } +/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return + code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ + +static void +x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno, int *sysret) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + long l_sysno; + long l_sysret; + + collect_register_by_name (regcache, "orig_rax", &l_sysno); + collect_register_by_name (regcache, "rax", &l_sysret); + *sysno = (int) l_sysno; + *sysret = (int) l_sysret; + } + else + { + collect_register_by_name (regcache, "orig_eax", sysno); + collect_register_by_name (regcache, "eax", sysret); + } +} + static int x86_supports_tracepoints (void) { @@ -3307,6 +3332,7 @@ struct linux_target_ops the_low_target = x86_linux_new_fork, x86_linux_prepare_to_resume, x86_linux_process_qsupported, + x86_get_syscall_trapinfo, x86_supports_tracepoints, x86_get_thread_area, x86_install_fast_tracepoint_jump_pad, diff --git a/gdb/gdbserver/nto-low.c b/gdb/gdbserver/nto-low.c index ee043b120830..2783c1a8b375 100644 --- a/gdb/gdbserver/nto-low.c +++ b/gdb/gdbserver/nto-low.c @@ -979,6 +979,7 @@ static struct target_ops nto_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index 05e3d635f597..52fc12fa1013 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1123,6 +1123,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, case TARGET_WAITKIND_VFORK_DONE: case TARGET_WAITKIND_EXECD: case TARGET_WAITKIND_THREAD_CREATED: + case TARGET_WAITKIND_SYSCALL_ENTRY: + case TARGET_WAITKIND_SYSCALL_RETURN: { struct thread_info *saved_thread; const char **regp; @@ -1172,6 +1174,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, sprintf (buf, "T%02xcreate:;", signal); } + else if ((status->kind == TARGET_WAITKIND_SYSCALL_ENTRY) + || (status->kind == TARGET_WAITKIND_SYSCALL_RETURN)) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + ? "syscall_entry" : "syscall_return"); + + sprintf (buf, "T%02x%s:%x;", signal, event, + status->value.syscall_number); + } else sprintf (buf, "T%02x", status->value.sig); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index 6d151ee35d39..e63656b9c0f6 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -597,6 +597,52 @@ handle_general_set (char *own_buf) return; } + if (startswith (own_buf, "QCatchSyscalls:1")) + { + const char *p; + CORE_ADDR sysno; + struct process_info *process; + + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + process = current_process (); + + VEC_truncate (int, process->syscalls_to_catch, 0); + + p = own_buf + strlen("QCatchSyscalls:1"); + if (*p == ';') + { + p += 1; + while (*p) + { + p = decode_address_to_semicolon (&sysno, p); + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); + } + } + else + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); + + write_ok (own_buf); + return; + } + + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) + { + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + VEC_free (int, current_process ()->syscalls_to_catch); + write_ok (own_buf); + return; + } + if (startswith (own_buf, "QProgramSignals:")) { int numsigs = (int) GDB_SIGNAL_LAST, i; @@ -2219,6 +2265,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) "PacketSize=%x;QPassSignals+;QProgramSignals+", PBUFSIZ - 1); + if (target_supports_catch_syscall ()) + strcat (own_buf, ";QCatchSyscalls+"); + if (the_target->qxfer_libraries_svr4 != NULL) strcat (own_buf, ";qXfer:libraries-svr4:read+" ";augmented-libraries-svr4-read+"); diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index dc0361fdcd14..bc2abd5f50c8 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -134,4 +134,10 @@ extern void discard_queued_stop_replies (ptid_t ptid); as large as the largest register set supported by gdbserver. */ #define PBUFSIZ 16384 +/* Definition for an unknown syscall, used basically in error-cases. */ +#define UNKNOWN_SYSCALL (-1) + +/* Definition for any syscall, used for unfiltered syscall reporting. */ +#define ANY_SYSCALL (-2) + #endif /* SERVER_H */ diff --git a/gdb/gdbserver/spu-low.c b/gdb/gdbserver/spu-low.c index 64a440cf7ea2..9b3e84e33f52 100644 --- a/gdb/gdbserver/spu-low.c +++ b/gdb/gdbserver/spu-low.c @@ -699,6 +699,7 @@ static struct target_ops spu_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index 1a38b2052c2c..a13c94163d38 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -312,6 +312,10 @@ struct target_ops features with COUNT elements. */ void (*process_qsupported) (char **features, int count); + /* Return 1 if the target supports catch syscall, 0 (or leave the + callback NULL) otherwise. */ + int (*supports_catch_syscall) (void); + /* Return 1 if the target supports tracepoints, 0 (or leave the callback NULL) otherwise. */ int (*supports_tracepoints) (void); @@ -542,6 +546,10 @@ int kill_inferior (int); the_target->process_qsupported (features, count); \ } while (0) +#define target_supports_catch_syscall() \ + (the_target->supports_catch_syscall ? \ + (*the_target->supports_catch_syscall) () : 0) + #define target_supports_tracepoints() \ (the_target->supports_tracepoints \ ? (*the_target->supports_tracepoints) () : 0) diff --git a/gdb/gdbserver/win32-low.c b/gdb/gdbserver/win32-low.c index ba20aea35a71..78d0c80b2c62 100644 --- a/gdb/gdbserver/win32-low.c +++ b/gdb/gdbserver/win32-low.c @@ -1844,6 +1844,7 @@ static struct target_ops win32_target_ops = { NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index f7b45f7bc693..1c5a4a92a05a 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -93,7 +93,7 @@ struct lwp_info or to a local variable in lin_lwp_wait. */ struct target_waitstatus waitstatus; - /* Signal wether we are in a SYSCALL_ENTRY or + /* Signal whether we are in a SYSCALL_ENTRY or in a SYSCALL_RETURN event. Values: - TARGET_WAITKIND_SYSCALL_ENTRY diff --git a/gdb/remote.c b/gdb/remote.c index 52c5df84c41d..66e2cc9b8faa 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1392,6 +1392,7 @@ enum { PACKET_qSupported, PACKET_qTStatus, PACKET_QPassSignals, + PACKET_QCatchSyscalls, PACKET_QProgramSignals, PACKET_qCRC, PACKET_qSearch_memory, @@ -1986,6 +1987,99 @@ remote_pass_signals (struct target_ops *self, } } +/* If 'QCatchSyscalls' is supported, tell the remote stub + to report syscalls to GDB. */ + +static int +remote_set_syscall_catchpoint (struct target_ops *self, + int pid, int needed, int any_count, + int table_size, int *table) +{ + char *catch_packet, *p; + enum packet_result result; + int n_sysno = 0; + + if (remote_protocol_packets[PACKET_QCatchSyscalls].support == PACKET_DISABLE) + { + /* Not supported. */ + return 1; + } + + if (needed && !any_count) + { + int i; + + /* Count how many syscalls are to be caught (table[sysno] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i]) + n_sysno++; + } + } + + if (remote_debug) + { + fprintf_unfiltered (gdb_stdlog, + "remote_set_syscall_catchpoint " + "pid %d needed %d any_count %d n_sysno %d\n", + pid, needed, any_count, n_sysno); + } + + if (needed) + { + /* Prepare a packet with the sysno list, assuming max 8+1 + characters for a sysno. If the resulting packet size is too + big, fallback on the non selective packet. */ + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; + + catch_packet = xmalloc (maxpktsz); + strcpy (catch_packet, "QCatchSyscalls:1"); + if (!any_count) + { + int i; + char *p; + + p = catch_packet; + p += strlen (p); + + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i]) + { + xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); + p += strlen (p); + } + } + } + if (strlen (catch_packet) > get_remote_packet_size ()) + { + /* catch_packet too big. Fallback to less efficient + non selective mode, with GDB doing the filtering. */ + catch_packet[strlen ("QCatchSyscalls:1")] = 0; + } + } + else + { + catch_packet = xmalloc (strlen ("QCatchSyscalls:0") + 1); + strcpy (catch_packet, "QCatchSyscalls:0"); + } + + { + struct remote_state *rs = get_remote_state (); + char *buf = rs->buf; + + putpkt (catch_packet); + getpkt (&rs->buf, &rs->buf_size, 0); + result = packet_ok (buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); + xfree (catch_packet); + if (result == PACKET_OK) + return 0; + else + return -1; + } +} + /* If 'QProgramSignals' is supported, tell the remote stub what signals it should pass through to the inferior when detaching. */ @@ -4466,6 +4560,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_traceframe_info }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, + { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet, + PACKET_QCatchSyscalls }, { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QProgramSignals }, { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, @@ -6371,6 +6467,22 @@ Packet: '%s'\n"), if (strprefix (p, p1, "thread")) event->ptid = read_ptid (++p1, &p); + else if (strprefix (p, p1, "syscall_entry")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } + else if (strprefix (p, p1, "syscall_return")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } else if (strprefix (p, p1, "watch") || strprefix (p, p1, "rwatch") || strprefix (p, p1, "awatch")) @@ -12975,6 +13087,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_load = remote_load; remote_ops.to_mourn_inferior = remote_mourn; remote_ops.to_pass_signals = remote_pass_signals; + remote_ops.to_set_syscall_catchpoint = remote_set_syscall_catchpoint; remote_ops.to_program_signals = remote_program_signals; remote_ops.to_thread_alive = remote_thread_alive; remote_ops.to_thread_name = remote_thread_name; @@ -13549,6 +13662,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], "QPassSignals", "pass-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QCatchSyscalls], + "QCatchSyscalls", "catch-syscalls", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], "QProgramSignals", "program-signals", 0); diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp index c1cfe23cdddb..0ba078db22ac 100644 --- a/gdb/testsuite/gdb.base/catch-syscall.exp +++ b/gdb/testsuite/gdb.base/catch-syscall.exp @@ -19,7 +19,15 @@ # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> # on September/2008. -if { [is_remote target] || ![isnative] } then { +if { ![isnative] } then { + continue +} + +# This shall be updated whenever QCatchSyscalls packet support is implemented +# on some gdbserver architecture. +if { [is_remote target] + && ![istarget "x86_64-*-linux*"] + && ![istarget "i\[34567\]86-*-linux*"] } { continue } @@ -390,7 +398,10 @@ proc do_syscall_tests {} { if [runto_main] then { test_catch_syscall_skipping_return } # Testing the 'catch syscall' command starting mid-vfork. - if [runto_main] then { test_catch_syscall_mid_vfork } + # (Only local or extended-remote can use "catch vfork".) + if { ![is_remote target] || [target_info gdb_protocol] == "extended-remote" } { + if [runto_main] then { test_catch_syscall_mid_vfork } + } # Testing if the 'catch syscall' command works when switching to # different architectures on-the-fly (PR gdb/10737). -- 2.5.0 ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-04 2:27 ` [PATCH v3 2/2] Implement 'catch syscall' for gdbserver Josh Stone @ 2015-12-04 8:45 ` Eli Zaretskii 2015-12-05 2:14 ` Josh Stone 2015-12-04 13:18 ` Pedro Alves 2016-01-09 3:09 ` [PATCH v4] " Josh Stone 2 siblings, 1 reply; 49+ messages in thread From: Eli Zaretskii @ 2015-12-04 8:45 UTC (permalink / raw) To: Josh Stone Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42, jistone > From: Josh Stone <jistone@redhat.com> > Cc: philippe.waroquiers@skynet.be, sergiodj@redhat.com, palves@redhat.com, eliz@gnu.org, xdje42@gmail.com, Josh Stone <jistone@redhat.com> > Date: Thu, 3 Dec 2015 18:26:46 -0800 > > This adds a new QCatchSyscalls packet to enable 'catch syscall', and new > stop reasons "syscall_entry" and "syscall_return" for those events. It > is currently only supported on Linux x86 and x86_64. > > gdb/ChangeLog: > > 2015-12-03 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new > GDBserver support for catch syscall. > * remote.c (PACKET_QCatchSyscalls): New enum. > (remote_set_syscall_catchpoint): New function. > (remote_protocol_features): New element for QCatchSyscalls. > (remote_parse_stop_reply): Parse syscall_entry/return stops. > (init_remote_ops): Install remote_set_syscall_catchpoint. > (_initialize_remote): Config QCatchSyscalls. > * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. > > gdb/doc/ChangeLog: > > 2015-12-03 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > (Stop Reply Packets): List the syscall entry and return stop reasons. > (General Query Packets): Describe QCatchSyscalls, and add it to the > table and detailed list of stub features. Any changes since v2 in the documentation parts that require a fresh review? Thanks. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-04 8:45 ` Eli Zaretskii @ 2015-12-05 2:14 ` Josh Stone 2015-12-05 8:02 ` Eli Zaretskii 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2015-12-05 2:14 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42 On 12/04/2015 12:44 AM, Eli Zaretskii wrote: >> From: Josh Stone <jistone@redhat.com> >> Cc: philippe.waroquiers@skynet.be, sergiodj@redhat.com, palves@redhat.com, eliz@gnu.org, xdje42@gmail.com, Josh Stone <jistone@redhat.com> >> Date: Thu, 3 Dec 2015 18:26:46 -0800 >> >> This adds a new QCatchSyscalls packet to enable 'catch syscall', and new >> stop reasons "syscall_entry" and "syscall_return" for those events. It >> is currently only supported on Linux x86 and x86_64. >> >> gdb/ChangeLog: >> >> 2015-12-03 Josh Stone <jistone@redhat.com> >> Philippe Waroquiers <philippe.waroquiers@skynet.be> >> >> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new >> GDBserver support for catch syscall. >> * remote.c (PACKET_QCatchSyscalls): New enum. >> (remote_set_syscall_catchpoint): New function. >> (remote_protocol_features): New element for QCatchSyscalls. >> (remote_parse_stop_reply): Parse syscall_entry/return stops. >> (init_remote_ops): Install remote_set_syscall_catchpoint. >> (_initialize_remote): Config QCatchSyscalls. >> * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. >> >> gdb/doc/ChangeLog: >> >> 2015-12-03 Josh Stone <jistone@redhat.com> >> Philippe Waroquiers <philippe.waroquiers@skynet.be> >> >> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. >> (Stop Reply Packets): List the syscall entry and return stop reasons. >> (General Query Packets): Describe QCatchSyscalls, and add it to the >> table and detailed list of stub features. > > Any changes since v2 in the documentation parts that require a fresh > review? I made the changes you requested in v2 -- v3 just has some merge-resolution in NEWS. But Pedro has noted some more things to document for the next round. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-05 2:14 ` Josh Stone @ 2015-12-05 8:02 ` Eli Zaretskii 2015-12-07 16:50 ` Josh Stone 0 siblings, 1 reply; 49+ messages in thread From: Eli Zaretskii @ 2015-12-05 8:02 UTC (permalink / raw) To: Josh Stone; +Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42 > Cc: gdb-patches@sourceware.org, philippe.waroquiers@skynet.be, > sergiodj@redhat.com, palves@redhat.com, xdje42@gmail.com > From: Josh Stone <jistone@redhat.com> > Date: Fri, 4 Dec 2015 18:14:51 -0800 > > On 12/04/2015 12:44 AM, Eli Zaretskii wrote: > >> From: Josh Stone <jistone@redhat.com> > >> Cc: philippe.waroquiers@skynet.be, sergiodj@redhat.com, palves@redhat.com, eliz@gnu.org, xdje42@gmail.com, Josh Stone <jistone@redhat.com> > >> Date: Thu, 3 Dec 2015 18:26:46 -0800 > >> > >> This adds a new QCatchSyscalls packet to enable 'catch syscall', and new > >> stop reasons "syscall_entry" and "syscall_return" for those events. It > >> is currently only supported on Linux x86 and x86_64. > >> > >> gdb/ChangeLog: > >> > >> 2015-12-03 Josh Stone <jistone@redhat.com> > >> Philippe Waroquiers <philippe.waroquiers@skynet.be> > >> > >> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new > >> GDBserver support for catch syscall. > >> * remote.c (PACKET_QCatchSyscalls): New enum. > >> (remote_set_syscall_catchpoint): New function. > >> (remote_protocol_features): New element for QCatchSyscalls. > >> (remote_parse_stop_reply): Parse syscall_entry/return stops. > >> (init_remote_ops): Install remote_set_syscall_catchpoint. > >> (_initialize_remote): Config QCatchSyscalls. > >> * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. > >> > >> gdb/doc/ChangeLog: > >> > >> 2015-12-03 Josh Stone <jistone@redhat.com> > >> Philippe Waroquiers <philippe.waroquiers@skynet.be> > >> > >> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > >> (Stop Reply Packets): List the syscall entry and return stop reasons. > >> (General Query Packets): Describe QCatchSyscalls, and add it to the > >> table and detailed list of stub features. > > > > Any changes since v2 in the documentation parts that require a fresh > > review? > > I made the changes you requested in v2 -- v3 just has some > merge-resolution in NEWS. But Pedro has noted some more things to > document for the next round. Then I guess it's better if I review the next round, is that right? Or do you mean this v3 _is_ that next round? Thanks. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-05 8:02 ` Eli Zaretskii @ 2015-12-07 16:50 ` Josh Stone 2015-12-07 17:15 ` Eli Zaretskii 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2015-12-07 16:50 UTC (permalink / raw) To: Eli Zaretskii; +Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42 On 12/05/2015 12:00 AM, Eli Zaretskii wrote: >>> Any changes since v2 in the documentation parts that require a fresh >>> review? >> >> I made the changes you requested in v2 -- v3 just has some >> merge-resolution in NEWS. But Pedro has noted some more things to >> document for the next round. > > Then I guess it's better if I review the next round, is that right? > Or do you mean this v3 _is_ that next round? The former -- I mean v4 will have a few additions. Sorry if I confused you by explicitly CCing. I just included everyone who had commented at all on prior versions, but maybe that's too greedy. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-07 16:50 ` Josh Stone @ 2015-12-07 17:15 ` Eli Zaretskii 0 siblings, 0 replies; 49+ messages in thread From: Eli Zaretskii @ 2015-12-07 17:15 UTC (permalink / raw) To: Josh Stone; +Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42 > Cc: gdb-patches@sourceware.org, philippe.waroquiers@skynet.be, > sergiodj@redhat.com, palves@redhat.com, xdje42@gmail.com > From: Josh Stone <jistone@redhat.com> > Date: Mon, 7 Dec 2015 08:50:42 -0800 > > On 12/05/2015 12:00 AM, Eli Zaretskii wrote: > >>> Any changes since v2 in the documentation parts that require a fresh > >>> review? > >> > >> I made the changes you requested in v2 -- v3 just has some > >> merge-resolution in NEWS. But Pedro has noted some more things to > >> document for the next round. > > > > Then I guess it's better if I review the next round, is that right? > > Or do you mean this v3 _is_ that next round? > > The former -- I mean v4 will have a few additions. OK, will wait then. > Sorry if I confused you by explicitly CCing. I just included everyone > who had commented at all on prior versions, but maybe that's too greedy. No need to be sorry, nothing bad happened. Thanks. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-04 2:27 ` [PATCH v3 2/2] Implement 'catch syscall' for gdbserver Josh Stone 2015-12-04 8:45 ` Eli Zaretskii @ 2015-12-04 13:18 ` Pedro Alves 2015-12-05 2:16 ` Josh Stone 2016-01-09 3:09 ` [PATCH v4] " Josh Stone 2 siblings, 1 reply; 49+ messages in thread From: Pedro Alves @ 2015-12-04 13:18 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 Quick question: What is supposed to happen to the QCatchSyscalls when the process execs? I'm thinking of 64-bit inferior execing 32-bit inferior, etc. The syscall numbers aren't necessarily shared between the different architectures. This implementation deletes discards the previous QCatchSyscalls on exec, and I think that's what makes sense, but, I think that this should be explicit in the packet's description. I'm not sure gdb clears the inferior's "syscalls to the caught" VEC on exec events, but it probably does (if it doesn't, I think it should.) On 12/04/2015 02:26 AM, Josh Stone wrote: > This adds a new QCatchSyscalls packet to enable 'catch syscall', and new > stop reasons "syscall_entry" and "syscall_return" for those events. It > is currently only supported on Linux x86 and x86_64. > > gdb/ChangeLog: > > 2015-12-03 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new > GDBserver support for catch syscall. > * remote.c (PACKET_QCatchSyscalls): New enum. > (remote_set_syscall_catchpoint): New function. > (remote_protocol_features): New element for QCatchSyscalls. > (remote_parse_stop_reply): Parse syscall_entry/return stops. > (init_remote_ops): Install remote_set_syscall_catchpoint. > (_initialize_remote): Config QCatchSyscalls. > * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. > > gdb/doc/ChangeLog: > > 2015-12-03 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > (Stop Reply Packets): List the syscall entry and return stop reasons. > (General Query Packets): Describe QCatchSyscalls, and add it to the > table and detailed list of stub features. > > gdb/gdbserver/ChangeLog: > > 2015-12-03 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * inferiors.h: Include "gdb_vecs.h". > (struct process_info): Add syscalls_to_catch. > * inferiors.c (remove_process): Free syscalls_to_catch. > * remote-utils.c (prepare_resume_reply): Report syscall_entry and > syscall_return stops. > * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. > * server.c (handle_general_set): Handle QCatchSyscalls. > (handle_query): Report support for QCatchSyscalls. > * target.h (struct target_ops): Add supports_catch_syscall. > (target_supports_catch_syscall): New macro. > * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. > (struct lwp_info): Add syscall_state. > * linux-low.c (handle_extended_wait): Mark syscall_state as an entry. > (get_syscall_trapinfo): New function, proxy to the_low_target. > (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. > (linux_low_filter_event): Toggle syscall_state entry/return for > syscall traps, and set it ignored for all others. > (gdb_catching_syscalls_p): New function. > (gdb_catch_this_syscall_p): New function. > (linux_wait_1): Handle SYSCALL_SIGTRAP. > (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. > (linux_supports_catch_syscall): New function. > (linux_target_ops): Install it. > * linux-x86-low.c (x86_get_syscall_trapinfo): New function. > (the_low_target): Install it. > * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. > * spu-low.c (spu_target_ops): Likewise. > * win32-low.c (win32_target_ops): Likewise. > > gdb/testsuite/ChangeLog: > > 2015-12-03 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux > remote targets. > (do_syscall_tests): Only test mid-vfork on local or extended-remote. > --- > gdb/NEWS | 10 +++ > gdb/doc/gdb.texinfo | 56 +++++++++++++ > gdb/gdbserver/inferiors.c | 1 + > gdb/gdbserver/inferiors.h | 5 ++ > gdb/gdbserver/linux-low.c | 140 ++++++++++++++++++++++++++++++- > gdb/gdbserver/linux-low.h | 13 +++ > gdb/gdbserver/linux-x86-low.c | 26 ++++++ > gdb/gdbserver/nto-low.c | 1 + > gdb/gdbserver/remote-utils.c | 12 +++ > gdb/gdbserver/server.c | 49 +++++++++++ > gdb/gdbserver/server.h | 6 ++ > gdb/gdbserver/spu-low.c | 1 + > gdb/gdbserver/target.h | 8 ++ > gdb/gdbserver/win32-low.c | 1 + > gdb/linux-nat.h | 2 +- > gdb/remote.c | 116 +++++++++++++++++++++++++ > gdb/testsuite/gdb.base/catch-syscall.exp | 15 +++- > 17 files changed, 456 insertions(+), 6 deletions(-) > > diff --git a/gdb/NEWS b/gdb/NEWS > index a222dfb491f0..1917523d8249 100644 > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -112,6 +112,11 @@ N stop reply > threads are stopped). The remote stub reports support for this stop > reply to GDB's qSupported query. > > +QCatchSyscalls:1 [;SYSNO]... > +QCatchSyscalls:0 > + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") > + catching syscalls from the inferior process. > + > * Extended-remote exec events > > ** GDB now has support for exec events on extended-remote Linux targets. > @@ -127,6 +132,11 @@ show remote exec-event-feature-packet > The reply to qXfer:threads:read may now include a name attribute for each > thread. > > +* New features in the GDB remote stub, GDBserver > + > + ** GDBserver now supports catch syscall. Currently enabled > + on x86/x86_64 GNU/Linux targets. > + > *** Changes in GDB 7.10 > Please mention the new set/show commands as well. > +@item QCatchSyscalls > +The remote stub understands the @samp{QCatchSyscalls} packet > +(@pxref{QCatchSyscalls}). > + > @item QPassSignals > The remote stub understands the @samp{QPassSignals} packet > (@pxref{QPassSignals}). You also need to list the new commands in the table below: For each packet @var{name}, the command to enable or disable the packet is @code{set remote @var{name}-packet}. The available settings are: > /* Generic information for tracking a list of ``inferiors'' - threads, > processes, etc. */ > struct inferior_list > @@ -67,6 +69,9 @@ struct process_info > /* The list of installed fast tracepoints. */ > struct fast_tracepoint_jump *fast_tracepoint_jumps; > > + /* The list of syscalls to report, or just ANY_SYSCALL. */ > + VEC (int) *syscalls_to_catch; "just" here means that it's a list with a single element that happens to be ANY_SYSCALL; I think it's helpful for the reader to be explicit and expand the "or just ANY_SYSCALL" comment little bit. > + > const struct target_desc *tdesc; > > /* Private target data. */ > diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c > index 5e2dc5857a8d..cceede6fe408 100644 > --- a/gdb/gdbserver/linux-low.h > +++ b/gdb/gdbserver/linux-low.h > @@ -201,6 +201,12 @@ struct linux_target_ops > /* Hook to support target specific qSupported. */ > void (*process_qsupported) (char **, int count); > > + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the > + return code. Only to be called when inferior is stopped > + due to SYSCALL_SIGTRAP. */ > + void (*get_syscall_trapinfo) (struct regcache *regcache, > + int *sysno, int *sysret); > + As you're not putting this new callback at the end of the struct, you need to install a NULL callback in all linux-*-low.c files (all archs) that install linux_target_ops methods after process_qsupported. Otherwise you'll break their builds. > /* Returns true if the low target supports tracepoints. */ > int (*supports_tracepoints) (void); > > @@ -277,6 +283,13 @@ struct lwp_info > event already received in a wait()). */ > int stopped; > > + /* Signal whether we are in a SYSCALL_ENTRY or > + in a SYSCALL_RETURN event. > + Values: > + - TARGET_WAITKIND_SYSCALL_ENTRY > + - TARGET_WAITKIND_SYSCALL_RETURN */ > + enum target_waitkind syscall_state; > + > /* When stopped is set, the last wait status recorded for this lwp. */ > int last_status; > > diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c > index 18adf5ee7d17..1caf71edf485 100644 > @@ -1172,6 +1174,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, > > sprintf (buf, "T%02xcreate:;", signal); > } > + else if ((status->kind == TARGET_WAITKIND_SYSCALL_ENTRY) > + || (status->kind == TARGET_WAITKIND_SYSCALL_RETURN)) Unnecessary parens. > + { > + enum gdb_signal signal = GDB_SIGNAL_TRAP; > + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY > + ? "syscall_entry" : "syscall_return"); > + > + sprintf (buf, "T%02x%s:%x;", signal, event, > + status->value.syscall_number); > + } > else > sprintf (buf, "T%02x", status->value.sig); > > diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c > index 6d151ee35d39..e63656b9c0f6 100644 > --- a/gdb/gdbserver/server.c > +++ b/gdb/gdbserver/server.c > @@ -597,6 +597,52 @@ handle_general_set (char *own_buf) > return; > } > > + if (startswith (own_buf, "QCatchSyscalls:1")) > + { > + const char *p; > + CORE_ADDR sysno; > + struct process_info *process; > + > + if (!target_running () || !target_supports_catch_syscall ()) > + { > + write_enn (own_buf); > + return; > + } I think you should merge this with > + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) > + { > + if (!target_running () || !target_supports_catch_syscall ()) > + { > + write_enn (own_buf); > + return; > + } into a single if (startswith (own_buf, "QCatchSyscalls:") { ... if (!target_running () || !target_supports_catch_syscall ()) { write_enn (own_buf); return; } See "QNonStop:" handling. The end result is that "QCatchSyscalls:2" is treated as an error instead of returning the empty packet. > + > + process = current_process (); > + > + VEC_truncate (int, process->syscalls_to_catch, 0); > + > + p = own_buf + strlen("QCatchSyscalls:1"); > + if (*p == ';') > + { > + p += 1; > + while (*p) while (*p != '\0) > + { > + p = decode_address_to_semicolon (&sysno, p); > + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); > + } > + } > + else > + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); > + > + write_ok (own_buf); > + return; > + } > + > + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) > + { > + if (!target_running () || !target_supports_catch_syscall ()) > + { > + write_enn (own_buf); > + return; > + } > + > + VEC_free (int, current_process ()->syscalls_to_catch); > + write_ok (own_buf); > + return; > + } > + > if (startswith (own_buf, "QProgramSignals:")) > { > int numsigs = (int) GDB_SIGNAL_LAST, i; > @@ -2219,6 +2265,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) > "PacketSize=%x;QPassSignals+;QProgramSignals+", > PBUFSIZ - 1); > > + if (target_supports_catch_syscall ()) > + strcat (own_buf, ";QCatchSyscalls+"); > + > if (the_target->qxfer_libraries_svr4 != NULL) > strcat (own_buf, ";qXfer:libraries-svr4:read+" > ";augmented-libraries-svr4-read+"); > diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h > index dc0361fdcd14..bc2abd5f50c8 100644 > + if (needed && !any_count) > + { > + int i; > + > + /* Count how many syscalls are to be caught (table[sysno] != 0). */ > + for (i = 0; i < table_size; i++) > + { > + if (table[i]) if (table[i] != 0) just like the comment. :-) > + n_sysno++; > + } > + } > + > + if (remote_debug) > + { > + fprintf_unfiltered (gdb_stdlog, > + "remote_set_syscall_catchpoint " > + "pid %d needed %d any_count %d n_sysno %d\n", > + pid, needed, any_count, n_sysno); > + } > + > + if (needed) > + { > + /* Prepare a packet with the sysno list, assuming max 8+1 > + characters for a sysno. If the resulting packet size is too > + big, fallback on the non selective packet. */ "non-selective packet" > + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; > + > + catch_packet = xmalloc (maxpktsz); > + strcpy (catch_packet, "QCatchSyscalls:1"); > + if (!any_count) > + { > + int i; > + char *p; > + > + p = catch_packet; > + p += strlen (p); > + > + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ > + for (i = 0; i < table_size; i++) > + { > + if (table[i]) Likewise. > + { > + xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); > + p += strlen (p); This looks like: len = xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); p += len; > + } > + } > + } > + if (strlen (catch_packet) > get_remote_packet_size ()) > + { > + /* catch_packet too big. Fallback to less efficient > + non selective mode, with GDB doing the filtering. */ > + catch_packet[strlen ("QCatchSyscalls:1")] = 0; catch_packet[sizeof ("QCatchSyscalls:1") - 1] = 0; > + } > + } > + else > + { > + catch_packet = xmalloc (strlen ("QCatchSyscalls:0") + 1); > + strcpy (catch_packet, "QCatchSyscalls:0"); catch_packet = xstrdup ("QCatchSyscalls:0"); > + } > + > + { > + struct remote_state *rs = get_remote_state (); > + char *buf = rs->buf; > + > + putpkt (catch_packet); > + getpkt (&rs->buf, &rs->buf_size, 0); > + result = packet_ok (buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); getpkt takes a pointer to pointer because it may xrealloc 'rs->buf'. So this 'buf' reference may be dangling. Just drop the 'buf' local. > + xfree (catch_packet); putpkt/getpkt may throw. This should be freed with a cleanup instead. > + if (result == PACKET_OK) > + return 0; > + else > + return -1; > + } > +} > + > /* If 'QProgramSignals' is supported, tell the remote stub what > signals it should pass through to the inferior when detaching. */ > > diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp > index c1cfe23cdddb..0ba078db22ac 100644 > --- a/gdb/testsuite/gdb.base/catch-syscall.exp > +++ b/gdb/testsuite/gdb.base/catch-syscall.exp > @@ -19,7 +19,15 @@ > # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> > # on September/2008. > > -if { [is_remote target] || ![isnative] } then { > +if { ![isnative] } then { > + continue > +} > + > +# This shall be updated whenever QCatchSyscalls packet support is implemented > +# on some gdbserver architecture. > +if { [is_remote target] > + && ![istarget "x86_64-*-linux*"] > + && ![istarget "i\[34567\]86-*-linux*"] } { > continue > } This check won't reach the "continue" when testing with --target_board=native-extended-gdbserver on some arch that doesn't implement QCatchSyscall yet. That board is not "is_remote". I'd actually favor dropping the arch check altogether. Otherwise it's very likely that arch maintainers won't ever notice there's a new method they can wire in. > > @@ -390,7 +398,10 @@ proc do_syscall_tests {} { > if [runto_main] then { test_catch_syscall_skipping_return } > > # Testing the 'catch syscall' command starting mid-vfork. > - if [runto_main] then { test_catch_syscall_mid_vfork } > + # (Only local or extended-remote can use "catch vfork".) > + if { ![is_remote target] || [target_info gdb_protocol] == "extended-remote" } { I think IWBN to add a supports_catch_fork proc to lib/gdb.exp. These checks are getting duplicated (and not sure they are consistent) in several places. E.g., here, your now catch-fork-static.exp test, the test that was based on, etc... > + if [runto_main] then { test_catch_syscall_mid_vfork } > + } > > # Testing if the 'catch syscall' command works when switching to > # different architectures on-the-fly (PR gdb/10737). Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-04 13:18 ` Pedro Alves @ 2015-12-05 2:16 ` Josh Stone 2015-12-08 13:31 ` Pedro Alves ` (2 more replies) 0 siblings, 3 replies; 49+ messages in thread From: Josh Stone @ 2015-12-05 2:16 UTC (permalink / raw) To: Pedro Alves, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 On 12/04/2015 05:18 AM, Pedro Alves wrote: > Quick question: What is supposed to happen to the QCatchSyscalls > when the process execs? I'm thinking of 64-bit inferior execing > 32-bit inferior, etc. The syscall numbers aren't necessarily shared > between the different architectures. This implementation deletes discards > the previous QCatchSyscalls on exec, and I think that's what makes sense, > but, I think that this should be explicit in the packet's description. Yes, I think it should be cleared to avoid any assumption about the architecture. I'll add a note in the description codifying this. > I'm not sure gdb clears the inferior's "syscalls to the caught" VEC > on exec events, but it probably does (if it doesn't, I think it should.) I'll see if I can find out. Something else I just realized - my syscall_state accounting gets lost when an exec creates a new lwp_info. GDB is sending another QCatchSyscalls for the "new" process, and then the exec return is thought to be a syscall_entry. That's easy enough to correct, but I should write a new test for this too. (and see what gdb alone does...) On a total tangent, is it ever possible that GDB/GDBserver might try to read and modify registers from a PTRACE_EVENT stop? If so, you should beware that registers may actually be in flux. I ran into this with Dyninst, which I fixed here[1] 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. [1] http://git.dyninst.org/?p=dyninst.git;a=commit;h=b89ea1d19677fa0dd9c605ef492c5f6dabf15752 > On 12/04/2015 02:26 AM, Josh Stone wrote: >> This adds a new QCatchSyscalls packet to enable 'catch syscall', and new >> stop reasons "syscall_entry" and "syscall_return" for those events. It >> is currently only supported on Linux x86 and x86_64. >> >> gdb/ChangeLog: >> >> 2015-12-03 Josh Stone <jistone@redhat.com> >> Philippe Waroquiers <philippe.waroquiers@skynet.be> >> >> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and new >> GDBserver support for catch syscall. >> * remote.c (PACKET_QCatchSyscalls): New enum. >> (remote_set_syscall_catchpoint): New function. >> (remote_protocol_features): New element for QCatchSyscalls. >> (remote_parse_stop_reply): Parse syscall_entry/return stops. >> (init_remote_ops): Install remote_set_syscall_catchpoint. >> (_initialize_remote): Config QCatchSyscalls. >> * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. >> >> gdb/doc/ChangeLog: >> >> 2015-12-03 Josh Stone <jistone@redhat.com> >> Philippe Waroquiers <philippe.waroquiers@skynet.be> >> >> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. >> (Stop Reply Packets): List the syscall entry and return stop reasons. >> (General Query Packets): Describe QCatchSyscalls, and add it to the >> table and detailed list of stub features. >> >> gdb/gdbserver/ChangeLog: >> >> 2015-12-03 Josh Stone <jistone@redhat.com> >> Philippe Waroquiers <philippe.waroquiers@skynet.be> >> >> * inferiors.h: Include "gdb_vecs.h". >> (struct process_info): Add syscalls_to_catch. >> * inferiors.c (remove_process): Free syscalls_to_catch. >> * remote-utils.c (prepare_resume_reply): Report syscall_entry and >> syscall_return stops. >> * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. >> * server.c (handle_general_set): Handle QCatchSyscalls. >> (handle_query): Report support for QCatchSyscalls. >> * target.h (struct target_ops): Add supports_catch_syscall. >> (target_supports_catch_syscall): New macro. >> * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. >> (struct lwp_info): Add syscall_state. >> * linux-low.c (handle_extended_wait): Mark syscall_state as an entry. >> (get_syscall_trapinfo): New function, proxy to the_low_target. >> (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. >> (linux_low_filter_event): Toggle syscall_state entry/return for >> syscall traps, and set it ignored for all others. >> (gdb_catching_syscalls_p): New function. >> (gdb_catch_this_syscall_p): New function. >> (linux_wait_1): Handle SYSCALL_SIGTRAP. >> (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. >> (linux_supports_catch_syscall): New function. >> (linux_target_ops): Install it. >> * linux-x86-low.c (x86_get_syscall_trapinfo): New function. >> (the_low_target): Install it. >> * nto-low.c (nto_target_ops): Install NULL supports_catch_syscall. >> * spu-low.c (spu_target_ops): Likewise. >> * win32-low.c (win32_target_ops): Likewise. >> >> gdb/testsuite/ChangeLog: >> >> 2015-12-03 Josh Stone <jistone@redhat.com> >> Philippe Waroquiers <philippe.waroquiers@skynet.be> >> >> * gdb.base/catch-syscall.exp: Enable testing for x86 and x86_64 linux >> remote targets. >> (do_syscall_tests): Only test mid-vfork on local or extended-remote. >> --- >> gdb/NEWS | 10 +++ >> gdb/doc/gdb.texinfo | 56 +++++++++++++ >> gdb/gdbserver/inferiors.c | 1 + >> gdb/gdbserver/inferiors.h | 5 ++ >> gdb/gdbserver/linux-low.c | 140 ++++++++++++++++++++++++++++++- >> gdb/gdbserver/linux-low.h | 13 +++ >> gdb/gdbserver/linux-x86-low.c | 26 ++++++ >> gdb/gdbserver/nto-low.c | 1 + >> gdb/gdbserver/remote-utils.c | 12 +++ >> gdb/gdbserver/server.c | 49 +++++++++++ >> gdb/gdbserver/server.h | 6 ++ >> gdb/gdbserver/spu-low.c | 1 + >> gdb/gdbserver/target.h | 8 ++ >> gdb/gdbserver/win32-low.c | 1 + >> gdb/linux-nat.h | 2 +- >> gdb/remote.c | 116 +++++++++++++++++++++++++ >> gdb/testsuite/gdb.base/catch-syscall.exp | 15 +++- >> 17 files changed, 456 insertions(+), 6 deletions(-) >> >> diff --git a/gdb/NEWS b/gdb/NEWS >> index a222dfb491f0..1917523d8249 100644 >> --- a/gdb/NEWS >> +++ b/gdb/NEWS >> @@ -112,6 +112,11 @@ N stop reply >> threads are stopped). The remote stub reports support for this stop >> reply to GDB's qSupported query. >> >> +QCatchSyscalls:1 [;SYSNO]... >> +QCatchSyscalls:0 >> + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") >> + catching syscalls from the inferior process. >> + >> * Extended-remote exec events >> >> ** GDB now has support for exec events on extended-remote Linux targets. >> @@ -127,6 +132,11 @@ show remote exec-event-feature-packet >> The reply to qXfer:threads:read may now include a name attribute for each >> thread. >> >> +* New features in the GDB remote stub, GDBserver >> + >> + ** GDBserver now supports catch syscall. Currently enabled >> + on x86/x86_64 GNU/Linux targets. >> + >> *** Changes in GDB 7.10 >> > > Please mention the new set/show commands as well. OK. Looking at "exec" for a model, I guess I should also mention the syscall_entry/return stop reasons and the qSupported addition. >> +@item QCatchSyscalls >> +The remote stub understands the @samp{QCatchSyscalls} packet >> +(@pxref{QCatchSyscalls}). >> + >> @item QPassSignals >> The remote stub understands the @samp{QPassSignals} packet >> (@pxref{QPassSignals}). > > You also need to list the new commands in the table below: > > For each packet @var{name}, the command to enable or disable the > packet is @code{set remote @var{name}-packet}. The available settings > are: It's already added in the first patch hunk of this file, no? Related, I just noticed the code was checking only for remote support, not the local enabled state. I'll fix that to use packet_support(). >> /* Generic information for tracking a list of ``inferiors'' - threads, >> processes, etc. */ >> struct inferior_list >> @@ -67,6 +69,9 @@ struct process_info >> /* The list of installed fast tracepoints. */ >> struct fast_tracepoint_jump *fast_tracepoint_jumps; >> >> + /* The list of syscalls to report, or just ANY_SYSCALL. */ >> + VEC (int) *syscalls_to_catch; > > "just" here means that it's a list with a single element that > happens to be ANY_SYSCALL; I think it's helpful for the reader to > be explicit and expand the "or just ANY_SYSCALL" comment little bit. OK, I'll expand this. >> + >> const struct target_desc *tdesc; >> >> /* Private target data. */ >> diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c >> index 5e2dc5857a8d..cceede6fe408 100644 > > > >> --- a/gdb/gdbserver/linux-low.h >> +++ b/gdb/gdbserver/linux-low.h >> @@ -201,6 +201,12 @@ struct linux_target_ops >> /* Hook to support target specific qSupported. */ >> void (*process_qsupported) (char **, int count); >> >> + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the >> + return code. Only to be called when inferior is stopped >> + due to SYSCALL_SIGTRAP. */ >> + void (*get_syscall_trapinfo) (struct regcache *regcache, >> + int *sysno, int *sysret); >> + > > As you're not putting this new callback at the end of the struct, > you need to install a NULL callback in all linux-*-low.c files (all > archs) that install linux_target_ops methods after process_qsupported. > Otherwise you'll break their builds. Ah, indeed. It seems more convenient to put the new field at the end, but right now it roughly mirrors the placement of the new target_ops field. Maybe that should be at the end too, then I can touch fewer files overall. (i.e. no change in targets I'm not implementing.) >> /* Returns true if the low target supports tracepoints. */ >> int (*supports_tracepoints) (void); >> >> @@ -277,6 +283,13 @@ struct lwp_info >> event already received in a wait()). */ >> int stopped; >> >> + /* Signal whether we are in a SYSCALL_ENTRY or >> + in a SYSCALL_RETURN event. >> + Values: >> + - TARGET_WAITKIND_SYSCALL_ENTRY >> + - TARGET_WAITKIND_SYSCALL_RETURN */ >> + enum target_waitkind syscall_state; >> + >> /* When stopped is set, the last wait status recorded for this lwp. */ >> int last_status; >> >> diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c >> index 18adf5ee7d17..1caf71edf485 100644 > > > >> @@ -1172,6 +1174,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, >> >> sprintf (buf, "T%02xcreate:;", signal); >> } >> + else if ((status->kind == TARGET_WAITKIND_SYSCALL_ENTRY) >> + || (status->kind == TARGET_WAITKIND_SYSCALL_RETURN)) > > Unnecessary parens. OK, removed. >> + { >> + enum gdb_signal signal = GDB_SIGNAL_TRAP; >> + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY >> + ? "syscall_entry" : "syscall_return"); >> + >> + sprintf (buf, "T%02x%s:%x;", signal, event, >> + status->value.syscall_number); >> + } >> else >> sprintf (buf, "T%02x", status->value.sig); >> >> diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c >> index 6d151ee35d39..e63656b9c0f6 100644 >> --- a/gdb/gdbserver/server.c >> +++ b/gdb/gdbserver/server.c >> @@ -597,6 +597,52 @@ handle_general_set (char *own_buf) >> return; >> } >> >> + if (startswith (own_buf, "QCatchSyscalls:1")) >> + { >> + const char *p; >> + CORE_ADDR sysno; >> + struct process_info *process; >> + >> + if (!target_running () || !target_supports_catch_syscall ()) >> + { >> + write_enn (own_buf); >> + return; >> + } > > I think you should merge this with > >> + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) >> + { >> + if (!target_running () || !target_supports_catch_syscall ()) >> + { >> + write_enn (own_buf); >> + return; >> + } > > into a single > > if (startswith (own_buf, "QCatchSyscalls:") > { > ... > if (!target_running () || !target_supports_catch_syscall ()) > { > write_enn (own_buf); > return; > } > > See "QNonStop:" handling. The end result is that "QCatchSyscalls:2" > is treated as an error instead of returning the empty packet. OK, I will merge these and make it parse more strictly. >> + >> + process = current_process (); >> + >> + VEC_truncate (int, process->syscalls_to_catch, 0); >> + >> + p = own_buf + strlen("QCatchSyscalls:1"); >> + if (*p == ';') >> + { >> + p += 1; >> + while (*p) > > while (*p != '\0) OK >> + { >> + p = decode_address_to_semicolon (&sysno, p); >> + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); >> + } >> + } >> + else >> + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); >> + >> + write_ok (own_buf); >> + return; >> + } >> + >> + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) >> + { >> + if (!target_running () || !target_supports_catch_syscall ()) >> + { >> + write_enn (own_buf); >> + return; >> + } >> + >> + VEC_free (int, current_process ()->syscalls_to_catch); >> + write_ok (own_buf); >> + return; >> + } >> + >> if (startswith (own_buf, "QProgramSignals:")) >> { >> int numsigs = (int) GDB_SIGNAL_LAST, i; >> @@ -2219,6 +2265,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) >> "PacketSize=%x;QPassSignals+;QProgramSignals+", >> PBUFSIZ - 1); >> >> + if (target_supports_catch_syscall ()) >> + strcat (own_buf, ";QCatchSyscalls+"); >> + >> if (the_target->qxfer_libraries_svr4 != NULL) >> strcat (own_buf, ";qXfer:libraries-svr4:read+" >> ";augmented-libraries-svr4-read+"); >> diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h >> index dc0361fdcd14..bc2abd5f50c8 100644 > > > >> + if (needed && !any_count) >> + { >> + int i; >> + >> + /* Count how many syscalls are to be caught (table[sysno] != 0). */ >> + for (i = 0; i < table_size; i++) >> + { >> + if (table[i]) > > if (table[i] != 0) > > just like the comment. :-) OK >> + n_sysno++; >> + } >> + } >> + >> + if (remote_debug) >> + { >> + fprintf_unfiltered (gdb_stdlog, >> + "remote_set_syscall_catchpoint " >> + "pid %d needed %d any_count %d n_sysno %d\n", >> + pid, needed, any_count, n_sysno); >> + } >> + >> + if (needed) >> + { >> + /* Prepare a packet with the sysno list, assuming max 8+1 >> + characters for a sysno. If the resulting packet size is too >> + big, fallback on the non selective packet. */ > > "non-selective packet" OK >> + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; >> + >> + catch_packet = xmalloc (maxpktsz); >> + strcpy (catch_packet, "QCatchSyscalls:1"); >> + if (!any_count) >> + { >> + int i; >> + char *p; >> + >> + p = catch_packet; >> + p += strlen (p); >> + >> + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ >> + for (i = 0; i < table_size; i++) >> + { >> + if (table[i]) > > Likewise. OK >> + { >> + xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); >> + p += strlen (p); > > This looks like: > > len = xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); > p += len; OK, I see, since xsnprintf asserts that the return count did fit, it can be used directly. I guess "p += xsnprintf (...)" should do fine. >> + } >> + } >> + } >> + if (strlen (catch_packet) > get_remote_packet_size ()) >> + { >> + /* catch_packet too big. Fallback to less efficient >> + non selective mode, with GDB doing the filtering. */ >> + catch_packet[strlen ("QCatchSyscalls:1")] = 0; > > catch_packet[sizeof ("QCatchSyscalls:1") - 1] = 0; OK >> + } >> + } >> + else >> + { >> + catch_packet = xmalloc (strlen ("QCatchSyscalls:0") + 1); >> + strcpy (catch_packet, "QCatchSyscalls:0"); > > catch_packet = xstrdup ("QCatchSyscalls:0"); OK >> + } >> + >> + { >> + struct remote_state *rs = get_remote_state (); >> + char *buf = rs->buf; >> + >> + putpkt (catch_packet); >> + getpkt (&rs->buf, &rs->buf_size, 0); >> + result = packet_ok (buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); > > getpkt takes a pointer to pointer because it may xrealloc 'rs->buf'. > So this 'buf' reference may be dangling. Just drop the 'buf' local. OK >> + xfree (catch_packet); > > putpkt/getpkt may throw. This should be freed with a cleanup instead. OK >> + if (result == PACKET_OK) >> + return 0; >> + else >> + return -1; >> + } >> +} >> + >> /* If 'QProgramSignals' is supported, tell the remote stub what >> signals it should pass through to the inferior when detaching. */ >> > > > >> diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp >> index c1cfe23cdddb..0ba078db22ac 100644 >> --- a/gdb/testsuite/gdb.base/catch-syscall.exp >> +++ b/gdb/testsuite/gdb.base/catch-syscall.exp >> @@ -19,7 +19,15 @@ >> # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> >> # on September/2008. >> >> -if { [is_remote target] || ![isnative] } then { >> +if { ![isnative] } then { >> + continue >> +} >> + >> +# This shall be updated whenever QCatchSyscalls packet support is implemented >> +# on some gdbserver architecture. >> +if { [is_remote target] >> + && ![istarget "x86_64-*-linux*"] >> + && ![istarget "i\[34567\]86-*-linux*"] } { >> continue >> } > > This check won't reach the "continue" when testing > with --target_board=native-extended-gdbserver on some arch that doesn't > implement QCatchSyscall yet. That board is not "is_remote". > > I'd actually favor dropping the arch check altogether. Otherwise it's very > likely that arch maintainers won't ever notice there's a new method they > can wire in. OK, I'll just remove it then. >> >> @@ -390,7 +398,10 @@ proc do_syscall_tests {} { >> if [runto_main] then { test_catch_syscall_skipping_return } >> >> # Testing the 'catch syscall' command starting mid-vfork. >> - if [runto_main] then { test_catch_syscall_mid_vfork } >> + # (Only local or extended-remote can use "catch vfork".) >> + if { ![is_remote target] || [target_info gdb_protocol] == "extended-remote" } { > > I think IWBN to add a supports_catch_fork proc to lib/gdb.exp. These > checks are getting duplicated (and not sure they are consistent) in > several places. E.g., here, your now catch-fork-static.exp test, the > test that was based on, etc... Yeah, well this one is "vfork", but it still conceptually overlaps with what foll-vfork.exp checks. For the moment, I guess I can just remove the latter clause, since you pointed out that native-extended-gdbserver is already not "is_remote". >> + if [runto_main] then { test_catch_syscall_mid_vfork } >> + } >> >> # Testing if the 'catch syscall' command works when switching to >> # different architectures on-the-fly (PR gdb/10737). > > Thanks, > Pedro Alves > ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-05 2:16 ` Josh Stone @ 2015-12-08 13:31 ` Pedro Alves 2015-12-08 19:02 ` Josh Stone 2015-12-08 13:37 ` Pedro Alves 2015-12-11 21:19 ` Josh Stone 2 siblings, 1 reply; 49+ messages in thread From: Pedro Alves @ 2015-12-08 13:31 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 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[1] though I can't find the discussion now. > Ouch. > 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. > > [1] > http://git.dyninst.org/?p=dyninst.git;a=commit;h=b89ea1d19677fa0dd9c605ef492c5f6dabf15752 Just to be clear, doesn't $orig_rax help here? Are you saving/restoring that? 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. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-08 13:31 ` Pedro Alves @ 2015-12-08 19:02 ` Josh Stone 0 siblings, 0 replies; 49+ messages in thread From: Josh Stone @ 2015-12-08 19:02 UTC (permalink / raw) To: Pedro Alves, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 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[1] though I can't find the discussion now. >> > > Ouch. > >> 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. >> >> [1] >> http://git.dyninst.org/?p=dyninst.git;a=commit;h=b89ea1d19677fa0dd9c605ef492c5f6dabf15752 > > 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 PTRACE_SYSCALL might. > 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. :) ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-05 2:16 ` Josh Stone 2015-12-08 13:31 ` Pedro Alves @ 2015-12-08 13:37 ` Pedro Alves 2015-12-11 21:19 ` Josh Stone 2 siblings, 0 replies; 49+ messages in thread From: Pedro Alves @ 2015-12-08 13:37 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 On 12/05/2015 02:16 AM, Josh Stone wrote: >> You also need to list the new commands in the table below: >> >> For each packet @var{name}, the command to enable or disable the >> packet is @code{set remote @var{name}-packet}. The available settings >> are: > > It's already added in the first patch hunk of this file, no? Indeed. Sorry, got confused. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-05 2:16 ` Josh Stone 2015-12-08 13:31 ` Pedro Alves 2015-12-08 13:37 ` Pedro Alves @ 2015-12-11 21:19 ` Josh Stone 2015-12-16 15:42 ` Pedro Alves 2 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2015-12-11 21:19 UTC (permalink / raw) To: Pedro Alves, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 On 12/04/2015 06:16 PM, Josh Stone wrote: > On 12/04/2015 05:18 AM, Pedro Alves wrote: >> Quick question: What is supposed to happen to the QCatchSyscalls >> when the process execs? I'm thinking of 64-bit inferior execing >> 32-bit inferior, etc. The syscall numbers aren't necessarily shared >> between the different architectures. This implementation deletes discards >> the previous QCatchSyscalls on exec, and I think that's what makes sense, >> but, I think that this should be explicit in the packet's description. > > Yes, I think it should be cleared to avoid any assumption about the > architecture. I'll add a note in the description codifying this. After exploration, I'm having second thoughts about this point. Yes, the current implementation clears it, but only when PTRACE_O_TRACEEXEC is enabled to actually get that event. That's only if the client sent "qSupports:exec-events+". Otherwise, the server doesn't even know an exec happened, so it can't really promise to reset the syscall table. Since the server doesn't promise to always catch execs, I think we should actually go the other way to stay consistent. Let the syscall list be carried over, and document that clients should probably send a new list after execs in case the architecture changed. Some clients may just choose to live with the assumption that the arch is consistent in their environment. Thoughts? >> I'm not sure gdb clears the inferior's "syscalls to the caught" VEC >> on exec events, but it probably does (if it doesn't, I think it should.) > > I'll see if I can find out. AFAICT the only time anything is removed from syscall_catchpoint's VEC syscalls_to_be_caught is in breakpoint_ops->remove_location and ->dtor, respectively remove_catch_syscall and dtor_catch_syscall. And since this list isn't stored in the lwp structure itself, the exec doesn't really affect anything. Right? ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 2/2] Implement 'catch syscall' for gdbserver 2015-12-11 21:19 ` Josh Stone @ 2015-12-16 15:42 ` Pedro Alves 0 siblings, 0 replies; 49+ messages in thread From: Pedro Alves @ 2015-12-16 15:42 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 Hi Josh. On 12/11/2015 09:19 PM, Josh Stone wrote: > On 12/04/2015 06:16 PM, Josh Stone wrote: >> On 12/04/2015 05:18 AM, Pedro Alves wrote: >>> Quick question: What is supposed to happen to the QCatchSyscalls >>> when the process execs? I'm thinking of 64-bit inferior execing >>> 32-bit inferior, etc. The syscall numbers aren't necessarily shared >>> between the different architectures. This implementation deletes discards >>> the previous QCatchSyscalls on exec, and I think that's what makes sense, >>> but, I think that this should be explicit in the packet's description. >> >> Yes, I think it should be cleared to avoid any assumption about the >> architecture. I'll add a note in the description codifying this. > > After exploration, I'm having second thoughts about this point. Yes, > the current implementation clears it, but only when PTRACE_O_TRACEEXEC > is enabled to actually get that event. That's only if the client sent > "qSupports:exec-events+". Otherwise, the server doesn't even know an > exec happened, so it can't really promise to reset the syscall table. Hmm. It sounds reasonable. However, I think that gdb will always want to listen to exec events. It has to, in order to install breakpoints in the new image, and make sure that it doesn't incorrectly remove old breakpoints in the new image either the next time the program stops. That older gdb's weren't aware of execs is plain and simply a bug. I understand you may be thinking of strace instead of gdb though, which mainly only cares about syscalls. I think even strace always need to handle exec events too, to handle the case that the exec event is reported to the thread group leader, even if it was some other thread that execed. But I see the point that this may avoid extra stops and traffic in some scenarios, so I'm fine with specifying it that way. > > Since the server doesn't promise to always catch execs, I think we > should actually go the other way to stay consistent. If the server doesn't catch execs, then gdb won't know about them either, and so from gdb's perpective, the syscalls-to-catch-list doesn't change either. It's as-if the exec didn't happen, so the server would naturally catch syscalls across the exec. Doesn't seem to me that there'd be an issue here. > Let the syscall > list be carried over, and document that clients should probably send a > new list after execs in case the architecture changed. Some clients may > just choose to live with the assumption that the arch is consistent in > their environment. We really should say "probably" in the docs. Stub authors won't know what to do then. We should be definitive. On the gdb side, I think that determining whether the arch changed would be somewhat a complication -- the place we discover the new arch isn't the same place we install new breakpoints. We could perhaps have the core always install the catchpoints and then we could handle that by making remote.c remember the last arch the syscalls list was set to for the given inferior, and compare that arch with the inferior's current arch, somehow generically. BTW, am I right that with your current patch, if the user sets 10 syscall catchpoints, remote_set_syscall_catchpoint will be called 10 times, and thus gdbserver gets 10 QCatchSyscalls packets? > >>> I'm not sure gdb clears the inferior's "syscalls to the caught" VEC >>> on exec events, but it probably does (if it doesn't, I think it should.) >> >> I'll see if I can find out. > > AFAICT the only time anything is removed from syscall_catchpoint's VEC > syscalls_to_be_caught is in breakpoint_ops->remove_location and ->dtor, > respectively remove_catch_syscall and dtor_catch_syscall. And since > this list isn't stored in the lwp structure itself, the exec doesn't > really affect anything. Right? > Hmm. Then it sounds like we still mishandle e.g., "catch syscall open" across execs that change archs, as described at: https://sourceware.org/bugzilla/show_bug.cgi?id=10737#c5 Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* [PATCH v4] Implement 'catch syscall' for gdbserver 2015-12-04 2:27 ` [PATCH v3 2/2] Implement 'catch syscall' for gdbserver Josh Stone 2015-12-04 8:45 ` Eli Zaretskii 2015-12-04 13:18 ` Pedro Alves @ 2016-01-09 3:09 ` Josh Stone 2016-01-09 7:37 ` Eli Zaretskii ` (3 more replies) 2 siblings, 4 replies; 49+ messages in thread From: Josh Stone @ 2016-01-09 3:09 UTC (permalink / raw) To: gdb-patches Cc: philippe.waroquiers, sergiodj, palves, eliz, xdje42, scox, Josh Stone This adds a new QCatchSyscalls packet to enable 'catch syscall', and new stop reasons "syscall_entry" and "syscall_return" for those events. It is currently only supported on Linux x86 and x86_64. gdb/ChangeLog: 2016-01-08 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and the syscall_entry and syscall_return stop reasons. Mention GDB support for remote catch syscall. * remote.c (PACKET_QCatchSyscalls): New enum. (remote_set_syscall_catchpoint): New function. (remote_protocol_features): New element for QCatchSyscalls. (remote_parse_stop_reply): Parse syscall_entry/return stops. (init_remote_ops): Install remote_set_syscall_catchpoint. (_initialize_remote): Config QCatchSyscalls. * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. gdb/doc/ChangeLog: 2016-01-08 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. (Stop Reply Packets): List the syscall entry and return stop reasons. (General Query Packets): Describe QCatchSyscalls, and add it to the table and detailed list of stub features. gdb/gdbserver/ChangeLog: 2016-01-08 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * inferiors.h: Include "gdb_vecs.h". (struct process_info): Add syscalls_to_catch. * inferiors.c (remove_process): Free syscalls_to_catch. * remote-utils.c (prepare_resume_reply): Report syscall_entry and syscall_return stops. * server.h (UNKNOWN_SYSCALL, ANY_SYSCALL): Define. * server.c (handle_general_set): Handle QCatchSyscalls. (handle_query): Report support for QCatchSyscalls. * target.h (struct target_ops): Add supports_catch_syscall. (target_supports_catch_syscall): New macro. * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo. (struct lwp_info): Add syscall_state. * linux-low.c (handle_extended_wait): Mark syscall_state as an entry. Maintain syscall_state and syscalls_to_catch across exec. (get_syscall_trapinfo): New function, proxy to the_low_target. (linux_low_ptrace_options): Enable PTRACE_O_TRACESYSGOOD. (linux_low_filter_event): Toggle syscall_state entry/return for syscall traps, and set it ignored for all others. (gdb_catching_syscalls_p): New function. (gdb_catch_this_syscall_p): New function. (linux_wait_1): Handle SYSCALL_SIGTRAP. (linux_resume_one_lwp_throw): Add PTRACE_SYSCALL possibility. (linux_supports_catch_syscall): New function. (linux_target_ops): Install it. * linux-x86-low.c (x86_get_syscall_trapinfo): New function. (the_low_target): Install it. gdb/testsuite/ChangeLog: 2016-01-08 Josh Stone <jistone@redhat.com> Philippe Waroquiers <philippe.waroquiers@skynet.be> * gdb.base/catch-syscall.c (do_execve): New variable. (main): Conditionally trigger an execve. * gdb.base/catch-syscall.exp: Enable testing for remote targets. (test_catch_syscall_execve): New, check entry/return across execve. (do_syscall_tests): Call test_catch_syscall_execve. --- gdb/NEWS | 24 +++++ gdb/doc/gdb.texinfo | 61 ++++++++++++ gdb/gdbserver/inferiors.c | 1 + gdb/gdbserver/inferiors.h | 6 ++ gdb/gdbserver/linux-low.c | 155 ++++++++++++++++++++++++++++++- gdb/gdbserver/linux-low.h | 13 +++ gdb/gdbserver/linux-x86-low.c | 26 ++++++ gdb/gdbserver/remote-utils.c | 12 +++ gdb/gdbserver/server.c | 51 ++++++++++ gdb/gdbserver/server.h | 6 ++ gdb/gdbserver/target.h | 8 ++ gdb/linux-nat.h | 2 +- gdb/remote.c | 110 ++++++++++++++++++++++ gdb/testsuite/gdb.base/catch-syscall.c | 9 +- gdb/testsuite/gdb.base/catch-syscall.exp | 31 ++++++- 15 files changed, 507 insertions(+), 8 deletions(-) diff --git a/gdb/NEWS b/gdb/NEWS index 484d98d24143..adb4d9790065 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -120,6 +120,21 @@ N stop reply threads are stopped). The remote stub reports support for this stop reply to GDB's qSupported query. +QCatchSyscalls:1 [;SYSNO]... +QCatchSyscalls:0 + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") + catching syscalls from the inferior process. + +syscall_entry stop reason + Indicates that a syscall was just called. + +syscall_return stop reason + Indicates that a syscall just returned. + +QCatchSyscalls:1 in qSupported + The qSupported packet may now include QCatchSyscalls:1 in the reply + to indicate support for catching syscalls. + * Extended-remote exec events ** GDB now has support for exec events on extended-remote Linux targets. @@ -142,6 +157,15 @@ show remote exec-event-feature-packet this enables follow-fork-mode, detach-on-fork, follow-exec-mode, and fork and exec catchpoints. +* Remote syscall events + + ** GDB now has support for catch syscall on remote Linux targets, + currently enabled on x86/x86_64 architectures. + +set remote catch-syscall-packet +show remote catch-syscall-packet + Set/show the use of the remote catch syscall feature. + * MI changes ** The -var-set-format command now accepts the zero-hexadecimal diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 0778383280a7..e18b27ec4315 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -20261,6 +20261,10 @@ are: @tab @code{qSupported} @tab Remote communications parameters +@item @code{catch-syscalls} +@tab @code{QCatchSyscalls} +@tab @code{catch syscall} + @item @code{pass-signals} @tab @code{QPassSignals} @tab @code{handle @var{signal}} @@ -35580,6 +35584,11 @@ The currently defined stop reasons are: The packet indicates a watchpoint hit, and @var{r} is the data address, in hex. +@item syscall_entry +@itemx syscall_return +The packet indicates a syscall entry or return, and @var{r} is the +syscall number, in hex. + @cindex shared library events, remote reply @item library The packet indicates that the loaded libraries have changed. @@ -36072,6 +36081,49 @@ by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). Use of this packet is controlled by the @code{set non-stop} command; @pxref{Non-Stop Mode}. +@item QCatchSyscalls:1 @r{[};@var{sysno}@r{]}@dots{} +@itemx QCatchSyscalls:0 +@cindex catch syscalls from inferior, remote request +@cindex @samp{QCatchSyscalls} packet +@anchor{QCatchSyscalls} +Enable (@samp{QCatchSyscalls:1}) or disable (@samp{QCatchSyscalls:0}) +catching syscalls from the inferior process. + +For @samp{QCatchSyscalls:1}, each listed syscall @var{sysno} (encoded +in hex) should be reported to @value{GDBN}. If no syscall @var{sysno} +is listed, every system call should be reported. + +Note that if a syscall not in the list is reported, @value{GDBN} will +still filter the event according to its own list from all corresponding +@code{catch syscall} commands. However, it is more efficient to only +report the requested syscalls. + +Multiple @samp{QCatchSyscalls:1} packets do not combine; any earlier +@samp{QCatchSyscalls:1} list is completely replaced by the new list. + +If the inferior process execs, the state of @samp{QCatchSyscalls} is +kept for the new process too. On targets where exec may affect syscall +numbers, for example with exec between 32 and 64-bit processes, the +client should send a new packet with the new syscall list. + +Reply: +@table @samp +@item OK +The request succeeded. + +@item E @var{nn} +An error occurred. @var{nn} are hex digits. + +@item @w{} +An empty reply indicates that @samp{QCatchSyscalls} is not supported by +the stub. +@end table + +Use of this packet is controlled by the @code{set remote catch-syscalls} +command (@pxref{Remote Configuration, set remote catch-syscalls}). +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + @item QPassSignals: @var{signal} @r{[};@var{signal}@r{]}@dots{} @cindex pass signals to inferior, remote request @cindex @samp{QPassSignals} packet @@ -36523,6 +36575,11 @@ These are the currently defined stub features and their properties: @tab @samp{-} @tab Yes +@item @samp{QCatchSyscalls} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QPassSignals} @tab No @tab @samp{-} @@ -36726,6 +36783,10 @@ packet (@pxref{qXfer fdpic loadmap read}). The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). +@item QCatchSyscalls +The remote stub understands the @samp{QCatchSyscalls} packet +(@pxref{QCatchSyscalls}). + @item QPassSignals The remote stub understands the @samp{QPassSignals} packet (@pxref{QPassSignals}). diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c index c884b55f383a..4bea4fd7a91b 100644 --- a/gdb/gdbserver/inferiors.c +++ b/gdb/gdbserver/inferiors.c @@ -339,6 +339,7 @@ remove_process (struct process_info *process) free_all_breakpoints (process); gdb_assert (find_thread_process (process) == NULL); remove_inferior (&all_processes, &process->entry); + VEC_free (int, process->syscalls_to_catch); free (process); } diff --git a/gdb/gdbserver/inferiors.h b/gdb/gdbserver/inferiors.h index af65718ad4f9..00dfe60e0c5f 100644 --- a/gdb/gdbserver/inferiors.h +++ b/gdb/gdbserver/inferiors.h @@ -19,6 +19,8 @@ #ifndef INFERIORS_H #define INFERIORS_H +#include "gdb_vecs.h" + /* Generic information for tracking a list of ``inferiors'' - threads, processes, etc. */ struct inferior_list @@ -67,6 +69,10 @@ struct process_info /* The list of installed fast tracepoints. */ struct fast_tracepoint_jump *fast_tracepoint_jumps; + /* The list of syscalls to report, or just a single element, ANY_SYSCALL, + for unfiltered syscall reporting. */ + VEC (int) *syscalls_to_catch; + const struct target_desc *tdesc; /* Private target data. */ diff --git a/gdb/gdbserver/linux-low.c b/gdb/gdbserver/linux-low.c index 4f8f57392101..c787309b53a0 100644 --- a/gdb/gdbserver/linux-low.c +++ b/gdb/gdbserver/linux-low.c @@ -461,6 +461,11 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) gdb_assert (event_lwp->waitstatus.kind == TARGET_WAITKIND_IGNORE); + /* All extended events we currently use are mid-syscall. Only + PTRACE_EVENT_STOP is delivered more like a signal-stop, but + you have to be using PTRACE_SEIZE to get that. */ + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + if ((event == PTRACE_EVENT_FORK) || (event == PTRACE_EVENT_VFORK) || (event == PTRACE_EVENT_CLONE)) { @@ -611,6 +616,7 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) else if (event == PTRACE_EVENT_EXEC && report_exec_events) { struct process_info *proc; + VEC (int) *syscalls_to_catch; ptid_t event_ptid; pid_t event_pid; @@ -624,8 +630,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) event_ptid = ptid_of (event_thr); event_pid = ptid_get_pid (event_ptid); - /* Delete the execing process and all its threads. */ + /* Save the syscall list from the execing process. */ proc = get_thread_process (event_thr); + syscalls_to_catch = proc->syscalls_to_catch; + proc->syscalls_to_catch = NULL; + + /* Delete the execing process and all its threads. */ linux_mourn (proc); current_thread = NULL; @@ -648,6 +658,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) event_thr->last_resume_kind = resume_continue; event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; + /* Update syscall state in the new lwp, effectively mid-syscall too. + The client really should send a new list to catch, in case the + architecture changed, but for ANY_SYSCALL it doesn't matter. */ + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + proc->syscalls_to_catch = syscalls_to_catch; + /* Report the event. */ *orig_event_lwp = event_lwp; return 0; @@ -682,6 +698,40 @@ get_pc (struct lwp_info *lwp) return pc; } +/* This function should only be called if LWP got a SYSCALL_SIGTRAP. + Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. */ + +static void +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno, int *sysret) +{ + struct thread_info *saved_thread; + struct regcache *regcache; + + if (the_low_target.get_syscall_trapinfo == NULL) + { + /* If we cannot get the syscall trapinfo, report an unknown + system call number and -ENOSYS return value. */ + *sysno = UNKNOWN_SYSCALL; + *sysret = -ENOSYS; + return; + } + + saved_thread = current_thread; + current_thread = get_lwp_thread (lwp); + + regcache = get_thread_regcache (current_thread, 1); + (*the_low_target.get_syscall_trapinfo) (regcache, sysno, sysret); + + if (debug_threads) + { + debug_printf ("get_syscall_trapinfo sysno %d sysret %d\n", + *sysno, *sysret); + } + + current_thread = saved_thread; +} + /* This function should only be called if LWP got a SIGTRAP. The SIGTRAP could mean several things. @@ -2236,6 +2286,8 @@ linux_low_ptrace_options (int attached) if (report_exec_events) options |= PTRACE_O_TRACEEXEC; + options |= PTRACE_O_TRACESYSGOOD; + return options; } @@ -2364,6 +2416,21 @@ linux_low_filter_event (int lwpid, int wstat) child->must_set_ptrace_flags = 0; } + /* Always update syscall_state, even if it will be filtered later. */ + if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SYSCALL_SIGTRAP) + { + child->syscall_state + = (child->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY + ? TARGET_WAITKIND_SYSCALL_RETURN + : TARGET_WAITKIND_SYSCALL_ENTRY); + } + else + { + /* Almost all other ptrace-stops are known to be outside of system + calls, with further exceptions in handle_extended_wait. */ + child->syscall_state = TARGET_WAITKIND_IGNORE; + } + /* Be careful to not overwrite stop_pc until check_stopped_by_breakpoint is called. */ if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP @@ -2973,6 +3040,44 @@ filter_exit_event (struct lwp_info *event_child, return ptid; } +/* Returns 1 if GDB is interested in any event_child syscalls. */ + +static int +gdb_catching_syscalls_p (struct lwp_info *event_child) +{ + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + return !VEC_empty (int, proc->syscalls_to_catch); +} + +/* Returns 1 if GDB is interested in the event_child syscall. + Only to be called when stopped reason is SYSCALL_SIGTRAP. */ + +static int +gdb_catch_this_syscall_p (struct lwp_info *event_child) +{ + int i, iter; + int sysno, sysret; + struct thread_info *thread = get_lwp_thread (event_child); + struct process_info *proc = get_thread_process (thread); + + if (VEC_empty (int, proc->syscalls_to_catch)) + return 0; + + if (VEC_index (int, proc->syscalls_to_catch, 0) == ANY_SYSCALL) + return 1; + + get_syscall_trapinfo (event_child, &sysno, &sysret); + for (i = 0; + VEC_iterate (int, proc->syscalls_to_catch, i, iter); + i++) + if (iter == sysno) + return 1; + + return 0; +} + /* Wait for process, returns status. */ static ptid_t @@ -3307,6 +3412,22 @@ linux_wait_1 (ptid_t ptid, /* Check whether GDB would be interested in this event. */ + /* Check if GDB is interested in this syscall. */ + if (WIFSTOPPED (w) + && WSTOPSIG (w) == SYSCALL_SIGTRAP + && !gdb_catch_this_syscall_p (event_child)) + { + if (debug_threads) + { + debug_printf ("Ignored syscall for LWP %ld.\n", + lwpid_of (current_thread)); + } + + linux_resume_one_lwp (event_child, event_child->stepping, + 0, NULL); + return ignore_event (ourstatus); + } + /* If GDB is not interested in this signal, don't stop other threads, and don't report it to GDB. Just resume the inferior right away. We do this for threading-related signals as well as @@ -3559,8 +3680,16 @@ linux_wait_1 (ptid_t ptid, } } - if (current_thread->last_resume_kind == resume_stop - && WSTOPSIG (w) == SIGSTOP) + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) + { + int sysret; + + get_syscall_trapinfo (event_child, + &ourstatus->value.syscall_number, &sysret); + ourstatus->kind = event_child->syscall_state; + } + else if (current_thread->last_resume_kind == resume_stop + && WSTOPSIG (w) == SIGSTOP) { /* A thread that has been requested to stop by GDB with vCont;t, and it stopped cleanly, so report as SIG0. The use of @@ -4017,6 +4146,7 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, struct thread_info *thread = get_lwp_thread (lwp); struct thread_info *saved_thread; int fast_tp_collecting; + int ptrace_request; struct process_info *proc = get_thread_process (thread); /* Note that target description may not be initialised @@ -4204,7 +4334,14 @@ linux_resume_one_lwp_throw (struct lwp_info *lwp, regcache_invalidate_thread (thread); errno = 0; lwp->stepping = step; - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread), + if (step) + ptrace_request = PTRACE_SINGLESTEP; + else if (gdb_catching_syscalls_p (lwp)) + ptrace_request = PTRACE_SYSCALL; + else + ptrace_request = PTRACE_CONT; + ptrace (ptrace_request, + lwpid_of (thread), (PTRACE_TYPE_ARG3) 0, /* Coerce to a uintptr_t first to avoid potential gcc warning of coercing an 8 byte integer to a 4 byte pointer. */ @@ -6286,6 +6423,13 @@ linux_process_qsupported (char **features, int count) } static int +linux_supports_catch_syscall (void) +{ + return (the_low_target.get_syscall_trapinfo != NULL + && linux_supports_tracesysgood()); +} + +static int linux_supports_tracepoints (void) { if (*the_low_target.supports_tracepoints == NULL) @@ -7209,7 +7353,8 @@ static struct target_ops linux_target_ops = { linux_sw_breakpoint_from_kind, linux_proc_tid_get_name, linux_breakpoint_kind_from_current_state, - linux_supports_software_single_step + linux_supports_software_single_step, + linux_supports_catch_syscall, }; #ifdef HAVE_LINUX_REGSETS diff --git a/gdb/gdbserver/linux-low.h b/gdb/gdbserver/linux-low.h index e80c67f54097..751eea18eaf8 100644 --- a/gdb/gdbserver/linux-low.h +++ b/gdb/gdbserver/linux-low.h @@ -240,6 +240,12 @@ struct linux_target_ops /* See target.h. */ int (*supports_hardware_single_step) (void); + + /* Fill *SYSNO with the syscall nr trapped. Fill *SYSRET with the + return code. Only to be called when inferior is stopped + due to SYSCALL_SIGTRAP. */ + void (*get_syscall_trapinfo) (struct regcache *regcache, + int *sysno, int *sysret); }; extern struct linux_target_ops the_low_target; @@ -278,6 +284,13 @@ struct lwp_info event already received in a wait()). */ int stopped; + /* Signal whether we are in a SYSCALL_ENTRY or + in a SYSCALL_RETURN event. + Values: + - TARGET_WAITKIND_SYSCALL_ENTRY + - TARGET_WAITKIND_SYSCALL_RETURN */ + enum target_waitkind syscall_state; + /* When stopped is set, the last wait status recorded for this lwp. */ int last_status; diff --git a/gdb/gdbserver/linux-x86-low.c b/gdb/gdbserver/linux-x86-low.c index 0432a86aab2b..4a01750c1724 100644 --- a/gdb/gdbserver/linux-x86-low.c +++ b/gdb/gdbserver/linux-x86-low.c @@ -1438,6 +1438,31 @@ x86_arch_setup (void) current_process ()->tdesc = x86_linux_read_description (); } +/* Fill *SYSNO and *SYSRET with the syscall nr trapped and the syscall return + code. This should only be called if LWP got a SYSCALL_SIGTRAP. */ + +static void +x86_get_syscall_trapinfo (struct regcache *regcache, int *sysno, int *sysret) +{ + int use_64bit = register_size (regcache->tdesc, 0) == 8; + + if (use_64bit) + { + long l_sysno; + long l_sysret; + + collect_register_by_name (regcache, "orig_rax", &l_sysno); + collect_register_by_name (regcache, "rax", &l_sysret); + *sysno = (int) l_sysno; + *sysret = (int) l_sysret; + } + else + { + collect_register_by_name (regcache, "orig_eax", sysno); + collect_register_by_name (regcache, "eax", sysret); + } +} + static int x86_supports_tracepoints (void) { @@ -3315,6 +3340,7 @@ struct linux_target_ops the_low_target = x86_supports_range_stepping, NULL, /* breakpoint_kind_from_current_state */ x86_supports_hardware_single_step, + x86_get_syscall_trapinfo, }; void diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c index c5f4647052c0..ec69b63c32c6 100644 --- a/gdb/gdbserver/remote-utils.c +++ b/gdb/gdbserver/remote-utils.c @@ -1132,6 +1132,8 @@ prepare_resume_reply (char *buf, ptid_t ptid, case TARGET_WAITKIND_VFORK_DONE: case TARGET_WAITKIND_EXECD: case TARGET_WAITKIND_THREAD_CREATED: + case TARGET_WAITKIND_SYSCALL_ENTRY: + case TARGET_WAITKIND_SYSCALL_RETURN: { struct thread_info *saved_thread; const char **regp; @@ -1181,6 +1183,16 @@ prepare_resume_reply (char *buf, ptid_t ptid, sprintf (buf, "T%02xcreate:;", signal); } + else if (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + || status->kind == TARGET_WAITKIND_SYSCALL_RETURN) + { + enum gdb_signal signal = GDB_SIGNAL_TRAP; + const char *event = (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + ? "syscall_entry" : "syscall_return"); + + sprintf (buf, "T%02x%s:%x;", signal, event, + status->value.syscall_number); + } else sprintf (buf, "T%02x", status->value.sig); diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c index fe7195ddab09..13fe159e4bef 100644 --- a/gdb/gdbserver/server.c +++ b/gdb/gdbserver/server.c @@ -624,6 +624,54 @@ handle_general_set (char *own_buf) return; } + if (startswith (own_buf, "QCatchSyscalls:")) + { + const char *p = own_buf + sizeof ("QCatchSyscalls:") - 1; + int enabled = -1; + CORE_ADDR sysno; + struct process_info *process; + + if (!target_running () || !target_supports_catch_syscall ()) + { + write_enn (own_buf); + return; + } + + if (strcmp (p, "0") == 0) + enabled = 0; + else if (p[0] == '1' && (p[1] == ';' || p[1] == '\0')) + enabled = 1; + else + { + fprintf (stderr, "Unknown catch-syscalls mode requested: %s\n", + own_buf); + write_enn (own_buf); + return; + } + + process = current_process (); + VEC_truncate (int, process->syscalls_to_catch, 0); + + if (enabled) + { + p += 1; + if (*p == ';') + { + p += 1; + while (*p != '\0') + { + p = decode_address_to_semicolon (&sysno, p); + VEC_safe_push (int, process->syscalls_to_catch, (int) sysno); + } + } + else + VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL); + } + + write_ok (own_buf); + return; + } + if (strcmp (own_buf, "QStartNoAckMode") == 0) { if (remote_debug) @@ -2200,6 +2248,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p) "PacketSize=%x;QPassSignals+;QProgramSignals+", PBUFSIZ - 1); + if (target_supports_catch_syscall ()) + strcat (own_buf, ";QCatchSyscalls+"); + if (the_target->qxfer_libraries_svr4 != NULL) strcat (own_buf, ";qXfer:libraries-svr4:read+" ";augmented-libraries-svr4-read+"); diff --git a/gdb/gdbserver/server.h b/gdb/gdbserver/server.h index 58cf342ed368..3d78fb319514 100644 --- a/gdb/gdbserver/server.h +++ b/gdb/gdbserver/server.h @@ -134,4 +134,10 @@ extern void discard_queued_stop_replies (ptid_t ptid); as large as the largest register set supported by gdbserver. */ #define PBUFSIZ 16384 +/* Definition for an unknown syscall, used basically in error-cases. */ +#define UNKNOWN_SYSCALL (-1) + +/* Definition for any syscall, used for unfiltered syscall reporting. */ +#define ANY_SYSCALL (-2) + #endif /* SERVER_H */ diff --git a/gdb/gdbserver/target.h b/gdb/gdbserver/target.h index cbdb8d98d221..5af205139d1d 100644 --- a/gdb/gdbserver/target.h +++ b/gdb/gdbserver/target.h @@ -467,6 +467,10 @@ struct target_ops /* Returns true if the target can software single step. */ int (*supports_software_single_step) (void); + + /* Return 1 if the target supports catch syscall, 0 (or leave the + callback NULL) otherwise. */ + int (*supports_catch_syscall) (void); }; extern struct target_ops *the_target; @@ -542,6 +546,10 @@ int kill_inferior (int); the_target->process_qsupported (features, count); \ } while (0) +#define target_supports_catch_syscall() \ + (the_target->supports_catch_syscall ? \ + (*the_target->supports_catch_syscall) () : 0) + #define target_supports_tracepoints() \ (the_target->supports_tracepoints \ ? (*the_target->supports_tracepoints) () : 0) diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h index 7bdeb314a663..73888e5f3364 100644 --- a/gdb/linux-nat.h +++ b/gdb/linux-nat.h @@ -88,7 +88,7 @@ struct lwp_info or to a local variable in lin_lwp_wait. */ struct target_waitstatus waitstatus; - /* Signal wether we are in a SYSCALL_ENTRY or + /* Signal whether we are in a SYSCALL_ENTRY or in a SYSCALL_RETURN event. Values: - TARGET_WAITKIND_SYSCALL_ENTRY diff --git a/gdb/remote.c b/gdb/remote.c index 528d863762cc..e825d27d8405 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -1392,6 +1392,7 @@ enum { PACKET_qSupported, PACKET_qTStatus, PACKET_QPassSignals, + PACKET_QCatchSyscalls, PACKET_QProgramSignals, PACKET_qCRC, PACKET_qSearch_memory, @@ -1987,6 +1988,93 @@ remote_pass_signals (struct target_ops *self, } } +/* If 'QCatchSyscalls' is supported, tell the remote stub + to report syscalls to GDB. */ + +static int +remote_set_syscall_catchpoint (struct target_ops *self, + int pid, int needed, int any_count, + int table_size, int *table) +{ + char *catch_packet; + enum packet_result result; + int n_sysno = 0; + + if (packet_support (PACKET_QCatchSyscalls) == PACKET_DISABLE) + { + /* Not supported. */ + return 1; + } + + if (needed && !any_count) + { + int i; + + /* Count how many syscalls are to be caught (table[sysno] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i] != 0) + n_sysno++; + } + } + + if (remote_debug) + { + fprintf_unfiltered (gdb_stdlog, + "remote_set_syscall_catchpoint " + "pid %d needed %d any_count %d n_sysno %d\n", + pid, needed, any_count, n_sysno); + } + + if (needed) + { + /* Prepare a packet with the sysno list, assuming max 8+1 + characters for a sysno. If the resulting packet size is too + big, fallback on the non-selective packet. */ + const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1; + + catch_packet = xmalloc (maxpktsz); + strcpy (catch_packet, "QCatchSyscalls:1"); + if (!any_count) + { + int i; + char *p; + + p = catch_packet; + p += strlen (p); + + /* Add in catch_packet each syscall to be caught (table[i] != 0). */ + for (i = 0; i < table_size; i++) + { + if (table[i] != 0) + p += xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i); + } + } + if (strlen (catch_packet) > get_remote_packet_size ()) + { + /* catch_packet too big. Fallback to less efficient + non selective mode, with GDB doing the filtering. */ + catch_packet[sizeof ("QCatchSyscalls:1") - 1] = 0; + } + } + else + catch_packet = xstrdup ("QCatchSyscalls:0"); + + { + struct cleanup *old_chain = make_cleanup (xfree, catch_packet); + struct remote_state *rs = get_remote_state (); + + putpkt (catch_packet); + getpkt (&rs->buf, &rs->buf_size, 0); + result = packet_ok (rs->buf, &remote_protocol_packets[PACKET_QCatchSyscalls]); + do_cleanups (old_chain); + if (result == PACKET_OK) + return 0; + else + return -1; + } +} + /* If 'QProgramSignals' is supported, tell the remote stub what signals it should pass through to the inferior when detaching. */ @@ -4467,6 +4555,8 @@ static const struct protocol_feature remote_protocol_features[] = { PACKET_qXfer_traceframe_info }, { "QPassSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QPassSignals }, + { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet, + PACKET_QCatchSyscalls }, { "QProgramSignals", PACKET_DISABLE, remote_supported_packet, PACKET_QProgramSignals }, { "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet, @@ -6371,6 +6461,22 @@ Packet: '%s'\n"), if (strprefix (p, p1, "thread")) event->ptid = read_ptid (++p1, &p); + else if (strprefix (p, p1, "syscall_entry")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } + else if (strprefix (p, p1, "syscall_return")) + { + ULONGEST sysno; + + event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; + p = unpack_varlen_hex (++p1, &sysno); + event->ws.value.syscall_number = (int) sysno; + } else if (strprefix (p, p1, "watch") || strprefix (p, p1, "rwatch") || strprefix (p, p1, "awatch")) @@ -12976,6 +13082,7 @@ Specify the serial device it is connected to\n\ remote_ops.to_load = remote_load; remote_ops.to_mourn_inferior = remote_mourn; remote_ops.to_pass_signals = remote_pass_signals; + remote_ops.to_set_syscall_catchpoint = remote_set_syscall_catchpoint; remote_ops.to_program_signals = remote_program_signals; remote_ops.to_thread_alive = remote_thread_alive; remote_ops.to_thread_name = remote_thread_name; @@ -13542,6 +13649,9 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL, add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals], "QPassSignals", "pass-signals", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QCatchSyscalls], + "QCatchSyscalls", "catch-syscalls", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals], "QProgramSignals", "program-signals", 0); diff --git a/gdb/testsuite/gdb.base/catch-syscall.c b/gdb/testsuite/gdb.base/catch-syscall.c index e65d4a4906c3..98222fa78819 100644 --- a/gdb/testsuite/gdb.base/catch-syscall.c +++ b/gdb/testsuite/gdb.base/catch-syscall.c @@ -31,13 +31,20 @@ int write_syscall = SYS_write; int unknown_syscall = 123456789; int exit_group_syscall = SYS_exit_group; +/* Set by the test when it wants execve. */ +int do_execve = 0; + int -main (void) +main (int argc, char *const argv[]) { int fd[2]; char buf1[2] = "a"; char buf2[2]; + /* Test a simple self-exec, but only on request. */ + if (do_execve) + execv (*argv, argv); + /* A close() with a wrong argument. We are only interested in the syscall. */ close (-1); diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp index 26fb6a513a42..70a75553e945 100644 --- a/gdb/testsuite/gdb.base/catch-syscall.exp +++ b/gdb/testsuite/gdb.base/catch-syscall.exp @@ -19,7 +19,7 @@ # It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com> # on September/2008. -if { [is_remote target] || ![isnative] } then { +if { ![isnative] } then { continue } @@ -322,6 +322,32 @@ proc test_catch_syscall_mid_vfork {} { } } +proc test_catch_syscall_execve {} { + global gdb_prompt decimal + + with_test_prefix "execve" { + + # Tell the test program we want an execve. + gdb_test_no_output "set do_execve = 1" + + # Check for entry/return across the execve, making sure that the + # syscall_state isn't lost when turning into a new process. + insert_catch_syscall_with_arg "execve" + check_continue "execve" + + # Remotes that don't track exec may report the raw SIGTRAP for it. + # If we use stepi now, we'll get a consistent trap for all targets. + gdb_test "stepi" ".*" "step after execve" + + # Continue to main so extended-remote can read files as needed. + # (Otherwise that "Reading" output confuses gdb_continue_to_end.) + gdb_continue "main" + + # Now can we finish? + check_for_program_end + } +} + proc test_catch_syscall_fail_nodatadir {} { with_test_prefix "fail no datadir" { # Sanitizing. @@ -392,6 +418,9 @@ proc do_syscall_tests {} { # Testing the 'catch syscall' command starting mid-vfork. if [runto_main] then { test_catch_syscall_mid_vfork } + # Testing that 'catch syscall' entry/return tracks across execve. + if [runto_main] then { test_catch_syscall_execve } + # Testing if the 'catch syscall' command works when switching to # different architectures on-the-fly (PR gdb/10737). if [runto_main] then { test_catch_syscall_multi_arch } -- 2.5.0 ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-01-09 3:09 ` [PATCH v4] " Josh Stone @ 2016-01-09 7:37 ` Eli Zaretskii 2016-01-11 17:44 ` Philippe Waroquiers ` (2 subsequent siblings) 3 siblings, 0 replies; 49+ messages in thread From: Eli Zaretskii @ 2016-01-09 7:37 UTC (permalink / raw) To: Josh Stone Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42, scox > From: Josh Stone <jistone@redhat.com> > Cc: philippe.waroquiers@skynet.be, sergiodj@redhat.com, palves@redhat.com, > eliz@gnu.org, xdje42@gmail.com, scox@redhat.com, > Josh Stone <jistone@redhat.com> > Date: Fri, 8 Jan 2016 19:09:14 -0800 > > This adds a new QCatchSyscalls packet to enable 'catch syscall', and new > stop reasons "syscall_entry" and "syscall_return" for those events. It > is currently only supported on Linux x86 and x86_64. > > gdb/ChangeLog: > > 2016-01-08 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * NEWS (Changes since GDB 7.10): Mention QCatchSyscalls and the > syscall_entry and syscall_return stop reasons. Mention GDB > support for remote catch syscall. > * remote.c (PACKET_QCatchSyscalls): New enum. > (remote_set_syscall_catchpoint): New function. > (remote_protocol_features): New element for QCatchSyscalls. > (remote_parse_stop_reply): Parse syscall_entry/return stops. > (init_remote_ops): Install remote_set_syscall_catchpoint. > (_initialize_remote): Config QCatchSyscalls. > * linux-nat.h (struct lwp_info) <syscall_state>: Comment typo. > > gdb/doc/ChangeLog: > > 2016-01-08 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > (Stop Reply Packets): List the syscall entry and return stop reasons. > (General Query Packets): Describe QCatchSyscalls, and add it to the > table and detailed list of stub features. OK for the documentation parts. Thanks. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-01-09 3:09 ` [PATCH v4] " Josh Stone 2016-01-09 7:37 ` Eli Zaretskii @ 2016-01-11 17:44 ` Philippe Waroquiers 2016-01-12 12:05 ` Pedro Alves 2016-05-29 16:47 ` [doc] NEWS: QCatchSyscalls: simplify Jan Kratochvil 3 siblings, 0 replies; 49+ messages in thread From: Philippe Waroquiers @ 2016-01-11 17:44 UTC (permalink / raw) To: Josh Stone; +Cc: gdb-patches, sergiodj, palves, eliz, xdje42, scox On Fri, 2016-01-08 at 19:09 -0800, Josh Stone wrote: > This adds a new QCatchSyscalls packet to enable 'catch syscall', and new > stop reasons "syscall_entry" and "syscall_return" for those events. It > is currently only supported on Linux x86 and x86_64. I did some basic tests of the v4 patch on x86, and also with a (patched) valgrind gdbserver. No problem encountered. So, if/when this patch is committed in gdb, I will also commit the catch syscall support in the valgrind gdbserver (which will provide catch syscall on all valgrind architectures i.e. x86/amd64/ppc32/ppc64/mips32/mips64/tilegx/s390x/arm/arm64). So, awaiting commit ... Philippe ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-01-09 3:09 ` [PATCH v4] " Josh Stone 2016-01-09 7:37 ` Eli Zaretskii 2016-01-11 17:44 ` Philippe Waroquiers @ 2016-01-12 12:05 ` Pedro Alves 2016-01-12 19:10 ` Josh Stone 2016-05-29 16:47 ` [doc] NEWS: QCatchSyscalls: simplify Jan Kratochvil 3 siblings, 1 reply; 49+ messages in thread From: Pedro Alves @ 2016-01-12 12:05 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42, scox On 01/09/2016 03:09 AM, Josh Stone wrote: > > 2016-01-08 Josh Stone <jistone@redhat.com> > Philippe Waroquiers <philippe.waroquiers@skynet.be> > > * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. > (Stop Reply Packets): List the syscall entry and return stop reasons. > (General Query Packets): Describe QCatchSyscalls, and add it to the > table and detailed list of stub features. > "table of detailed", I think. > @@ -648,6 +658,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) > event_thr->last_resume_kind = resume_continue; > event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; > > + /* Update syscall state in the new lwp, effectively mid-syscall too. > + The client really should send a new list to catch, in case the > + architecture changed, but for ANY_SYSCALL it doesn't matter. */ > + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; > + proc->syscalls_to_catch = syscalls_to_catch; The tone of this comment sounds to me as if the client should always send a new list, just in case, but for some odd reason it sometimes doesn't. I think we want to convey the opposite, like: /* Update syscall state in the new lwp, effectively mid-syscall too. */ event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; /* Restore the list to catch. Don't rely on the client, which is free to avoid sending a new list when the architecture doesn't change. Also, for ANY_SYSCALL, the architecture doesn't really matter. */ proc->syscalls_to_catch = syscalls_to_catch; > > static int > +linux_supports_catch_syscall (void) > +{ > + return (the_low_target.get_syscall_trapinfo != NULL > + && linux_supports_tracesysgood()); Space: "linux_supports_tracesysgood ()" > > +proc test_catch_syscall_execve {} { > + global gdb_prompt decimal > + > + with_test_prefix "execve" { > + > + # Tell the test program we want an execve. > + gdb_test_no_output "set do_execve = 1" > + > + # Check for entry/return across the execve, making sure that the > + # syscall_state isn't lost when turning into a new process. > + insert_catch_syscall_with_arg "execve" > + check_continue "execve" > + > + # Remotes that don't track exec may report the raw SIGTRAP for it. > + # If we use stepi now, we'll get a consistent trap for all targets. > + gdb_test "stepi" ".*" "step after execve" Why is it important to do this raw SIGTRAP handling? What happens if you don't do this? Won't those targets already FAIL the check_continue tests? Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-01-12 12:05 ` Pedro Alves @ 2016-01-12 19:10 ` Josh Stone 2016-01-12 19:22 ` Pedro Alves 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2016-01-12 19:10 UTC (permalink / raw) To: Pedro Alves, gdb-patches Cc: philippe.waroquiers, sergiodj, eliz, xdje42, scox On 01/12/2016 04:05 AM, Pedro Alves wrote: > On 01/09/2016 03:09 AM, Josh Stone wrote: > >> >> 2016-01-08 Josh Stone <jistone@redhat.com> >> Philippe Waroquiers <philippe.waroquiers@skynet.be> >> >> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. >> (Stop Reply Packets): List the syscall entry and return stop reasons. >> (General Query Packets): Describe QCatchSyscalls, and add it to the >> table and detailed list of stub features. >> > > "table of detailed", I think. I'm referring to two hunks: - the table: Feature Name / Value Required / Default / Probe Allowed - the list below it, "currently defined stub features, in more detail" Maybe I just need another article, "to the table and the detailed list" >> @@ -648,6 +658,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) >> event_thr->last_resume_kind = resume_continue; >> event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; >> >> + /* Update syscall state in the new lwp, effectively mid-syscall too. >> + The client really should send a new list to catch, in case the >> + architecture changed, but for ANY_SYSCALL it doesn't matter. */ >> + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; >> + proc->syscalls_to_catch = syscalls_to_catch; > > The tone of this comment sounds to me as if the client should always > send a new list, just in case, but for some odd reason it sometimes doesn't. > > I think we want to convey the opposite, like: > > /* Update syscall state in the new lwp, effectively mid-syscall too. */ > event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; > > /* Restore the list to catch. Don't rely on the client, which is free > to avoid sending a new list when the architecture doesn't change. > Also, for ANY_SYSCALL, the architecture doesn't really matter. */ > proc->syscalls_to_catch = syscalls_to_catch; Sure, I'll take your rewrite verbatim, if you don't mind. >> static int >> +linux_supports_catch_syscall (void) >> +{ >> + return (the_low_target.get_syscall_trapinfo != NULL >> + && linux_supports_tracesysgood()); > > Space: "linux_supports_tracesysgood ()" OK >> +proc test_catch_syscall_execve {} { >> + global gdb_prompt decimal >> + >> + with_test_prefix "execve" { >> + >> + # Tell the test program we want an execve. >> + gdb_test_no_output "set do_execve = 1" >> + >> + # Check for entry/return across the execve, making sure that the >> + # syscall_state isn't lost when turning into a new process. >> + insert_catch_syscall_with_arg "execve" >> + check_continue "execve" >> + >> + # Remotes that don't track exec may report the raw SIGTRAP for it. >> + # If we use stepi now, we'll get a consistent trap for all targets. >> + gdb_test "stepi" ".*" "step after execve" > > Why is it important to do this raw SIGTRAP handling? What happens if you don't > do this? Won't those targets already FAIL the check_continue tests? Just in case, the context from Linux man ptrace: If the PTRACE_O_TRACEEXEC option is not in effect for the execing tracee, and if the tracee was PTRACE_ATTACHed rather that PTRACE_SEIZEd, the kernel delivers an extra SIGTRAP to the tracee after execve(2) returns. This is an ordinary signal (similar to one which can be generated by kill -TRAP), not a special kind of ptrace-stop. Since that's a signal-stop *after* execve returns, the check_continue will have succeeded already. The check_continue is really the only bit I care about for this test anyway. The rest is just trying to finish the target process cleanly. I was having trouble matching consistent output since plain remote was getting that SIGTRAP, but extended-remote would use exec events and not report anything extra. Adding the stepi made both stop the same way. This is moot now, since plain remotes are now tracking exec events too. I developed this test just before that went in last month. :) I just tried with that stepi commented out, and the test still passes on local, remote, and extended-remote, so I'll remove it. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-01-12 19:10 ` Josh Stone @ 2016-01-12 19:22 ` Pedro Alves 2016-01-12 20:01 ` Josh Stone 0 siblings, 1 reply; 49+ messages in thread From: Pedro Alves @ 2016-01-12 19:22 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42, scox On 01/12/2016 07:10 PM, Josh Stone wrote: > On 01/12/2016 04:05 AM, Pedro Alves wrote: >> On 01/09/2016 03:09 AM, Josh Stone wrote: >> >>> >>> 2016-01-08 Josh Stone <jistone@redhat.com> >>> Philippe Waroquiers <philippe.waroquiers@skynet.be> >>> >>> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. >>> (Stop Reply Packets): List the syscall entry and return stop reasons. >>> (General Query Packets): Describe QCatchSyscalls, and add it to the >>> table and detailed list of stub features. >>> >> >> "table of detailed", I think. > > I'm referring to two hunks: > - the table: Feature Name / Value Required / Default / Probe Allowed > - the list below it, "currently defined stub features, in more detail" > > Maybe I just need another article, "to the table and the detailed list" Ah. Yes, that way I think wouldn't have been confused. > >>> @@ -648,6 +658,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) >>> event_thr->last_resume_kind = resume_continue; >>> event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; >>> >>> + /* Update syscall state in the new lwp, effectively mid-syscall too. >>> + The client really should send a new list to catch, in case the >>> + architecture changed, but for ANY_SYSCALL it doesn't matter. */ >>> + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; >>> + proc->syscalls_to_catch = syscalls_to_catch; >> >> The tone of this comment sounds to me as if the client should always >> send a new list, just in case, but for some odd reason it sometimes doesn't. >> >> I think we want to convey the opposite, like: >> >> /* Update syscall state in the new lwp, effectively mid-syscall too. */ >> event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; >> >> /* Restore the list to catch. Don't rely on the client, which is free >> to avoid sending a new list when the architecture doesn't change. >> Also, for ANY_SYSCALL, the architecture doesn't really matter. */ >> proc->syscalls_to_catch = syscalls_to_catch; > > Sure, I'll take your rewrite verbatim, if you don't mind. Certainly don't mind. > >>> static int >>> +linux_supports_catch_syscall (void) >>> +{ >>> + return (the_low_target.get_syscall_trapinfo != NULL >>> + && linux_supports_tracesysgood()); >> >> Space: "linux_supports_tracesysgood ()" > > OK > >>> +proc test_catch_syscall_execve {} { >>> + global gdb_prompt decimal >>> + >>> + with_test_prefix "execve" { >>> + >>> + # Tell the test program we want an execve. >>> + gdb_test_no_output "set do_execve = 1" >>> + >>> + # Check for entry/return across the execve, making sure that the >>> + # syscall_state isn't lost when turning into a new process. >>> + insert_catch_syscall_with_arg "execve" >>> + check_continue "execve" >>> + >>> + # Remotes that don't track exec may report the raw SIGTRAP for it. >>> + # If we use stepi now, we'll get a consistent trap for all targets. >>> + gdb_test "stepi" ".*" "step after execve" >> >> Why is it important to do this raw SIGTRAP handling? What happens if you don't >> do this? Won't those targets already FAIL the check_continue tests? > > Just in case, the context from Linux man ptrace: > > If the PTRACE_O_TRACEEXEC option is not in effect for the execing > tracee, and if the tracee was PTRACE_ATTACHed rather that > PTRACE_SEIZEd, the kernel delivers an extra SIGTRAP to the tracee > after execve(2) returns. This is an ordinary signal (similar to > one which can be generated by kill -TRAP), not a special kind of > ptrace-stop. > > Since that's a signal-stop *after* execve returns, the check_continue > will have succeeded already. Still can't see how that step would help -- check_continue does two "continue"s. So one would stop at the random SIGTRAP, and FAIL, and another would lose control of the inferior, probably running to end. > > The check_continue is really the only bit I care about for this test > anyway. The rest is just trying to finish the target process cleanly. > I was having trouble matching consistent output since plain remote was > getting that SIGTRAP, but extended-remote would use exec events and not > report anything extra. Adding the stepi made both stop the same way. > > This is moot now, since plain remotes are now tracking exec events too. > I developed this test just before that went in last month. :) > I just tried with that stepi commented out, and the test still passes on > local, remote, and extended-remote, so I'll remove it. OK, yes, let's drop it then. :-) Patch is OK with these changes, BTW. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-01-12 19:22 ` Pedro Alves @ 2016-01-12 20:01 ` Josh Stone 2016-03-29 14:27 ` Yao Qi 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2016-01-12 20:01 UTC (permalink / raw) To: Pedro Alves, gdb-patches Cc: philippe.waroquiers, sergiodj, eliz, xdje42, scox On 01/12/2016 11:22 AM, Pedro Alves wrote: > On 01/12/2016 07:10 PM, Josh Stone wrote: >> On 01/12/2016 04:05 AM, Pedro Alves wrote: >>> On 01/09/2016 03:09 AM, Josh Stone wrote: >>> >>>> >>>> 2016-01-08 Josh Stone <jistone@redhat.com> >>>> Philippe Waroquiers <philippe.waroquiers@skynet.be> >>>> >>>> * gdb.texinfo (Remote Configuration): List the QCatchSyscalls packet. >>>> (Stop Reply Packets): List the syscall entry and return stop reasons. >>>> (General Query Packets): Describe QCatchSyscalls, and add it to the >>>> table and detailed list of stub features. >>>> >>> >>> "table of detailed", I think. >> >> I'm referring to two hunks: >> - the table: Feature Name / Value Required / Default / Probe Allowed >> - the list below it, "currently defined stub features, in more detail" >> >> Maybe I just need another article, "to the table and the detailed list" > > Ah. Yes, that way I think wouldn't have been confused. > >> >>>> @@ -648,6 +658,12 @@ handle_extended_wait (struct lwp_info **orig_event_lwp, int wstat) >>>> event_thr->last_resume_kind = resume_continue; >>>> event_thr->last_status.kind = TARGET_WAITKIND_IGNORE; >>>> >>>> + /* Update syscall state in the new lwp, effectively mid-syscall too. >>>> + The client really should send a new list to catch, in case the >>>> + architecture changed, but for ANY_SYSCALL it doesn't matter. */ >>>> + event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; >>>> + proc->syscalls_to_catch = syscalls_to_catch; >>> >>> The tone of this comment sounds to me as if the client should always >>> send a new list, just in case, but for some odd reason it sometimes doesn't. >>> >>> I think we want to convey the opposite, like: >>> >>> /* Update syscall state in the new lwp, effectively mid-syscall too. */ >>> event_lwp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; >>> >>> /* Restore the list to catch. Don't rely on the client, which is free >>> to avoid sending a new list when the architecture doesn't change. >>> Also, for ANY_SYSCALL, the architecture doesn't really matter. */ >>> proc->syscalls_to_catch = syscalls_to_catch; >> >> Sure, I'll take your rewrite verbatim, if you don't mind. > > Certainly don't mind. > > >> >>>> static int >>>> +linux_supports_catch_syscall (void) >>>> +{ >>>> + return (the_low_target.get_syscall_trapinfo != NULL >>>> + && linux_supports_tracesysgood()); >>> >>> Space: "linux_supports_tracesysgood ()" >> >> OK >> >>>> +proc test_catch_syscall_execve {} { >>>> + global gdb_prompt decimal >>>> + >>>> + with_test_prefix "execve" { >>>> + >>>> + # Tell the test program we want an execve. >>>> + gdb_test_no_output "set do_execve = 1" >>>> + >>>> + # Check for entry/return across the execve, making sure that the >>>> + # syscall_state isn't lost when turning into a new process. >>>> + insert_catch_syscall_with_arg "execve" >>>> + check_continue "execve" >>>> + >>>> + # Remotes that don't track exec may report the raw SIGTRAP for it. >>>> + # If we use stepi now, we'll get a consistent trap for all targets. >>>> + gdb_test "stepi" ".*" "step after execve" >>> >>> Why is it important to do this raw SIGTRAP handling? What happens if you don't >>> do this? Won't those targets already FAIL the check_continue tests? >> >> Just in case, the context from Linux man ptrace: >> >> If the PTRACE_O_TRACEEXEC option is not in effect for the execing >> tracee, and if the tracee was PTRACE_ATTACHed rather that >> PTRACE_SEIZEd, the kernel delivers an extra SIGTRAP to the tracee >> after execve(2) returns. This is an ordinary signal (similar to >> one which can be generated by kill -TRAP), not a special kind of >> ptrace-stop. >> >> Since that's a signal-stop *after* execve returns, the check_continue >> will have succeeded already. > > Still can't see how that step would help -- check_continue does two > "continue"s. So one would stop at the random SIGTRAP, and FAIL, > and another would lose control of the inferior, probably running > to end. The first continue hits syscall_entry:execve. The second continue hits syscall_return:execve. The second is the bug I fixed -- if it forgot syscall_state across exec, the return was reported like another entry. After that, there might be an impending SIGTRAP stop, depending on whether PTRACE_O_TRACEEXEC is active. The step was a way of just effecting a SIGTRAP for everyone, so it was easy to match. >> The check_continue is really the only bit I care about for this test >> anyway. The rest is just trying to finish the target process cleanly. >> I was having trouble matching consistent output since plain remote was >> getting that SIGTRAP, but extended-remote would use exec events and not >> report anything extra. Adding the stepi made both stop the same way. >> >> This is moot now, since plain remotes are now tracking exec events too. >> I developed this test just before that went in last month. :) >> I just tried with that stepi commented out, and the test still passes on >> local, remote, and extended-remote, so I'll remove it. > > OK, yes, let's drop it then. :-) > > Patch is OK with these changes, BTW. Great! I'll make these final tweaks and push it out. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-01-12 20:01 ` Josh Stone @ 2016-03-29 14:27 ` Yao Qi 2016-03-29 18:12 ` Josh Stone 0 siblings, 1 reply; 49+ messages in thread From: Yao Qi @ 2016-03-29 14:27 UTC (permalink / raw) To: Josh Stone Cc: Pedro Alves, gdb-patches, philippe.waroquiers, sergiodj, eliz, xdje42, scox Josh Stone <jistone@redhat.com> writes: > Great! I'll make these final tweaks and push it out. Hi Josh, This commit causes some fails on s39x, and ppc, as shown in buildbot. I saw them in aarch64 test as well. Could you take a look? https://sourceware.org/ml/gdb-testers/2016-q1/msg01544.html https://sourceware.org/ml/gdb-testers/2016-q1/msg01601.html -- Yao (齐尧) ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-03-29 14:27 ` Yao Qi @ 2016-03-29 18:12 ` Josh Stone 2016-03-29 23:49 ` Josh Stone 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2016-03-29 18:12 UTC (permalink / raw) To: Yao Qi Cc: Pedro Alves, gdb-patches, philippe.waroquiers, sergiodj, eliz, xdje42, scox On 03/29/2016 07:26 AM, Yao Qi wrote: > Hi Josh, > This commit causes some fails on s39x, and ppc, as shown in buildbot. I > saw them in aarch64 test as well. Could you take a look? > > https://sourceware.org/ml/gdb-testers/2016-q1/msg01544.html > https://sourceware.org/ml/gdb-testers/2016-q1/msg01601.html Hmm. That new test is meant to make sure that the syscall entry/return state is not lost across an execve. In the failure I knew, the execve return was interpreted as an additional syscall entry. But in the cases you've shown, it didn't catch syscall return from execve at all! I will investigate more... Josh ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-03-29 18:12 ` Josh Stone @ 2016-03-29 23:49 ` Josh Stone 2016-03-30 12:23 ` Yao Qi 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2016-03-29 23:49 UTC (permalink / raw) To: Yao Qi Cc: Pedro Alves, gdb-patches, philippe.waroquiers, sergiodj, eliz, xdje42, scox On 03/29/2016 11:12 AM, Josh Stone wrote: > On 03/29/2016 07:26 AM, Yao Qi wrote: >> Hi Josh, >> This commit causes some fails on s39x, and ppc, as shown in buildbot. I >> saw them in aarch64 test as well. Could you take a look? >> >> https://sourceware.org/ml/gdb-testers/2016-q1/msg01544.html >> https://sourceware.org/ml/gdb-testers/2016-q1/msg01601.html > > Hmm. That new test is meant to make sure that the syscall entry/return > state is not lost across an execve. In the failure I knew, the execve > return was interpreted as an additional syscall entry. But in the cases > you've shown, it didn't catch syscall return from execve at all! > > I will investigate more... So, it seems those architectures don't preserve their original syscall numbers across an execve. $ gdb -ex 'catch syscall execve' -ex 'run' -ex 'catch syscall' \ -ex 'continue' --args sh -c /bin/true PPC64 and Aarch64 both read their syscall numbers from registers, and here they both get 0 ("restart_syscall" and "io_setup" respectively). S390X tries to decode it from the SVC instruction at PC-2, which will definitely fail after an execve -- gdb reports syscall -1. So when the catchpoint is only for execve, they continue past this one since the number doesn't look like execve. The good news is that all three do call it a syscall *return*, which was the main point of this particular test. If there's no objection, I can try to update the test to work more like my command above, matching any syscall at all on the return side of execve. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-03-29 23:49 ` Josh Stone @ 2016-03-30 12:23 ` Yao Qi 2016-03-31 1:10 ` Josh Stone 0 siblings, 1 reply; 49+ messages in thread From: Yao Qi @ 2016-03-30 12:23 UTC (permalink / raw) To: Josh Stone Cc: Yao Qi, Pedro Alves, gdb-patches, philippe.waroquiers, sergiodj, eliz, xdje42, scox Josh Stone <jistone@redhat.com> writes: Hi Josh, Thanks for the looking into this... > So, it seems those architectures don't preserve their original syscall > numbers across an execve. > > $ gdb -ex 'catch syscall execve' -ex 'run' -ex 'catch syscall' \ > -ex 'continue' --args sh -c /bin/true > > PPC64 and Aarch64 both read their syscall numbers from registers, and > here they both get 0 ("restart_syscall" and "io_setup" respectively). > S390X tries to decode it from the SVC instruction at PC-2, which will > definitely fail after an execve -- gdb reports syscall -1. I think it reveals a bug on getting syscall number. If the register having syscall number isn't preserved across the syscall, GDB should read syscall number somewhere else. > > So when the catchpoint is only for execve, they continue past this one > since the number doesn't look like execve. > > The good news is that all three do call it a syscall *return*, which was > the main point of this particular test. If there's no objection, I can > try to update the test to work more like my command above, matching any > syscall at all on the return side of execve. -- Yao (齐尧) ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-03-30 12:23 ` Yao Qi @ 2016-03-31 1:10 ` Josh Stone 2016-04-01 13:05 ` Yao Qi 0 siblings, 1 reply; 49+ messages in thread From: Josh Stone @ 2016-03-31 1:10 UTC (permalink / raw) To: Yao Qi Cc: Pedro Alves, gdb-patches, philippe.waroquiers, sergiodj, eliz, xdje42, scox On 03/30/2016 05:23 AM, Yao Qi wrote: > Josh Stone <jistone@redhat.com> writes: > > Hi Josh, > Thanks for the looking into this... > >> So, it seems those architectures don't preserve their original syscall >> numbers across an execve. >> >> $ gdb -ex 'catch syscall execve' -ex 'run' -ex 'catch syscall' \ >> -ex 'continue' --args sh -c /bin/true >> >> PPC64 and Aarch64 both read their syscall numbers from registers, and >> here they both get 0 ("restart_syscall" and "io_setup" respectively). >> S390X tries to decode it from the SVC instruction at PC-2, which will >> definitely fail after an execve -- gdb reports syscall -1. > > I think it reveals a bug on getting syscall number. If the register > having syscall number isn't preserved across the syscall, GDB should > read syscall number somewhere else. Well, sure, but I have no idea where that somewhere else could be. Note these architectures do work for other syscall returns. It's just that execve is a bit special by switching the whole process out. I suppose we could try to save the number on syscall entry, and just report that again when it returns. But it's not 100% sure that we'll see every entry first. For instance, one could 'catch execve' first, which will continue until PTRACE_EVENT_EXEC mid-syscall, then turn on 'catch syscall' and see what returns. (This is similar to what test_catch_syscall_mid_vfork checks.) BTW, even x86 is a little suspect if you cross compat modes. The number is preserved in orig_rax, but if you exec'ed from a 64-bit process to 32-bit, that number would still be the 64-bit NR_execve. It happens to still apparently work in that case because gdb isn't reloading its syscall mapping. But continue and it next gets: Catchpoint 2 (call to syscall recvfrom), 0xf7ff29b9 in brk () from /lib/ld-linux.so.2 i.e. 32-bit syscall brk is incorrectly called recvfrom. >> So when the catchpoint is only for execve, they continue past this one >> since the number doesn't look like execve. >> >> The good news is that all three do call it a syscall *return*, which was >> the main point of this particular test. If there's no objection, I can >> try to update the test to work more like my command above, matching any >> syscall at all on the return side of execve. > ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-03-31 1:10 ` Josh Stone @ 2016-04-01 13:05 ` Yao Qi 2016-04-01 16:38 ` Josh Stone 0 siblings, 1 reply; 49+ messages in thread From: Yao Qi @ 2016-04-01 13:05 UTC (permalink / raw) To: Josh Stone Cc: Yao Qi, Pedro Alves, gdb-patches, philippe.waroquiers, sergiodj, eliz, xdje42, scox Josh Stone <jistone@redhat.com> writes: > Well, sure, but I have no idea where that somewhere else could be. > > Note these architectures do work for other syscall returns. It's just > that execve is a bit special by switching the whole process out. I talked with a kernel people, looks GDB can't fetch the syscall number on execve exit. > > I suppose we could try to save the number on syscall entry, and just > report that again when it returns. But it's not 100% sure that we'll Yes, that is what I am thinking too. > see every entry first. For instance, one could 'catch execve' first, > which will continue until PTRACE_EVENT_EXEC mid-syscall, then turn on > 'catch syscall' and see what returns. > (This is similar to what test_catch_syscall_mid_vfork checks.) Yeah, we can't guarantee syscall enter comes into first. I doubt 'lp->syscall_state' is confused in this case too, no? -- Yao (齐尧) ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v4] Implement 'catch syscall' for gdbserver 2016-04-01 13:05 ` Yao Qi @ 2016-04-01 16:38 ` Josh Stone 0 siblings, 0 replies; 49+ messages in thread From: Josh Stone @ 2016-04-01 16:38 UTC (permalink / raw) To: Yao Qi Cc: Pedro Alves, gdb-patches, philippe.waroquiers, sergiodj, eliz, xdje42, scox On 04/01/2016 06:05 AM, Yao Qi wrote: > Josh Stone <jistone@redhat.com> writes: > >> Well, sure, but I have no idea where that somewhere else could be. >> >> Note these architectures do work for other syscall returns. It's just >> that execve is a bit special by switching the whole process out. > > I talked with a kernel people, looks GDB can't fetch the syscall number > on execve exit. > >> >> I suppose we could try to save the number on syscall entry, and just >> report that again when it returns. But it's not 100% sure that we'll > > Yes, that is what I am thinking too. I guess then it's a question whether we try to save this as much as possible, or only for cases that look like execve (on entry). >> see every entry first. For instance, one could 'catch execve' first, >> which will continue until PTRACE_EVENT_EXEC mid-syscall, then turn on >> 'catch syscall' and see what returns. >> (This is similar to what test_catch_syscall_mid_vfork checks.) > > Yeah, we can't guarantee syscall enter comes into first. I doubt > 'lp->syscall_state' is confused in this case too, no? This is one of the things I fixed. We know that events like PTRACE_EVENT_EXEC are mid-syscall, even if we didn't see the entry, so a syscall event that follows must be a return. And other ptrace stops are never mid-syscall, so a syscall that follows those must be an entry. This is set in linux_handle_extended_wait and wait_lwp. ^ permalink raw reply [flat|nested] 49+ messages in thread
* [doc] NEWS: QCatchSyscalls: simplify 2016-01-09 3:09 ` [PATCH v4] " Josh Stone ` (2 preceding siblings ...) 2016-01-12 12:05 ` Pedro Alves @ 2016-05-29 16:47 ` Jan Kratochvil 2016-05-29 17:29 ` Eli Zaretskii 3 siblings, 1 reply; 49+ messages in thread From: Jan Kratochvil @ 2016-05-29 16:47 UTC (permalink / raw) To: Eli Zaretskii Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, eliz, xdje42, scox, Josh Stone [-- Attachment #1: Type: text/plain, Size: 931 bytes --] On Sat, 09 Jan 2016 04:09:14 +0100, Josh Stone wrote: > --- a/gdb/NEWS > +++ b/gdb/NEWS > @@ -120,6 +120,21 @@ N stop reply > threads are stopped). The remote stub reports support for this stop > reply to GDB's qSupported query. > > +QCatchSyscalls:1 [;SYSNO]... > +QCatchSyscalls:0 > + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") > + catching syscalls from the inferior process. > + > +syscall_entry stop reason > + Indicates that a syscall was just called. > + > +syscall_return stop reason > + Indicates that a syscall just returned. > + > +QCatchSyscalls:1 in qSupported > + The qSupported packet may now include QCatchSyscalls:1 in the reply > + to indicate support for catching syscalls. > + > * Extended-remote exec events > > ** GDB now has support for exec events on extended-remote Linux targets. I find this format non-standard/confusing. OK to check-in this update? Thanks, Jan [-- Attachment #2: 1 --] [-- Type: text/plain, Size: 1220 bytes --] gdb/ChangeLog 2016-05-29 Jan Kratochvil <jan.kratochvil@redhat.com> * NEWS (QCatchSyscalls): Remove the parameter. Include ... (QCatchSyscalls:1 in qSupported) ... this separate entry which got deleted. diff --git a/gdb/NEWS b/gdb/NEWS index f874f03..dce79a2 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -250,10 +250,9 @@ N stop reply threads are stopped). The remote stub reports support for this stop reply to GDB's qSupported query. -QCatchSyscalls:1 [;SYSNO]... -QCatchSyscalls:0 - Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") - catching syscalls from the inferior process. +QCatchSyscalls + Enables/disables catching syscalls from the inferior process. + The remote stub reports support for this packet to GDB's qSupported query. syscall_entry stop reason Indicates that a syscall was just called. @@ -261,10 +260,6 @@ syscall_entry stop reason syscall_return stop reason Indicates that a syscall just returned. -QCatchSyscalls:1 in qSupported - The qSupported packet may now include QCatchSyscalls:1 in the reply - to indicate support for catching syscalls. - * Extended-remote exec events ** GDB now has support for exec events on extended-remote Linux targets. ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [doc] NEWS: QCatchSyscalls: simplify 2016-05-29 16:47 ` [doc] NEWS: QCatchSyscalls: simplify Jan Kratochvil @ 2016-05-29 17:29 ` Eli Zaretskii 2016-05-29 17:50 ` Jan Kratochvil 0 siblings, 1 reply; 49+ messages in thread From: Eli Zaretskii @ 2016-05-29 17:29 UTC (permalink / raw) To: Jan Kratochvil Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42, scox, jistone > Date: Sun, 29 May 2016 18:47:45 +0200 > From: Jan Kratochvil <jan.kratochvil@redhat.com> > Cc: gdb-patches@sourceware.org, philippe.waroquiers@skynet.be, > sergiodj@redhat.com, palves@redhat.com, eliz@gnu.org, xdje42@gmail.com, > scox@redhat.com, Josh Stone <jistone@redhat.com> > > On Sat, 09 Jan 2016 04:09:14 +0100, Josh Stone wrote: > > --- a/gdb/NEWS > > +++ b/gdb/NEWS > > @@ -120,6 +120,21 @@ N stop reply > > threads are stopped). The remote stub reports support for this stop > > reply to GDB's qSupported query. > > > > +QCatchSyscalls:1 [;SYSNO]... > > +QCatchSyscalls:0 > > + Enable ("QCatchSyscalls:1") or disable ("QCatchSyscalls:0") > > + catching syscalls from the inferior process. > > + > > +syscall_entry stop reason > > + Indicates that a syscall was just called. > > + > > +syscall_return stop reason > > + Indicates that a syscall just returned. > > + > > +QCatchSyscalls:1 in qSupported > > + The qSupported packet may now include QCatchSyscalls:1 in the reply > > + to indicate support for catching syscalls. > > + > > * Extended-remote exec events > > > > ** GDB now has support for exec events on extended-remote Linux targets. > > I find this format non-standard/confusing. OK to check-in this update? Is it really that bad? I generally tend to let people say things in their own words, as long as it's readable. But if you insist... ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [doc] NEWS: QCatchSyscalls: simplify 2016-05-29 17:29 ` Eli Zaretskii @ 2016-05-29 17:50 ` Jan Kratochvil 2016-05-29 18:19 ` Eli Zaretskii 0 siblings, 1 reply; 49+ messages in thread From: Jan Kratochvil @ 2016-05-29 17:50 UTC (permalink / raw) To: Eli Zaretskii Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42, scox, jistone On Sun, 29 May 2016 19:29:19 +0200, Eli Zaretskii wrote: > Is it really that bad? I generally tend to let people say things in > their own words, as long as it's readable. But if you insist... That :1 and :0 was confusing to me as it is very different from all the other remote packets announced in the NEWS file, therefore I was looking at the protocol how is this packet special. How can be ':' a part of the packet name when ':' is a parameter delimiter? And I haven't found anything special on this packet. Similarly the qSupported looked special to me and again it does not seem to be anyhow special. Even "N stop reply" announced right above uses the standard template. Besides that all IMO one of the purposes of the NEWS file is to be brief. Sure I do not mind but I was reviewing a derived downstream documentation and I just found it. Jan ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [doc] NEWS: QCatchSyscalls: simplify 2016-05-29 17:50 ` Jan Kratochvil @ 2016-05-29 18:19 ` Eli Zaretskii 2016-05-29 18:47 ` [commit] " Jan Kratochvil 0 siblings, 1 reply; 49+ messages in thread From: Eli Zaretskii @ 2016-05-29 18:19 UTC (permalink / raw) To: Jan Kratochvil Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42, scox, jistone > Date: Sun, 29 May 2016 19:50:32 +0200 > From: Jan Kratochvil <jan.kratochvil@redhat.com> > Cc: gdb-patches@sourceware.org, philippe.waroquiers@skynet.be, > sergiodj@redhat.com, palves@redhat.com, xdje42@gmail.com, > scox@redhat.com, jistone@redhat.com > > On Sun, 29 May 2016 19:29:19 +0200, Eli Zaretskii wrote: > > Is it really that bad? I generally tend to let people say things in > > their own words, as long as it's readable. But if you insist... > > That :1 and :0 was confusing to me as it is very different from all the other > remote packets announced in the NEWS file, therefore I was looking at the > protocol how is this packet special. How can be ':' a part of the packet name > when ':' is a parameter delimiter? And I haven't found anything special on > this packet. > > Similarly the qSupported looked special to me and again it does not seem to be > anyhow special. Even "N stop reply" announced right above uses the standard > template. > > Besides that all IMO one of the purposes of the NEWS file is to be brief. > > Sure I do not mind but I was reviewing a derived downstream documentation and > I just found it. If you feel strongly about this, please go ahead and commit. Thanks. ^ permalink raw reply [flat|nested] 49+ messages in thread
* [commit] [doc] NEWS: QCatchSyscalls: simplify 2016-05-29 18:19 ` Eli Zaretskii @ 2016-05-29 18:47 ` Jan Kratochvil 0 siblings, 0 replies; 49+ messages in thread From: Jan Kratochvil @ 2016-05-29 18:47 UTC (permalink / raw) To: Eli Zaretskii Cc: gdb-patches, philippe.waroquiers, sergiodj, palves, xdje42, scox, jistone On Sun, 29 May 2016 20:18:13 +0200, Eli Zaretskii wrote: > If you feel strongly about this, please go ahead and commit. Checked in: aab3c527d779a8e833a469203336afcc17512559 Thanks, Jan ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors 2015-12-04 2:26 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Josh Stone 2015-12-04 2:27 ` [PATCH v3 2/2] Implement 'catch syscall' for gdbserver Josh Stone @ 2015-12-04 12:16 ` Pedro Alves 2015-12-05 2:14 ` Josh Stone 1 sibling, 1 reply; 49+ messages in thread From: Pedro Alves @ 2015-12-04 12:16 UTC (permalink / raw) To: Josh Stone, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 Hi Josh, Thanks for the update, and thanks for the new test. On 12/04/2015 02:26 AM, Josh Stone wrote: > 2015-12-03 Josh Stone <jistone@redhat.com> > > * gdb.base/catch-static-fork.exp: New. Nit, to me, "catch-fork-static.exp" would be more natural. As it reads as something about either "catch static" or about a "static fork". > +gdb_test "run" "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \ > + "run to fork" > Please avoid hardcoding the "run" command: gdb_run_cmd gdb_test "" \ "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \ "run to fork" Even though "catch fork" currently doesn't work with plain "target remote", which doesn't do "run", there are patches pending to make it work. With this change, this test should then work with --target_board=native-gdbserver too. OK with that change. Thanks, Pedro Alves ^ permalink raw reply [flat|nested] 49+ messages in thread
* Re: [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors 2015-12-04 12:16 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Pedro Alves @ 2015-12-05 2:14 ` Josh Stone 0 siblings, 0 replies; 49+ messages in thread From: Josh Stone @ 2015-12-05 2:14 UTC (permalink / raw) To: Pedro Alves, gdb-patches; +Cc: philippe.waroquiers, sergiodj, eliz, xdje42 On 12/04/2015 04:16 AM, Pedro Alves wrote: > Hi Josh, > > Thanks for the update, and thanks for the new test. > > On 12/04/2015 02:26 AM, Josh Stone wrote: > >> 2015-12-03 Josh Stone <jistone@redhat.com> >> >> * gdb.base/catch-static-fork.exp: New. > > Nit, to me, "catch-fork-static.exp" would be more natural. > As it reads as something about either "catch static" or > about a "static fork". Sure, I'll rename it. >> +gdb_test "run" "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \ >> + "run to fork" >> > > Please avoid hardcoding the "run" command: > > gdb_run_cmd > gdb_test "" \ > "Catchpoint \[0-9\]* \\(forked process \[0-9\]*\\),.*" \ > "run to fork" > > Even though "catch fork" currently doesn't work with plain > "target remote", which doesn't do "run", there are patches pending > to make it work. With this change, this test should then work > with --target_board=native-gdbserver too. Great, I'll make this change too. > OK with that change. Thanks, I'll push it out with those tweaks. ^ permalink raw reply [flat|nested] 49+ messages in thread
end of thread, other threads:[~2016-05-29 18:47 UTC | newest] Thread overview: 49+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-10-30 11:02 [PATCH] Implement 'catch syscall' for gdbserver Josh Stone 2015-10-30 13:26 ` Eli Zaretskii 2015-11-01 22:15 ` Doug Evans 2015-11-02 18:24 ` Josh Stone 2015-11-21 10:29 ` Philippe Waroquiers 2015-11-23 4:20 ` Doug Evans 2015-11-23 4:20 ` Doug Evans 2015-11-25 2:37 ` Josh Stone 2015-11-26 2:53 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Josh Stone 2015-11-26 2:54 ` [PATCH v2 2/2] Implement 'catch syscall' for gdbserver Josh Stone 2015-11-26 10:34 ` [PATCH v2 1/2] gdbserver: Set Linux ptrace options ASAP Pedro Alves 2015-11-30 18:50 ` Josh Stone 2015-12-01 20:17 ` Josh Stone 2015-12-02 14:01 ` Pedro Alves 2015-12-04 2:26 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Josh Stone 2015-12-04 2:27 ` [PATCH v3 2/2] Implement 'catch syscall' for gdbserver Josh Stone 2015-12-04 8:45 ` Eli Zaretskii 2015-12-05 2:14 ` Josh Stone 2015-12-05 8:02 ` Eli Zaretskii 2015-12-07 16:50 ` Josh Stone 2015-12-07 17:15 ` Eli Zaretskii 2015-12-04 13:18 ` Pedro Alves 2015-12-05 2:16 ` Josh Stone 2015-12-08 13:31 ` Pedro Alves 2015-12-08 19:02 ` Josh Stone 2015-12-08 13:37 ` Pedro Alves 2015-12-11 21:19 ` Josh Stone 2015-12-16 15:42 ` Pedro Alves 2016-01-09 3:09 ` [PATCH v4] " Josh Stone 2016-01-09 7:37 ` Eli Zaretskii 2016-01-11 17:44 ` Philippe Waroquiers 2016-01-12 12:05 ` Pedro Alves 2016-01-12 19:10 ` Josh Stone 2016-01-12 19:22 ` Pedro Alves 2016-01-12 20:01 ` Josh Stone 2016-03-29 14:27 ` Yao Qi 2016-03-29 18:12 ` Josh Stone 2016-03-29 23:49 ` Josh Stone 2016-03-30 12:23 ` Yao Qi 2016-03-31 1:10 ` Josh Stone 2016-04-01 13:05 ` Yao Qi 2016-04-01 16:38 ` Josh Stone 2016-05-29 16:47 ` [doc] NEWS: QCatchSyscalls: simplify Jan Kratochvil 2016-05-29 17:29 ` Eli Zaretskii 2016-05-29 17:50 ` Jan Kratochvil 2016-05-29 18:19 ` Eli Zaretskii 2016-05-29 18:47 ` [commit] " Jan Kratochvil 2015-12-04 12:16 ` [PATCH v3 1/2] gdbserver: set ptrace flags after creating inferiors Pedro Alves 2015-12-05 2:14 ` Josh Stone
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).