This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

RFA [PATCH] Implement 'catch syscall' for gdbserver


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  <philippe.waroquiers@skynet.be>

	* 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  <philippe.waroquiers@skynet.be>

	* 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  <philippe.waroquiers@skynet.be>

	* 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  <philippe.waroquiers@skynet.be>

	* 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 <sergiodj@linux.vnet.ibm.com>
 # 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*"]



Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]