public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [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 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 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 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

* 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-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: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-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-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-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
  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

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).