Implementing catch syscall.
* amd64-linux-tdep.c: Include xml-syscall.h header, define the XML syscall name for the architecture. (amd64_linux_get_syscall_number): New function. (amd64_linux_init_abi): Register the correct functions for syscall catchpoint; set the correct syscall file name. * breakpoint.c: New include: xml-syscall.h. (set_raw_breakpoint_without_location): Setting the parameters for the catch syscall feature. (insert_catch_syscall): New. (remove_catch_syscall): New. (breakpoint_hit_catch_syscall): New. (print_it_catch_syscall): New. (print_one_catch_syscall): New. (print_mention_catch_syscall): New. (catch_syscall_breakpoint_ops): New. (syscall_catchpoint_p): New. (create_catchpoint_without_mention): New. (create_catchpoint): Modified in order to use create_catchpoint_without_mention. (create_syscall_event_catchpoint): New. (clean_up_filters): New. (catch_syscall_split_args): New. (catch_syscall_command_1): New. (delete_breakpoint): Add cleanup for catch syscall. (is_syscall_catchpoint_enabled): New. (catch_syscall_enabled): New. (catching_syscall_number): New. (catch_syscall_completer): New completer function. (add_catch_command): Add the completer function for catchpoints. * breakpoint.h (syscalls_to_be_caught): New vector. (catch_syscall_enabled): New. (catching_syscall_number): New. * gdbarch.c: Regenerated. * gdbarch.h: Regenerated. * gdbarch.sh: Add syscall catchpoint functions and structures. (get_syscall_number): New. (UNKNOWN_SYSCALL): New definition. * i386-linux-nat.c (i386_linux_resume): Select the proper request to be made for ptrace() considering if we are catching syscalls or not. * i386-linux-tdep.c: Include xml-syscall.h header, define the XML syscall name for the architecture. (i386_linux_get_syscall_number): New. (i386_linux_init_abi): Register the correct functions for syscall catchpoint; set the correct syscall file name. * inf-child.c (inf_child_set_syscall_catchpoint): New. (inf_child_target): Assign default values to target_ops. * inf-ptrace.c (inf_ptrace_resume): Select the proper request to be made for ptrace() considering if we are catching syscalls or not. * inferior.h (struct inferior): Included new variables any_syscall_count, syscalls_counts and total_syscalls_count, used to keep track of requested syscall catchpoints. * infrun.c (resume): Add syscall catchpoint. (deal_with_syscall_event): New. (handle_inferior_event): Add syscall entry/return events. (inferior_has_called_syscall): New. * linux-nat.c: Define some helpful variables to track wether we have support for the needed ptrace option. (linux_test_for_tracesysgood): New. (linux_supports_tracesysgood): New. (linux_enable_tracesysgood): New. (linux_enable_event_reporting): Save the current used ptrace options. (linux_child_post_attach): Calling linux_enable_tracesysgood. (linux_child_post_startup_inferior): Likewise. (linux_child_set_syscall_catchpoint): New function. (linux_handle_extended_wait): Handle the case which the inferior stops because it has called or returned from a syscall. (linux_target_install_ops): Install the necessary functions to handle syscall catchpoints. * linux-nat.h (struct lwp_info): Include syscall_state into the structure, which indicates if we are in a syscall entry or return. * ppc-linux-tdep.c: Include xml-syscall.h header, define the XML syscall filename for the arch. (ppc_linux_get_syscall_number): New. (ppc_linux_init_abi): Register the correct functions for syscall catchpoint; setting the correct name for the XML syscall file. * target.c (update_current_target): Update/copy functions related to syscall catchpoint. (target_waitstatus_to_string): Add syscall catchpoint entry/return events. * target.h (struct target_waitstatus): Add syscall number. (struct syscall): New struct to hold information about syscalls in the system. (struct target_ops): Add ops for syscall catchpoint. (inferior_has_called_syscall): New. (target_set_syscall_catchpoint): New. * xml-support.c (xml_fetch_content_from_file): New function, transferred from xml-tdesc.c. * xml-support.h (xml_fetch_content_from_file): New. * xml-tdesc.c (fetch_xml_from_file): Function removed; transferred to xml-support.c. (file_read_description_xml): Updated to use the new xml_fetch_content_from_file function. * syscalls/gdb-syscalls.dtd: New definition file for syscall's XML support. * syscalls/amd64-linux.xml: New file containing information about syscalls for GNU/Linux systems that use amd64 architecture. * syscalls/i386-linux.xml: New file containing information about syscalls for GNU/Linux systems that use i386 architecture. * syscalls/ppc-linux.xml: New file containing information about syscalls for GNU/Linux systems that use PPC architecture. * syscalls/ppc64-linux.xml: New file containing information about syscalls for GNU/Linux systems that use PPC64 architecture. * xml-syscall.c: New file containing functions for manipulating syscall's XML files. * xml-syscall.h: New file, exporting the functions above mentioned. * Makefile.in: Support for relocatable GDB datadir and XML syscall. * NEWS: Added information about the catch syscall feature. * doc/gdb.texinfo (Set Catchpoints): Documentation about the new feature. * testsuite/Makefile.in: Inclusion of catch-syscall object. * testsuite/gdb.base/catch-syscall.c: New file. * testsuite/gdb.base/catch-syscall.exp: New file.
This commit is contained in:
parent
22fe6da0f9
commit
a96d9b2e9a
27 changed files with 1358 additions and 99 deletions
144
gdb/linux-nat.c
144
gdb/linux-nat.c
|
@ -67,6 +67,10 @@
|
|||
# endif
|
||||
#endif /* HAVE_PERSONALITY */
|
||||
|
||||
/* To be used when one needs to know wether a
|
||||
WSTOPSIG (status) is a syscall */
|
||||
#define TRAP_IS_SYSCALL (SIGTRAP | 0x80)
|
||||
|
||||
/* This comment documents high-level logic of this file.
|
||||
|
||||
Waiting for events in sync mode
|
||||
|
@ -279,6 +283,11 @@ struct simple_pid_list *stopped_pids;
|
|||
|
||||
static int linux_supports_tracefork_flag = -1;
|
||||
|
||||
/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACESYSGOOD
|
||||
can not be used, 1 if it can. */
|
||||
|
||||
static int linux_supports_tracesysgood_flag = -1;
|
||||
|
||||
/* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have
|
||||
PTRACE_O_TRACEVFORKDONE. */
|
||||
|
||||
|
@ -290,6 +299,9 @@ static int linux_supports_tracevforkdone_flag = -1;
|
|||
linux_nat_wait should behave as if async mode was off. */
|
||||
static int linux_nat_async_mask_value = 1;
|
||||
|
||||
/* Stores the current used ptrace() options. */
|
||||
static int current_ptrace_options = 0;
|
||||
|
||||
/* The read/write ends of the pipe registered as waitable file in the
|
||||
event loop. */
|
||||
static int linux_nat_event_pipe[2] = { -1, -1 };
|
||||
|
@ -525,6 +537,43 @@ linux_test_for_tracefork (int original_pid)
|
|||
restore_child_signals_mask (&prev_mask);
|
||||
}
|
||||
|
||||
/* Determine if PTRACE_O_TRACESYSGOOD can be used to follow syscalls.
|
||||
|
||||
We try to enable syscall tracing on ORIGINAL_PID. If this fails,
|
||||
we know that the feature is not available. This may change the tracing
|
||||
options for ORIGINAL_PID, but we'll be setting them shortly anyway. */
|
||||
|
||||
static void
|
||||
linux_test_for_tracesysgood (int original_pid)
|
||||
{
|
||||
int ret;
|
||||
sigset_t prev_mask;
|
||||
|
||||
/* We don't want those ptrace calls to be interrupted. */
|
||||
block_child_signals (&prev_mask);
|
||||
|
||||
linux_supports_tracesysgood_flag = 0;
|
||||
|
||||
ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD);
|
||||
if (ret != 0)
|
||||
goto out;
|
||||
|
||||
linux_supports_tracesysgood_flag = 1;
|
||||
out:
|
||||
restore_child_signals_mask (&prev_mask);
|
||||
}
|
||||
|
||||
/* Determine wether we support PTRACE_O_TRACESYSGOOD option available.
|
||||
This function also sets linux_supports_tracesysgood_flag. */
|
||||
|
||||
static int
|
||||
linux_supports_tracesysgood (int pid)
|
||||
{
|
||||
if (linux_supports_tracesysgood_flag == -1)
|
||||
linux_test_for_tracesysgood (pid);
|
||||
return linux_supports_tracesysgood_flag;
|
||||
}
|
||||
|
||||
/* Return non-zero iff we have tracefork functionality available.
|
||||
This function also sets linux_supports_tracefork_flag. */
|
||||
|
||||
|
@ -544,12 +593,27 @@ linux_supports_tracevforkdone (int pid)
|
|||
return linux_supports_tracevforkdone_flag;
|
||||
}
|
||||
|
||||
static void
|
||||
linux_enable_tracesysgood (ptid_t ptid)
|
||||
{
|
||||
int pid = ptid_get_lwp (ptid);
|
||||
|
||||
if (pid == 0)
|
||||
pid = ptid_get_pid (ptid);
|
||||
|
||||
if (linux_supports_tracesysgood (pid) == 0)
|
||||
return;
|
||||
|
||||
current_ptrace_options |= PTRACE_O_TRACESYSGOOD;
|
||||
|
||||
ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
linux_enable_event_reporting (ptid_t ptid)
|
||||
{
|
||||
int pid = ptid_get_lwp (ptid);
|
||||
int options;
|
||||
|
||||
if (pid == 0)
|
||||
pid = ptid_get_pid (ptid);
|
||||
|
@ -557,15 +621,16 @@ linux_enable_event_reporting (ptid_t ptid)
|
|||
if (! linux_supports_tracefork (pid))
|
||||
return;
|
||||
|
||||
options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
|
||||
| PTRACE_O_TRACECLONE;
|
||||
current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
|
||||
| PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE;
|
||||
|
||||
if (linux_supports_tracevforkdone (pid))
|
||||
options |= PTRACE_O_TRACEVFORKDONE;
|
||||
current_ptrace_options |= PTRACE_O_TRACEVFORKDONE;
|
||||
|
||||
/* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
|
||||
read-only process state. */
|
||||
|
||||
ptrace (PTRACE_SETOPTIONS, pid, 0, options);
|
||||
ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -573,6 +638,7 @@ linux_child_post_attach (int pid)
|
|||
{
|
||||
linux_enable_event_reporting (pid_to_ptid (pid));
|
||||
check_for_thread_db ();
|
||||
linux_enable_tracesysgood (pid_to_ptid (pid));
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -580,6 +646,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
|
|||
{
|
||||
linux_enable_event_reporting (ptid);
|
||||
check_for_thread_db ();
|
||||
linux_enable_tracesysgood (ptid);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -810,6 +877,20 @@ linux_child_insert_exec_catchpoint (int pid)
|
|||
error (_("Your system does not support exec catchpoints."));
|
||||
}
|
||||
|
||||
static int
|
||||
linux_child_set_syscall_catchpoint (int pid, int needed, int any_count,
|
||||
int table_size, int *table)
|
||||
{
|
||||
if (! linux_supports_tracesysgood (pid))
|
||||
error (_("Your system does not support syscall catchpoints."));
|
||||
/* On GNU/Linux, we ignore the arguments. It means that we only
|
||||
enable the syscall catchpoints, but do not disable them.
|
||||
|
||||
Also, we do not use the `table' information because we do not
|
||||
filter system calls here. We let GDB do the logic for us. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
|
||||
are processes sharing the same VM space. A multi-threaded process
|
||||
is basically a group of such processes. However, such a grouping
|
||||
|
@ -1982,6 +2063,47 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/* Used for 'catch syscall' feature. */
|
||||
if (WSTOPSIG (status) == TRAP_IS_SYSCALL)
|
||||
{
|
||||
if (catch_syscall_enabled () == 0)
|
||||
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||
else
|
||||
{
|
||||
struct regcache *regcache = get_thread_regcache (lp->ptid);
|
||||
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||
|
||||
ourstatus->value.syscall_number =
|
||||
(int) gdbarch_get_syscall_number (gdbarch, lp->ptid);
|
||||
|
||||
/* If we are catching this specific syscall number, then we
|
||||
should update the target_status to reflect which event
|
||||
has occurred. But if this syscall is not to be caught,
|
||||
then we can safely mark the event as a SYSCALL_RETURN.
|
||||
|
||||
This is particularly needed if:
|
||||
|
||||
- We are catching any syscalls, or
|
||||
- We are catching the syscall "exit"
|
||||
|
||||
In this case, as the syscall "exit" *doesn't* return,
|
||||
then GDB would be confused because it would mark the last
|
||||
syscall event as a SYSCALL_ENTRY. After that, if we re-ran the
|
||||
inferior GDB will think that the first syscall event is
|
||||
the opposite of a SYSCALL_ENTRY, which is the SYSCALL_RETURN.
|
||||
Therefore, GDB would report inverted syscall events. */
|
||||
if (catching_syscall_number (ourstatus->value.syscall_number))
|
||||
ourstatus->kind =
|
||||
(lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ?
|
||||
TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY;
|
||||
else
|
||||
ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
|
||||
|
||||
lp->syscall_state = ourstatus->kind;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
internal_error (__FILE__, __LINE__,
|
||||
_("unknown ptrace event %d"), event);
|
||||
}
|
||||
|
@ -2580,11 +2702,16 @@ linux_nat_filter_event (int lwpid, int status, int options)
|
|||
}
|
||||
|
||||
/* Save the trap's siginfo in case we need it later. */
|
||||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
|
||||
if (WIFSTOPPED (status)
|
||||
&& (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == TRAP_IS_SYSCALL))
|
||||
save_siginfo (lp);
|
||||
|
||||
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
||||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
|
||||
/* Handle GNU/Linux's extended waitstatus for trace events.
|
||||
It is necessary to check if WSTOPSIG is signaling that
|
||||
the inferior is entering/exiting a system call. */
|
||||
if (WIFSTOPPED (status)
|
||||
&& ((WSTOPSIG (status) == TRAP_IS_SYSCALL)
|
||||
|| (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)))
|
||||
{
|
||||
if (debug_linux_nat)
|
||||
fprintf_unfiltered (gdb_stdlog,
|
||||
|
@ -4510,6 +4637,7 @@ linux_target_install_ops (struct target_ops *t)
|
|||
t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint;
|
||||
t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint;
|
||||
t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
|
||||
t->to_set_syscall_catchpoint = linux_child_set_syscall_catchpoint;
|
||||
t->to_pid_to_exec_file = linux_child_pid_to_exec_file;
|
||||
t->to_post_startup_inferior = linux_child_post_startup_inferior;
|
||||
t->to_post_attach = linux_child_post_attach;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue