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]

RFC [PATCH] gdbsrv catch syscall


I am busy implementing "catch syscall" for gdbserver (x86 and
amd64).

  what is still missing: NEWS, ChangeLogs, testing as 
     at this moment, it was only tested manually on x86 with
     GDBSERVER and with a (patched) Valgrind gdbserver).
  Also, the ptrace PTRACE_O_TRACESYSGOOD needed will
  better be (re-)done when the 'Shared ptrace options'
  patch is committed.

Current patch for GDB and GDBSERVER included below for comments.

The basic idea is a new packet  
   `QCatchSyscalls:1 [;SYSNO]...'
   `QCatchSyscalls:0'
        Enable (`QCatchSyscalls:1') or disable (`QCatchSyscalls:0')
        catching syscalls from the inferior process.
and two new stop reasons:
    `syscall_entry'
    `syscall_return'
          The packet indicates a syscall entry or return, and R is the
          syscall number, in hex.
(see doc patch in gdb.info for more details)

Implementing that, I have encountered a few glitches
in GDB "native" catch syscall.

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. small copy/paste error in GDB/mi documentation:
    `syscall-entry'
          The inferior entered a system call.  This is reported when
          `catch syscall' (*note Set Catchpoints::) has been used.

    `syscall-entry' <<<<< should be syscall-return
          The inferior returned from a system call.  This is reported
          when `catch syscall' (*note Set Catchpoints::) has been used.

3. I think that with 'set breakpoint always-inserted on',
   disabling/removing 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.

Thanks for feedback

Philippe

Index: remote.c
===================================================================
RCS file: /cvs/src/src/gdb/remote.c,v
retrieving revision 1.576
diff -u -p -r1.576 remote.c
--- remote.c	14 Aug 2013 18:17:50 -0000	1.576
+++ remote.c	21 Aug 2013 22:15:58 -0000
@@ -1340,6 +1340,7 @@ enum {
   PACKET_qSupported,
   PACKET_qTStatus,
   PACKET_QPassSignals,
+  PACKET_QCatchSyscalls,
   PACKET_QProgramSignals,
   PACKET_qSearch_memory,
   PACKET_vAttach,
@@ -1728,6 +1729,90 @@ 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";
+	  char *p;
+	  int i;
+	  const int maxpktsz = strlen (q1) + n_sysno * 9 + 1;
+
+	  catch_packet = xmalloc (maxpktsz);
+	  strcpy (catch_packet, q1);
+	  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 +4101,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 +5370,8 @@ typedef struct stop_reply
 
   int stopped_by_watchpoint_p;
   CORE_ADDR watch_data_address;
-
+  
+  int syscall;
   int solibs_changed;
   int replay_event;
 
@@ -5546,12 +5634,12 @@ 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;
   event->regcache = NULL;
   event->core = -1;
-
   switch (buf[0])
     {
     case 'T':		/* Status with PC, SP, FP, ...	*/
@@ -5596,6 +5684,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 +5785,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;
@@ -11501,6 +11610,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;
@@ -11995,6 +12105,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: doc/gdb.texinfo
===================================================================
RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v
retrieving revision 1.1103
diff -u -p -r1.1103 gdb.texinfo
--- doc/gdb.texinfo	5 Aug 2013 15:39:25 -0000	1.1103
+++ doc/gdb.texinfo	21 Aug 2013 22:16:02 -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}}
@@ -38065,6 +38069,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.
@@ -38435,6 +38444,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
@@ -38798,6 +38845,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{-}
@@ -38958,6 +39010,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.244
diff -u -p -r1.244 linux-low.c
--- gdbserver/linux-low.c	14 Aug 2013 02:22:19 -0000	1.244
+++ gdbserver/linux-low.c	21 Aug 2013 22:16:04 -0000
@@ -69,6 +69,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
@@ -560,6 +565,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.
 
@@ -2326,6 +2358,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
@@ -2607,6 +2662,19 @@ Check if we're already there.\n",
 
   /* Check whether GDB would be interested in this event.  */
 
+  /* Check if GDB is interested in this sycall.  */
+  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
@@ -2785,7 +2853,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,
@@ -3347,7 +3426,10 @@ 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 (PTRACE_SETOPTIONS, lwpid_of (lwp), (PTRACE_TYPE_ARG3) 0,// qcatchsyscalls TBD clean ....
+	  PTRACE_O_TRACESYSGOOD);
+  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.  */
@@ -5348,6 +5430,12 @@ linux_process_qsupported (const char *qu
 }
 
 static int
+linux_supports_catch_syscall (void)
+{
+  return the_low_target.get_syscall_trapinfo != NULL;
+}
+
+static int
 linux_supports_tracepoints (void)
 {
   if (*the_low_target.supports_tracepoints == NULL)
@@ -6038,6 +6126,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.64
diff -u -p -r1.64 linux-low.h
--- gdbserver/linux-low.h	14 Aug 2013 02:22:19 -0000	1.64
+++ gdbserver/linux-low.h	21 Aug 2013 22:16:04 -0000
@@ -186,6 +186,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	21 Aug 2013 22:16:04 -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	21 Aug 2013 22:16:04 -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.195
diff -u -p -r1.195 server.c
--- gdbserver/server.c	24 Jul 2013 16:20:12 -0000	1.195
+++ gdbserver/server.c	21 Aug 2013 22:16:04 -0000
@@ -70,6 +70,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;
 
@@ -506,6 +509,46 @@ handle_general_set (char *own_buf)
       return;
     }
 
+  if (strncmp ("QCatchSyscalls:1", own_buf, strlen ("QPassSignals: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;
@@ -1739,6 +1782,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	21 Aug 2013 22:16:04 -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.69
diff -u -p -r1.69 target.h
--- gdbserver/target.h	24 Jul 2013 16:20:12 -0000	1.69
+++ gdbserver/target.h	21 Aug 2013 22:16:04 -0000
@@ -265,6 +265,10 @@ struct target_ops
   /* Target specific qSupported support.  */
   void (*process_qsupported) (const char *);
 
+  /* Return 1 if the target supporst 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);
@@ -411,6 +415,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	21 Aug 2013 22:16:05 -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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]