aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2016-01-12 12:27:27 -0800
committerJosh Stone <jistone@redhat.com>2016-01-12 12:27:27 -0800
commit82075af2c14b1f8a54fa5796fb63f7ef23f98d9d (patch)
tree91cbb8ff3107608f7b93c82e3d0f532e5a739911 /gdb/gdbserver
parent41549dfbcc747d0dc4a97c9a427c3a29e9878f05 (diff)
downloadgdb-82075af2c14b1f8a54fa5796fb63f7ef23f98d9d.zip
gdb-82075af2c14b1f8a54fa5796fb63f7ef23f98d9d.tar.gz
gdb-82075af2c14b1f8a54fa5796fb63f7ef23f98d9d.tar.bz2
Implement 'catch syscall' for gdbserver
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-12 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-12 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 the detailed list of stub features. gdb/gdbserver/ChangeLog: 2016-01-12 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-12 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.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog30
-rw-r--r--gdb/gdbserver/inferiors.c1
-rw-r--r--gdb/gdbserver/inferiors.h6
-rw-r--r--gdb/gdbserver/linux-low.c157
-rw-r--r--gdb/gdbserver/linux-low.h13
-rw-r--r--gdb/gdbserver/linux-x86-low.c26
-rw-r--r--gdb/gdbserver/remote-utils.c12
-rw-r--r--gdb/gdbserver/server.c51
-rw-r--r--gdb/gdbserver/server.h6
-rw-r--r--gdb/gdbserver/target.h8
10 files changed, 305 insertions, 5 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 3c2d6db..757424c 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,33 @@
+2016-01-12 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.
+
2016-01-12 Mike Frysinger <vapier@gentoo.org>
* acinclude.m4: Include new ../warning.m4 file.
diff --git a/gdb/gdbserver/inferiors.c b/gdb/gdbserver/inferiors.c
index c884b55..4bea4fd 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 af65718..00dfe60 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 47f0f9d..7c77a2f 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,14 @@ 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. */
+ 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;
+
/* Report the event. */
*orig_event_lwp = event_lwp;
return 0;
@@ -682,6 +700,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 +2288,8 @@ linux_low_ptrace_options (int attached)
if (report_exec_events)
options |= PTRACE_O_TRACEEXEC;
+ options |= PTRACE_O_TRACESYSGOOD;
+
return options;
}
@@ -2364,6 +2418,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 +3042,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 +3414,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 +3682,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 +4148,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 +4336,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 +6425,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 +7355,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 e80c67f..751eea1 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 0432a86..4a01750 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 40bd373..15cdbe1 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 440c076..301dea9 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 58cf342..3d78fb3 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 cbdb8d9..5af2051 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)