* [PATCH 1/3] catch syscall -- try 5 -- Source code modifications
@ 2009-04-23 0:34 Sérgio Durigan Júnior
2009-04-25 9:27 ` Eli Zaretskii
0 siblings, 1 reply; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2009-04-23 0:34 UTC (permalink / raw)
To: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 4331 bytes --]
Here goes the source-code modifications.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
gdb/ChangeLog:
2009-04-22 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* breakpoint.c: New include: xml-syscall.h.
(set_raw_breakpoint_without_location): Setting the parameters
for the catch syscall feature.
(any_syscall_count, syscalls_counts,
total_syscalls_count): New variables to keep track of requested
syscall catchpoints.
(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.
* 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_target_install_ops): Setting the default methods.
(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.
[-- Attachment #2: catch-syscall-source-code-mod.patch --]
[-- Type: text/x-patch, Size: 55291 bytes --]
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index cf0c5a1..c390ede 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -58,6 +58,7 @@
#include "top.h"
#include "wrapper.h"
#include "valprint.h"
+#include "xml-syscall.h"
/* readline include files */
#include "readline/readline.h"
@@ -199,6 +200,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
static void insert_breakpoint_locations (void);
+static int syscall_catchpoint_p (struct breakpoint *b);
+
static void tracepoints_info (char *, int);
static void delete_trace_command (char *, int);
@@ -4274,6 +4277,7 @@ set_raw_breakpoint_without_location (enum bptype bptype)
b->frame_id = null_frame_id;
b->forked_inferior_pid = null_ptid;
b->exec_pathname = NULL;
+ b->syscalls_to_be_caught = NULL;
b->ops = NULL;
b->condition_not_parsed = 0;
@@ -4797,7 +4801,265 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
print_mention_catch_vfork
};
-/* Create a new breakpoint of the bp_catchpoint kind and return it.
+/* We keep a count of the number of times the user has requested a
+ particular syscall to be tracked, and pass this information to the
+ target. This lets capable targets implement filtering directly. */
+
+/* Number of times that "any" syscall is requested. */
+static int any_syscall_count;
+
+/* Count of each system call. */
+VEC(int) *syscalls_counts;
+
+/* This counts all syscall catch requests, so we can readily determine
+ if any catching is necessary. */
+static int total_syscalls_count;
+
+/* Implement the "insert" breakpoint_ops method for syscall
+ catchpoints. */
+
+static void
+insert_catch_syscall (struct breakpoint *b)
+{
+ ++total_syscalls_count;
+ if (!b->syscalls_to_be_caught)
+ ++any_syscall_count;
+ else
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ int elem;
+ if (iter >= VEC_length (int, syscalls_counts))
+ {
+ int old_size = VEC_length (int, syscalls_counts);
+ uintptr_t vec_addr_offset = old_size * ((uintptr_t) sizeof (int));
+ uintptr_t vec_addr;
+ VEC_safe_grow (int, syscalls_counts, iter + 1);
+ vec_addr = (uintptr_t) VEC_address (int, syscalls_counts) + vec_addr_offset;
+ memset ((void *) vec_addr, 0,
+ (iter + 1 - old_size) * sizeof (int));
+ }
+ elem = VEC_index (int, syscalls_counts, iter);
+ VEC_replace (int, syscalls_counts, iter, ++elem);
+ }
+ }
+
+ target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ VEC_length (int, syscalls_counts),
+ VEC_address (int, syscalls_counts));
+}
+
+/* Implement the "remove" breakpoint_ops method for syscall
+ catchpoints. */
+
+static int
+remove_catch_syscall (struct breakpoint *b)
+{
+ --total_syscalls_count;
+ if (!b->syscalls_to_be_caught)
+ --any_syscall_count;
+ else
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ int elem;
+ if (iter >= VEC_length (int, syscalls_counts))
+ {
+ /* Shouldn't happen. */
+ continue;
+ }
+ elem = VEC_index (int, syscalls_counts, iter);
+ VEC_replace (int, syscalls_counts, iter, --elem);
+ }
+ }
+
+ return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ VEC_length (int, syscalls_counts),
+ VEC_address (int, syscalls_counts));
+}
+
+/* Implement the "breakpoint_hit" breakpoint_ops method for syscall
+ catchpoints. */
+
+static int
+breakpoint_hit_catch_syscall (struct breakpoint *b)
+{
+ /* We must check if we are catching specific syscalls in this breakpoint.
+ If we are, then we must guarantee that the called syscall is the same
+ syscall we are catching. */
+ int syscall_number = 0;
+
+ if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
+ return 0;
+
+ /* Now, checking if the syscall is the same. */
+ if (b->syscalls_to_be_caught)
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ if (syscall_number == iter)
+ break;
+ /* Not the same. */
+ if (!iter)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Implement the "print_it" breakpoint_ops method for syscall
+ catchpoints. */
+
+static enum print_stop_action
+print_it_catch_syscall (struct breakpoint *b)
+{
+ /* These are needed because we want to know in which state a
+ syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
+ or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
+ must print "called syscall" or "returned from syscall". */
+ ptid_t ptid;
+ struct target_waitstatus last;
+ struct syscall s;
+ struct cleanup *old_chain;
+ char *syscall_id;
+
+ get_last_target_status (&ptid, &last);
+
+ get_syscall_by_number (last.value.syscall_number, &s);
+
+ annotate_catchpoint (b->number);
+
+ if (s.name == NULL)
+ syscall_id = xstrprintf ("%d", last.value.syscall_number);
+ else
+ syscall_id = xstrprintf ("'%s'", s.name);
+
+ old_chain = make_cleanup (xfree, syscall_id);
+
+ if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
+ printf_filtered (_("\nCatchpoint %d (call to syscall %s), "),
+ b->number, syscall_id);
+ else if (last.kind == TARGET_WAITKIND_SYSCALL_RETURN)
+ printf_filtered (_("\nCatchpoint %d (returned from syscall %s), "),
+ b->number, syscall_id);
+
+ do_cleanups (old_chain);
+
+ return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for syscall
+ catchpoints. */
+
+static void
+print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr)
+{
+ struct value_print_options opts;
+
+ get_user_print_options (&opts);
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (opts.addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ ui_out_text (uiout, "syscall(s) \"");
+ if (b->syscalls_to_be_caught)
+ {
+ int i, iter;
+ char *text = xstrprintf ("%s", "");
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ char *x = text;
+ struct syscall s;
+ get_syscall_by_number (iter, &s);
+
+ if (s.name != NULL)
+ text = xstrprintf ("%s%s, ", text, s.name);
+ else
+ text = xstrprintf ("%s%d, ", text, iter);
+
+ /* We have to xfree the last 'text' (now stored at 'x')
+ because xstrprintf dinamically allocates new space for it
+ on every call. */
+ xfree (x);
+ }
+ /* Remove the last comma. */
+ text[strlen (text) - 2] = '\0';
+ ui_out_field_string (uiout, "what", text);
+ }
+ else
+ ui_out_field_string (uiout, "what", "<any syscall>");
+ ui_out_text (uiout, "\" ");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for syscall
+ catchpoints. */
+
+static void
+print_mention_catch_syscall (struct breakpoint *b)
+{
+ if (b->syscalls_to_be_caught)
+ {
+ int i, iter;
+ printf_filtered (_("Catchpoint %d (syscall(s)"), b->number);
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ struct syscall s;
+ get_syscall_by_number (iter, &s);
+
+ if (s.name)
+ printf_filtered (" '%s'", s.name);
+ else
+ printf_filtered (" %d", iter);
+ }
+ printf_filtered (")");
+ }
+ else
+ printf_filtered (_("Catchpoint %d (any syscall)"),
+ b->number);
+}
+
+/* The breakpoint_ops structure to be used in syscall catchpoints. */
+
+static struct breakpoint_ops catch_syscall_breakpoint_ops =
+{
+ insert_catch_syscall,
+ remove_catch_syscall,
+ breakpoint_hit_catch_syscall,
+ print_it_catch_syscall,
+ print_one_catch_syscall,
+ print_mention_catch_syscall
+};
+
+/* Returns non-zero if 'b' is a syscall catchpoint. */
+
+static int
+syscall_catchpoint_p (struct breakpoint *b)
+{
+ return (b->ops == &catch_syscall_breakpoint_ops);
+}
+
+/* Create a new breakpoint of the bp_catchpoint kind and return it,
+ but does NOT mention it nor update the global location list.
+ This is useful if you need to fill more fields in the
+ struct breakpoint before calling mention.
If TEMPFLAG is non-zero, then make the breakpoint temporary.
If COND_STRING is not NULL, then store it in the breakpoint.
@@ -4805,16 +5067,13 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
to the catchpoint. */
static struct breakpoint *
-create_catchpoint (int tempflag, char *cond_string,
- struct breakpoint_ops *ops)
+create_catchpoint_without_mention (int tempflag, char *cond_string,
+ struct breakpoint_ops *ops)
{
struct symtab_and_line sal;
struct breakpoint *b;
init_sal (&sal);
- sal.pc = 0;
- sal.symtab = NULL;
- sal.line = 0;
b = set_raw_breakpoint (sal, bp_catchpoint);
set_breakpoint_count (breakpoint_count + 1);
@@ -4828,6 +5087,23 @@ create_catchpoint (int tempflag, char *cond_string,
b->disposition = tempflag ? disp_del : disp_donttouch;
b->ops = ops;
+ return b;
+}
+
+/* Create a new breakpoint of the bp_catchpoint kind and return it.
+
+ If TEMPFLAG is non-zero, then make the breakpoint temporary.
+ If COND_STRING is not NULL, then store it in the breakpoint.
+ OPS, if not NULL, is the breakpoint_ops structure associated
+ to the catchpoint. */
+
+static struct breakpoint *
+create_catchpoint (int tempflag, char *cond_string,
+ struct breakpoint_ops *ops)
+{
+ struct breakpoint *b =
+ create_catchpoint_without_mention (tempflag, cond_string, ops);
+
mention (b);
update_global_location_list (1);
@@ -4912,6 +5188,21 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
print_mention_catch_exec
};
+static void
+create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
+ struct breakpoint_ops *ops)
+{
+ struct breakpoint *b =
+ create_catchpoint_without_mention (tempflag, NULL, ops);
+
+ b->syscalls_to_be_caught = filter;
+
+ /* Now, we have to mention the breakpoint and update the global
+ location list. */
+ mention (b);
+ update_global_location_list (1);
+}
+
static int
hw_breakpoint_used_count (void)
{
@@ -6836,6 +7127,112 @@ catch_ada_exception_command (char *arg, int from_tty,
from_tty);
}
+/* Cleanup function for a syscall filter list. */
+static void
+clean_up_filters (void *arg)
+{
+ VEC(int) *iter = *(VEC(int) **) arg;
+ VEC_free (int, iter);
+}
+
+/* Splits the argument using space as delimiter. Returns an xmalloc'd
+ filter list, or NULL if no filtering is required. */
+static VEC(int) *
+catch_syscall_split_args (char *arg)
+{
+ VEC(int) *result = NULL;
+ struct cleanup *cleanup = make_cleanup (clean_up_filters, &result);
+
+ while (*arg != '\0')
+ {
+ int i, syscall_number;
+ char *endptr;
+ char cur_name[128];
+ struct syscall s;
+
+ /* Skip whitespace. */
+ while (isspace (*arg))
+ arg++;
+
+ for (i = 0; arg[i] && !isspace (arg[i]); ++i)
+ cur_name[i] = arg[i];
+ cur_name[i] = '\0';
+ arg += i;
+
+ /* Check if the user provided a syscall name or a number. */
+ syscall_number = (int) strtol (cur_name, &endptr, 10);
+ if (*endptr == '\0')
+ {
+ get_syscall_by_number (syscall_number, &s);
+
+ if (s.name == NULL)
+ /* We can issue just a warning, but still create the catchpoint.
+ This is because, even not knowing the syscall name that
+ this number represents, we can still try to catch the syscall
+ number. */
+ warning (_("The number '%d' does not represent a known syscall."),
+ syscall_number);
+ }
+ else
+ {
+ /* We have a name. Let's check if it's valid and convert it
+ to a number. */
+ get_syscall_by_name (cur_name, &s);
+
+ if (s.number == UNKNOWN_SYSCALL)
+ /* Here we have to issue an error instead of a warning, because
+ GDB cannot do anything useful if there's no syscall number to
+ be caught. */
+ error (_("Unknown syscall name '%s'."), cur_name);
+ }
+
+ /* Ok, it's valid. */
+ VEC_safe_push (int, result, s.number);
+ }
+
+ discard_cleanups (cleanup);
+ return result;
+}
+
+/* Implement the "catch syscall" command. */
+
+static void
+catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
+{
+ int tempflag;
+ VEC(int) *filter;
+ struct syscall s;
+
+ /* Checking if the feature if supported. */
+ if (gdbarch_get_syscall_number_p (current_gdbarch) == 0)
+ error (_("The feature 'catch syscall' is not supported on \
+this architeture yet."));
+
+ tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+ ep_skip_leading_whitespace (&arg);
+
+ /* We need to do this first "dummy" translation in order
+ to get the syscall XML file loaded or, most important,
+ to display a warning to the user if there's no XML file
+ for his/her architecture. */
+ get_syscall_by_number (0, &s);
+
+ /* The allowed syntax is:
+ catch syscall
+ catch syscall <name | number> [<name | number> ... <name | number>]
+
+ Let's check if there's a syscall name. */
+
+ if (arg != NULL)
+ filter = catch_syscall_split_args (arg);
+ else
+ filter = NULL;
+
+ create_syscall_event_catchpoint (tempflag, filter,
+ &catch_syscall_breakpoint_ops);
+}
+
/* Implement the "catch assert" command. */
static void
@@ -7302,6 +7699,7 @@ delete_breakpoint (struct breakpoint *bpt)
xfree (bpt->source_file);
if (bpt->exec_pathname != NULL)
xfree (bpt->exec_pathname);
+ clean_up_filters (&bpt->syscalls_to_be_caught);
/* Be sure no bpstat's are pointing at it after it's been freed. */
/* FIXME, how can we find all bpstat's?
@@ -8215,6 +8613,58 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
return 0;
}
+/* Returns 0 if 'bp' is NOT a syscall catchpoint,
+ non-zero otherwise. */
+static int
+is_syscall_catchpoint_enabled (struct breakpoint *bp)
+{
+ if (syscall_catchpoint_p (bp)
+ && bp->enable_state != bp_disabled
+ && bp->enable_state != bp_call_disabled)
+ return 1;
+ else
+ return 0;
+}
+
+int
+catch_syscall_enabled (void)
+{
+ return total_syscalls_count != 0;
+}
+
+int
+catching_syscall_number (int syscall_number)
+{
+ struct breakpoint *bp;
+
+ ALL_BREAKPOINTS (bp)
+ if (is_syscall_catchpoint_enabled (bp))
+ {
+ if (bp->syscalls_to_be_caught)
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, bp->syscalls_to_be_caught, i, iter);
+ i++)
+ if (syscall_number == iter)
+ return 1;
+ }
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Complete syscall names. Used by "catch syscall". */
+static char **
+catch_syscall_completer (struct cmd_list_element *cmd,
+ char *text, char *word)
+{
+ const char **list = get_syscall_names ();
+ return (list == NULL) ? NULL : complete_on_enum (list, text, word);
+}
+
/* Tracepoint-specific operations. */
/* Set tracepoint count to NUM. */
@@ -8565,6 +9015,8 @@ static void
add_catch_command (char *name, char *docstring,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element *command),
+ char **(*completer) (struct cmd_list_element *cmd,
+ char *text, char *word),
void *user_data_catch,
void *user_data_tcatch)
{
@@ -8574,11 +9026,13 @@ add_catch_command (char *name, char *docstring,
&catch_cmdlist);
set_cmd_sfunc (command, sfunc);
set_cmd_context (command, user_data_catch);
+ set_cmd_completer (command, completer);
command = add_cmd (name, class_breakpoint, NULL, docstring,
&tcatch_cmdlist);
set_cmd_sfunc (command, sfunc);
set_cmd_context (command, user_data_tcatch);
+ set_cmd_completer (command, completer);
}
void
@@ -8855,36 +9309,50 @@ Set temporary catchpoints to catch events."),
Catch an exception, when caught.\n\
With an argument, catch only exceptions with the given name."),
catch_catch_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("throw", _("\
Catch an exception, when thrown.\n\
With an argument, catch only exceptions with the given name."),
catch_throw_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("fork", _("Catch calls to fork."),
catch_fork_command_1,
+ NULL,
(void *) (uintptr_t) catch_fork_permanent,
(void *) (uintptr_t) catch_fork_temporary);
add_catch_command ("vfork", _("Catch calls to vfork."),
catch_fork_command_1,
+ NULL,
(void *) (uintptr_t) catch_vfork_permanent,
(void *) (uintptr_t) catch_vfork_temporary);
add_catch_command ("exec", _("Catch calls to exec."),
catch_exec_command_1,
+ NULL,
+ CATCH_PERMANENT,
+ CATCH_TEMPORARY);
+ add_catch_command ("syscall", _("\
+Catch system calls.\n\
+With an argument, catch only that syscall."),
+ catch_syscall_command_1,
+ catch_syscall_completer,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("exception", _("\
Catch Ada exceptions, when raised.\n\
With an argument, catch only exceptions with the given name."),
catch_ada_exception_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("assert", _("\
Catch failed Ada assertions, when raised.\n\
With an argument, catch only exceptions with the given name."),
catch_assert_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 17b2761..42ded0a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -33,7 +33,8 @@ struct block;
#define BREAKPOINT_MAX 16
\f
-/* Type of breakpoint. */
+
+/* Type of breakpoint. */
/* FIXME In the future, we should fold all other breakpoint-like things into
here. This includes:
@@ -339,6 +340,9 @@ enum watchpoint_triggered
watch_triggered_yes
};
+/* This is used to declare the VEC syscalls_to_be_caught. */
+DEF_VEC_I(int);
+
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);
@@ -447,6 +451,12 @@ struct breakpoint
triggered. */
char *exec_pathname;
+ /* Syscall numbers used for the 'catch syscall' feature.
+ If no syscall has been specified for filtering, its value is NULL.
+ Otherwise, it holds a list of all syscalls to be caught.
+ The list elements are allocated with xmalloc. */
+ VEC(int) *syscalls_to_be_caught;
+
/* Methods associated with this breakpoint. */
struct breakpoint_ops *ops;
@@ -873,6 +883,15 @@ extern int breakpoints_always_inserted_mode (void);
in our opinion won't ever trigger. */
extern void breakpoint_retire_moribund (void);
+/* Checks if we are catching syscalls or not.
+ Returns 0 if not, greater than 0 if we are. */
+extern int catch_syscall_enabled (void);
+
+/* Checks if we are catching syscalls with the specific
+ syscall_number. Used for "filtering" the catchpoints.
+ Returns 0 if not, greater than 0 if we are. */
+extern int catching_syscall_number (int syscall_number);
+
/* Tell a breakpoint to be quiet. */
extern void make_breakpoint_silent (struct breakpoint *);
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 3273b34..80987d1 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -243,6 +243,7 @@ struct gdbarch
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
gdbarch_record_special_symbol_ftype *record_special_symbol;
+ gdbarch_get_syscall_number_ftype *get_syscall_number;
int has_global_solist;
};
@@ -378,6 +379,7 @@ struct gdbarch startup_gdbarch =
default_target_signal_to_host, /* target_signal_to_host */
0, /* get_siginfo_type */
0, /* record_special_symbol */
+ 0, /* get_syscall_number */
0, /* has_global_solist */
/* startup_gdbarch() */
};
@@ -634,6 +636,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of get_siginfo_type, has predicate */
/* Skip verify of record_special_symbol, has predicate */
+ /* Skip verify of get_syscall_number, has predicate */
/* Skip verify of has_global_solist, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
@@ -859,6 +862,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: get_siginfo_type = <%s>\n",
host_address_to_string (gdbarch->get_siginfo_type));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_number_p() = %d\n",
+ gdbarch_get_syscall_number_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_number = <%s>\n",
+ host_address_to_string (gdbarch->get_syscall_number));
+ fprintf_unfiltered (file,
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
@@ -3333,6 +3342,30 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch,
}
int
+gdbarch_get_syscall_number_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_number != NULL;
+}
+
+LONGEST
+gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_number != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_number called\n");
+ return gdbarch->get_syscall_number (gdbarch, ptid);
+}
+
+void
+set_gdbarch_get_syscall_number (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_number_ftype get_syscall_number)
+{
+ gdbarch->get_syscall_number = get_syscall_number;
+}
+
+int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 04c8920..ffbfe10 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -52,6 +52,7 @@ struct bp_target_info;
struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
+struct syscall;
extern struct gdbarch *current_gdbarch;
extern struct gdbarch *target_gdbarch;
@@ -839,6 +840,15 @@ typedef void (gdbarch_record_special_symbol_ftype) (struct gdbarch *gdbarch, str
extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym);
extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol);
+/* Function for the 'catch syscall' feature.
+ Get architecture-specific system calls information from registers. */
+
+extern int gdbarch_get_syscall_number_p (struct gdbarch *gdbarch);
+
+typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, ptid_t ptid);
+extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid);
+extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number);
+
/* True if the list of shared libraries is one and only for all
processes, as opposed to a list of shared libraries per inferior.
When this property is true, GDB assumes that since shared libraries
@@ -848,6 +858,9 @@ extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_
extern int gdbarch_has_global_solist (struct gdbarch *gdbarch);
extern void set_gdbarch_has_global_solist (struct gdbarch *gdbarch, int has_global_solist);
+/* Definition for an unknown syscall, used basically in error-cases. */
+#define UNKNOWN_SYSCALL (-1)
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index f93bfc1..55844a6 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -724,6 +724,11 @@ M:struct type *:get_siginfo_type:void:
# Record architecture-specific information from the symbol table.
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+# Function for the 'catch syscall' feature.
+
+# Get architecture-specific system calls information from registers.
+M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+
# True if the list of shared libraries is one and only for all
# processes, as opposed to a list of shared libraries per inferior.
# When this property is true, GDB assumes that since shared libraries
@@ -842,6 +847,7 @@ struct bp_target_info;
struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
+struct syscall;
extern struct gdbarch *current_gdbarch;
extern struct gdbarch *target_gdbarch;
@@ -911,6 +917,9 @@ done
# close it off
cat <<EOF
+/* Definition for an unknown syscall, used basically in error-cases. */
+#define UNKNOWN_SYSCALL (-1)
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 2366474..687eccd 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -751,7 +751,12 @@ i386_linux_resume (struct target_ops *ops,
{
int pid = PIDGET (ptid);
- int request = PTRACE_CONT;
+ int request;
+
+ if (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 1a2e4f0..4a421ee 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -37,6 +37,10 @@
#include "symtab.h"
#include "arch-utils.h"
#include "regset.h"
+#include "xml-syscall.h"
+
+/* The syscall's XML filename for i386. */
+#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml"
/* Supported register note sections. */
static struct core_regset_section i386_linux_regset_sections[] =
@@ -349,6 +353,26 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
}
\f
+static 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;
+}
+
/* 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
@@ -471,6 +495,11 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_displaced_step_location (gdbarch,
displaced_step_at_entry_point);
+ /* Functions for 'catch syscall'. */
+ set_xml_syscall_file_name (XML_SYSCALL_FILENAME_I386);
+ set_gdbarch_get_syscall_number (gdbarch,
+ i386_linux_get_syscall_number);
+
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
}
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index 38311f1..fc968cf 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -148,6 +148,15 @@ inf_child_remove_exec_catchpoint (int pid)
}
static int
+inf_child_set_syscall_catchpoint (int pid, int needed, int any_count,
+ int table_size, int *table)
+{
+ /* This version of Unix doesn't support notification of syscall
+ events. */
+ return 0;
+}
+
+static int
inf_child_can_run (void)
{
return 1;
@@ -190,6 +199,7 @@ inf_child_target (void)
t->to_follow_fork = inf_child_follow_fork;
t->to_insert_exec_catchpoint = inf_child_insert_exec_catchpoint;
t->to_remove_exec_catchpoint = inf_child_remove_exec_catchpoint;
+ t->to_set_syscall_catchpoint = inf_child_set_syscall_catchpoint;
t->to_can_run = inf_child_can_run;
t->to_pid_to_exec_file = inf_child_pid_to_exec_file;
t->to_stratum = process_stratum;
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index f088ffd..186b419 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -356,13 +356,18 @@ inf_ptrace_resume (struct target_ops *ops,
ptid_t ptid, int step, enum target_signal signal)
{
pid_t pid = ptid_get_pid (ptid);
- int request = PT_CONTINUE;
+ int request;
if (pid == -1)
/* Resume all threads. Traditionally ptrace() only supports
single-threaded processes, so simply resume the inferior. */
pid = ptid_get_pid (inferior_ptid);
+ if (catch_syscall_enabled () > 0)
+ request = PT_SYSCALL;
+ else
+ request = PT_CONTINUE;
+
if (step)
{
/* If this system does not support PT_STEP, a higher level
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b9fba6f..4059bd5 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1058,7 +1058,7 @@ a command like `return' or `jump' to continue execution."));
if (step)
step = maybe_software_singlestep (gdbarch, pc);
- /* If there were any forks/vforks/execs that were caught and are
+ /* If there were any forks/vforks/execs/syscalls that were caught and are
now to be followed, then do so. */
switch (pending_follow.kind)
{
@@ -1081,6 +1081,11 @@ a command like `return' or `jump' to continue execution."));
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
break;
+ case TARGET_WAITKIND_SYSCALL_ENTRY:
+ case TARGET_WAITKIND_SYSCALL_RETURN:
+ pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+ break;
+
default:
break;
}
@@ -1522,7 +1527,7 @@ init_wait_for_inferior (void)
breakpoint_init_inferior (inf_starting);
- /* The first resume is not following a fork/vfork/exec. */
+ /* The first resume is not following a fork/vfork/exec/syscall. */
pending_follow.kind = TARGET_WAITKIND_SPURIOUS; /* I.e., none. */
clear_proceed_status ();
@@ -1866,6 +1871,10 @@ wait_for_inferior (int treat_exec_as_sigtrap)
state. */
old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+ if (ecs->ws.kind == TARGET_WAITKIND_SYSCALL_ENTRY
+ || ecs->ws.kind == TARGET_WAITKIND_SYSCALL_RETURN)
+ ecs->ws.value.syscall_number = UNKNOWN_SYSCALL;
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
@@ -2177,6 +2186,55 @@ ensure_not_running (void)
error_is_running ();
}
+/* Auxiliary function that handles syscall entry/return events.
+ It returns 1 if the inferior should keep going (and GDB
+ should ignore the event), or 0 if the event deserves to be
+ processed. */
+static int
+deal_with_syscall_event (struct execution_control_state *ecs)
+{
+ int syscall_number = gdbarch_get_syscall_number (current_gdbarch,
+ ecs->ptid);
+ target_last_waitstatus.value.syscall_number = syscall_number;
+
+ if (catch_syscall_enabled () > 0
+ && catching_syscall_number (syscall_number) > 0)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
+ syscall_number);
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
+ pending_follow.kind = ecs->ws.kind;
+
+ if (!ptid_equal (ecs->ptid, inferior_ptid))
+ {
+ context_switch (ecs->ptid);
+ reinit_frame_cache ();
+ }
+
+ stop_pc = read_pc ();
+
+ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+
+ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
+
+ /* If no catchpoint triggered for this, then keep going. */
+ if (ecs->random_signal)
+ {
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+ keep_going (ecs);
+ return 1;
+ }
+ return 0;
+ }
+ else
+ {
+ resume (0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return 1;
+ }
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
appropriate action. */
@@ -2471,9 +2529,11 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_SYSCALL_ENTRY:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
- resume (0, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
+ /* Getting the current syscall number */
+ if (deal_with_syscall_event (ecs) != 0)
+ return;
+ goto process_event_stop_test;
+ break;
/* Before examining the threads further, step this thread to
get it entirely out of the syscall. (We get notice of the
@@ -2483,9 +2543,10 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_SYSCALL_RETURN:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
- target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
+ if (deal_with_syscall_event (ecs) != 0)
+ return;
+ goto process_event_stop_test;
+ break;
case TARGET_WAITKIND_STOPPED:
if (debug_infrun)
@@ -5206,6 +5267,25 @@ inferior_has_execd (ptid_t pid, char **execd_pathname)
return 1;
}
+int
+inferior_has_called_syscall (ptid_t pid, int *syscall_number)
+{
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ get_last_target_status (&last_ptid, &last);
+
+ if (last.kind != TARGET_WAITKIND_SYSCALL_ENTRY &&
+ last.kind != TARGET_WAITKIND_SYSCALL_RETURN)
+ return 0;
+
+ if (!ptid_equal (last_ptid, pid))
+ return 0;
+
+ *syscall_number = last.value.syscall_number;
+ return 1;
+}
+
/* Oft used ptids */
ptid_t null_ptid;
ptid_t minus_one_ptid;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 0679173..b0b8818 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -61,6 +61,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
@@ -281,6 +285,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. */
@@ -292,6 +301,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 };
@@ -636,6 +648,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. */
@@ -655,12 +702,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);
+}
+
\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);
@@ -668,15 +730,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
@@ -684,6 +747,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
@@ -691,6 +755,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
+ linux_enable_tracesysgood (ptid);
}
static int
@@ -931,6 +996,16 @@ 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."));
+ /* We ignore the arguments. */
+ 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
@@ -1996,6 +2071,39 @@ 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 caught,
+ then we can safely mark the event as a SYSCALL_RETURN.
+
+ This is needed so that GDB doesn't get confused when
+ the program is re-run'ed and no syscalls were caught
+ in the first run. */
+ 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);
}
@@ -2606,11 +2714,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,
@@ -4265,6 +4378,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;
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index fec5139..36d2439 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -70,6 +70,13 @@ 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
+ in a SYSCALL_RETURN event.
+ Values:
+ - TARGET_WAITKIND_SYSCALL_ENTRY
+ - TARGET_WAITKIND_SYSCALL_RETURN */
+ int syscall_state;
+
/* Next LWP in list. */
struct lwp_info *next;
};
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index d08d4fc..b9d0275 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"
@@ -53,6 +54,9 @@
#include "features/rs6000/powerpc-isa205-vsx64l.c"
#include "features/rs6000/powerpc-e500l.c"
+/* The syscall's XML filename for PPC and PPC64. */
+#define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml"
+#define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml"
/* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
in much the same fashion as memory_remove_breakpoint in mem-break.c,
@@ -1009,6 +1013,38 @@ 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. */
+static 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);
+ struct cleanup *cleanbuf;
+ /* 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));
+
+ cleanbuf = make_cleanup (xfree, buf);
+
+ /* 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);
+ do_cleanups (cleanbuf);
+
+ return ret;
+}
+
static void
ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
@@ -1080,6 +1116,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
/* Handle inferior calls during interrupted system calls. */
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
+ /* Get the syscall number from the arch's register. */
+ set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+
if (tdep->wordsize == 4)
{
/* Until November 2001, gcc did not comply with the 32 bit SysV
@@ -1099,6 +1138,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
+ /* Setting the correct XML syscall filename. */
+ set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
+
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
@@ -1116,6 +1158,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_lp64_fetch_link_map_offsets);
+ /* Setting the correct XML syscall filename. */
+ set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
+
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
diff --git a/gdb/target.c b/gdb/target.c
index f7366f8..85ff352 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -459,6 +459,7 @@ update_current_target (void)
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
+ INHERIT (to_set_syscall_catchpoint, t);
INHERIT (to_has_exited, t);
/* Do not inherit to_mourn_inferiour. */
INHERIT (to_can_run, t);
@@ -602,6 +603,9 @@ update_current_target (void)
de_fault (to_remove_exec_catchpoint,
(int (*) (int))
tcomplain);
+ de_fault (to_set_syscall_catchpoint,
+ (int (*) (int, int, int, int, int *))
+ tcomplain);
de_fault (to_has_exited,
(int (*) (int, int, int *))
return_zero);
@@ -2696,9 +2700,9 @@ target_waitstatus_to_string (const struct target_waitstatus *ws)
case TARGET_WAITKIND_EXECD:
return xstrprintf ("%sexecd", kind_str);
case TARGET_WAITKIND_SYSCALL_ENTRY:
- return xstrprintf ("%ssyscall-entry", kind_str);
+ return xstrprintf ("%sentered syscall", kind_str);
case TARGET_WAITKIND_SYSCALL_RETURN:
- return xstrprintf ("%ssyscall-return", kind_str);
+ return xstrprintf ("%sexited syscall", kind_str);
case TARGET_WAITKIND_SPURIOUS:
return xstrprintf ("%sspurious", kind_str);
case TARGET_WAITKIND_IGNORE:
diff --git a/gdb/target.h b/gdb/target.h
index e7f087b..5044bcf 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -140,18 +140,34 @@ struct target_waitstatus
{
enum target_waitkind kind;
- /* Forked child pid, execd pathname, exit status or signal number. */
+ /* Forked child pid, execd pathname, exit status, signal number or
+ syscall number. */
union
{
int integer;
enum target_signal sig;
ptid_t related_pid;
char *execd_pathname;
- int syscall_id;
+ int syscall_number;
}
value;
};
+/* The structure below stores information about a system call.
+ It is basically used in the "catch syscall" command, and in
+ every function that gives information about a system call.
+
+ It's also good to mention that its fields represent everything
+ that we currently know about a syscall in GDB. */
+struct syscall
+ {
+ /* The syscall number. */
+ int number;
+
+ /* The syscall name. */
+ const char *name;
+ };
+
/* Return a pretty printed form of target_waitstatus.
Space for the result is malloc'd, caller must free. */
extern char *target_waitstatus_to_string (const struct target_waitstatus *);
@@ -392,6 +408,7 @@ struct target_ops
int (*to_follow_fork) (struct target_ops *, int);
void (*to_insert_exec_catchpoint) (int);
int (*to_remove_exec_catchpoint) (int);
+ int (*to_set_syscall_catchpoint) (int, int, int, int, int *);
int (*to_has_exited) (int, int, int *);
void (*to_mourn_inferior) (struct target_ops *);
int (*to_can_run) (void);
@@ -723,6 +740,8 @@ extern int inferior_has_vforked (ptid_t pid, ptid_t *child_pid);
extern int inferior_has_execd (ptid_t pid, char **execd_pathname);
+extern int inferior_has_called_syscall (ptid_t pid, int *syscall_number);
+
/* From exec.c */
extern void print_section_info (struct target_ops *, bfd *);
@@ -880,6 +899,17 @@ int target_follow_fork (int follow_child);
#define target_remove_exec_catchpoint(pid) \
(*current_target.to_remove_exec_catchpoint) (pid)
+/* Syscall catch. NEEDED is nonzero if any syscall catch (of any
+ kind) is requested. ANY_COUNT is nonzero if a generic
+ (filter-less) syscall catch is being requested. TABLE is an array
+ of ints, indexed by syscall number. An element in this array is
+ nonzero if that syscall should be caught. TABLE_SIZE is the number
+ of elements in TABLE. */
+
+#define target_set_syscall_catchpoint(pid, needed, any_count, table_size, table) \
+ (*current_target.to_set_syscall_catchpoint) (pid, needed, any_count, \
+ table_size, table)
+
/* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the
exit code of PID, if any. */
diff --git a/gdb/xml-support.c b/gdb/xml-support.c
index 937c6c3..ad20d3b 100644
--- a/gdb/xml-support.c
+++ b/gdb/xml-support.c
@@ -1036,6 +1036,66 @@ obstack_xml_printf (struct obstack *obstack, const char *format, ...)
va_end (ap);
}
+char *
+xml_fetch_content_from_file (const char *filename, void *baton)
+{
+ const char *dirname = baton;
+ FILE *file;
+ struct cleanup *back_to;
+ char *text;
+ size_t len, offset;
+
+ if (dirname && *dirname)
+ {
+ char *fullname = concat (dirname, "/", filename, (char *) NULL);
+ if (fullname == NULL)
+ nomem (0);
+ file = fopen (fullname, FOPEN_RT);
+ xfree (fullname);
+ }
+ else
+ file = fopen (filename, FOPEN_RT);
+
+ if (file == NULL)
+ return NULL;
+
+ back_to = make_cleanup_fclose (file);
+
+ /* Read in the whole file, one chunk at a time. */
+ len = 4096;
+ offset = 0;
+ text = xmalloc (len);
+ make_cleanup (free_current_contents, &text);
+ while (1)
+ {
+ size_t bytes_read;
+
+ /* Continue reading where the last read left off. Leave at least
+ one byte so that we can NUL-terminate the result. */
+ bytes_read = fread (text + offset, 1, len - offset - 1, file);
+ if (ferror (file))
+ {
+ warning (_("Read error from \"%s\""), filename);
+ do_cleanups (back_to);
+ return NULL;
+ }
+
+ offset += bytes_read;
+
+ if (feof (file))
+ break;
+
+ len = len * 2;
+ text = xrealloc (text, len);
+ }
+
+ fclose (file);
+ discard_cleanups (back_to);
+
+ text[offset] = '\0';
+ return text;
+}
+
void _initialize_xml_support (void);
void
diff --git a/gdb/xml-support.h b/gdb/xml-support.h
index d6105f7..135263d 100644
--- a/gdb/xml-support.h
+++ b/gdb/xml-support.h
@@ -240,4 +240,10 @@ extern void obstack_xml_printf (struct obstack *obstack,
const char *format, ...)
ATTRIBUTE_PRINTF_2;
+/* Open FILENAME, read all its text into memory, close it, and return
+ the text. If something goes wrong, return NULL and warn. */
+
+extern char *xml_fetch_content_from_file (const char *filename,
+ void *baton);
+
#endif
diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
index 1d4e12c..8038dbd 100644
--- a/gdb/xml-tdesc.c
+++ b/gdb/xml-tdesc.c
@@ -421,69 +421,6 @@ tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
#endif /* HAVE_LIBEXPAT */
\f
-/* Open FILENAME, read all its text into memory, close it, and return
- the text. If something goes wrong, return NULL and warn. */
-
-static char *
-fetch_xml_from_file (const char *filename, void *baton)
-{
- const char *dirname = baton;
- FILE *file;
- struct cleanup *back_to;
- char *text;
- size_t len, offset;
-
- if (dirname && *dirname)
- {
- char *fullname = concat (dirname, "/", filename, (char *) NULL);
- if (fullname == NULL)
- nomem (0);
- file = fopen (fullname, FOPEN_RT);
- xfree (fullname);
- }
- else
- file = fopen (filename, FOPEN_RT);
-
- if (file == NULL)
- return NULL;
-
- back_to = make_cleanup_fclose (file);
-
- /* Read in the whole file, one chunk at a time. */
- len = 4096;
- offset = 0;
- text = xmalloc (len);
- make_cleanup (free_current_contents, &text);
- while (1)
- {
- size_t bytes_read;
-
- /* Continue reading where the last read left off. Leave at least
- one byte so that we can NUL-terminate the result. */
- bytes_read = fread (text + offset, 1, len - offset - 1, file);
- if (ferror (file))
- {
- warning (_("Read error from \"%s\""), filename);
- do_cleanups (back_to);
- return NULL;
- }
-
- offset += bytes_read;
-
- if (feof (file))
- break;
-
- len = len * 2;
- text = xrealloc (text, len);
- }
-
- fclose (file);
- discard_cleanups (back_to);
-
- text[offset] = '\0';
- return text;
-}
-
/* Read an XML target description from FILENAME. Parse it, and return
the parsed description. */
@@ -495,7 +432,7 @@ file_read_description_xml (const char *filename)
struct cleanup *back_to;
char *dirname;
- tdesc_str = fetch_xml_from_file (filename, NULL);
+ tdesc_str = xml_fetch_content_from_file (filename, NULL);
if (tdesc_str == NULL)
{
warning (_("Could not open \"%s\""), filename);
@@ -508,7 +445,7 @@ file_read_description_xml (const char *filename)
if (dirname != NULL)
make_cleanup (xfree, dirname);
- tdesc = tdesc_parse_xml (tdesc_str, fetch_xml_from_file, dirname);
+ tdesc = tdesc_parse_xml (tdesc_str, xml_fetch_content_from_file, dirname);
do_cleanups (back_to);
return tdesc;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] catch syscall -- try 5 -- Source code modifications
2009-04-23 0:34 [PATCH 1/3] catch syscall -- try 5 -- Source code modifications Sérgio Durigan Júnior
@ 2009-04-25 9:27 ` Eli Zaretskii
2009-04-26 21:31 ` Sérgio Durigan Júnior
0 siblings, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2009-04-25 9:27 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: Wed, 22 Apr 2009 21:33:03 -0300
>
> Here goes the source-code modifications.
Thanks. I have a few minor comments:
> (any_syscall_count, syscalls_counts,
> total_syscalls_count): New variables to keep track of requested
> syscall catchpoints.
The GNU Coding Standards specify the following formatting of log
entries with long lists that don't fit on a single line:
(any_syscall_count, syscalls_counts)
(total_syscalls_count): New variables to keep track of requested
syscall catchpoints.
IOW, close the parens and re-open them on the next line.
> +/* We keep a count of the number of times the user has requested a
> + particular syscall to be tracked, and pass this information to the
> + target. This lets capable targets implement filtering directly. */
Could you please expand the last sentence in this comment? What kind
of filtering we are talking here about? I'm worried that someone who
might be willing to implement such filtering on a ``capable target''
won't understand how to go about that.
> + add_catch_command ("syscall", _("\
> +Catch system calls.\n\
> +With an argument, catch only that syscall."),
I think we should tell in the doc string of this command something
about the format of the argument(s).
> + /* 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 caught,
^^^^^^^^^^^^^
"not to be caught"
> + This is needed so that GDB doesn't get confused when
> + the program is re-run'ed and no syscalls were caught
> + in the first run. */
I think "re-ran" is better than "re-run'ed". More importantly, I
don't understand why GDB would be confused by this sequence of events,
so perhaps you could expand the comment.
> + /* Handle GNU/Linux's extended waitstatus for trace events.
> + It is necessary to check if WSTOPSIG is signaling a that
^
This "a" should be either removed or replaced by something else.
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] catch syscall -- try 5 -- Source code modifications
2009-04-25 9:27 ` Eli Zaretskii
@ 2009-04-26 21:31 ` Sérgio Durigan Júnior
2009-04-26 21:35 ` Sérgio Durigan Júnior
0 siblings, 1 reply; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2009-04-26 21:31 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 4551 bytes --]
Hi Eli,
On Sat, 2009-04-25 at 12:26 +0300, Eli Zaretskii wrote:
> > From: =?ISO-8859-1?Q?S=E9rgio?= Durigan =?ISO-8859-1?Q?J=FAnior?= <sergiodj@linux.vnet.ibm.com>
> > Date: Wed, 22 Apr 2009 21:33:03 -0300
Thanks for the comments. Here goes the new version.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
gdb/ChangeLog:
2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* breakpoint.c: New include: xml-syscall.h.
(set_raw_breakpoint_without_location): Setting the parameters
for the catch syscall feature.
(any_syscall_count, syscalls_counts)
(total_syscalls_count): New variables to keep track of requested
syscall catchpoints.
(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.
* 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_target_install_ops): Setting the default methods.
(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.
[-- Attachment #2: catch-syscall-source-code-mod.patch --]
[-- Type: text/x-patch, Size: 56317 bytes --]
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 330a53a..8c4a496 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -58,6 +58,7 @@
#include "top.h"
#include "wrapper.h"
#include "valprint.h"
+#include "xml-syscall.h"
/* readline include files */
#include "readline/readline.h"
@@ -199,6 +200,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
static void insert_breakpoint_locations (void);
+static int syscall_catchpoint_p (struct breakpoint *b);
+
static void tracepoints_info (char *, int);
static void delete_trace_command (char *, int);
@@ -4274,6 +4277,7 @@ set_raw_breakpoint_without_location (enum bptype bptype)
b->frame_id = null_frame_id;
b->forked_inferior_pid = null_ptid;
b->exec_pathname = NULL;
+ b->syscalls_to_be_caught = NULL;
b->ops = NULL;
b->condition_not_parsed = 0;
@@ -4797,7 +4801,276 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
print_mention_catch_vfork
};
-/* Create a new breakpoint of the bp_catchpoint kind and return it.
+/* We keep a count of the number of times the user has requested a
+ particular syscall to be tracked, and pass this information to the
+ target. This lets capable targets implement filtering directly. */
+
+/* Number of times that "any" syscall is requested. */
+static int any_syscall_count;
+
+/* Count of each system call. */
+VEC(int) *syscalls_counts;
+
+/* This counts all syscall catch requests, so we can readily determine
+ if any catching is necessary. */
+static int total_syscalls_count;
+
+/* Implement the "insert" breakpoint_ops method for syscall
+ catchpoints. */
+
+static void
+insert_catch_syscall (struct breakpoint *b)
+{
+ ++total_syscalls_count;
+ if (!b->syscalls_to_be_caught)
+ ++any_syscall_count;
+ else
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ int elem;
+ if (iter >= VEC_length (int, syscalls_counts))
+ {
+ int old_size = VEC_length (int, syscalls_counts);
+ uintptr_t vec_addr_offset = old_size * ((uintptr_t) sizeof (int));
+ uintptr_t vec_addr;
+ VEC_safe_grow (int, syscalls_counts, iter + 1);
+ vec_addr = (uintptr_t) VEC_address (int, syscalls_counts) + vec_addr_offset;
+ memset ((void *) vec_addr, 0,
+ (iter + 1 - old_size) * sizeof (int));
+ }
+ elem = VEC_index (int, syscalls_counts, iter);
+ VEC_replace (int, syscalls_counts, iter, ++elem);
+ }
+ }
+
+ target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ VEC_length (int, syscalls_counts),
+ VEC_address (int, syscalls_counts));
+}
+
+/* Implement the "remove" breakpoint_ops method for syscall
+ catchpoints. */
+
+static int
+remove_catch_syscall (struct breakpoint *b)
+{
+ --total_syscalls_count;
+ if (!b->syscalls_to_be_caught)
+ --any_syscall_count;
+ else
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ int elem;
+ if (iter >= VEC_length (int, syscalls_counts))
+ {
+ /* Shouldn't happen. */
+ continue;
+ }
+ elem = VEC_index (int, syscalls_counts, iter);
+ VEC_replace (int, syscalls_counts, iter, --elem);
+ }
+ }
+
+ return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ VEC_length (int, syscalls_counts),
+ VEC_address (int, syscalls_counts));
+}
+
+/* Implement the "breakpoint_hit" breakpoint_ops method for syscall
+ catchpoints. */
+
+static int
+breakpoint_hit_catch_syscall (struct breakpoint *b)
+{
+ /* We must check if we are catching specific syscalls in this breakpoint.
+ If we are, then we must guarantee that the called syscall is the same
+ syscall we are catching. */
+ int syscall_number = 0;
+
+ if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
+ return 0;
+
+ /* Now, checking if the syscall is the same. */
+ if (b->syscalls_to_be_caught)
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ if (syscall_number == iter)
+ break;
+ /* Not the same. */
+ if (!iter)
+ return 0;
+ }
+
+ return 1;
+}
+
+/* Implement the "print_it" breakpoint_ops method for syscall
+ catchpoints. */
+
+static enum print_stop_action
+print_it_catch_syscall (struct breakpoint *b)
+{
+ /* These are needed because we want to know in which state a
+ syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
+ or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
+ must print "called syscall" or "returned from syscall". */
+ ptid_t ptid;
+ struct target_waitstatus last;
+ struct syscall s;
+ struct cleanup *old_chain;
+ char *syscall_id;
+
+ get_last_target_status (&ptid, &last);
+
+ get_syscall_by_number (last.value.syscall_number, &s);
+
+ annotate_catchpoint (b->number);
+
+ if (s.name == NULL)
+ syscall_id = xstrprintf ("%d", last.value.syscall_number);
+ else
+ syscall_id = xstrprintf ("'%s'", s.name);
+
+ old_chain = make_cleanup (xfree, syscall_id);
+
+ if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
+ printf_filtered (_("\nCatchpoint %d (call to syscall %s), "),
+ b->number, syscall_id);
+ else if (last.kind == TARGET_WAITKIND_SYSCALL_RETURN)
+ printf_filtered (_("\nCatchpoint %d (returned from syscall %s), "),
+ b->number, syscall_id);
+
+ do_cleanups (old_chain);
+
+ return PRINT_SRC_AND_LOC;
+}
+
+/* Implement the "print_one" breakpoint_ops method for syscall
+ catchpoints. */
+
+static void
+print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr)
+{
+ struct value_print_options opts;
+
+ get_user_print_options (&opts);
+ /* Field 4, the address, is omitted (which makes the columns
+ not line up too nicely with the headers, but the effect
+ is relatively readable). */
+ if (opts.addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+
+ if (b->syscalls_to_be_caught
+ && VEC_length (int, b->syscalls_to_be_caught) > 1)
+ ui_out_text (uiout, "syscalls \"");
+ else
+ ui_out_text (uiout, "syscall \"");
+
+ if (b->syscalls_to_be_caught)
+ {
+ int i, iter;
+ char *text = xstrprintf ("%s", "");
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ char *x = text;
+ struct syscall s;
+ get_syscall_by_number (iter, &s);
+
+ if (s.name != NULL)
+ text = xstrprintf ("%s%s, ", text, s.name);
+ else
+ text = xstrprintf ("%s%d, ", text, iter);
+
+ /* We have to xfree the last 'text' (now stored at 'x')
+ because xstrprintf dinamically allocates new space for it
+ on every call. */
+ xfree (x);
+ }
+ /* Remove the last comma. */
+ text[strlen (text) - 2] = '\0';
+ ui_out_field_string (uiout, "what", text);
+ }
+ else
+ ui_out_field_string (uiout, "what", "<any syscall>");
+ ui_out_text (uiout, "\" ");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for syscall
+ catchpoints. */
+
+static void
+print_mention_catch_syscall (struct breakpoint *b)
+{
+ if (b->syscalls_to_be_caught)
+ {
+ int i, iter;
+
+ if (VEC_length (int, b->syscalls_to_be_caught) > 1)
+ printf_filtered (_("Catchpoint %d (syscalls"), b->number);
+ else
+ printf_filtered (_("Catchpoint %d (syscall"), b->number);
+
+ for (i = 0;
+ VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+ i++)
+ {
+ struct syscall s;
+ get_syscall_by_number (iter, &s);
+
+ if (s.name)
+ printf_filtered (" '%s' [%d]", s.name, s.number);
+ else
+ printf_filtered (" %d", s.number);
+ }
+ printf_filtered (")");
+ }
+ else
+ printf_filtered (_("Catchpoint %d (any syscall)"),
+ b->number);
+}
+
+/* The breakpoint_ops structure to be used in syscall catchpoints. */
+
+static struct breakpoint_ops catch_syscall_breakpoint_ops =
+{
+ insert_catch_syscall,
+ remove_catch_syscall,
+ breakpoint_hit_catch_syscall,
+ print_it_catch_syscall,
+ print_one_catch_syscall,
+ print_mention_catch_syscall
+};
+
+/* Returns non-zero if 'b' is a syscall catchpoint. */
+
+static int
+syscall_catchpoint_p (struct breakpoint *b)
+{
+ return (b->ops == &catch_syscall_breakpoint_ops);
+}
+
+/* Create a new breakpoint of the bp_catchpoint kind and return it,
+ but does NOT mention it nor update the global location list.
+ This is useful if you need to fill more fields in the
+ struct breakpoint before calling mention.
If TEMPFLAG is non-zero, then make the breakpoint temporary.
If COND_STRING is not NULL, then store it in the breakpoint.
@@ -4805,16 +5078,13 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
to the catchpoint. */
static struct breakpoint *
-create_catchpoint (int tempflag, char *cond_string,
- struct breakpoint_ops *ops)
+create_catchpoint_without_mention (int tempflag, char *cond_string,
+ struct breakpoint_ops *ops)
{
struct symtab_and_line sal;
struct breakpoint *b;
init_sal (&sal);
- sal.pc = 0;
- sal.symtab = NULL;
- sal.line = 0;
b = set_raw_breakpoint (sal, bp_catchpoint);
set_breakpoint_count (breakpoint_count + 1);
@@ -4828,6 +5098,23 @@ create_catchpoint (int tempflag, char *cond_string,
b->disposition = tempflag ? disp_del : disp_donttouch;
b->ops = ops;
+ return b;
+}
+
+/* Create a new breakpoint of the bp_catchpoint kind and return it.
+
+ If TEMPFLAG is non-zero, then make the breakpoint temporary.
+ If COND_STRING is not NULL, then store it in the breakpoint.
+ OPS, if not NULL, is the breakpoint_ops structure associated
+ to the catchpoint. */
+
+static struct breakpoint *
+create_catchpoint (int tempflag, char *cond_string,
+ struct breakpoint_ops *ops)
+{
+ struct breakpoint *b =
+ create_catchpoint_without_mention (tempflag, cond_string, ops);
+
mention (b);
update_global_location_list (1);
@@ -4912,6 +5199,21 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
print_mention_catch_exec
};
+static void
+create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
+ struct breakpoint_ops *ops)
+{
+ struct breakpoint *b =
+ create_catchpoint_without_mention (tempflag, NULL, ops);
+
+ b->syscalls_to_be_caught = filter;
+
+ /* Now, we have to mention the breakpoint and update the global
+ location list. */
+ mention (b);
+ update_global_location_list (1);
+}
+
static int
hw_breakpoint_used_count (void)
{
@@ -6836,6 +7138,112 @@ catch_ada_exception_command (char *arg, int from_tty,
from_tty);
}
+/* Cleanup function for a syscall filter list. */
+static void
+clean_up_filters (void *arg)
+{
+ VEC(int) *iter = *(VEC(int) **) arg;
+ VEC_free (int, iter);
+}
+
+/* Splits the argument using space as delimiter. Returns an xmalloc'd
+ filter list, or NULL if no filtering is required. */
+static VEC(int) *
+catch_syscall_split_args (char *arg)
+{
+ VEC(int) *result = NULL;
+ struct cleanup *cleanup = make_cleanup (clean_up_filters, &result);
+
+ while (*arg != '\0')
+ {
+ int i, syscall_number;
+ char *endptr;
+ char cur_name[128];
+ struct syscall s;
+
+ /* Skip whitespace. */
+ while (isspace (*arg))
+ arg++;
+
+ for (i = 0; arg[i] && !isspace (arg[i]); ++i)
+ cur_name[i] = arg[i];
+ cur_name[i] = '\0';
+ arg += i;
+
+ /* Check if the user provided a syscall name or a number. */
+ syscall_number = (int) strtol (cur_name, &endptr, 10);
+ if (*endptr == '\0')
+ {
+ get_syscall_by_number (syscall_number, &s);
+
+ if (s.name == NULL)
+ /* We can issue just a warning, but still create the catchpoint.
+ This is because, even not knowing the syscall name that
+ this number represents, we can still try to catch the syscall
+ number. */
+ warning (_("The number '%d' does not represent a known syscall."),
+ syscall_number);
+ }
+ else
+ {
+ /* We have a name. Let's check if it's valid and convert it
+ to a number. */
+ get_syscall_by_name (cur_name, &s);
+
+ if (s.number == UNKNOWN_SYSCALL)
+ /* Here we have to issue an error instead of a warning, because
+ GDB cannot do anything useful if there's no syscall number to
+ be caught. */
+ error (_("Unknown syscall name '%s'."), cur_name);
+ }
+
+ /* Ok, it's valid. */
+ VEC_safe_push (int, result, s.number);
+ }
+
+ discard_cleanups (cleanup);
+ return result;
+}
+
+/* Implement the "catch syscall" command. */
+
+static void
+catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
+{
+ int tempflag;
+ VEC(int) *filter;
+ struct syscall s;
+
+ /* Checking if the feature if supported. */
+ if (gdbarch_get_syscall_number_p (current_gdbarch) == 0)
+ error (_("The feature 'catch syscall' is not supported on \
+this architeture yet."));
+
+ tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+ ep_skip_leading_whitespace (&arg);
+
+ /* We need to do this first "dummy" translation in order
+ to get the syscall XML file loaded or, most important,
+ to display a warning to the user if there's no XML file
+ for his/her architecture. */
+ get_syscall_by_number (0, &s);
+
+ /* The allowed syntax is:
+ catch syscall
+ catch syscall <name | number> [<name | number> ... <name | number>]
+
+ Let's check if there's a syscall name. */
+
+ if (arg != NULL)
+ filter = catch_syscall_split_args (arg);
+ else
+ filter = NULL;
+
+ create_syscall_event_catchpoint (tempflag, filter,
+ &catch_syscall_breakpoint_ops);
+}
+
/* Implement the "catch assert" command. */
static void
@@ -7302,6 +7710,7 @@ delete_breakpoint (struct breakpoint *bpt)
xfree (bpt->source_file);
if (bpt->exec_pathname != NULL)
xfree (bpt->exec_pathname);
+ clean_up_filters (&bpt->syscalls_to_be_caught);
/* Be sure no bpstat's are pointing at it after it's been freed. */
/* FIXME, how can we find all bpstat's?
@@ -8215,6 +8624,58 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
return 0;
}
+/* Returns 0 if 'bp' is NOT a syscall catchpoint,
+ non-zero otherwise. */
+static int
+is_syscall_catchpoint_enabled (struct breakpoint *bp)
+{
+ if (syscall_catchpoint_p (bp)
+ && bp->enable_state != bp_disabled
+ && bp->enable_state != bp_call_disabled)
+ return 1;
+ else
+ return 0;
+}
+
+int
+catch_syscall_enabled (void)
+{
+ return total_syscalls_count != 0;
+}
+
+int
+catching_syscall_number (int syscall_number)
+{
+ struct breakpoint *bp;
+
+ ALL_BREAKPOINTS (bp)
+ if (is_syscall_catchpoint_enabled (bp))
+ {
+ if (bp->syscalls_to_be_caught)
+ {
+ int i, iter;
+ for (i = 0;
+ VEC_iterate (int, bp->syscalls_to_be_caught, i, iter);
+ i++)
+ if (syscall_number == iter)
+ return 1;
+ }
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Complete syscall names. Used by "catch syscall". */
+static char **
+catch_syscall_completer (struct cmd_list_element *cmd,
+ char *text, char *word)
+{
+ const char **list = get_syscall_names ();
+ return (list == NULL) ? NULL : complete_on_enum (list, text, word);
+}
+
/* Tracepoint-specific operations. */
/* Set tracepoint count to NUM. */
@@ -8565,6 +9026,8 @@ static void
add_catch_command (char *name, char *docstring,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element *command),
+ char **(*completer) (struct cmd_list_element *cmd,
+ char *text, char *word),
void *user_data_catch,
void *user_data_tcatch)
{
@@ -8574,11 +9037,13 @@ add_catch_command (char *name, char *docstring,
&catch_cmdlist);
set_cmd_sfunc (command, sfunc);
set_cmd_context (command, user_data_catch);
+ set_cmd_completer (command, completer);
command = add_cmd (name, class_breakpoint, NULL, docstring,
&tcatch_cmdlist);
set_cmd_sfunc (command, sfunc);
set_cmd_context (command, user_data_tcatch);
+ set_cmd_completer (command, completer);
}
void
@@ -8855,36 +9320,56 @@ Set temporary catchpoints to catch events."),
Catch an exception, when caught.\n\
With an argument, catch only exceptions with the given name."),
catch_catch_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("throw", _("\
Catch an exception, when thrown.\n\
With an argument, catch only exceptions with the given name."),
catch_throw_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("fork", _("Catch calls to fork."),
catch_fork_command_1,
+ NULL,
(void *) (uintptr_t) catch_fork_permanent,
(void *) (uintptr_t) catch_fork_temporary);
add_catch_command ("vfork", _("Catch calls to vfork."),
catch_fork_command_1,
+ NULL,
(void *) (uintptr_t) catch_vfork_permanent,
(void *) (uintptr_t) catch_vfork_temporary);
add_catch_command ("exec", _("Catch calls to exec."),
catch_exec_command_1,
+ NULL,
+ CATCH_PERMANENT,
+ CATCH_TEMPORARY);
+ add_catch_command ("syscall", _("\
+Catch system calls.\n\
+The program can take one or more arguments (syscalls names\n\
+and/or numbers), in which case it will catch the syscalls\n\
+provided. It can also take no arguments, in which case it\n\
+will catch every syscall.\n\
+The argument(s) should be the syscall name(s) (if your system\n\
+has support for it), or the syscall number(s). If you need\n\
+more information, please refer to GDB manual."),
+ catch_syscall_command_1,
+ catch_syscall_completer,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("exception", _("\
Catch Ada exceptions, when raised.\n\
With an argument, catch only exceptions with the given name."),
catch_ada_exception_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("assert", _("\
Catch failed Ada assertions, when raised.\n\
With an argument, catch only exceptions with the given name."),
catch_assert_command,
+ NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 17b2761..42ded0a 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -33,7 +33,8 @@ struct block;
#define BREAKPOINT_MAX 16
\f
-/* Type of breakpoint. */
+
+/* Type of breakpoint. */
/* FIXME In the future, we should fold all other breakpoint-like things into
here. This includes:
@@ -339,6 +340,9 @@ enum watchpoint_triggered
watch_triggered_yes
};
+/* This is used to declare the VEC syscalls_to_be_caught. */
+DEF_VEC_I(int);
+
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);
@@ -447,6 +451,12 @@ struct breakpoint
triggered. */
char *exec_pathname;
+ /* Syscall numbers used for the 'catch syscall' feature.
+ If no syscall has been specified for filtering, its value is NULL.
+ Otherwise, it holds a list of all syscalls to be caught.
+ The list elements are allocated with xmalloc. */
+ VEC(int) *syscalls_to_be_caught;
+
/* Methods associated with this breakpoint. */
struct breakpoint_ops *ops;
@@ -873,6 +883,15 @@ extern int breakpoints_always_inserted_mode (void);
in our opinion won't ever trigger. */
extern void breakpoint_retire_moribund (void);
+/* Checks if we are catching syscalls or not.
+ Returns 0 if not, greater than 0 if we are. */
+extern int catch_syscall_enabled (void);
+
+/* Checks if we are catching syscalls with the specific
+ syscall_number. Used for "filtering" the catchpoints.
+ Returns 0 if not, greater than 0 if we are. */
+extern int catching_syscall_number (int syscall_number);
+
/* Tell a breakpoint to be quiet. */
extern void make_breakpoint_silent (struct breakpoint *);
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 3273b34..80987d1 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -243,6 +243,7 @@ struct gdbarch
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
gdbarch_record_special_symbol_ftype *record_special_symbol;
+ gdbarch_get_syscall_number_ftype *get_syscall_number;
int has_global_solist;
};
@@ -378,6 +379,7 @@ struct gdbarch startup_gdbarch =
default_target_signal_to_host, /* target_signal_to_host */
0, /* get_siginfo_type */
0, /* record_special_symbol */
+ 0, /* get_syscall_number */
0, /* has_global_solist */
/* startup_gdbarch() */
};
@@ -634,6 +636,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of get_siginfo_type, has predicate */
/* Skip verify of record_special_symbol, has predicate */
+ /* Skip verify of get_syscall_number, has predicate */
/* Skip verify of has_global_solist, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
@@ -859,6 +862,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: get_siginfo_type = <%s>\n",
host_address_to_string (gdbarch->get_siginfo_type));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_number_p() = %d\n",
+ gdbarch_get_syscall_number_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_number = <%s>\n",
+ host_address_to_string (gdbarch->get_syscall_number));
+ fprintf_unfiltered (file,
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
@@ -3333,6 +3342,30 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch,
}
int
+gdbarch_get_syscall_number_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_number != NULL;
+}
+
+LONGEST
+gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_number != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_number called\n");
+ return gdbarch->get_syscall_number (gdbarch, ptid);
+}
+
+void
+set_gdbarch_get_syscall_number (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_number_ftype get_syscall_number)
+{
+ gdbarch->get_syscall_number = get_syscall_number;
+}
+
+int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 04c8920..ffbfe10 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -52,6 +52,7 @@ struct bp_target_info;
struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
+struct syscall;
extern struct gdbarch *current_gdbarch;
extern struct gdbarch *target_gdbarch;
@@ -839,6 +840,15 @@ typedef void (gdbarch_record_special_symbol_ftype) (struct gdbarch *gdbarch, str
extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym);
extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol);
+/* Function for the 'catch syscall' feature.
+ Get architecture-specific system calls information from registers. */
+
+extern int gdbarch_get_syscall_number_p (struct gdbarch *gdbarch);
+
+typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, ptid_t ptid);
+extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid);
+extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number);
+
/* True if the list of shared libraries is one and only for all
processes, as opposed to a list of shared libraries per inferior.
When this property is true, GDB assumes that since shared libraries
@@ -848,6 +858,9 @@ extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_
extern int gdbarch_has_global_solist (struct gdbarch *gdbarch);
extern void set_gdbarch_has_global_solist (struct gdbarch *gdbarch, int has_global_solist);
+/* Definition for an unknown syscall, used basically in error-cases. */
+#define UNKNOWN_SYSCALL (-1)
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
diff --git a/gdb/gdbarch.sh b/gdb/gdbarch.sh
index f93bfc1..55844a6 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -724,6 +724,11 @@ M:struct type *:get_siginfo_type:void:
# Record architecture-specific information from the symbol table.
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+# Function for the 'catch syscall' feature.
+
+# Get architecture-specific system calls information from registers.
+M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+
# True if the list of shared libraries is one and only for all
# processes, as opposed to a list of shared libraries per inferior.
# When this property is true, GDB assumes that since shared libraries
@@ -842,6 +847,7 @@ struct bp_target_info;
struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
+struct syscall;
extern struct gdbarch *current_gdbarch;
extern struct gdbarch *target_gdbarch;
@@ -911,6 +917,9 @@ done
# close it off
cat <<EOF
+/* Definition for an unknown syscall, used basically in error-cases. */
+#define UNKNOWN_SYSCALL (-1)
+
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
diff --git a/gdb/i386-linux-nat.c b/gdb/i386-linux-nat.c
index 2366474..687eccd 100644
--- a/gdb/i386-linux-nat.c
+++ b/gdb/i386-linux-nat.c
@@ -751,7 +751,12 @@ i386_linux_resume (struct target_ops *ops,
{
int pid = PIDGET (ptid);
- int request = PTRACE_CONT;
+ int request;
+
+ if (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 1a2e4f0..4a421ee 100644
--- a/gdb/i386-linux-tdep.c
+++ b/gdb/i386-linux-tdep.c
@@ -37,6 +37,10 @@
#include "symtab.h"
#include "arch-utils.h"
#include "regset.h"
+#include "xml-syscall.h"
+
+/* The syscall's XML filename for i386. */
+#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml"
/* Supported register note sections. */
static struct core_regset_section i386_linux_regset_sections[] =
@@ -349,6 +353,26 @@ i386_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
}
\f
+static 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;
+}
+
/* 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
@@ -471,6 +495,11 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
set_gdbarch_displaced_step_location (gdbarch,
displaced_step_at_entry_point);
+ /* Functions for 'catch syscall'. */
+ set_xml_syscall_file_name (XML_SYSCALL_FILENAME_I386);
+ set_gdbarch_get_syscall_number (gdbarch,
+ i386_linux_get_syscall_number);
+
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
}
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index 38311f1..fc968cf 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -148,6 +148,15 @@ inf_child_remove_exec_catchpoint (int pid)
}
static int
+inf_child_set_syscall_catchpoint (int pid, int needed, int any_count,
+ int table_size, int *table)
+{
+ /* This version of Unix doesn't support notification of syscall
+ events. */
+ return 0;
+}
+
+static int
inf_child_can_run (void)
{
return 1;
@@ -190,6 +199,7 @@ inf_child_target (void)
t->to_follow_fork = inf_child_follow_fork;
t->to_insert_exec_catchpoint = inf_child_insert_exec_catchpoint;
t->to_remove_exec_catchpoint = inf_child_remove_exec_catchpoint;
+ t->to_set_syscall_catchpoint = inf_child_set_syscall_catchpoint;
t->to_can_run = inf_child_can_run;
t->to_pid_to_exec_file = inf_child_pid_to_exec_file;
t->to_stratum = process_stratum;
diff --git a/gdb/inf-ptrace.c b/gdb/inf-ptrace.c
index f088ffd..186b419 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -356,13 +356,18 @@ inf_ptrace_resume (struct target_ops *ops,
ptid_t ptid, int step, enum target_signal signal)
{
pid_t pid = ptid_get_pid (ptid);
- int request = PT_CONTINUE;
+ int request;
if (pid == -1)
/* Resume all threads. Traditionally ptrace() only supports
single-threaded processes, so simply resume the inferior. */
pid = ptid_get_pid (inferior_ptid);
+ if (catch_syscall_enabled () > 0)
+ request = PT_SYSCALL;
+ else
+ request = PT_CONTINUE;
+
if (step)
{
/* If this system does not support PT_STEP, a higher level
diff --git a/gdb/infrun.c b/gdb/infrun.c
index b9fba6f..4059bd5 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1058,7 +1058,7 @@ a command like `return' or `jump' to continue execution."));
if (step)
step = maybe_software_singlestep (gdbarch, pc);
- /* If there were any forks/vforks/execs that were caught and are
+ /* If there were any forks/vforks/execs/syscalls that were caught and are
now to be followed, then do so. */
switch (pending_follow.kind)
{
@@ -1081,6 +1081,11 @@ a command like `return' or `jump' to continue execution."));
pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
break;
+ case TARGET_WAITKIND_SYSCALL_ENTRY:
+ case TARGET_WAITKIND_SYSCALL_RETURN:
+ pending_follow.kind = TARGET_WAITKIND_SPURIOUS;
+ break;
+
default:
break;
}
@@ -1522,7 +1527,7 @@ init_wait_for_inferior (void)
breakpoint_init_inferior (inf_starting);
- /* The first resume is not following a fork/vfork/exec. */
+ /* The first resume is not following a fork/vfork/exec/syscall. */
pending_follow.kind = TARGET_WAITKIND_SPURIOUS; /* I.e., none. */
clear_proceed_status ();
@@ -1866,6 +1871,10 @@ wait_for_inferior (int treat_exec_as_sigtrap)
state. */
old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
+ if (ecs->ws.kind == TARGET_WAITKIND_SYSCALL_ENTRY
+ || ecs->ws.kind == TARGET_WAITKIND_SYSCALL_RETURN)
+ ecs->ws.value.syscall_number = UNKNOWN_SYSCALL;
+
/* Now figure out what to do with the result of the result. */
handle_inferior_event (ecs);
@@ -2177,6 +2186,55 @@ ensure_not_running (void)
error_is_running ();
}
+/* Auxiliary function that handles syscall entry/return events.
+ It returns 1 if the inferior should keep going (and GDB
+ should ignore the event), or 0 if the event deserves to be
+ processed. */
+static int
+deal_with_syscall_event (struct execution_control_state *ecs)
+{
+ int syscall_number = gdbarch_get_syscall_number (current_gdbarch,
+ ecs->ptid);
+ target_last_waitstatus.value.syscall_number = syscall_number;
+
+ if (catch_syscall_enabled () > 0
+ && catching_syscall_number (syscall_number) > 0)
+ {
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
+ syscall_number);
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
+ pending_follow.kind = ecs->ws.kind;
+
+ if (!ptid_equal (ecs->ptid, inferior_ptid))
+ {
+ context_switch (ecs->ptid);
+ reinit_frame_cache ();
+ }
+
+ stop_pc = read_pc ();
+
+ ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
+
+ ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
+
+ /* If no catchpoint triggered for this, then keep going. */
+ if (ecs->random_signal)
+ {
+ ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
+ keep_going (ecs);
+ return 1;
+ }
+ return 0;
+ }
+ else
+ {
+ resume (0, TARGET_SIGNAL_0);
+ prepare_to_wait (ecs);
+ return 1;
+ }
+}
+
/* Given an execution control state that has been freshly filled in
by an event from the inferior, figure out what it means and take
appropriate action. */
@@ -2471,9 +2529,11 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_SYSCALL_ENTRY:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
- resume (0, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
+ /* Getting the current syscall number */
+ if (deal_with_syscall_event (ecs) != 0)
+ return;
+ goto process_event_stop_test;
+ break;
/* Before examining the threads further, step this thread to
get it entirely out of the syscall. (We get notice of the
@@ -2483,9 +2543,10 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_SYSCALL_RETURN:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
- target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
- prepare_to_wait (ecs);
- return;
+ if (deal_with_syscall_event (ecs) != 0)
+ return;
+ goto process_event_stop_test;
+ break;
case TARGET_WAITKIND_STOPPED:
if (debug_infrun)
@@ -5206,6 +5267,25 @@ inferior_has_execd (ptid_t pid, char **execd_pathname)
return 1;
}
+int
+inferior_has_called_syscall (ptid_t pid, int *syscall_number)
+{
+ struct target_waitstatus last;
+ ptid_t last_ptid;
+
+ get_last_target_status (&last_ptid, &last);
+
+ if (last.kind != TARGET_WAITKIND_SYSCALL_ENTRY &&
+ last.kind != TARGET_WAITKIND_SYSCALL_RETURN)
+ return 0;
+
+ if (!ptid_equal (last_ptid, pid))
+ return 0;
+
+ *syscall_number = last.value.syscall_number;
+ return 1;
+}
+
/* Oft used ptids */
ptid_t null_ptid;
ptid_t minus_one_ptid;
diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
index 0679173..ab6b798 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -61,6 +61,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
@@ -281,6 +285,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. */
@@ -292,6 +301,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 };
@@ -636,6 +648,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. */
@@ -655,12 +702,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);
+}
+
\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);
@@ -668,15 +730,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
@@ -684,6 +747,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
@@ -691,6 +755,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
+ linux_enable_tracesysgood (ptid);
}
static int
@@ -931,6 +996,16 @@ 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."));
+ /* We ignore the arguments. */
+ 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
@@ -1996,6 +2071,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);
}
@@ -2606,11 +2722,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,
@@ -4265,6 +4386,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;
diff --git a/gdb/linux-nat.h b/gdb/linux-nat.h
index fec5139..36d2439 100644
--- a/gdb/linux-nat.h
+++ b/gdb/linux-nat.h
@@ -70,6 +70,13 @@ 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
+ in a SYSCALL_RETURN event.
+ Values:
+ - TARGET_WAITKIND_SYSCALL_ENTRY
+ - TARGET_WAITKIND_SYSCALL_RETURN */
+ int syscall_state;
+
/* Next LWP in list. */
struct lwp_info *next;
};
diff --git a/gdb/ppc-linux-tdep.c b/gdb/ppc-linux-tdep.c
index d08d4fc..b9d0275 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"
@@ -53,6 +54,9 @@
#include "features/rs6000/powerpc-isa205-vsx64l.c"
#include "features/rs6000/powerpc-e500l.c"
+/* The syscall's XML filename for PPC and PPC64. */
+#define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml"
+#define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml"
/* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
in much the same fashion as memory_remove_breakpoint in mem-break.c,
@@ -1009,6 +1013,38 @@ 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. */
+static 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);
+ struct cleanup *cleanbuf;
+ /* 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));
+
+ cleanbuf = make_cleanup (xfree, buf);
+
+ /* 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);
+ do_cleanups (cleanbuf);
+
+ return ret;
+}
+
static void
ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
@@ -1080,6 +1116,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
/* Handle inferior calls during interrupted system calls. */
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
+ /* Get the syscall number from the arch's register. */
+ set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
+
if (tdep->wordsize == 4)
{
/* Until November 2001, gcc did not comply with the 32 bit SysV
@@ -1099,6 +1138,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
+ /* Setting the correct XML syscall filename. */
+ set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
+
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
@@ -1116,6 +1158,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
set_solib_svr4_fetch_link_map_offsets
(gdbarch, svr4_lp64_fetch_link_map_offsets);
+ /* Setting the correct XML syscall filename. */
+ set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
+
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
diff --git a/gdb/target.c b/gdb/target.c
index f7366f8..85ff352 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -459,6 +459,7 @@ update_current_target (void)
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
+ INHERIT (to_set_syscall_catchpoint, t);
INHERIT (to_has_exited, t);
/* Do not inherit to_mourn_inferiour. */
INHERIT (to_can_run, t);
@@ -602,6 +603,9 @@ update_current_target (void)
de_fault (to_remove_exec_catchpoint,
(int (*) (int))
tcomplain);
+ de_fault (to_set_syscall_catchpoint,
+ (int (*) (int, int, int, int, int *))
+ tcomplain);
de_fault (to_has_exited,
(int (*) (int, int, int *))
return_zero);
@@ -2696,9 +2700,9 @@ target_waitstatus_to_string (const struct target_waitstatus *ws)
case TARGET_WAITKIND_EXECD:
return xstrprintf ("%sexecd", kind_str);
case TARGET_WAITKIND_SYSCALL_ENTRY:
- return xstrprintf ("%ssyscall-entry", kind_str);
+ return xstrprintf ("%sentered syscall", kind_str);
case TARGET_WAITKIND_SYSCALL_RETURN:
- return xstrprintf ("%ssyscall-return", kind_str);
+ return xstrprintf ("%sexited syscall", kind_str);
case TARGET_WAITKIND_SPURIOUS:
return xstrprintf ("%sspurious", kind_str);
case TARGET_WAITKIND_IGNORE:
diff --git a/gdb/target.h b/gdb/target.h
index e7f087b..5044bcf 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -140,18 +140,34 @@ struct target_waitstatus
{
enum target_waitkind kind;
- /* Forked child pid, execd pathname, exit status or signal number. */
+ /* Forked child pid, execd pathname, exit status, signal number or
+ syscall number. */
union
{
int integer;
enum target_signal sig;
ptid_t related_pid;
char *execd_pathname;
- int syscall_id;
+ int syscall_number;
}
value;
};
+/* The structure below stores information about a system call.
+ It is basically used in the "catch syscall" command, and in
+ every function that gives information about a system call.
+
+ It's also good to mention that its fields represent everything
+ that we currently know about a syscall in GDB. */
+struct syscall
+ {
+ /* The syscall number. */
+ int number;
+
+ /* The syscall name. */
+ const char *name;
+ };
+
/* Return a pretty printed form of target_waitstatus.
Space for the result is malloc'd, caller must free. */
extern char *target_waitstatus_to_string (const struct target_waitstatus *);
@@ -392,6 +408,7 @@ struct target_ops
int (*to_follow_fork) (struct target_ops *, int);
void (*to_insert_exec_catchpoint) (int);
int (*to_remove_exec_catchpoint) (int);
+ int (*to_set_syscall_catchpoint) (int, int, int, int, int *);
int (*to_has_exited) (int, int, int *);
void (*to_mourn_inferior) (struct target_ops *);
int (*to_can_run) (void);
@@ -723,6 +740,8 @@ extern int inferior_has_vforked (ptid_t pid, ptid_t *child_pid);
extern int inferior_has_execd (ptid_t pid, char **execd_pathname);
+extern int inferior_has_called_syscall (ptid_t pid, int *syscall_number);
+
/* From exec.c */
extern void print_section_info (struct target_ops *, bfd *);
@@ -880,6 +899,17 @@ int target_follow_fork (int follow_child);
#define target_remove_exec_catchpoint(pid) \
(*current_target.to_remove_exec_catchpoint) (pid)
+/* Syscall catch. NEEDED is nonzero if any syscall catch (of any
+ kind) is requested. ANY_COUNT is nonzero if a generic
+ (filter-less) syscall catch is being requested. TABLE is an array
+ of ints, indexed by syscall number. An element in this array is
+ nonzero if that syscall should be caught. TABLE_SIZE is the number
+ of elements in TABLE. */
+
+#define target_set_syscall_catchpoint(pid, needed, any_count, table_size, table) \
+ (*current_target.to_set_syscall_catchpoint) (pid, needed, any_count, \
+ table_size, table)
+
/* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the
exit code of PID, if any. */
diff --git a/gdb/xml-support.c b/gdb/xml-support.c
index 937c6c3..ad20d3b 100644
--- a/gdb/xml-support.c
+++ b/gdb/xml-support.c
@@ -1036,6 +1036,66 @@ obstack_xml_printf (struct obstack *obstack, const char *format, ...)
va_end (ap);
}
+char *
+xml_fetch_content_from_file (const char *filename, void *baton)
+{
+ const char *dirname = baton;
+ FILE *file;
+ struct cleanup *back_to;
+ char *text;
+ size_t len, offset;
+
+ if (dirname && *dirname)
+ {
+ char *fullname = concat (dirname, "/", filename, (char *) NULL);
+ if (fullname == NULL)
+ nomem (0);
+ file = fopen (fullname, FOPEN_RT);
+ xfree (fullname);
+ }
+ else
+ file = fopen (filename, FOPEN_RT);
+
+ if (file == NULL)
+ return NULL;
+
+ back_to = make_cleanup_fclose (file);
+
+ /* Read in the whole file, one chunk at a time. */
+ len = 4096;
+ offset = 0;
+ text = xmalloc (len);
+ make_cleanup (free_current_contents, &text);
+ while (1)
+ {
+ size_t bytes_read;
+
+ /* Continue reading where the last read left off. Leave at least
+ one byte so that we can NUL-terminate the result. */
+ bytes_read = fread (text + offset, 1, len - offset - 1, file);
+ if (ferror (file))
+ {
+ warning (_("Read error from \"%s\""), filename);
+ do_cleanups (back_to);
+ return NULL;
+ }
+
+ offset += bytes_read;
+
+ if (feof (file))
+ break;
+
+ len = len * 2;
+ text = xrealloc (text, len);
+ }
+
+ fclose (file);
+ discard_cleanups (back_to);
+
+ text[offset] = '\0';
+ return text;
+}
+
void _initialize_xml_support (void);
void
diff --git a/gdb/xml-support.h b/gdb/xml-support.h
index d6105f7..135263d 100644
--- a/gdb/xml-support.h
+++ b/gdb/xml-support.h
@@ -240,4 +240,10 @@ extern void obstack_xml_printf (struct obstack *obstack,
const char *format, ...)
ATTRIBUTE_PRINTF_2;
+/* Open FILENAME, read all its text into memory, close it, and return
+ the text. If something goes wrong, return NULL and warn. */
+
+extern char *xml_fetch_content_from_file (const char *filename,
+ void *baton);
+
#endif
diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c
index 1d4e12c..8038dbd 100644
--- a/gdb/xml-tdesc.c
+++ b/gdb/xml-tdesc.c
@@ -421,69 +421,6 @@ tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
#endif /* HAVE_LIBEXPAT */
\f
-/* Open FILENAME, read all its text into memory, close it, and return
- the text. If something goes wrong, return NULL and warn. */
-
-static char *
-fetch_xml_from_file (const char *filename, void *baton)
-{
- const char *dirname = baton;
- FILE *file;
- struct cleanup *back_to;
- char *text;
- size_t len, offset;
-
- if (dirname && *dirname)
- {
- char *fullname = concat (dirname, "/", filename, (char *) NULL);
- if (fullname == NULL)
- nomem (0);
- file = fopen (fullname, FOPEN_RT);
- xfree (fullname);
- }
- else
- file = fopen (filename, FOPEN_RT);
-
- if (file == NULL)
- return NULL;
-
- back_to = make_cleanup_fclose (file);
-
- /* Read in the whole file, one chunk at a time. */
- len = 4096;
- offset = 0;
- text = xmalloc (len);
- make_cleanup (free_current_contents, &text);
- while (1)
- {
- size_t bytes_read;
-
- /* Continue reading where the last read left off. Leave at least
- one byte so that we can NUL-terminate the result. */
- bytes_read = fread (text + offset, 1, len - offset - 1, file);
- if (ferror (file))
- {
- warning (_("Read error from \"%s\""), filename);
- do_cleanups (back_to);
- return NULL;
- }
-
- offset += bytes_read;
-
- if (feof (file))
- break;
-
- len = len * 2;
- text = xrealloc (text, len);
- }
-
- fclose (file);
- discard_cleanups (back_to);
-
- text[offset] = '\0';
- return text;
-}
-
/* Read an XML target description from FILENAME. Parse it, and return
the parsed description. */
@@ -495,7 +432,7 @@ file_read_description_xml (const char *filename)
struct cleanup *back_to;
char *dirname;
- tdesc_str = fetch_xml_from_file (filename, NULL);
+ tdesc_str = xml_fetch_content_from_file (filename, NULL);
if (tdesc_str == NULL)
{
warning (_("Could not open \"%s\""), filename);
@@ -508,7 +445,7 @@ file_read_description_xml (const char *filename)
if (dirname != NULL)
make_cleanup (xfree, dirname);
- tdesc = tdesc_parse_xml (tdesc_str, fetch_xml_from_file, dirname);
+ tdesc = tdesc_parse_xml (tdesc_str, xml_fetch_content_from_file, dirname);
do_cleanups (back_to);
return tdesc;
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] catch syscall -- try 5 -- Source code modifications
2009-04-26 21:31 ` Sérgio Durigan Júnior
@ 2009-04-26 21:35 ` Sérgio Durigan Júnior
2009-04-27 15:07 ` Hui Zhu
2009-04-27 18:50 ` Eli Zaretskii
0 siblings, 2 replies; 6+ messages in thread
From: Sérgio Durigan Júnior @ 2009-04-26 21:35 UTC (permalink / raw)
To: Eli Zaretskii; +Cc: gdb-patches
[-- Attachment #1: Type: text/plain, Size: 1123 bytes --]
Hello,
On Sun, 2009-04-26 at 18:30 -0300, Sérgio Durigan Júnior wrote:
> Hi Eli,
>
> On Sat, 2009-04-25 at 12:26 +0300, Eli Zaretskii wrote:
> > > From: =?ISO-8859-1?Q?S=E9rgio?= Durigan =?ISO-8859-1?Q?J=FAnior?= <sergiodj@linux.vnet.ibm.com>
> > > Date: Wed, 22 Apr 2009 21:33:03 -0300
>
> Thanks for the comments. Here goes the new version.
I've made a mistake, sorry. This is the new version.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
gdb/ChangeLog:
2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* Makefile.in: Support for relocatable GDB datadir and XML
syscall.
* NEWS: Added information about the catch syscall feature.
gdb/doc/ChangeLog:
2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* gdb.texinfo (Set Catchpoints): Documentation about the new
feature.
gdb/testsuite/ChangeLog:
2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* Makefile.in: Inclusion of catch-syscall object.
* gdb.base/catch-syscall.c: New file.
* gdb.base/catch-syscall.exp: New file.
[-- Attachment #2: catch-syscall-build-test-doc.patch --]
[-- Type: text/x-patch, Size: 28374 bytes --]
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 35c3813..df29e50 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -166,6 +166,9 @@ INTL_CFLAGS = @INCINTL@
TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@
TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
+# Did the user give us a --with-gdb-datadir option?
+GDB_DATADIR_PATH = @GDB_DATADIR_PATH@
+
# Helper code from gnulib.
LIBGNU = gnulib/libgnu.a
INCGNU = -I$(srcdir)/gnulib -Ignulib
@@ -458,6 +461,7 @@ TARGET_OBS = @TARGET_OBS@
# All target-dependent objects files that require 64-bit CORE_ADDR
# (used with --enable-targets=all --enable-64-bit-bfd).
ALL_64_TARGET_OBS = \
+ linux-tdep.o \
alphabsd-tdep.o alphafbsd-tdep.o alpha-linux-tdep.o alpha-mdebug-tdep.o \
alphanbsd-tdep.o alphaobsd-tdep.o alpha-osf1-tdep.o alpha-tdep.o \
amd64fbsd-tdep.o amd64-dicos-tdep.o amd64-linux-tdep.o amd64nbsd-tdep.o \
@@ -469,6 +473,7 @@ ALL_64_TARGET_OBS = \
# All other target-dependent objects files (used with --enable-targets=all).
ALL_TARGET_OBS = \
+ linux-tdep.o \
armbsd-tdep.o arm-linux-tdep.o armnbsd-tdep.o armobsd-tdep.o \
arm-tdep.o arm-wince-tdep.o \
avr-tdep.o \
@@ -664,6 +669,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
valarith.c valops.c valprint.c value.c varobj.c vec.c \
wrapper.c \
xml-tdesc.c xml-support.c \
+ linux-tdep.c \
+ xml-syscall.c \
inferior.c gdb_usleep.c
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@@ -674,7 +681,7 @@ LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
# wrong if TAGS has files twice). Because this is tricky to get
# right, it is probably easiest just to list .h files here directly.
-HFILES_NO_SRCDIR = osf-share/cma_debug_client.h \
+HFILES_NO_SRCDIR = osf-share/cma_debug_client.h linux-tdep.h \
osf-share/HP800/cma_thread_io.h osf-share/cma_sequence.h \
osf-share/cma_mutex.h osf-share/cma_semaphore_defs.h \
osf-share/cma_list.h osf-share/cma_handle.h osf-share/cma_stack.h \
@@ -735,7 +742,7 @@ config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \
annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \
remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
-gdb_usleep.h
+xml-syscall.h gdb_usleep.h
# Header files that already have srcdir in them, or which are in objdir.
@@ -814,10 +821,16 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
trad-frame.o \
tramp-frame.o \
solib.o solib-null.o \
- prologue-value.o memory-map.o xml-support.o \
+ prologue-value.o memory-map.o xml-support.o xml-syscall.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o osdata.o gdb_usleep.o
+# Definitions for the syscall's XML files and dir
+XML_SYSCALLS_DIR = syscalls/
+XML_SYSCALLS_FILES = gdb-syscalls.dtd \
+ ppc-linux.xml ppc64-linux.xml \
+ i386-linux.xml amd64-linux.xml
+
TSOBS = inflow.o
SUBDIRS = @subdirs@
@@ -851,11 +864,41 @@ generated_files = config.h observer.h observer.inc ada-lex.c \
$(COMPILE) $<
$(POSTCOMPILE)
-all: gdb$(EXEEXT) $(CONFIG_ALL)
+all: gdb$(EXEEXT) $(CONFIG_ALL) xml-syscall-copy
@$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do
.PHONY: all-tui
all-tui: $(TUI)$(EXEEXT)
+# This is needed for running GDB from the build directory
+.PHONY: xml-syscall-copy
+xml-syscall-copy:
+ if [ "`cd $(srcdir) && pwd`" != "`pwd`" ] ; then \
+ mkdir -p ./$(XML_SYSCALLS_DIR) ; \
+ list='$(XML_SYSCALLS_FILES)' ; \
+ for file in $$list ; do \
+ f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \
+ if test -f $$f ; then \
+ $(INSTALL_DATA) $$f \
+ ./$(XML_SYSCALLS_DIR) ; \
+ fi ; \
+ done ; \
+ fi ;
+
+# This target is responsible for properly installing the syscalls'
+# XML files in the system.
+.PHONY: xml-syscall-install
+xml-syscall-install:
+ $(SHELL) $(srcdir)/../mkinstalldirs \
+ $(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \
+ list='$(XML_SYSCALLS_FILES)' ; \
+ for file in $$list ; do \
+ f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \
+ if test -f $$f ; then \
+ $(INSTALL_DATA) $$f \
+ $(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \
+ fi ; \
+ done ;
+
installcheck:
# The check target can not use subdir_do, because subdir_do does not
@@ -909,8 +952,11 @@ gdb.z:gdb.1
# source file and doesn't care about rebuilding or just wants to save the
# time it takes for make to check that all is up to date.
# install-only is intended to address that need.
-install: all install-only
-install-only: $(CONFIG_INSTALL)
+install: all install-only
+
+# The "install-only" target also installs the syscalls' XML files in
+# the system.
+install-only: $(CONFIG_INSTALL) xml-syscall-install
transformed_name=`t='$(program_transform_name)'; \
echo gdb | sed -e "$$t"` ; \
if test "x$$transformed_name" = x; then \
@@ -1268,6 +1314,7 @@ force_update:
MAKEOVERRIDES=
ALLDEPFILES = \
+ linux-tdep.c \
aix-thread.c \
alpha-nat.c alphabsd-nat.c alpha-linux-nat.c \
alpha-tdep.c alpha-mdebug-tdep.c \
diff --git a/gdb/NEWS b/gdb/NEWS
index 8382026..e045551 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,35 @@
*** Changes since GDB 6.8
+* GDB now has the new command `catch syscall'. It can be used to
+catch when the inferior calls a system call, or when the system call
+returns. Also, you can specify which system calls you would like GDB
+to catch (or issue only a `catch syscall' without arguments, which will
+make GDB catch every system call). For instance, if you would like to
+catch the system call close, you would issue a:
+
+ (gdb) catch syscall close
+
+Then, when the program is running again, GDB will keep track of all
+the system calls the inferior is calling, and will stop the execution
+if the system call called or returned is equal to the system call
+that you asked it to catch (note that if you did not provide any system
+call, then GDB would stop on any system call). After stopping the
+inferior, GDB will print something like:
+
+ Catchpoint 1 (call to syscall 'close'),
+ 0xb7ff831d in ?? () from /lib/ld-linux.so.2
+
+It indicates that the correct system call was caught. If you choose
+to continue the execution of the inferior from this point, then you
+should see GDB catching the return of this system call, like that:
+
+ Catchpoint 1 (returned from syscall 'close'),
+ 0xb7ff831d in ?? () from /lib/ld-linux.so.2
+
+This feature is available with a native GDB running on the Linux Kernel,
+under the following architectures: x86, PowerPC and PowerPC64.
+
* GDB now supports hardware watchpoints on MIPS/Linux systems. This
feature is available with a native GDB running on kernel version
2.6.28 or later.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 7ae9e1c..2fb46b2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3640,6 +3640,137 @@ A failed Ada assertion.
A call to @code{exec}. This is currently only available for HP-UX
and @sc{gnu}/Linux.
+@item syscall
+@itemx syscall @r{[}@var{name} @r{|} @var{number}@r{]} @r{...}
+@cindex break on a system call.
+A call to or return from a system call, a.k.a.@: @dfn{syscall}. A
+syscall is a mechanism for application programs to request a service
+from the operating system (OS) or one of the OS system services.
+@value{GDBN} can catch some or all of the syscalls issued by the
+debuggee, and show the related information for each syscall. If no
+argument is specified, calls to and returns from all system calls
+will be caught.
+
+@var{name} can be any system call name that is valid for the
+underlying OS. Just what syscalls are valid depends on the OS. On
+GNU and Unix systems, you can find the full list of valid syscall
+names on @file{/usr/include/asm/unistd.h}.
+
+@c For MS-Windows, the syscall names and the corresponding numbers
+@c can be found, e.g., on this URL:
+@c http://www.metasploit.com/users/opcode/syscalls.html
+@c but we don't support Windows syscalls yet.
+
+Normally, @value{GDBN} knows in advance which syscalls are valid for
+each OS, so you can use the @value{GDBN} command-line completion
+facilities (@pxref{Completion,, command completion}) to list the
+available choices.
+
+You may also specify the system call numerically. A syscall's
+number is the value passed to the OS's syscall dispatcher to
+identify the requested service. When you specify the syscall by its
+name, @value{GDBN} uses its database of syscalls to convert the name
+into the corresponding numeric code, but using the number directly
+may be useful if @value{GDBN}'s database does not have the complete
+list of syscalls on your system (e.g., because @value{GDBN} lags
+behind the OS upgrades).
+
+The example below illustrates how this command works if you don't provide
+arguments to it:
+
+@smallexample
+(@value{GDBP}) catch syscall
+Catchpoint 1 (syscall)
+(@value{GDBP}) r
+Starting program: /tmp/catch-syscall
+
+Catchpoint 1 (call to syscall 'close'), \
+ 0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP}) c
+Continuing.
+
+Catchpoint 1 (returned from syscall 'close'), \
+ 0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP})
+@end smallexample
+
+Here is an example of catching a system call by name:
+
+@smallexample
+(@value{GDBP}) catch syscall chroot
+Catchpoint 1 (syscall 'chroot' [61])
+(@value{GDBP}) r
+Starting program: /tmp/catch-syscall
+
+Catchpoint 1 (call to syscall 'chroot'), \
+ 0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP}) c
+Continuing.
+
+Catchpoint 1 (returned from syscall 'chroot'), \
+ 0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP})
+@end smallexample
+
+An example of specifying a system call numerically. In the case
+below, the syscall number has a corresponding entry in the XML
+file, so @value{GDBN} finds its name and prints it:
+
+@smallexample
+(@value{GDBP}) catch syscall 252
+Catchpoint 1 (syscall(s) 'exit_group')
+(@value{GDBP}) r
+Starting program: /tmp/catch-syscall
+
+Catchpoint 1 (call to syscall 'exit_group'), \
+ 0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP}) c
+Continuing.
+
+Program exited normally.
+(@value{GDBP})
+@end smallexample
+
+However, there can be situations when there is no corresponding name
+in XML file for that syscall number. In this case, @value{GDBN} prints
+a warning message saying that it was not able to find the syscall name,
+but the catchpoint will be set anyway. See the example below:
+
+@smallexample
+(@value{GDBP}) catch syscall 764
+warning: The number '764' does not represent a known syscall.
+Catchpoint 2 (syscall 764)
+(@value{GDBP})
+@end smallexample
+
+If you configure @value{GDBN} using the @samp{--without-expat} option,
+it will not be able to display syscall names. Also, if your
+architecture does not have an XML file describing its system calls,
+you will not be able to see the syscall names. It is important to
+notice that these two features are used for accessing the syscall
+name database. In either case, you will see a warning like this:
+
+@smallexample
+(@value{GDBP}) catch syscall
+warning: Could not open "syscalls/i386-linux.xml"
+warning: Could not load the syscall XML file 'syscalls/i386-linux.xml'.
+GDB will not be able to display syscall names.
+Catchpoint 1 (syscall)
+(@value{GDBP})
+@end smallexample
+
+Of course, the file name will change depending on your architecture and system.
+
+Still using the example above, you can also try to catch a syscall by its
+number. In this case, you would see something like:
+
+@smallexample
+(@value{GDBP}) catch syscall 252
+Catchpoint 1 (syscall(s) 252)
+@end smallexample
+
+Again, in this case @value{GDBN} would not be able to display syscall's names.
+
@item fork
A call to @code{fork}. This is currently only available for HP-UX
and @sc{gnu}/Linux.
diff --git a/gdb/testsuite/gdb.base/Makefile.in b/gdb/testsuite/gdb.base/Makefile.in
index 9f382db..12db521 100644
--- a/gdb/testsuite/gdb.base/Makefile.in
+++ b/gdb/testsuite/gdb.base/Makefile.in
@@ -12,7 +12,7 @@ EXECUTABLES = all-types annota1 bitfields break \
scope section_command setshow setvar shmain sigall signals \
solib solib_sl so-impl-ld so-indr-cl \
step-line step-test structs structs2 \
- twice-tmp varargs vforked-prog watchpoint whatis
+ twice-tmp varargs vforked-prog watchpoint whatis catch-syscall
MISCELLANEOUS = coremmap.data ../foobar.baz \
shr1.sl shr2.sl solib_sl.sl solib1.sl solib2.sl
diff --git a/gdb/testsuite/gdb.base/catch-syscall.c b/gdb/testsuite/gdb.base/catch-syscall.c
new file mode 100644
index 0000000..64850de
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-syscall.c
@@ -0,0 +1,25 @@
+/* This file is used to test the 'catch syscall' feature on GDB.
+
+ Please, if you are going to edit this file DO NOT change the syscalls
+ being called (nor the order of them). If you really must do this, then
+ take a look at catch-syscall.exp and modify there too.
+
+ Written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
+ September, 2008 */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+int
+main (void)
+{
+ /* A close() with a wrong argument. We are only
+ interested in the syscall. */
+ close (-1);
+
+ chroot (".");
+
+ /* The last syscall. Do not change this. */
+ _exit (0);
+}
diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp
new file mode 100644
index 0000000..ff56de7
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-syscall.exp
@@ -0,0 +1,445 @@
+# Copyright 1997, 1999, 2007, 2008 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/>.
+
+
+# This program tests the 'catch syscall' functionality.
+#
+# It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
+# on September/2008.
+
+if { [is_remote target] || ![isnative] } then {
+ continue
+}
+
+set prms_id 0
+set bug_id 0
+
+global srcfile
+set testfile "catch-syscall"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+# All (but the last) syscalls from the example code
+# They are ordered according to the file, so do not change this.
+set all_syscalls { "close" "chroot" }
+set all_syscalls_numbers { }
+# The last syscall (exit()) does not return, so
+# we cannot expect the catchpoint to be triggered
+# twice. It is a special case.
+set last_syscall "exit_group"
+
+if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+ untested catch-syscall.exp
+ return -1
+}
+
+# Until "catch syscall" is implemented on other targets...
+if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then {
+ continue
+}
+
+# This shall be updated whenever 'catch syscall' is implemented
+# on some architecture.
+#if { ![istarget "x86_64-*-linux*"] && ![istarget "i\[34567\]86-*-linux*"]
+if { ![istarget "i\[34567\]86-*-linux*"]
+ && ![istarget "powerpc-*-linux*"] && ![istarget "powerpc64-*-linux*"] } {
+ continue
+}
+
+# Internal procedure used to check if, after issuing a 'catch syscall'
+# command (without arguments), the 'info breakpoints' command displays
+# that '"any syscall"' is to be caught.
+proc check_info_bp_any_syscall {} {
+ global gdb_prompt
+
+ # Verifying that the catchpoint appears in the 'info breakpoints'
+ # command, but with "<any syscall>".
+ set thistest "catch syscall appears in 'info breakpoints'"
+ gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall \"<any syscall>\".*" $thistest
+}
+
+# Internal procedure used to check if, after issuing a 'catch syscall X'
+# command (with arguments), the 'info breakpoints' command displays
+# that the syscall 'X' is to be caught.
+proc check_info_bp_specific_syscall { syscall } {
+ global gdb_prompt
+
+ set thistest "syscall(s) $syscall appears in 'info breakpoints'"
+ gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall(\[(\]s\[)\])? (.)?${syscall}(.)?.*" $thistest
+}
+
+# Internal procedure used to check if, after issuing a 'catch syscall X'
+# command (with many arguments), the 'info breakpoints' command displays
+# that the syscalls 'X' are to be caught.
+proc check_info_bp_many_syscalls { syscalls } {
+ global gdb_prompt
+ set filter_str ""
+
+ foreach name $syscalls {
+ set filter_str "${filter_str}${name}, "
+ }
+
+ set filter_str [ string trimright $filter_str ", " ]
+
+ set thistest "syscalls $filter_str appears in 'info breakpoints'"
+ gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscalls (.)?${filter_str}(.)?.*" $thistest
+}
+
+# This procedure checks if there was a call to a syscall.
+proc check_call_to_syscall { syscall } {
+ global gdb_prompt
+
+ set thistest "program has called $syscall"
+ gdb_test "continue" "Catchpoint .*(call to syscall .?${syscall}.?).*" $thistest
+}
+
+# This procedure checks if the syscall returned.
+proc check_return_from_syscall { syscall } {
+ global gdb_prompt
+
+ set thistest "syscall $syscall has returned"
+ gdb_test "continue" "Catchpoint .*(returned from syscall (.)?${syscall}(.)?).*" $thistest
+}
+
+# Internal procedure that performs two 'continue' commands and checks if
+# a syscall call AND return occur.
+proc check_continue { syscall } {
+ global gdb_prompt
+
+ # Testing if the 'continue' stops at the
+ # specified syscall_name. If it does, then it should
+ # first print that the infeior has called the syscall,
+ # and after print that the syscall has returned.
+
+ # Testing if the inferiorr has called the syscall.
+ check_call_to_syscall $syscall
+ # And now, that the syscall has returned.
+ check_return_from_syscall $syscall
+}
+
+# Inserts a syscall catchpoint with an argument.
+proc insert_catch_syscall_with_arg { syscall } {
+ global gdb_prompt
+
+ # Trying to set the catchpoint
+ set thistest "catch syscall with arguments ($syscall)"
+ gdb_test "catch syscall $syscall" "Catchpoint .*(syscall (.)?${syscall}(.)?( \[\[0-9\]+\])?).*" $thistest
+
+ check_info_bp_specific_syscall $syscall
+}
+
+# Inserts a syscall catchpoint with many arguments.
+proc insert_catch_syscall_with_many_args { syscalls numbers } {
+ global gdb_prompt
+ set catch [ join $syscalls " " ]
+ set filter_str ""
+
+ foreach name $syscalls number $numbers {
+ set filter_str "${filter_str}'${name}' \[${number}\] "
+ }
+
+ set filter_str [ string trimright $filter_str " " ]
+
+ # Trying to set the catchpoint
+ set thistest "catch syscall with arguments ($filter_str)"
+ gdb_test "catch syscall $catch" "Catchpoint .*(syscalls (.)?${filter_str}(.)?).*" $thistest
+
+ check_info_bp_many_syscalls $syscalls
+}
+
+proc check_for_program_end {} {
+ global gdb_prompt
+
+ # Deleting the catchpoints
+ delete_breakpoints
+
+ set thistest "successful program end"
+ gdb_test "continue" "Program exited normally.*" $thistest
+
+}
+
+proc test_catch_syscall_without_args {} {
+ global gdb_prompt all_syscalls last_syscall
+
+ # Trying to set the syscall
+ set thistest "setting catch syscall without arguments"
+ gdb_test "catch syscall" "Catchpoint .*(syscall).*" $thistest
+
+ check_info_bp_any_syscall
+
+ # We have to check every syscall
+ foreach name $all_syscalls {
+ check_continue $name
+ }
+
+ # At last but not least, we check if the inferior
+ # has called the last (exit) syscall.
+ check_call_to_syscall $last_syscall
+
+ # Now let's see if the inferior correctly finishes.
+ check_for_program_end
+}
+
+proc test_catch_syscall_with_args {} {
+ global gdb_prompt
+ set syscall_name "close"
+
+ insert_catch_syscall_with_arg $syscall_name
+
+ # Can we continue until we catch the syscall?
+ check_continue $syscall_name
+
+ # Now let's see if the inferior correctly finishes.
+ check_for_program_end
+}
+
+proc test_catch_syscall_with_many_args {} {
+ global gdb_prompt all_syscalls all_syscalls_numbers
+
+ insert_catch_syscall_with_many_args $all_syscalls $all_syscalls_numbers
+
+ # Can we continue until we catch the syscalls?
+ foreach name $all_syscalls {
+ check_continue $name
+ }
+
+ # Now let's see if the inferior correctly finishes.
+ check_for_program_end
+}
+
+proc test_catch_syscall_with_wrong_args {} {
+ global gdb_prompt
+ # mlock is not called from the source
+ set syscall_name "mlock"
+
+ insert_catch_syscall_with_arg $syscall_name
+
+ # Now, we must verify if the program stops with a continue.
+ # If it doesn't, everything is right (since we don't have
+ # a syscall named "mlock" in it). Otherwise, this is a failure.
+ set thistest "catch syscall with unused syscall ($syscall_name)"
+ gdb_test "continue" "Program exited normally.*" $thistest
+}
+
+proc test_catch_syscall_restarting_inferior {} {
+ global gdb_prompt
+ set syscall_name "chroot"
+
+ insert_catch_syscall_with_arg $syscall_name
+
+ # Let's first reach the call of the syscall.
+ check_call_to_syscall $syscall_name
+
+ # Now, restart the program
+ rerun_to_main
+
+ # And check for call/return
+ check_continue $syscall_name
+
+ # Can we finish?
+ check_for_program_end
+}
+
+proc do_syscall_tests {} {
+ global gdb_prompt srcdir
+
+ # First, we need to set GDB datadir.
+ send_gdb "set data-directory $srcdir/..\n"
+ gdb_expect 10 {
+ -re "$gdb_prompt $" {
+ verbose "Setting GDB datadir to $srcdir/..." 2
+ }
+ timeout {
+ error "Couldn't set GDB datadir."
+ }
+ }
+
+ # Verify that the 'catch syscall' help is available
+ set thistest "help catch syscall"
+ gdb_test "help catch syscall" "Catch system calls.*" $thistest
+
+ # Try to set a catchpoint to a nonsense syscall
+ set thistest "catch syscall to a nonsense syscall is prohibited"
+ gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .*" $thistest
+
+ # Testing the 'catch syscall' command without arguments.
+ # This test should catch any syscalls.
+ if [runto_main] then { test_catch_syscall_without_args }
+
+ # Testing the 'catch syscall' command with arguments.
+ # This test should only catch the specified syscall.
+ if [runto_main] then { test_catch_syscall_with_args }
+
+ # Testing the 'catch syscall' command with many arguments.
+ # This test should catch $all_syscalls.
+ if [runto_main] then { test_catch_syscall_with_many_args }
+
+ # Testing the 'catch syscall' command with WRONG arguments.
+ # This test should not trigger any catchpoints.
+ if [runto_main] then { test_catch_syscall_with_wrong_args }
+
+ # Testing the 'catch' syscall command during a restart of
+ # the inferior.
+ if [runto_main] then { test_catch_syscall_restarting_inferior }
+}
+
+proc test_catch_syscall_fail_noxml {} {
+ global gdb_prompt
+
+ # Sanitizing.
+ delete_breakpoints
+
+ # Testing to see if we receive a warning when calling "catch syscall"
+ # without XML support.
+ set thistest "Catch syscall displays a warning when there is no XML support"
+ gdb_test "catch syscall" "warning: Could not open .*warning: Could not load the syscall XML file .*GDB will not be able to display syscall names.*Catchpoint .*(syscall).*" $thistest
+
+ # Since the catchpoint was set, we must check if it's present at
+ # "info breakpoints"
+ check_info_bp_any_syscall
+
+ # Sanitizing.
+ delete_breakpoints
+}
+
+proc test_catch_syscall_without_args_noxml {} {
+ # We will need the syscall names even not using it
+ # because we need to know know many syscalls are in
+ # the example file.
+ global gdb_prompt all_syscalls last_syscall
+
+ delete_breakpoints
+
+ set thistest "Catch syscall without arguments and without XML support"
+ gdb_test "catch syscall" "Catchpoint .*(syscall).*"
+
+ # Now, we should be able to set a catchpoint,
+ # and GDB shall not display the warning anymore.
+ foreach name $all_syscalls {
+ # Unfortunately, we don't know the syscall number
+ # that will be caught because this information is
+ # arch-dependent. Thus, we try to catch anything
+ # similar to a number.
+ check_continue "\[0-9\]*"
+ }
+
+ # At last but not least, we check if the inferior
+ # has called the last (exit) syscall.
+ check_call_to_syscall "\[0-9\]*"
+
+ delete_breakpoints
+}
+
+proc test_catch_syscall_with_args_noxml {} {
+ global gdb_prompt
+
+ # The number of the "close" syscall. This is our
+ # option for a "long-estabilished" syscall in all
+ # Linux architectures, but unfortunately x86_64 and
+ # a few other platforms don't "follow the convention".
+ # Because of this, we need this ugly check :-(.
+ set close_number ""
+ if { [istarget "x86_64-*-linux*"] } {
+ set close_number "3"
+ } else {
+ set close_number "6"
+ }
+
+ delete_breakpoints
+
+ insert_catch_syscall_with_arg $close_number
+
+ check_continue $close_number
+
+ delete_breakpoints
+}
+
+proc test_catch_syscall_with_wrong_args_noxml {} {
+ global gdb_prompt
+
+ delete_breakpoints
+
+ # Even without XML support, GDB should not accept unknown
+ # syscall names for the catchpoint.
+ set thistest "Catch a nonsense syscall without XML support"
+ gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .nonsense_syscall.*" $thistest
+
+ delete_breakpoints
+}
+
+proc do_syscall_tests_without_xml {} {
+ global gdb_prompt srcdir
+
+ # In this case, we don't need to set GDB's datadir because
+ # we want GDB to display only numbers, not names. So, let's
+ # begin with the tests.
+
+ # The first test is to see if GDB displays a warning when we
+ # try to catch syscalls without the XML support.
+ test_catch_syscall_fail_noxml
+
+ # Now, let's test if we can catch syscalls without XML support.
+ # We should succeed, but GDB is not supposed to print syscall names.
+ if [runto_main] then { test_catch_syscall_without_args_noxml }
+
+ # The only valid argument "catch syscall" should accept is the
+ # syscall number, and not the name (since it can't translate a
+ # name to a number).
+ #
+ # It's worth mentioning that we only try to catch the syscall
+ # close(). This is because the syscall number is an arch-dependent
+ # information, so we can't assume that we know every syscall number
+ # in this system. Therefore, we have decided to use a "long-estabilished"
+ # system call, and close() just sounded the right choice :-).
+ if [runto_main] then { test_catch_syscall_with_args_noxml }
+
+ # Now, we'll try to provide a syscall name (valid or not) to the command,
+ # and expect it to fail.
+ if [runto_main] then { test_catch_syscall_with_wrong_args_noxml }
+}
+
+# This procedure fills the vector "all_syscalls_numbers" with the proper
+# numbers for the used syscalls according to the architecture.
+proc fill_all_syscalls_numbers {} {
+ global all_syscalls_numbers
+
+ # For Linux on x86, PPC and PPC64, the numbers for the syscalls "close" and
+ # "chroot" are the same.
+ if { ![istarget "i\[34567\]86-*-linux*"]
+ || ![istarget "powerpc-*-linux*"] || ![istarget "powerpc64-*-linux*"] } {
+ set all_syscalls_numbers { "6" "61" }
+ }
+}
+
+# Start with a fresh gdb
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Execute the tests, using XML support
+do_syscall_tests
+
+# Restart gdb
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Execute the tests, without XML support. In this case, GDB will
+# only display syscall numbers, and not syscall names.
+do_syscall_tests_without_xml
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] catch syscall -- try 5 -- Source code modifications
2009-04-26 21:35 ` Sérgio Durigan Júnior
@ 2009-04-27 15:07 ` Hui Zhu
2009-04-27 18:50 ` Eli Zaretskii
1 sibling, 0 replies; 6+ messages in thread
From: Hui Zhu @ 2009-04-27 15:07 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: Eli Zaretskii, gdb-patches
The new version works ok with me.
i386-linux ubuntu
Thanks,
Hui
2009/4/27 Sérgio Durigan Júnior <sergiodj@linux.vnet.ibm.com>:
> Hello,
>
> On Sun, 2009-04-26 at 18:30 -0300, Sérgio Durigan Júnior wrote:
>> Hi Eli,
>>
>> On Sat, 2009-04-25 at 12:26 +0300, Eli Zaretskii wrote:
>> > > From: =?ISO-8859-1?Q?S=E9rgio?= Durigan =?ISO-8859-1?Q?J=FAnior?= <sergiodj@linux.vnet.ibm.com>
>> > > Date: Wed, 22 Apr 2009 21:33:03 -0300
>>
>> Thanks for the comments. Here goes the new version.
>
> I've made a mistake, sorry. This is the new version.
>
> Regards,
>
> --
> Sérgio Durigan Júnior
> Linux on Power Toolchain - Software Engineer
> Linux Technology Center - LTC
> IBM Brazil
>
> gdb/ChangeLog:
>
> 2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
>
> * Makefile.in: Support for relocatable GDB datadir and XML
> syscall.
> * NEWS: Added information about the catch syscall feature.
>
> gdb/doc/ChangeLog:
>
> 2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
>
> * gdb.texinfo (Set Catchpoints): Documentation about the new
> feature.
>
> gdb/testsuite/ChangeLog:
>
> 2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
>
> * Makefile.in: Inclusion of catch-syscall object.
> * gdb.base/catch-syscall.c: New file.
> * gdb.base/catch-syscall.exp: New file.
>
>
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [PATCH 1/3] catch syscall -- try 5 -- Source code modifications
2009-04-26 21:35 ` Sérgio Durigan Júnior
2009-04-27 15:07 ` Hui Zhu
@ 2009-04-27 18:50 ` Eli Zaretskii
1 sibling, 0 replies; 6+ messages in thread
From: Eli Zaretskii @ 2009-04-27 18:50 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>
> Cc: gdb-patches@sourceware.org
> Date: Sun, 26 Apr 2009 18:34:59 -0300
>
> * NEWS: Added information about the catch syscall feature.
>
> gdb/doc/ChangeLog:
>
> 2009-04-26 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
>
> * gdb.texinfo (Set Catchpoints): Documentation about the new
> feature.
These two parts are approved, thanks.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2009-04-27 18:50 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-04-23 0:34 [PATCH 1/3] catch syscall -- try 5 -- Source code modifications Sérgio Durigan Júnior
2009-04-25 9:27 ` Eli Zaretskii
2009-04-26 21:31 ` Sérgio Durigan Júnior
2009-04-26 21:35 ` Sérgio Durigan Júnior
2009-04-27 15:07 ` Hui Zhu
2009-04-27 18:50 ` Eli Zaretskii
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox