From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 28172 invoked by alias); 30 Aug 2013 15:26:48 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Received: (qmail 28105 invoked by uid 89); 30 Aug 2013 15:26:48 -0000 Received: from mailrelay002.isp.belgacom.be (HELO mailrelay002.isp.belgacom.be) (195.238.6.175) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 30 Aug 2013 15:26:47 +0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=3.7 required=5.0 tests=BAYES_00,CK_HELO_DYNAMIC_SPLIT_IP,HELO_DYNAMIC_SPLIT_IP,SPF_SOFTFAIL,TVD_RCVD_IP autolearn=no version=3.3.2 X-HELO: mailrelay002.isp.belgacom.be X-Belgacom-Dynamic: yes X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: ApMBAF65IFJtgbcb/2dsb2JhbAANTYc0vlyDOQkEfwgCJgJIAycarjR0kXKBKY0NhC2BNAOse4Fn Received: from 27.183-129-109.adsl-dyn.isp.belgacom.be (HELO [192.168.1.6]) ([109.129.183.27]) by relay.skynet.be with ESMTP; 30 Aug 2013 17:26:24 +0200 Subject: RFA [PATCH] Implement 'catch syscall' for gdbserver From: Philippe Waroquiers To: gdb-patches@sourceware.org Content-Type: text/plain; charset="UTF-8" Date: Fri, 30 Aug 2013 15:26:00 -0000 Message-ID: <1377876388.3041.3.camel@soleil> Mime-Version: 1.0 Content-Transfer-Encoding: 7bit X-SW-Source: 2013-08/txt/msg00922.txt.bz2 This is the 2nd version of the patch implementing 'catch syscalls' for gdbserver. First version was sent in an RFC (no feedback yet, so here is a completed and tested RFA ready version). Tested (no regression) on linux amd64, native and gdbserver. Manually tested with a patched Valgrind gdbserver. Here are the changes logs: ChangeLog 2013-xx-yy Philippe Waroquiers * NEWS: Document new QcatchSyscalls packet and its use in x86/amd64 linux gdbserver and Valgrind gdbserver. * remote.c (PACKET_QCatchSyscalls): New. (remote_protocol_features): Add Qcatchsyscalls. (remote_set_syscall_catchpoint): New function. (remote_parse_stop_reply): New stop reasons syscall_entry and syscall_return. (init_remote_ops): Registers remote_set_syscall_catchpoint and the config commands for [PACKET_QCatchSyscalls. * common/linux-ptrace.c (linux_check_ptrace_features): Detect PTRACE_O_TRACESYSGOOD for gdbserver. (ptrace_supports_feature): Initializes ptrace features if needed. doc/ChangeLog 2013-xx-yy Philippe Waroquiers * gdb.texinfo (General Query Packets): Document new QcatchSyscalls packet. (Stop Reply Packets): Document new stop reasons syscall_entry and syscall_return. (Async Records): fixed syscall-return item name. gdbserver/ChangeLog 2013-xx-yy Philippe Waroquiers * target.h (struct target_ops): Add supports_catch_syscall operation. * linux-low.h (struct linux_target_ops): Add get_syscall_trapinfo operation. * linux-low.c (linux_wait_1): Enables, detects and handle SYSCALL_SIGTRAP. (gdb_catched_syscall): New function. (get_syscall_trapinfo): New function. (linux_supports_catch_syscall): New function. (struct target_ops linux_target_ops): Set linux_supports_catch_syscall. * linux-x86-low.c (x86_get_syscall_trapinfo): New function. (struct linux_target_ops the_low_target): Set x86_get_syscall_trapinfo. * remote-utils.c (prepare_resume_reply): Handle status kinds TARGET_WAITKIND_SYSCALL_ENTRY and TARGET_WAITKIND_SYSCALL_RETURN. * server.h: Declare catch_syscalls_p, catched_syscalls_size and catched_syscalls. * server.c: Define catch_syscalls_p, catched_syscalls_size and catched_syscalls. (handle_general_set): Handle QCatchSyscalls packet. (handle_query): Reports if low target supports QCatchSyscalls. * win32-low.c (struct target_ops win32_target_op): Sets NULL for supports_catch_syscall. testsuite/ChangeLog 2013-xx-yy Philippe Waroquiers * gdb.base/catch-syscall.exp: Enables test for x86 and amd64 gdbserver. Two specific points that might be worth looking at (after this patch probably): 1. GDB native has a bug in the detection of "syscall entry/return", when the catch syscall is disabled when inferior is stopped on a syscall entry, and then catch syscall is re-enabled later: Catchpoint 1 (call to syscall brk), 0x00207ead in brk () from /lib/ld-linux.so.2 (gdb) break main Breakpoint 2 at 0x80486ca: file reach_thread_register.c, line 42. (gdb) disa 1 (gdb) c Continuing. [Thread debugging using libthread_db enabled] Using host libthread_db library "/lib/libthread_db.so.1". Breakpoint 2, main () at reach_thread_register.c:42 42 pthread_barrier_init(&bar, NULL, 2); (gdb) enable (gdb) c Continuing. Catchpoint 1 (returned from syscall mmap2), 0x00121416 in __kernel_vsyscall () (gdb) ^^^^^^^^^^^^^^^^^^^^^^^^^^^ should be call to syscall mmap2 /// after this, all entries are seen as returns, and all returns are seen /// as entries. In GDBSERVER, to differentiate entry from return, I use the syscall retcode -ENOSYS. This is working properly including for the case above. The only problem is that if a syscall is not implemented (and so really returns -ENOSYS) then GDBSERVER will wrongly report the return of the system call as an entry (but subsequent syscall entries/returns will be properly reported). Maybe there is a better approach, including for fixing the 'GDB native catch syscall' ? 2. GDB (probably in breakpoint.c) has a bug with catch syscalls in remote mode when 'set breakpoint always-inserted on' : Disabling all the catch syscalls does not cause a call to target_set_syscall_catchpoint with needed = 0, which means that QCatchSyscalls:0 is not sent. After that, GDBSERVER continues to report various syscalls to GDB, that filters them, so no functional bug, only efficiency bug. ----------------- Patch: Index: NEWS =================================================================== RCS file: /cvs/src/src/gdb/NEWS,v retrieving revision 1.611 diff -u -p -r1.611 NEWS --- NEWS 27 Aug 2013 05:20:56 -0000 1.611 +++ NEWS 30 Aug 2013 15:18:08 -0000 @@ -127,11 +127,21 @@ qXfer:libraries-svr4:read's annex necessary for library list updating, resulting in significant speedup. +QCatchSyscalls:1 [;SYSNO]... +QCatchSyscalls:0 + Enable (`QCatchSyscalls:1') or disable (`QCatchSyscalls:0') + catching syscalls from the inferior process. + + * New features in the GDB remote stub, GDBserver ** GDBserver now supports target-assisted range stepping. Currently enabled on x86/x86_64 GNU/Linux targets. + ** GDBserver now supports catch syscall catchpoints. Currently + enabled on x86/x86_64 GNU/Linux targets, and in the Valgrind + gdbserver. + ** GDBserver now adds element 'tvar' in the XML in the reply to 'qXfer:traceframe-info:read'. It has the id of the collected trace state variables. Index: remote.c =================================================================== RCS file: /cvs/src/src/gdb/remote.c,v retrieving revision 1.577 diff -u -p -r1.577 remote.c --- remote.c 23 Aug 2013 13:12:17 -0000 1.577 +++ remote.c 30 Aug 2013 15:18:09 -0000 @@ -1340,6 +1340,7 @@ enum { PACKET_qSupported, PACKET_qTStatus, PACKET_QPassSignals, + PACKET_QCatchSyscalls, PACKET_QProgramSignals, PACKET_qSearch_memory, PACKET_vAttach, @@ -1728,6 +1729,93 @@ remote_pass_signals (int numsigs, unsign } } +/* If 'QCatchSyscalls' is supported, tell the remote stub + to report syscalls to GDB. */ + +static int +remote_set_syscall_catchpoint (int pid, int needed, int any_count, + int table_size, int *table) +{ + if (remote_protocol_packets[PACKET_QCatchSyscalls].support != PACKET_DISABLE) + { + char *catch_packet, *p; + enum packet_result result; + int n_sysno = 0; + + if (needed && !any_count) + { + int i; + + 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 char *q1 = "QCatchSyscalls:1"; + int i; + const int maxpktsz = strlen (q1) + n_sysno * 9 + 1; + + catch_packet = xmalloc (maxpktsz); + strcpy (catch_packet, q1); + if (!any_count) + { + char *p; + p = catch_packet; + p += strlen(p); + 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 (q1)] = 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; + } + } + else + return 1; /* not supported */ +} + + /* If 'QProgramSignals' is supported, tell the remote stub what signals it should pass through to the inferior when detaching. */ @@ -4016,6 +4104,8 @@ static const struct protocol_feature rem 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, @@ -5283,7 +5373,8 @@ typedef struct stop_reply int stopped_by_watchpoint_p; CORE_ADDR watch_data_address; - + + int syscall; int solibs_changed; int replay_event; @@ -5546,6 +5637,7 @@ remote_parse_stop_reply (char *buf, stru event->ptid = null_ptid; event->ws.kind = TARGET_WAITKIND_IGNORE; event->ws.value.integer = 0; + event->syscall = 0; event->solibs_changed = 0; event->replay_event = 0; event->stopped_by_watchpoint_p = 0; @@ -5596,6 +5688,22 @@ Packet: '%s'\n"), p, buf); if (strncmp (p, "thread", p1 - p) == 0) event->ptid = read_ptid (++p1, &p); + else if (strncmp (p, "syscall_entry", p1 - p) == 0) + { + ULONGEST sysno; + event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY; + p = unpack_varlen_hex (++p1, &sysno); + event->syscall = 1; + event->ws.value.syscall_number = (int) sysno; + } + else if (strncmp (p, "syscall_return", p1 - p) == 0) + { + ULONGEST sysno; + event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN; + p = unpack_varlen_hex (++p1, &sysno); + event->syscall = 1; + event->ws.value.syscall_number = (int) sysno; + } else if ((strncmp (p, "watch", p1 - p) == 0) || (strncmp (p, "rwatch", p1 - p) == 0) || (strncmp (p, "awatch", p1 - p) == 0)) @@ -5681,6 +5789,11 @@ Packet: '%s'\n"), event->ws.kind = TARGET_WAITKIND_LOADED; else if (event->replay_event) event->ws.kind = TARGET_WAITKIND_NO_HISTORY; + else if (event->syscall) + { + gdb_assert (event->ws.kind == TARGET_WAITKIND_SYSCALL_ENTRY + || event->ws.kind == TARGET_WAITKIND_SYSCALL_RETURN); + } else { event->ws.kind = TARGET_WAITKIND_STOPPED; @@ -11452,6 +11565,7 @@ Specify the serial device it is connecte remote_ops.to_load = generic_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_find_new_threads = remote_threads_info; @@ -11946,6 +12060,9 @@ Show the maximum size of the address (in 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); Index: common/linux-ptrace.c =================================================================== RCS file: /cvs/src/src/gdb/common/linux-ptrace.c,v retrieving revision 1.12 diff -u -p -r1.12 linux-ptrace.c --- common/linux-ptrace.c 28 Aug 2013 14:09:31 -0000 1.12 +++ common/linux-ptrace.c 30 Aug 2013 15:18:09 -0000 @@ -361,16 +361,17 @@ linux_check_ptrace_features (void) return; } -#ifdef GDBSERVER - /* gdbserver does not support PTRACE_O_TRACESYSGOOD or - PTRACE_O_TRACEVFORKDONE yet. */ -#else - /* Check if the target supports PTRACE_O_TRACESYSGOOD. */ + /* Check if the target supports PTRACE_O_TRACESYSGOOD, keeping + PTRACE_O_TRACEFORK option activated. */ ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0, - (PTRACE_TYPE_ARG4) PTRACE_O_TRACESYSGOOD); + (PTRACE_TYPE_ARG4) (PTRACE_O_TRACEFORK + | PTRACE_O_TRACESYSGOOD)); if (ret == 0) current_ptrace_options |= PTRACE_O_TRACESYSGOOD; +#ifdef GDBSERVER + /* gdbserver does not support PTRACE_O_TRACEVFORKDONE yet. */ +#else /* Check if the target supports PTRACE_O_TRACEVFORKDONE. */ ret = ptrace (PTRACE_SETOPTIONS, child_pid, (PTRACE_TYPE_ARG3) 0, (PTRACE_TYPE_ARG4) (PTRACE_O_TRACEFORK @@ -474,6 +475,11 @@ linux_enable_event_reporting (pid_t pid) static int ptrace_supports_feature (int ptrace_options) { + /* Check if we have initialized the ptrace features for this + target. If not, do it now. */ + if (current_ptrace_options == -1) + linux_check_ptrace_features (); + gdb_assert (current_ptrace_options >= 0); return ((current_ptrace_options & ptrace_options) == ptrace_options); Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.1105 diff -u -p -r1.1105 gdb.texinfo --- doc/gdb.texinfo 27 Aug 2013 05:20:57 -0000 1.1105 +++ doc/gdb.texinfo 30 Aug 2013 15:18:15 -0000 @@ -18681,6 +18681,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}} @@ -38077,6 +38081,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. @@ -38447,6 +38456,44 @@ by supplying an appropriate @samp{qSuppo 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 signal is not catched. 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 @@ -38810,6 +38857,11 @@ These are the currently defined stub fea @tab @samp{-} @tab Yes +@item @samp{QCatchSyscalls} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QPassSignals} @tab No @tab @samp{-} @@ -38970,6 +39022,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}). Index: gdbserver/linux-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v retrieving revision 1.246 diff -u -p -r1.246 linux-low.c --- gdbserver/linux-low.c 28 Aug 2013 17:40:58 -0000 1.246 +++ gdbserver/linux-low.c 30 Aug 2013 15:18:16 -0000 @@ -72,6 +72,11 @@ #define W_STOPCODE(sig) ((sig) << 8 | 0x7f) #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 the kernel's hard limit. Not to be confused with SIGRTMIN. */ #ifndef __SIGRTMIN @@ -479,6 +484,33 @@ get_pc (struct lwp_info *lwp) return pc; } +/* This function should only be called if LWP got a SIGTRAP_SYSCALL. */ + +static void +get_syscall_trapinfo (struct lwp_info *lwp, int *sysno, int *sysret) +{ + struct thread_info *saved_inferior; + struct regcache *regcache; + + if (the_low_target.get_syscall_trapinfo == NULL) + { + *sysno = 0; + *sysret = 0; + } + + saved_inferior = current_inferior; + current_inferior = get_lwp_thread (lwp); + + regcache = get_thread_regcache (current_inferior, 1); + (*the_low_target.get_syscall_trapinfo) (regcache, sysno, sysret); + + if (debug_threads) + fprintf (stderr, "get_syscall_trapinfo sysno %d sysret %d\n", + *sysno, *sysret); + + current_inferior = saved_inferior; +} + /* This function should only be called if LWP got a SIGTRAP. The SIGTRAP could mean several things. @@ -2246,6 +2278,29 @@ linux_stabilize_threads (void) } } +/* Returns 1 if GDB is interested in the event_child syscall. + Only to be called when stopped reason is SIGTRAP_SYSCALL. */ + +static int +gdb_catched_syscall (struct lwp_info *event_child) +{ + int i; + int sysno, sysret; + + if (!catch_syscalls_p) + return 0; + + if (catched_syscalls_size == 0) + return 1; + + get_syscall_trapinfo (event_child, &sysno, &sysret); + for (i = 0; i < catched_syscalls_size; i++) + if (catched_syscalls[i] == sysno) + return 1; + + return 0; +} + /* Wait for process, returns status. */ static ptid_t @@ -2527,6 +2582,19 @@ Check if we're already there.\n", /* 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_catched_syscall (event_child)) + { + if (debug_threads) + fprintf (stderr, "Ignored syscall for LWP %ld.\n", + lwpid_of (event_child)); + linux_resume_one_lwp (event_child, event_child->stepping, + 0, NULL); + goto retry; + } + /* 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 @@ -2705,7 +2773,18 @@ Check if we're already there.\n", ourstatus->kind = TARGET_WAITKIND_STOPPED; - if (current_inferior->last_resume_kind == resume_stop + if (WSTOPSIG (w) == SYSCALL_SIGTRAP) + { + int sysret; + + get_syscall_trapinfo (event_child, + &ourstatus->value.syscall_number, &sysret); + if (sysret == -ENOSYS) + ourstatus->kind = TARGET_WAITKIND_SYSCALL_ENTRY; + else + ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN; + } + else if (current_inferior->last_resume_kind == resume_stop && WSTOPSIG (w) == SIGSTOP) { /* A thread that has been requested to stop by GDB with vCont;t, @@ -3267,7 +3346,8 @@ lwp %ld wants to get out of fast tracepo lwp->stopped = 0; lwp->stopped_by_watchpoint = 0; lwp->stepping = step; - ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (lwp), + ptrace (step ? PTRACE_SINGLESTEP : catch_syscalls_p ? PTRACE_SYSCALL : PTRACE_CONT, + lwpid_of (lwp), (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. */ @@ -5106,6 +5186,13 @@ linux_process_qsupported (const char *qu } 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) @@ -5796,6 +5883,7 @@ static struct target_ops linux_target_op linux_common_core_of_thread, linux_read_loadmap, linux_process_qsupported, + linux_supports_catch_syscall, linux_supports_tracepoints, linux_read_pc, linux_write_pc, Index: gdbserver/linux-low.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v retrieving revision 1.65 diff -u -p -r1.65 linux-low.h --- gdbserver/linux-low.h 22 Aug 2013 23:46:29 -0000 1.65 +++ gdbserver/linux-low.h 30 Aug 2013 15:18:16 -0000 @@ -187,6 +187,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); Index: gdbserver/linux-x86-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/linux-x86-low.c,v retrieving revision 1.49 diff -u -p -r1.49 linux-x86-low.c --- gdbserver/linux-x86-low.c 12 Jun 2013 16:05:39 -0000 1.49 +++ gdbserver/linux-x86-low.c 30 Aug 2013 15:18:16 -0000 @@ -1472,6 +1472,32 @@ x86_arch_setup (void) current_process ()->tdesc = x86_linux_read_description (); } +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) { @@ -3321,6 +3347,7 @@ struct linux_target_ops the_low_target = x86_linux_new_thread, 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, Index: gdbserver/remote-utils.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/remote-utils.c,v retrieving revision 1.98 diff -u -p -r1.98 remote-utils.c --- gdbserver/remote-utils.c 1 Jul 2013 11:19:27 -0000 1.98 +++ gdbserver/remote-utils.c 30 Aug 2013 15:18:16 -0000 @@ -1319,12 +1319,17 @@ prepare_resume_reply (char *buf, ptid_t switch (status->kind) { case TARGET_WAITKIND_STOPPED: + case TARGET_WAITKIND_SYSCALL_ENTRY: + case TARGET_WAITKIND_SYSCALL_RETURN: { struct thread_info *saved_inferior; const char **regp; struct regcache *regcache; - sprintf (buf, "T%02x", status->value.sig); + if (status->kind == TARGET_WAITKIND_STOPPED) + sprintf (buf, "T%02x", status->value.sig); + else + sprintf (buf, "T%02x", SIGTRAP); buf += strlen (buf); saved_inferior = current_inferior; @@ -1335,6 +1340,16 @@ prepare_resume_reply (char *buf, ptid_t regcache = get_thread_regcache (current_inferior, 1); + if (status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + || status->kind == TARGET_WAITKIND_SYSCALL_RETURN) + { + sprintf (buf, "%s:%x;", + status->kind == TARGET_WAITKIND_SYSCALL_ENTRY + ? "syscall_entry" : "syscall_return", + status->value.syscall_number); + buf += strlen (buf); + } + if (the_target->stopped_by_watchpoint != NULL && (*the_target->stopped_by_watchpoint) ()) { Index: gdbserver/server.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/server.c,v retrieving revision 1.196 diff -u -p -r1.196 server.c --- gdbserver/server.c 28 Aug 2013 17:40:58 -0000 1.196 +++ gdbserver/server.c 30 Aug 2013 15:18:17 -0000 @@ -71,6 +71,9 @@ int debug_threads; int debug_hw_points; int pass_signals[GDB_SIGNAL_LAST]; +int catch_syscalls_p; +int catched_syscalls_size; +int *catched_syscalls; int program_signals[GDB_SIGNAL_LAST]; int program_signals_p; @@ -507,6 +510,46 @@ handle_general_set (char *own_buf) return; } + if (strncmp ("QCatchSyscalls:1", own_buf, strlen ("QCatchSyscalls:1")) == 0) + { + int i; + const char *p; + CORE_ADDR sysno; + + catch_syscalls_p = 1; + if (catched_syscalls != NULL) + { + free (catched_syscalls); + catched_syscalls = NULL; + } + catched_syscalls_size = 0; + p = own_buf + strlen("QCatchSyscalls:1"); + while (*p) + { + if (*p++ == ';') + catched_syscalls_size++; + } + if (catched_syscalls_size > 0) + { + catched_syscalls = xmalloc (catched_syscalls_size * sizeof (int)); + p = strchr(own_buf, ';') + 1; + for (i = 0; i < catched_syscalls_size; i++) + { + p = decode_address_to_semicolon (&sysno, p); + catched_syscalls [i] = (int) sysno; + } + } + strcpy (own_buf, "OK"); + return; + } + + if (strcmp ("QCatchSyscalls:0", own_buf) == 0) + { + catch_syscalls_p = 0; + strcpy (own_buf, "OK"); + return; + } + if (strncmp ("QProgramSignals:", own_buf, strlen ("QProgramSignals:")) == 0) { int numsigs = (int) GDB_SIGNAL_LAST, i; @@ -1740,6 +1783,9 @@ handle_query (char *own_buf, int packet_ "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+"); Index: gdbserver/server.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/server.h,v retrieving revision 1.109 diff -u -p -r1.109 server.h --- gdbserver/server.h 1 Jul 2013 11:28:30 -0000 1.109 +++ gdbserver/server.h 30 Aug 2013 15:18:17 -0000 @@ -230,6 +230,15 @@ extern int server_waiting; extern int debug_threads; extern int debug_hw_points; extern int pass_signals[]; + +/* 1 if some (or all) syscalls are catched. */ +extern int catch_syscalls_p; +/* catched_syscalls is the list of syscalls to report to GDB. + If catch_syscalls_p and catched_syscalls == NULL, it means + all syscalls must be reported. */ +extern int catched_syscalls_size; +extern int *catched_syscalls; + extern int program_signals[]; extern int program_signals_p; Index: gdbserver/target.h =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/target.h,v retrieving revision 1.70 diff -u -p -r1.70 target.h --- gdbserver/target.h 19 Aug 2013 16:54:11 -0000 1.70 +++ gdbserver/target.h 30 Aug 2013 15:18:17 -0000 @@ -267,6 +267,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); @@ -413,6 +417,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) Index: gdbserver/win32-low.c =================================================================== RCS file: /cvs/src/src/gdb/gdbserver/win32-low.c,v retrieving revision 1.66 diff -u -p -r1.66 win32-low.c --- gdbserver/win32-low.c 2 Jul 2013 11:59:24 -0000 1.66 +++ gdbserver/win32-low.c 30 Aug 2013 15:18:17 -0000 @@ -1813,6 +1813,7 @@ static struct target_ops win32_target_op NULL, /* core_of_thread */ NULL, /* read_loadmap */ NULL, /* process_qsupported */ + NULL, /* supports_catch_syscall */ NULL, /* supports_tracepoints */ NULL, /* read_pc */ NULL, /* write_pc */ Index: testsuite/gdb.base/catch-syscall.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/catch-syscall.exp,v retrieving revision 1.19 diff -u -p -r1.19 catch-syscall.exp --- testsuite/gdb.base/catch-syscall.exp 22 Aug 2013 20:32:54 -0000 1.19 +++ testsuite/gdb.base/catch-syscall.exp 30 Aug 2013 15:18:17 -0000 @@ -19,7 +19,7 @@ # It was written by Sergio Durigan Junior # on September/2008. -if { [is_remote target] || ![isnative] } then { +if { ![isnative] } then { continue } @@ -28,6 +28,14 @@ if {![istarget "hppa*-hp-hpux*"] && ![is 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 shall be updated whenever 'catch syscall' is implemented # on some architecture. #if { ![istarget "i\[34567\]86-*-linux*"]