* [PATCH 2/4] 'catch syscall' feature -- Architecture-dependent part
@ 2008-11-04 4:32 Sérgio Durigan Júnior
2008-11-04 16:18 ` Tom Tromey
2008-11-04 21:18 ` Eli Zaretskii
0 siblings, 2 replies; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2008-11-04 4:32 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 2060 bytes --]
This is the architecture dependent part of the patch. It adds support
for PPC, PPC64 and i386 archs.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
gdb/ChangeLog
2008-11-04 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* 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: Define the syscall's XML struct to hold
information about syscalls.
(init_sysinfo): New.
(i386_linux_get_syscall_number): New.
(i386_linux_syscall_name_from_number): New.
(i386_linux_syscall_number_from_name): New.
(i386_linux_get_syscalls_names): New.
(i386_linux_init_abi): Register the correct functions for
syscall catchpoint.
* 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_passed_by_entrypoint): New.
(linux_enable_event_reporting): Save the current used ptrace()
options.
(linux_child_post_startup_inferior): Create the entry breakpoint.
(linux_child_insert_syscall_catchpoint): New.
(linux_child_remove_syscall_catchpoint): New.
(linux_nat_create_inferior): Properly set the flag which indicates
if the inferior have already passed through its entrypoint.
(linux_handle_extended_wait): Handle the case which the inferior stops
because it has called or returned from a syscall.
(linux_nat_filter_event): Likewise.
(linux_target_install_ops): Install the necessary functions to handle
syscall catchpoints and entry breakpoints.
* ppc-linux-tdep.c: Define the syscall's XML struct to hold
information about syscalls.
(ppc_linux_get_syscall_number): New.
(init_sysinfo): New.
(ppc_linux_syscall_name_from_number): New.
(ppc_linux_syscall_number_from_name): New.
(ppc_linux_get_syscalls_names): New.
(ppc_linux_init_abi): Register the correct functions for
syscall catchpoint.
[-- Attachment #2: catch-syscall-arch-dep.patch --]
[-- Type: text/x-patch, Size: 16754 bytes --]
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 146f5a6..c634275 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -748,7 +748,13 @@ i386_linux_resume (ptid_t ptid, int step, enum target_signal signal)
{
int pid = PIDGET (ptid);
- int request = PTRACE_CONT;
+ int request;
+
+ if (target_passed_by_entrypoint () > 0
+ && catch_syscall_enabled () > 0)
+ request = PTRACE_SYSCALL;
+ else
+ request = PTRACE_CONT;
if (step)
{
diff --git a/gdb/i386-linux-tdep.c b/gdb/i386-linux-tdep.c
index 5284f4a..451ef86 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -36,6 +36,14 @@
#include "symtab.h"
#include "arch-utils.h"
#include "regset.h"
+#include "xml-syscall.h"
+
+/* Structure used to store information about the available syscalls in
+ the system. */
+static const struct syscalls_info *sysinfo = NULL;
+
+/* A flag to tell if we already initialized the structure above. */
+static int have_initialized_sysinfo = 0;
/* Supported register note sections. */
static struct core_regset_section i386_linux_regset_sections[] =
@@ -348,6 +356,72 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
}
\f
+/* Initializes the syscalls_info structure according to the
+ architecture. */
+static void
+init_sysinfo (void)
+{
+ /* Did we already try to initialize the structure? */
+ if (have_initialized_sysinfo)
+ return;
+
+ sysinfo = xml_init_syscalls_info ("syscalls/i386-syscalls.xml");
+
+ have_initialized_sysinfo = 1;
+
+ if (sysinfo == NULL)
+ /* The initialization failed. Let's show a warning
+ message to the user (just this time) and leave. */
+ warning (_("Could not load the syscall XML file.\n\
+GDB will not be able to display syscalls names."));
+}
+
+LONGEST
+i386_linux_get_syscall_number (struct gdbarch *gdbarch,
+ ptid_t ptid)
+{
+ struct regcache *regcache = get_thread_regcache (ptid);
+ /* The content of a register. */
+ gdb_byte buf[4];
+ /* The result. */
+ LONGEST ret;
+
+ /* Getting the system call number from the register.
+ When dealing with x86 architecture, this information
+ is stored at %eax register. */
+ regcache_cooked_read (regcache, I386_LINUX_ORIG_EAX_REGNUM, buf);
+
+ ret = extract_signed_integer (buf, 4);
+
+ return ret;
+}
+
+const char *
+i386_linux_syscall_name_from_number (struct gdbarch *gdbarch,
+ int syscall_number)
+{
+ init_sysinfo ();
+
+ return xml_get_syscall_name (sysinfo, syscall_number);
+}
+
+int
+i386_linux_syscall_number_from_name (struct gdbarch *gdbarch,
+ const char *syscall_name)
+{
+ init_sysinfo ();
+
+ return xml_get_syscall_number (sysinfo, syscall_name);
+}
+
+const char **
+i386_linux_get_syscalls_names (struct gdbarch *gdbarch)
+{
+ init_sysinfo ();
+
+ return xml_list_of_syscalls (sysinfo);
+}
+
/* The register sets used in GNU/Linux ELF core-dumps are identical to
the register sets in `struct user' that are used for a.out
core-dumps. These are also used by ptrace(2). The corresponding
@@ -469,6 +543,16 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
simple_displaced_step_free_closure);
set_gdbarch_displaced_step_location (gdbarch,
displaced_step_at_entry_point);
+
+ /* Functions for 'catch syscall'. */
+ set_gdbarch_get_syscall_number (gdbarch,
+ i386_linux_get_syscall_number);
+ set_gdbarch_syscall_name_from_number (gdbarch,
+ i386_linux_syscall_name_from_number);
+ set_gdbarch_syscall_number_from_name (gdbarch,
+ i386_linux_syscall_number_from_name);
+ set_gdbarch_get_syscalls_names (gdbarch,
+ i386_linux_get_syscalls_names);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 56ec9cb..a63ee8d 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -57,6 +57,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
@@ -269,17 +273,29 @@ 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. */
static int linux_supports_tracevforkdone_flag = -1;
+/* If the inferior have passed through its entrypoint (AT_ENTRY),
+ then this flag is set to 1. Otherwise, its value is 0. */
+static int linux_passed_by_entrypoint_flag = 0;
+
/* Async mode support */
/* Zero if the async mode, although enabled, is masked, which means
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 };
@@ -624,6 +640,41 @@ linux_test_for_tracefork (int original_pid)
linux_nat_async_events (async_events_original_state);
}
+/* 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;
+ enum sigchld_state async_events_original_state;
+
+ async_events_original_state = linux_nat_async_events (sigchld_sync);
+
+ linux_supports_tracesysgood_flag = 0;
+
+ ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD);
+ if (ret != 0)
+ return;
+
+ linux_supports_tracesysgood_flag = 1;
+ linux_nat_async_events (async_events_original_state);
+}
+
+/* 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. */
@@ -643,12 +694,34 @@ 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;
+ linux_passed_by_entrypoint_flag = 1;
+
+ ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
+}
+
+static int
+linux_passed_by_entrypoint (void)
+{
+ return linux_passed_by_entrypoint_flag;
+}
+
\f
void
linux_enable_event_reporting (ptid_t ptid)
{
int pid = ptid_get_lwp (ptid);
- int options;
if (pid == 0)
pid = ptid_get_pid (ptid);
@@ -656,15 +729,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
@@ -679,6 +753,12 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
+ /* We have to create the entry breakpoint here because
+ if we have 'catch syscall' enabled, we ought to know
+ when to enable PTRACE_O_TRACESYSGOOD. Otherwise, we would
+ start catching syscalls from ld.so/libc (which is not
+ what we want). */
+ create_entry_breakpoint ();
}
static int
@@ -905,6 +985,19 @@ linux_child_insert_exec_catchpoint (int pid)
error (_("Your system does not support exec catchpoints."));
}
+static void
+linux_child_insert_syscall_catchpoint (int pid)
+{
+ if (! linux_supports_tracesysgood (pid))
+ error (_("Your system does not support syscall catchpoints."));
+}
+
+static int
+linux_child_remove_syscall_catchpoint (int pid)
+{
+ 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
@@ -1325,6 +1418,9 @@ linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
int personality_orig = 0, personality_set = 0;
#endif /* HAVE_PERSONALITY */
+ /* We are sarting, so we still have not passed through our entrypoint. */
+ linux_passed_by_entrypoint_flag = 0;
+
/* The fork_child mechanism is synchronous and calls target_wait, so
we have to mask the async mode. */
@@ -1955,6 +2051,27 @@ 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);
+ struct thread_info *th_info = find_thread_pid (lp->ptid);
+
+ ourstatus->kind =
+ (th_info->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ?
+ TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY;
+ th_info->syscall_state = ourstatus->kind;
+ ourstatus->value.syscall_number =
+ (int) gdbarch_get_syscall_number (gdbarch, lp->ptid);
+ }
+ return 0;
+ }
+
internal_error (__FILE__, __LINE__,
_("unknown ptrace event %d"), event);
}
@@ -2565,11 +2682,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 a 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,
@@ -4022,6 +4144,8 @@ 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_insert_syscall_catchpoint = linux_child_insert_syscall_catchpoint;
+ t->to_remove_syscall_catchpoint = linux_child_remove_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;
@@ -4029,6 +4153,9 @@ linux_target_install_ops (struct target_ops *t)
t->to_find_memory_regions = linux_nat_find_memory_regions;
t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+ t->to_enable_tracesysgood = linux_enable_tracesysgood;
+ t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
+
super_xfer_partial = t->to_xfer_partial;
t->to_xfer_partial = linux_xfer_partial;
}
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index 2804857..9c620ec 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -38,6 +38,7 @@
#include "trad-frame.h"
#include "frame-unwind.h"
#include "tramp-frame.h"
+#include "xml-syscall.h"
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
@@ -48,6 +49,13 @@
#include "features/rs6000/powerpc-e500l.c"
+/* Structure used to store information about the available syscalls in
+ the system. */
+static const struct syscalls_info *sysinfo = NULL;
+
+/* A flag to tell if we already initialized the structure above. */
+static int have_initialized_sysinfo = 0;
+
/* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
in much the same fashion as memory_remove_breakpoint in mem-break.c,
but is careful not to write back the previous contents if the code
@@ -1003,6 +1011,88 @@ ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
&& register_size (gdbarch, PPC_TRAP_REGNUM) > 0;
}
+/* Return the current system call's number present in the
+ r0 register. When the function fails, it returns -1. */
+LONGEST
+ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
+ ptid_t ptid)
+{
+ struct regcache *regcache = get_thread_regcache (ptid);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* The content of a register */
+ gdb_byte *buf;
+ /* The result */
+ LONGEST ret;
+
+ /* Make sure we're in a 32- or 64-bit machine */
+ gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8);
+
+ buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte));
+
+ /* Getting the system call number from the register.
+ When dealing with PowerPC architecture, this information
+ is stored at 0th register. */
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf);
+
+ ret = extract_signed_integer (buf, tdep->wordsize);
+ xfree (buf);
+
+ return ret;
+}
+
+/* Initializes the syscalls_info structure according to the
+ architecture. */
+static void
+init_sysinfo (struct gdbarch *gdbarch)
+{
+ struct gdbarch_tdep *tdep;
+
+ /* Did we already try to initialize the structure? */
+ if (have_initialized_sysinfo)
+ return;
+
+ tdep = gdbarch_tdep (gdbarch);
+
+ if (tdep->wordsize == 4)
+ sysinfo = xml_init_syscalls_info ("syscalls/ppc-syscalls.xml");
+ else
+ sysinfo = xml_init_syscalls_info ("syscalls/ppc64-syscalls.xml");
+
+ have_initialized_sysinfo = 1;
+
+ if (sysinfo == NULL)
+ /* The initialization failed. Let's show a warning
+ message to the user (just this time) and leave. */
+ warning (_("Could not load the syscall XML file.\n\
+GDB will not be able to display syscalls names."));
+}
+
+const char *
+ppc_linux_syscall_name_from_number (struct gdbarch *gdbarch,
+ int syscall_number)
+{
+ init_sysinfo (gdbarch);
+
+ return xml_get_syscall_name (sysinfo, syscall_number);
+}
+
+int
+ppc_linux_syscall_number_from_name (struct gdbarch *gdbarch,
+ const char *syscall_name)
+{
+ init_sysinfo (gdbarch);
+
+ return xml_get_syscall_number (sysinfo, syscall_name);
+}
+
+const char **
+ppc_linux_get_syscalls_names (struct gdbarch *gdbarch)
+{
+ init_sysinfo (gdbarch);
+
+ return xml_list_of_syscalls (sysinfo);
+}
+
static void
ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
@@ -1074,6 +1164,11 @@ ppc_linux_init_abi (struct gdbarch_info info,
/* Handle inferior calls during interrupted system calls. */
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
+ set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+ set_gdbarch_syscall_name_from_number (gdbarch, ppc_linux_syscall_name_from_number);
+ set_gdbarch_syscall_number_from_name (gdbarch, ppc_linux_syscall_number_from_name);
+ set_gdbarch_get_syscalls_names (gdbarch, ppc_linux_get_syscalls_names);
+
if (tdep->wordsize == 4)
{
/* Until November 2001, gcc did not comply with the 32 bit SysV
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/4] 'catch syscall' feature -- Architecture-dependent part
2008-11-04 4:32 [PATCH 2/4] 'catch syscall' feature -- Architecture-dependent part Sérgio Durigan Júnior
@ 2008-11-04 16:18 ` Tom Tromey
2008-11-04 16:50 ` Sérgio Durigan Júnior
2008-11-04 21:18 ` Eli Zaretskii
1 sibling, 1 reply; 6+ messages in thread
From: Tom Tromey @ 2008-11-04 16:18 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: gdb-patches
>>>>> "Sérgio" == Sérgio Durigan Júnior <sergiodj@linux.vnet.ibm.com> writes:
Sérgio> * i386-linux-tdep.c: Define the syscall's XML struct to hold
Sérgio> information about syscalls.
Sérgio> (init_sysinfo): New.
There is some code duplication between this and ppc-linux-tdep.c.
It seems to me that much of the Linux code will be shared by all
ports. So, I think the duplicated stuff should go in linux-nat.c.
Sérgio> (i386_linux_get_syscall_number): New.
Sérgio> (i386_linux_syscall_name_from_number): New.
Sérgio> (i386_linux_syscall_number_from_name): New.
Sérgio> (i386_linux_get_syscalls_names): New.
In the current patch, these could all be static. Aside from
i386_linux_get_syscall_number, perhaps they ought to be shared in
linux-nat.c though. The same applies for the equivalent PPC functions.
Sérgio> +/* Return the current system call's number present in the
Sérgio> + r0 register. When the function fails, it returns -1. */
Sérgio> +LONGEST
Sérgio> +ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
Sérgio> + ptid_t ptid)
Sérgio> +{
[...]
Sérgio> + buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte));
I suspect you need a cleanup here, rather than an explicit xfree. I
am not sure. If regcache_cooked_read can call error, then you need
one.
Tom
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/4] 'catch syscall' feature -- Architecture-dependent part
2008-11-04 16:18 ` Tom Tromey
@ 2008-11-04 16:50 ` Sérgio Durigan Júnior
0 siblings, 0 replies; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2008-11-04 16:50 UTC (permalink / raw)
To: tromey; +Cc: gdb-patches
Hi Tom,
On Tue, 2008-11-04 at 09:15 -0700, Tom Tromey wrote:
> >>>>> "Sérgio" == Sérgio Durigan Júnior <sergiodj@linux.vnet.ibm.com> writes:
>
> Sérgio> * i386-linux-tdep.c: Define the syscall's XML struct to hold
> Sérgio> information about syscalls.
> Sérgio> (init_sysinfo): New.
>
> There is some code duplication between this and ppc-linux-tdep.c.
> It seems to me that much of the Linux code will be shared by all
> ports. So, I think the duplicated stuff should go in linux-nat.c.
Thank you so much for this comment! I was aware of this replication, but
I still wasn't able to figure out a way to solve this. Now it looks so
obvious! I'll put the common functions in linux-nat.c :-).
> Sérgio> (i386_linux_get_syscall_number): New.
> Sérgio> (i386_linux_syscall_name_from_number): New.
> Sérgio> (i386_linux_syscall_number_from_name): New.
> Sérgio> (i386_linux_get_syscalls_names): New.
>
> In the current patch, these could all be static. Aside from
> i386_linux_get_syscall_number, perhaps they ought to be shared in
> linux-nat.c though. The same applies for the equivalent PPC functions.
Right, I'll do it for both. But I have a question. Depending on the
architecture, I must pick the correct XML file to open and parse. That's
why I've put these functions in separate files. So, do you have a clue
on how to solve this?
> Sérgio> +/* Return the current system call's number present in the
> Sérgio> + r0 register. When the function fails, it returns -1. */
> Sérgio> +LONGEST
> Sérgio> +ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
> Sérgio> + ptid_t ptid)
> Sérgio> +{
> [...]
> Sérgio> + buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte));
>
> I suspect you need a cleanup here, rather than an explicit xfree. I
> am not sure. If regcache_cooked_read can call error, then you need
> one.
Good point. I'll do that. Thanks.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/4] 'catch syscall' feature -- Architecture-dependent part
2008-11-04 4:32 [PATCH 2/4] 'catch syscall' feature -- Architecture-dependent part Sérgio Durigan Júnior
2008-11-04 16:18 ` Tom Tromey
@ 2008-11-04 21:18 ` Eli Zaretskii
1 sibling, 0 replies; 6+ messages in thread
From: Eli Zaretskii @ 2008-11-04 21:18 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: gdb-patches
> From: =?ISO-8859-1?Q?S=E9rgio?= Durigan =?ISO-8859-1?Q?J=FAnior?= <sergiodj@linux.vnet.ibm.com>
> Date: Tue, 04 Nov 2008 02:31:24 -0200
>
> This is the architecture dependent part of the patch. It adds support
> for PPC, PPC64 and i386 archs.
Thanks.
> + warning (_("Could not load the syscall XML file.\n\
I suggest to include the name of the file in the error message. That
might help the user to locate that file and overcome the problem.
Without the name, she is down to "strings | grep -i xml".
> +GDB will not be able to display syscalls names."));
^^^^^^^^^^^^^^
"syscall names".
(There's one more instance of this in the patches.)
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 2/4] catch syscall' feature -- Architecture-dependent part
2008-09-30 18:13 [PATCH 2/4] catch " Sérgio Durigan Júnior
@ 2008-10-06 19:14 ` Sérgio Durigan Júnior
0 siblings, 0 replies; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2008-10-06 19:14 UTC (permalink / raw)
To: gdb-patches
On Tue, 2008-09-30 at 15:13 -0300, Sérgio Durigan Júnior wrote:
> This is the architecture-dependent part of the patch.
>
> Because of that problem in PPC64 (see message 0/4), probably I'll have
> to edit this patch to make sure that the architecture supports syscall
> catchpoints. IMO, this can be done checking the
> 'gdbarch_get_syscall_number_p'. I think I'll let this modification to
> the second review of this patch :-).
FYI, the problem with PPC64 is already fixed in this patch. I have now
run the regression test and everything seems ok. So if this part of the
patch is accepted, there will be no problems in PowerPC 64-bit.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 2/4] catch syscall' feature -- Architecture-dependent part
@ 2008-09-30 18:13 Sérgio Durigan Júnior
2008-10-06 19:14 ` Sérgio Durigan Júnior
0 siblings, 1 reply; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2008-09-30 18:13 UTC (permalink / raw)
To: gdb-patches
This is the architecture-dependent part of the patch.
Because of that problem in PPC64 (see message 0/4), probably I'll have
to edit this patch to make sure that the architecture supports syscall
catchpoints. IMO, this can be done checking the
'gdbarch_get_syscall_number_p'. I think I'll let this modification to
the second review of this patch :-).
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
2008-09-29 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* 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_passed_by_entrypoint): New.
(linux_enable_event_reporting): Save the current used ptrace()
options.
(linux_child_post_startup_inferior): Create the entry breakpoint.
(linux_child_insert_syscall_catchpoint): New.
(linux_child_remove_syscall_catchpoint): New.
(linux_nat_create_inferior): Properly setting the flag which indicates
if the inferior have already passed through its entrypoint.
(linux_handle_extended_wait): Handle the case which the inferior stops
because it has called or returned from a syscall.
(linux_nat_filter_event): Likewise.
(linux_target_install_ops): Install the necessary functions to handle
syscall catchpoints and entry breakpoints.
* ppc-linux-tdep.c: Define the syscalls names for both PPC and PPC64.
(ppc_linux_get_syscall_number): New.
(ppc_linux_syscall_name_from_number): New.
(ppc64_linux_syscall_name_from_number): New.
(ppc_linux_syscall_number_from_name): New.
(ppc64_linux_syscall_number_from_name): New.
(ppc_linux_init_abi): Set the correct functions for syscall
catchpoint.
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index a0dc634..67ef708 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -57,6 +57,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
@@ -269,17 +273,29 @@ 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. */
static int linux_supports_tracevforkdone_flag = -1;
+/* If the inferior have passed through its entrypoint (AT_ENTRY),
+ then this flag is set to 1. Otherwise, its value is 0. */
+static int linux_passed_by_entrypoint_flag = 0;
+
/* Async mode support */
/* Zero if the async mode, although enabled, is masked, which means
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 };
@@ -609,6 +625,41 @@ linux_test_for_tracefork (int original_pid)
linux_nat_async_events (async_events_original_state);
}
+/* 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;
+ enum sigchld_state async_events_original_state;
+
+ async_events_original_state = linux_nat_async_events (sigchld_sync);
+
+ linux_supports_tracesysgood_flag = 0;
+
+ ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD);
+ if (ret != 0)
+ return;
+
+ linux_supports_tracesysgood_flag = 1;
+ linux_nat_async_events (async_events_original_state);
+}
+
+/* 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. */
@@ -628,12 +679,34 @@ 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;
+ linux_passed_by_entrypoint_flag = 1;
+
+ ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
+}
+
+static int
+linux_passed_by_entrypoint (void)
+{
+ return linux_passed_by_entrypoint_flag;
+}
+
\f
void
linux_enable_event_reporting (ptid_t ptid)
{
int pid = ptid_get_lwp (ptid);
- int options;
if (pid == 0)
pid = ptid_get_pid (ptid);
@@ -641,15 +714,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
@@ -664,6 +738,12 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
+ /* We have to create the entry breakpoint here because
+ if we have 'catch syscall' enabled, we ought to know
+ when to enable PTRACE_O_TRACESYSGOOD. Otherwise, we would
+ start catching syscalls from ld.so/libc (which is not
+ what we want). */
+ create_entry_breakpoint ();
}
static int
@@ -890,6 +970,19 @@ linux_child_insert_exec_catchpoint (int pid)
error (_("Your system does not support exec catchpoints."));
}
+static void
+linux_child_insert_syscall_catchpoint (int pid)
+{
+ if (! linux_supports_tracesysgood (pid))
+ error (_("Your system does not support syscall catchpoints."));
+}
+
+static int
+linux_child_remove_syscall_catchpoint (int pid)
+{
+ 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
@@ -1310,6 +1403,9 @@ linux_nat_create_inferior (char *exec_file, char *allargs, char **env,
int personality_orig = 0, personality_set = 0;
#endif /* HAVE_PERSONALITY */
+ /* We are sarting, so we still have not passed through our entrypoint. */
+ linux_passed_by_entrypoint_flag = 0;
+
/* The fork_child mechanism is synchronous and calls target_wait, so
we have to mask the async mode. */
@@ -1940,6 +2036,27 @@ 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);
+ struct thread_info *th_info = find_thread_pid (lp->ptid);
+
+ ourstatus->kind =
+ (th_info->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ?
+ TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY;
+ th_info->syscall_state = ourstatus->kind;
+ ourstatus->value.syscall_number =
+ (int) gdbarch_get_syscall_number (gdbarch, lp->ptid);
+ }
+ return 0;
+ }
+
internal_error (__FILE__, __LINE__,
_("unknown ptrace event %d"), event);
}
@@ -2550,11 +2667,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 a 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,
@@ -4000,6 +4122,8 @@ 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_insert_syscall_catchpoint = linux_child_insert_syscall_catchpoint;
+ t->to_remove_syscall_catchpoint = linux_child_remove_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;
@@ -4007,6 +4131,9 @@ linux_target_install_ops (struct target_ops *t)
t->to_find_memory_regions = linux_nat_find_memory_regions;
t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+ t->to_enable_tracesysgood = linux_enable_tracesysgood;
+ t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
+
super_xfer_partial = t->to_xfer_partial;
t->to_xfer_partial = linux_xfer_partial;
}
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index 2804857..f46b753 100644
--- a/gdb/ppc-linux-tdep.c
+++ b/gdb/ppc-linux-tdep.c
@@ -47,6 +47,142 @@
#include "features/rs6000/powerpc-vsx64l.c"
#include "features/rs6000/powerpc-e500l.c"
+/* Total number of syscalls */
+#define N_SYSCALLS 301
+
+/* Syscalls names for PPC 32-bit */
+static const char *syscalls_names[] = {
+ "restart_syscall", "exit", "fork", "read",
+ "write", "open", "close", "waitpid", "creat",
+ "link", "unlink", "execve", "chdir", "time",
+ "mknod", "chmod", "lchown", "break", "oldstat",
+ "lseek", "getpid", "mount", "umount", "setuid",
+ "getuid", "stime", "ptrace", "alarm", "oldfstat",
+ "pause", "utime", "stty", "gtty", "access", "nice",
+ "ftime", "sync", "kill", "rename", "mkdir", "rmdir",
+ "dup", "pipe", "times", "prof", "brk", "setgid",
+ "getgid", "signal", "geteuid", "getegid", "acct",
+ "umount2", "lock", "ioctl", "fcntl", "mpx", "setpgid",
+ "ulimit", "oldolduname", "umask", "chroot", "ustat",
+ "dup2", "getppid", "getpgrp", "setsid", "sigaction",
+ "sgetmask", "ssetmask", "setreuid", "setregid",
+ "sigsuspend", "sigpending", "sethostname", "setrlimit",
+ "getrlimit", "getrusage", "gettimeofday", "settimeofday",
+ "getgroups", "setgroups", "select", "symlink", "oldlstat",
+ "readlink", "uselib", "swapon", "reboot", "readdir",
+ "mmap", "munmap", "truncate", "ftruncate", "fchmod",
+ "fchown", "getpriority", "setpriority", "profil",
+ "statfs", "fstatfs", "ioperm", "socketcall", "syslog",
+ "setitimer", "getitimer", "stat", "lstat", "fstat",
+ "olduname", "iopl", "vhangup", "idle", "vm86", "wait4",
+ "swapoff", "sysinfo", "ipc", "fsync", "sigreturn",
+ "clone", "setdomainname", "uname", "modify_ldt",
+ "adjtimex", "mprotect", "sigprocmask", "create_module",
+ "init_module", "delete_module", "get_kernel_syms",
+ "quotactl", "getpgid", "fchdir", "bdflush", "sysfs",
+ "personality", "afs_syscall", "setfsuid", "setfsgid",
+ "_llseek", "getdents", "_newselect", "flock", "msync",
+ "readv", "writev", "getsid", "fdatasync", "_sysctl",
+ "mlock", "munlock", "mlockall", "munlockall",
+ "sched_setparam", "sched_getparam", "sched_setscheduler",
+ "sched_getscheduler", "sched_yield",
+ "sched_get_priority_max", "sched_get_priority_min",
+ "sched_rr_get_interval", "nanosleep", "mremap",
+ "setresuid", "getresuid", "query_module", "poll",
+ "nfsservctl", "setresgid", "getresgid", "prctl",
+ "rt_sigreturn", "rt_sigaction", "rt_sigprocmask",
+ "rt_sigpending", "rt_sigtimedwait", "rt_sigqueueinfo",
+ "rt_sigsuspend", "pread64", "pwrite64", "chown",
+ "getcwd", "capget", "capset", "sigaltstack", "sendfile",
+ "getpmsg", "putpmsg", "vfork", "ugetrlimit", "readahead",
+ "mmap2", "truncate64", "ftruncate64", "stat64", "lstat64",
+ "fstat64", "pciconfig_read", "pciconfig_write",
+ "pciconfig_iobase", "multiplexer", "getdents64",
+ "pivot_root", "fcntl64", "madvise", "mincore", "gettid",
+ "tkill", "setxattr", "lsetxattr", "fsetxattr",
+ "getxattr", "lgetxattr", "fgetxattr", "listxattr",
+ "llistxattr", "flistxattr", "removexattr", "lremovexattr",
+ "fremovexattr", "futex", "sched_setaffinity",
+ "sched_getaffinity", "", "tuxcall", "sendfile64",
+ "io_setup", "io_destroy", "io_getevents", "io_submit",
+ "io_cancel", "set_tid_address", "fadvise64", "exit_group",
+ "lookup_dcookie", "epoll_create", "epoll_ctl",
+ "epoll_wait", "remap_file_pages", "timer_create",
+ "timer_settime", "timer_gettime", "timer_getoverrun",
+ "timer_delete", "clock_settime", "clock_gettime",
+ "clock_getres", "clock_nanosleep", "swapcontext",
+ "tgkill", "utimes", "statfs64", "fstatfs64", "fadvise64_64",
+ "rtas", "sys_debug_setcontext", "", "", "mbind",
+ "get_mempolicy", "set_mempolicy", "mq_open", "mq_unlink",
+ "mq_timedsend", "mq_timedreceive", "mq_notify",
+ "mq_getsetattr", "kexec_load", "add_key", "request_key",
+ "keyctl", "waitid", "ioprio_set", "ioprio_get",
+ "inotify_init", "inotify_add_watch", "inotify_rm_watch",
+ "spu_run", "spu_create", "pselect6", "ppoll", "unshare",
+ "", "", "", "openat", "mkdirat", "mknodat", "fchownat",
+ "futimesat", "fstatat64", "unlinkat", "renameat",
+ "linkat", "symlinkat", "readlinkat", "fchmodat",
+ "faccessat", "", ""
+};
+
+/* Syscalls names for PPC 64-bit */
+static const char *syscalls_names64[] = {
+ "restart_syscall", "exit", "fork", "read", "write", "open",
+ "close", "waitpid", "creat", "link", "unlink", "execve",
+ "chdir", "time", "mknod", "chmod", "lchown", "break", "oldstat",
+ "lseek", "getpid", "mount", "umount", "setuid", "getuid", "stime",
+ "ptrace", "alarm", "oldfstat", "pause", "utime", "stty", "gtty",
+ "access", "nice", "ftime", "sync", "kill", "rename", "mkdir",
+ "rmdir", "dup", "pipe", "times", "prof", "brk", "setgid",
+ "getgid", "signal", "geteuid", "getegid", "acct", "umount2",
+ "lock", "ioctl", "fcntl", "mpx", "setpgid", "ulimit",
+ "oldolduname", "umask", "chroot", "ustat", "dup2", "getppid",
+ "getpgrp", "setsid", "sigaction", "sgetmask", "ssetmask",
+ "setreuid", "setregid", "sigsuspend", "sigpending", "sethostname",
+ "setrlimit", "getrlimit", "getrusage", "gettimeofday", "settimeofday",
+ "getgroups", "setgroups", "select", "symlink", "oldlstat",
+ "readlink", "uselib", "swapon", "reboot", "readdir", "mmap",
+ "munmap", "truncate", "ftruncate", "fchmod", "fchown", "getpriority",
+ "setpriority", "profil", "statfs", "fstatfs", "ioperm", "socketcall",
+ "syslog", "setitimer", "getitimer", "stat", "lstat", "fstat",
+ "olduname", "iopl", "vhangup", "idle", "vm86", "wait4", "swapoff",
+ "sysinfo", "ipc", "fsync", "sigreturn", "clone", "setdomainname",
+ "uname", "modify_ldt", "adjtimex", "mprotect", "sigprocmask",
+ "create_module", "init_module", "delete_module", "get_kernel_syms",
+ "quotactl", "getpgid", "fchdir", "bdflush", "sysfs", "personality",
+ "afs_syscall", "setfsuid", "setfsgid", "_llseek", "getdents",
+ "_newselect", "flock", "msync", "readv", "writev", "getsid",
+ "fdatasync", "_sysctl", "mlock", "munlock", "mlockall",
+ "munlockall", "sched_setparam", "sched_getparam", "sched_setscheduler",
+ "sched_getscheduler", "sched_yield", "sched_get_priority_max",
+ "sched_get_priority_min", "sched_rr_get_interval", "nanosleep",
+ "mremap", "setresuid", "getresuid", "query_module", "poll",
+ "nfsservctl", "setresgid", "getresgid", "prctl", "rt_sigreturn",
+ "rt_sigaction", "rt_sigprocmask", "rt_sigpending", "rt_sigtimedwait",
+ "rt_sigqueueinfo", "rt_sigsuspend", "pread64", "pwrite64", "chown",
+ "getcwd", "capget", "capset", "sigaltstack", "sendfile", "getpmsg",
+ "putpmsg", "vfork", "ugetrlimit", "readahead", "", "", "", "", "", "",
+ "pciconfig_read", "pciconfig_write", "pciconfig_iobase", "multiplexer",
+ "getdents64", "pivot_root", "", "madvise", "mincore", "gettid", "tkill",
+ "setxattr", "lsetxattr", "fsetxattr", "getxattr", "lgetxattr", "fgetxattr",
+ "listxattr", "llistxattr", "flistxattr", "removexattr", "lremovexattr",
+ "fremovexattr", "futex", "sched_setaffinity", "sched_getaffinity",
+ "", "tuxcall", "", "io_setup", "io_destroy", "io_getevents", "io_submit",
+ "io_cancel", "set_tid_address", "fadvise64", "exit_group", "lookup_dcookie",
+ "epoll_create", "epoll_ctl", "epoll_wait", "remap_file_pages",
+ "timer_create", "timer_settime", "timer_gettime", "timer_getoverrun",
+ "timer_delete", "clock_settime", "clock_gettime", "clock_getres",
+ "clock_nanosleep", "swapcontext", "tgkill", "utimes", "statfs64",
+ "fstatfs64", "", "rtas", "sys_debug_setcontext", "", "", "mbind",
+ "get_mempolicy", "set_mempolicy", "mq_open", "mq_unlink", "mq_timedsend",
+ "mq_timedreceive", "mq_notify", "mq_getsetattr", "kexec_load", "add_key",
+ "request_key", "keyctl", "waitid", "ioprio_set", "ioprio_get",
+ "inotify_init", "inotify_add_watch", "inotify_rm_watch", "spu_run",
+ "spu_create", "pselect6", "ppoll", "unshare", "", "", "",
+ "openat", "mkdirat", "mknodat", "fchownat", "futimesat", "newfstatat",
+ "unlinkat", "renameat", "linkat", "symlinkat", "readlinkat",
+ "fchmodat", "faccessat", "", ""
+};
/* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
in much the same fashion as memory_remove_breakpoint in mem-break.c,
@@ -1003,6 +1139,83 @@ ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
&& register_size (gdbarch, PPC_TRAP_REGNUM) > 0;
}
+/* Return the current system call's number present in the
+ r0 register. When the function fails, it returns -1. */
+LONGEST
+ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
+ ptid_t ptid)
+{
+ struct regcache *regcache = get_thread_regcache (ptid);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* The content of a register */
+ gdb_byte *buf;
+ /* The result */
+ LONGEST ret;
+
+ /* Make sure we're in a 32- or 64-bit machine */
+ gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8);
+
+ buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte));
+
+ /* Getting the system call number from the register.
+ When dealing with PowerPC architecture, this information
+ is stored at 0th register. */
+ regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf);
+
+ ret = extract_signed_integer (buf, tdep->wordsize);
+ xfree (buf);
+
+ return ret;
+}
+
+const char *
+ppc_linux_syscall_name_from_number (struct gdbarch *gdbarch,
+ int syscall_number)
+{
+ if (syscall_number < 0
+ || syscall_number >= N_SYSCALLS)
+ return NULL;
+
+ return syscalls_names[syscall_number];
+}
+
+const char *
+ppc64_linux_syscall_name_from_number (struct gdbarch *gdbarch,
+ int syscall_number)
+{
+ if (syscall_number < 0
+ || syscall_number >= N_SYSCALLS)
+ return NULL;
+
+ return syscalls_names64[syscall_number];
+}
+
+int
+ppc_linux_syscall_number_from_name (struct gdbarch *gdbarch,
+ const char *syscall_name)
+{
+ int i;
+
+ for (i = 0; i < N_SYSCALLS; i++)
+ if (strcmp (syscall_name, syscalls_names[i]) == 0)
+ return i;
+
+ return UNKNOWN_SYSCALL;
+}
+
+int
+ppc64_linux_syscall_number_from_name (struct gdbarch *gdbarch,
+ const char *syscall_name)
+{
+ int i;
+
+ for (i = 0; i < N_SYSCALLS; i++)
+ if (strcmp (syscall_name, syscalls_names64[i]) == 0)
+ return i;
+
+ return UNKNOWN_SYSCALL;
+}
+
static void
ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
@@ -1074,8 +1287,13 @@ ppc_linux_init_abi (struct gdbarch_info info,
/* Handle inferior calls during interrupted system calls. */
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
+ set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+
if (tdep->wordsize == 4)
{
+ set_gdbarch_syscall_name_from_number (gdbarch, ppc_linux_syscall_name_from_number);
+ set_gdbarch_syscall_number_from_name (gdbarch, ppc_linux_syscall_number_from_name);
+
/* Until November 2001, gcc did not comply with the 32 bit SysV
R4 ABI requirement that structures less than or equal to 8
bytes should be returned in registers. Instead GCC was using
@@ -1100,6 +1318,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
if (tdep->wordsize == 8)
{
+ set_gdbarch_syscall_name_from_number (gdbarch, ppc64_linux_syscall_name_from_number);
+ set_gdbarch_syscall_number_from_name (gdbarch, ppc64_linux_syscall_number_from_name);
+
/* Handle PPC GNU/Linux 64-bit function pointers (which are really
function descriptors). */
set_gdbarch_convert_from_func_ptr_addr
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2008-11-04 21:18 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2008-11-04 4:32 [PATCH 2/4] 'catch syscall' feature -- Architecture-dependent part Sérgio Durigan Júnior
2008-11-04 16:18 ` Tom Tromey
2008-11-04 16:50 ` Sérgio Durigan Júnior
2008-11-04 21:18 ` Eli Zaretskii
-- strict thread matches above, loose matches on Subject: below --
2008-09-30 18:13 [PATCH 2/4] catch " Sérgio Durigan Júnior
2008-10-06 19:14 ` Sérgio Durigan Júnior
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox