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.
This commit is contained in:
Josh Stone
2016-01-12 12:27:27 -08:00
parent 41549dfbcc
commit 82075af2c1
19 changed files with 566 additions and 8 deletions

View File

@@ -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);