* [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
@ 2009-01-26 0:31 Sérgio Durigan Júnior
2009-01-26 0:51 ` Pedro Alves
0 siblings, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-01-26 0:31 UTC (permalink / raw)
To: gdb-patches; +Cc: teawater
[-- Attachment #1: Type: text/plain, Size: 3430 bytes --]
Here goes the architecture-independent part of the patch.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
gdb/ChangeLog:
2009-01-25 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* breakpoint.c (clear_syscall_catchpoints_info): New function.
(set_raw_breakpoint_without_location): Setting the parameters
for the catch syscall feature.
(any_syscall_count, syscall_counts, syscalls_size,
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.
(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 (syscall_filter): New.
(struct breakpoint): Add field 'syscall_number' (used to know
which syscall triggered the catchpoint) and
'syscalls_to_be_caught' (used to know which syscalls we are trying
to catch).
(clear_syscall_catchpoints_info): New.
(catch_syscall_enabled): New.
(catching_syscall_number): New.
* defs.h (gdb_datadir): New variable.
* gdbarch.c: Regenerated.
* gdbarch.h: Regenerated.
* gdbarch.sh: Add syscall catchpoint functions.
(get_syscall_number): New.
(get_syscall_by_number): new.
(get_syscall_by_name): New.
(get_syscalls_names): New.
(xml_syscall_filename): New variable.
* 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.
* infcmd.c (run_command_1): Clean syscall catchpoint info on every
run.
* infrun.c (resume): Add syscall catchpoint and entry breakpoint.
(deal_with_syscall_event): New.
(handle_inferior_event): Add syscall entry/return events. Also,
add entry breakpoint event.
(inferior_has_called_syscall): New.
* main.c: Add gdb_datadir variable to store the current GDB datadir.
(captured_main): Add the GDB datadir relocatable handler.
* linux-nat.c (linux_child_post_attach): Calling
linux_enable_tracesysgood.
(linux_child_post_startup_inferior): Likewise.
(linux_target_install_ops): Setting the default methods.
* maint.c: Create the "maintenance set gdb_datadir" command.
* target.c (update_current_target): Update/copy functions related to
syscall catchpoint and entry breakpoint.
(debug_to_wait): 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 and entry
breakpoint.
(inferior_has_called_syscall): New.
(target_passed_by_entrypoint): New.
(target_set_syscall_catchpoint): New.
(target_enable_tracesysgood): New.
[-- Attachment #2: catch-syscall-arch-indep.patch --]
[-- Type: text/x-patch, Size: 48320 bytes --]
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 65bbca9..22c5e55 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -191,6 +191,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
static void insert_breakpoint_locations (void);
+static int syscall_catchpoint_p (struct breakpoint *b);
+
static const char *
bpdisp_text (enum bpdisp disp)
{
@@ -341,6 +343,18 @@ set_breakpoint_count (int num)
value_from_longest (builtin_type_int32, (LONGEST) num));
}
+/* Used in run_command to reset syscall catchpoints fields. */
+
+void
+clear_syscall_catchpoints_info (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (syscall_catchpoint_p (b))
+ b->syscall_number = UNKNOWN_SYSCALL;
+}
+
/* Used in run_command to zero the hit count when a new run starts. */
void
@@ -4135,6 +4149,8 @@ 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->syscall_number = UNKNOWN_SYSCALL;
b->ops = NULL;
b->condition_not_parsed = 0;
@@ -4654,7 +4670,238 @@ 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. */
+static int *syscalls_counts;
+
+/* Number of system entries in SYSCALLS_COUNTS. */
+static int syscalls_size;
+
+/* 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
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ if (iter->syscall >= syscalls_size)
+ {
+ syscalls_counts = xrealloc (syscalls_counts,
+ (iter->syscall + 1) * sizeof (int));
+ memset (&syscalls_counts[syscalls_size], 0,
+ (iter->syscall + 1 - syscalls_size) * sizeof (int));
+ }
+ ++syscalls_counts[iter->syscall];
+ }
+ }
+
+ target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ syscalls_size,
+ 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
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ if (iter->syscall >= syscalls_size)
+ {
+ /* Shouldn't happen. */
+ continue;
+ }
+ --syscalls_counts[iter->syscall];
+ }
+ }
+
+ return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ syscalls_size,
+ 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)
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ if (syscall_number == iter->syscall)
+ break;
+ /* Not the same. */
+ if (!iter)
+ return 0;
+ }
+
+ /* It's the same syscall. We can update the breakpoint struct
+ with the correct information. */
+ b->syscall_number = syscall_number;
+
+ 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;
+
+ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s);
+
+ get_last_target_status (&ptid, &last);
+
+ annotate_catchpoint (b->number);
+ printf_filtered (_("\nCatchpoint %d ("), b->number);
+
+ if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
+ printf_filtered (_("call to "));
+ else
+ printf_filtered (_("returned from "));
+
+ printf_filtered (_("syscall "));
+
+ if (s.name == NULL)
+ printf_filtered (_("%d"), b->syscall_number);
+ else
+ printf_filtered (_("'%s'"), s.name);
+
+ printf_filtered (_("), "));
+
+ 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;
+ struct syscall s;
+
+ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s);
+
+ 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 \"");
+ if (b->syscall_number != UNKNOWN_SYSCALL)
+ {
+ if (s.name)
+ ui_out_field_string (uiout, "what", s.name);
+ else
+ ui_out_field_int (uiout, "what", b->syscall_number);
+ }
+ 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)
+ {
+ struct syscall_filter *iter;
+ printf_filtered (_("Catchpoint %d (syscall(s)"), b->number);
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ struct syscall s;
+ gdbarch_get_syscall_by_number (current_gdbarch, iter->syscall, &s);
+
+ if (s.name)
+ printf_filtered (" '%s'", s.name);
+ else
+ printf_filtered (" %d", iter->syscall);
+ }
+ 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.
@@ -4662,16 +4909,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);
@@ -4685,6 +4929,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);
@@ -4769,6 +5030,23 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
print_mention_catch_exec
};
+static void
+create_syscall_event_catchpoint (int tempflag, struct syscall_filter *filter,
+ struct breakpoint_ops *ops)
+{
+ struct breakpoint *b =
+ create_catchpoint_without_mention (tempflag, NULL, ops);
+
+ b->syscalls_to_be_caught = filter;
+ /* We still don't know the syscall that will be caught :-). */
+ b->syscall_number = UNKNOWN_SYSCALL;
+
+ /* 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)
{
@@ -6659,6 +6937,122 @@ 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)
+{
+ struct syscall_filter *iter = *(struct syscall_filter **) arg;
+ while (iter)
+ {
+ struct syscall_filter *next = iter->next;
+ xfree (iter);
+ iter = next;
+ }
+}
+
+/* Splits the argument using space as delimiter. Returns an xmalloc'd
+ filter list, or NULL if no filtering is required. */
+static struct syscall_filter *
+catch_syscall_split_args (char *arg)
+{
+ struct syscall_filter *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_filter *new_filter;
+ 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')
+ {
+ gdbarch_get_syscall_by_number (current_gdbarch,
+ 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. */
+ gdbarch_get_syscall_by_name (current_gdbarch, 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. */
+ new_filter = XNEW (struct syscall_filter);
+ new_filter->syscall = s.number;
+ new_filter->next = result;
+ result = new_filter;
+ }
+
+ 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;
+ struct syscall_filter *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. */
+ gdbarch_get_syscall_by_number (current_gdbarch, 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
@@ -7125,6 +7519,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?
@@ -8032,6 +8427,56 @@ 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)
+ {
+ struct syscall_filter *iter;
+ for (iter = bp->syscalls_to_be_caught; iter; iter = iter->next)
+ if (syscall_number == iter->syscall)
+ return 1;
+ }
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Complete syscall names. Used by "catch syscall". */
+static char **
+catch_syscall_completer (char *text, char *word)
+{
+ const char **list =
+ gdbarch_get_syscall_names (current_gdbarch);
+ return (list == NULL) ? NULL : complete_on_enum (list, text, word);
+}
+
\f
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
@@ -8064,6 +8509,7 @@ static void
add_catch_command (char *name, char *docstring,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element *command),
+ char ** (*completion_function) (char *text, char *word),
void *user_data_catch,
void *user_data_tcatch)
{
@@ -8073,11 +8519,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, completion_function);
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, completion_function);
}
void
@@ -8352,36 +8800,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 b2db9eb..d176177 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:
@@ -337,6 +338,17 @@ enum watchpoint_triggered
watch_triggered_yes
};
+/* A syscall filter is represented as a linked list of syscall
+ numbers. */
+struct syscall_filter
+{
+ /* The system call to accept. */
+ int syscall;
+
+ /* The next filter. */
+ struct syscall_filter *next;
+};
+
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);
@@ -442,6 +454,20 @@ struct breakpoint
triggered. */
char *exec_pathname;
+ /* Syscall number used for the 'catch syscall' feature.
+ If no syscall has been called, its value is UNKNOWN_SYSCALL.
+ Otherwise, it holds the system call number in the target.
+
+ This field is only valid immediately after this catchpoint has
+ triggered. */
+ int syscall_number;
+
+ /* 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. */
+ struct syscall_filter *syscalls_to_be_caught;
+
/* Methods associated with this breakpoint. */
struct breakpoint_ops *ops;
@@ -782,6 +808,8 @@ extern void enable_watchpoints_after_interactive_call_stop (void);
extern enum command_control_type commands_from_control_command
(char *arg, struct command_line *cmd);
+extern void clear_syscall_catchpoints_info (void);
+
extern void clear_breakpoint_hit_counts (void);
extern int get_number (char **);
@@ -856,6 +884,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/defs.h b/gdb/defs.h
index 209b11d..92bbe5a 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -151,6 +151,9 @@ extern int dbx_commands;
/* System root path, used to find libraries etc. */
extern char *gdb_sysroot;
+/* GDB datadir, used to store data files. */
+extern char *gdb_datadir;
+
/* Search path for separate debug files. */
extern char *debug_file_directory;
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index c328a2b..48aa420 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -240,6 +240,11 @@ struct gdbarch
gdbarch_target_signal_from_host_ftype *target_signal_from_host;
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_record_special_symbol_ftype *record_special_symbol;
+ gdbarch_get_syscall_number_ftype *get_syscall_number;
+ gdbarch_get_syscall_by_number_ftype *get_syscall_by_number;
+ gdbarch_get_syscall_by_name_ftype *get_syscall_by_name;
+ gdbarch_get_syscall_names_ftype *get_syscall_names;
+ const char * xml_syscall_filename;
int has_global_solist;
};
@@ -372,6 +377,11 @@ struct gdbarch startup_gdbarch =
default_target_signal_from_host, /* target_signal_from_host */
default_target_signal_to_host, /* target_signal_to_host */
0, /* record_special_symbol */
+ 0, /* get_syscall_number */
+ 0, /* get_syscall_by_number */
+ 0, /* get_syscall_by_name */
+ 0, /* get_syscall_names */
+ 0, /* xml_syscall_filename */
0, /* has_global_solist */
/* startup_gdbarch() */
};
@@ -625,6 +635,11 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of target_signal_from_host, invalid_p == 0 */
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of record_special_symbol, has predicate */
+ /* Skip verify of get_syscall_number, has predicate */
+ /* Skip verify of get_syscall_by_number, has predicate */
+ /* Skip verify of get_syscall_by_name, has predicate */
+ /* Skip verify of get_syscall_names, has predicate */
+ /* Skip verify of xml_syscall_filename, invalid_p == 0 */
/* Skip verify of has_global_solist, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
@@ -835,6 +850,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: get_longjmp_target = <%s>\n",
host_address_to_string (gdbarch->get_longjmp_target));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_by_name_p() = %d\n",
+ gdbarch_get_syscall_by_name_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_by_name = <0x%lx>\n",
+ (long) gdbarch->get_syscall_by_name);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_by_number_p() = %d\n",
+ gdbarch_get_syscall_by_number_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_by_number = <0x%lx>\n",
+ (long) gdbarch->get_syscall_by_number);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_names_p() = %d\n",
+ gdbarch_get_syscall_names_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_names = <0x%lx>\n",
+ (long) gdbarch->get_syscall_names);
+ 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 = <0x%lx>\n",
+ (long) gdbarch->get_syscall_number);
+ fprintf_unfiltered (file,
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
@@ -1098,6 +1137,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: write_pc = <%s>\n",
host_address_to_string (gdbarch->write_pc));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: xml_syscall_filename = %s\n",
+ gdbarch->xml_syscall_filename);
if (gdbarch->dump_tdep != NULL)
gdbarch->dump_tdep (gdbarch, file);
}
@@ -3244,6 +3286,119 @@ 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_get_syscall_by_number_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_by_number != NULL;
+}
+
+void
+gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_by_number != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_number called\n");
+ gdbarch->get_syscall_by_number (gdbarch, syscall_number, s);
+}
+
+void
+set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_by_number_ftype get_syscall_by_number)
+{
+ gdbarch->get_syscall_by_number = get_syscall_by_number;
+}
+
+int
+gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_by_name != NULL;
+}
+
+void
+gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_by_name != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_name called\n");
+ gdbarch->get_syscall_by_name (gdbarch, syscall_name, s);
+}
+
+void
+set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_by_name_ftype get_syscall_by_name)
+{
+ gdbarch->get_syscall_by_name = get_syscall_by_name;
+}
+
+int
+gdbarch_get_syscall_names_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_names != NULL;
+}
+
+const char **
+gdbarch_get_syscall_names (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_names != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_names called\n");
+ return gdbarch->get_syscall_names (gdbarch);
+}
+
+void
+set_gdbarch_get_syscall_names (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_names_ftype get_syscall_names)
+{
+ gdbarch->get_syscall_names = get_syscall_names;
+}
+
+const char *
+gdbarch_xml_syscall_filename (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of xml_syscall_filename, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_xml_syscall_filename called\n");
+ return gdbarch->xml_syscall_filename;
+}
+
+void
+set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch,
+ const char * xml_syscall_filename)
+{
+ gdbarch->xml_syscall_filename = xml_syscall_filename;
+}
+
+int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 35f8a36..dd9950d 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;
@@ -811,6 +812,47 @@ 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);
+/* Functions 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);
+
+/* Fills the struct syscall (passed as argument) with the corresponding
+ system call represented by syscall_number. */
+
+extern int gdbarch_get_syscall_by_number_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_get_syscall_by_number_ftype) (struct gdbarch *gdbarch, int syscall_number, struct syscall *s);
+extern void gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s);
+extern void set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, gdbarch_get_syscall_by_number_ftype *get_syscall_by_number);
+
+/* Fills the struct syscall (passed as argument) with the corresponding
+ system call represented by syscall_name. */
+
+extern int gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_get_syscall_by_name_ftype) (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s);
+extern void gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s);
+extern void set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, gdbarch_get_syscall_by_name_ftype *get_syscall_by_name);
+
+/* Returns the array containing the syscall names for the architecture. */
+
+extern int gdbarch_get_syscall_names_p (struct gdbarch *gdbarch);
+
+typedef const char ** (gdbarch_get_syscall_names_ftype) (struct gdbarch *gdbarch);
+extern const char ** gdbarch_get_syscall_names (struct gdbarch *gdbarch);
+extern void set_gdbarch_get_syscall_names (struct gdbarch *gdbarch, gdbarch_get_syscall_names_ftype *get_syscall_names);
+
+/* Stores the name of syscall's XML file. Contains NULL if the file
+ was not set. */
+
+extern const char * gdbarch_xml_syscall_filename (struct gdbarch *gdbarch);
+extern void set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch, const char * xml_syscall_filename);
+
/* 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
@@ -820,6 +862,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 dc8fb08..953a30b 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -708,6 +708,26 @@ m:int:target_signal_to_host:enum target_signal ts:ts::default_target_signal_to_h
# Record architecture-specific information from the symbol table.
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+# Functions for the 'catch syscall' feature.
+
+# Get architecture-specific system calls information from registers.
+M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+
+# Fills the struct syscall (passed as argument) with the corresponding
+# system call represented by syscall_number.
+M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
+
+# Fills the struct syscall (passed as argument) with the corresponding
+# system call represented by syscall_name.
+M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
+
+# Returns the array containing the syscall names for the architecture.
+M:const char **:get_syscall_names:void:
+
+# Stores the name of syscall's XML file. Contains NULL if the file
+# was not set.
+v:const char *:xml_syscall_filename:::0:0::0:gdbarch->xml_syscall_filename
+
# 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
@@ -826,6 +846,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;
@@ -895,6 +916,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/inf-child.c b/gdb/inf-child.c
index 2e95c9b..25fcd8a 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -145,6 +145,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;
@@ -187,6 +196,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 538816d..3e34e25 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -352,13 +352,19 @@ static void
inf_ptrace_resume (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 (target_passed_by_entrypoint () > 0
+ && 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/infcmd.c b/gdb/infcmd.c
index 3696f79..b379ddd 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -466,6 +466,11 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
init_wait_for_inferior ();
clear_breakpoint_hit_counts ();
+ /* If we already caught a syscall catchpoint, then reset its
+ syscall_number information because we are starting all over
+ again. */
+ clear_syscall_catchpoints_info ();
+
/* Clean up any leftovers from other runs. Some other things from
this function should probably be moved into target_pre_inferior. */
target_pre_inferior (from_tty);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2b74beb..a991b9e 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1046,7 +1046,7 @@ a command like `return' or `jump' to continue execution."));
}
}
- /* 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)
{
@@ -1069,6 +1069,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;
}
@@ -1509,7 +1514,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 ();
@@ -2109,6 +2114,50 @@ 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);
+ if (catch_syscall_enabled () > 0
+ && catching_syscall_number (syscall_number) > 0)
+ {
+ 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. */
@@ -2403,9 +2452,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
@@ -2415,9 +2466,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)
@@ -5054,6 +5106,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 9a7e39c..1d0f66f 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -676,6 +676,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
@@ -683,6 +684,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
+ linux_enable_tracesysgood (ptid);
}
static int
@@ -4160,6 +4162,7 @@ linux_target_install_ops (struct target_ops *t)
t->to_follow_fork = linux_child_follow_fork;
t->to_find_memory_regions = linux_nat_find_memory_regions;
t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+ t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
super_xfer_partial = t->to_xfer_partial;
t->to_xfer_partial = linux_xfer_partial;
diff --git a/gdb/main.c b/gdb/main.c
index 0eb9596..a4405e7 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -62,6 +62,9 @@ int dbx_commands = 0;
/* System root path, used to find libraries etc. */
char *gdb_sysroot = 0;
+/* GDB datadir, used to store data files. */
+char *gdb_datadir = 0;
+
struct ui_file *gdb_stdout;
struct ui_file *gdb_stderr;
struct ui_file *gdb_stdlog;
@@ -274,6 +277,40 @@ captured_main (void *data)
}
}
+#ifdef GDB_DATADIR_RELOCATABLE
+ gdb_datadir = make_relative_prefix (argv[0], BINDIR, GDB_DATADIR);
+ if (gdb_datadir)
+ {
+ struct stat s;
+ int res = 0;
+
+ if (stat (gdb_datadir, &s) == 0)
+ if (S_ISDIR (s.st_mode))
+ res = 1;
+
+ if (res == 0)
+ {
+ xfree (gdb_datadir);
+ gdb_datadir = xstrdup (GDB_DATADIR);
+ }
+ }
+ else
+ gdb_datadir = xstrdup (GDB_DATADIR);
+#else
+ gdb_datadir = xstrdup (GDB_DATADIR);
+#endif /* GDB_DATADIR_RELOCATABLE */
+
+ /* Canonicalize the GDB's datadir path. */
+ if (*gdb_datadir)
+ {
+ char *canon_debug = lrealpath (gdb_datadir);
+ if (canon_debug)
+ {
+ xfree (gdb_datadir);
+ gdb_datadir = canon_debug;
+ }
+ }
+
/* There will always be an interpreter. Either the one passed into
this captured main, or one specified by the user at start up, or
the console. Initialize the interpreter to the one requested by
diff --git a/gdb/maint.c b/gdb/maint.c
index 489234c..fae0724 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -906,4 +906,12 @@ When enabled GDB is profiled."),
show_maintenance_profile_p,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
+ add_setshow_filename_cmd ("gdb_datadir", class_maintenance,
+ &gdb_datadir, _("Set GDB's datadir path."),
+ _("Show GDB's datadir path."),
+ _("\
+When set, GDB uses the specified path to search for data files."),
+ NULL, NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
}
diff --git a/gdb/target.c b/gdb/target.c
index 78a0a1b..91ca86b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -456,6 +456,8 @@ update_current_target (void)
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
+ INHERIT (to_passed_by_entrypoint, t);
+ INHERIT (to_set_syscall_catchpoint, t);
INHERIT (to_has_exited, t);
/* Do no inherit to_mourn_inferiour. */
INHERIT (to_can_run, t);
@@ -611,9 +613,15 @@ update_current_target (void)
de_fault (to_insert_exec_catchpoint,
(void (*) (int))
tcomplain);
+ de_fault (to_passed_by_entrypoint,
+ (int (*) (void))
+ tcomplain);
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);
@@ -2640,6 +2648,12 @@ debug_to_wait (ptid_t ptid, struct target_waitstatus *status)
case TARGET_WAITKIND_EXECD:
fprintf_unfiltered (gdb_stdlog, "execd\n");
break;
+ case TARGET_WAITKIND_SYSCALL_ENTRY:
+ fprintf_unfiltered (gdb_stdlog, "entered syscall\n");
+ break;
+ case TARGET_WAITKIND_SYSCALL_RETURN:
+ fprintf_unfiltered (gdb_stdlog, "exited syscall\n");
+ break;
case TARGET_WAITKIND_SPURIOUS:
fprintf_unfiltered (gdb_stdlog, "spurious\n");
break;
diff --git a/gdb/target.h b/gdb/target.h
index 188c9a4..cda6be9 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -139,18 +139,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 name. */
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;
+ };
+
/* Possible types of events that the inferior handler will have to
deal with. */
enum inferior_event_type
@@ -392,6 +408,8 @@ 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_passed_by_entrypoint) (void);
+ 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);
@@ -725,6 +743,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 *);
@@ -883,6 +903,21 @@ int target_follow_fork (int follow_child);
#define target_remove_exec_catchpoint(pid) \
(*current_target.to_remove_exec_catchpoint) (pid)
+/* Has the inferior already passed through its entrypoint? */
+#define target_passed_by_entrypoint() \
+ (*current_target.to_passed_by_entrypoint) ()
+
+/* 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. */
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-01-26 0:31 [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part Sérgio Durigan Júnior
@ 2009-01-26 0:51 ` Pedro Alves
2009-01-26 4:56 ` Sérgio Durigan Júnior
0 siblings, 1 reply; 19+ messages in thread
From: Pedro Alves @ 2009-01-26 0:51 UTC (permalink / raw)
To: gdb-patches; +Cc: Sérgio Durigan Júnior, teawater
One quick comment before bedtime :-),
On Monday 26 January 2009 00:30:31, Sérgio Durigan Júnior wrote:
> + printf_filtered (_("\nCatchpoint %d ("), b->number);
> +
> + if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
> + printf_filtered (_("call to "));
> + else
> + printf_filtered (_("returned from "));
> +
> + printf_filtered (_("syscall "));
> +
> + if (s.name == NULL)
> + printf_filtered (_("%d"), b->syscall_number);
> + else
> + printf_filtered (_("'%s'"), s.name);
> + printf_filtered (_("), "));
> +
Could you please combine this into full sentences, please? It
will be better for translation, and probably clearer to read. Say:
struct cleanup *old_chain;
char *syscall_id;
if (s.name == NULL)
syscall_id = xstrprintf ("%d", b->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), "),
syscall_id);
else
printf_filtered (_("\nCatchpoint %d (returned from %s), "),
syscall_id);
do_cleanups (old_chain);
--
Pedro Alves
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-01-26 0:51 ` Pedro Alves
@ 2009-01-26 4:56 ` Sérgio Durigan Júnior
2009-01-26 17:04 ` Sérgio Durigan Júnior
0 siblings, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-01-26 4:56 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, teawater
[-- Attachment #1: Type: text/plain, Size: 266 bytes --]
On Mon, 2009-01-26 at 00:53 +0000, Pedro Alves wrote:
> Could you please combine this into full sentences, please?
Done :-). Patch attached. Thanks!
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
[-- Attachment #2: catch-syscall-arch-indep.patch --]
[-- Type: text/x-patch, Size: 48477 bytes --]
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 65bbca9..b6bfa4a 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -191,6 +191,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
static void insert_breakpoint_locations (void);
+static int syscall_catchpoint_p (struct breakpoint *b);
+
static const char *
bpdisp_text (enum bpdisp disp)
{
@@ -341,6 +343,18 @@ set_breakpoint_count (int num)
value_from_longest (builtin_type_int32, (LONGEST) num));
}
+/* Used in run_command to reset syscall catchpoints fields. */
+
+void
+clear_syscall_catchpoints_info (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (syscall_catchpoint_p (b))
+ b->syscall_number = UNKNOWN_SYSCALL;
+}
+
/* Used in run_command to zero the hit count when a new run starts. */
void
@@ -4135,6 +4149,8 @@ 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->syscall_number = UNKNOWN_SYSCALL;
b->ops = NULL;
b->condition_not_parsed = 0;
@@ -4654,7 +4670,241 @@ 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. */
+static int *syscalls_counts;
+
+/* Number of system entries in SYSCALLS_COUNTS. */
+static int syscalls_size;
+
+/* 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
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ if (iter->syscall >= syscalls_size)
+ {
+ syscalls_counts = xrealloc (syscalls_counts,
+ (iter->syscall + 1) * sizeof (int));
+ memset (&syscalls_counts[syscalls_size], 0,
+ (iter->syscall + 1 - syscalls_size) * sizeof (int));
+ }
+ ++syscalls_counts[iter->syscall];
+ }
+ }
+
+ target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ syscalls_size,
+ 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
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ if (iter->syscall >= syscalls_size)
+ {
+ /* Shouldn't happen. */
+ continue;
+ }
+ --syscalls_counts[iter->syscall];
+ }
+ }
+
+ return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ syscalls_size,
+ 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)
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ if (syscall_number == iter->syscall)
+ break;
+ /* Not the same. */
+ if (!iter)
+ return 0;
+ }
+
+ /* It's the same syscall. We can update the breakpoint struct
+ with the correct information. */
+ b->syscall_number = syscall_number;
+
+ 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;
+
+ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s);
+
+ get_last_target_status (&ptid, &last);
+
+ annotate_catchpoint (b->number);
+
+ if (s.name == NULL)
+ syscall_id = xstrprintf ("%d", b->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
+ printf_filtered (_("\nCatchpoint %d (returned from %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;
+ struct syscall s;
+
+ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s);
+
+ 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 \"");
+ if (b->syscall_number != UNKNOWN_SYSCALL)
+ {
+ if (s.name)
+ ui_out_field_string (uiout, "what", s.name);
+ else
+ ui_out_field_int (uiout, "what", b->syscall_number);
+ }
+ 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)
+ {
+ struct syscall_filter *iter;
+ printf_filtered (_("Catchpoint %d (syscall(s)"), b->number);
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ struct syscall s;
+ gdbarch_get_syscall_by_number (current_gdbarch, iter->syscall, &s);
+
+ if (s.name)
+ printf_filtered (" '%s'", s.name);
+ else
+ printf_filtered (" %d", iter->syscall);
+ }
+ 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.
@@ -4662,16 +4912,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);
@@ -4685,6 +4932,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);
@@ -4769,6 +5033,23 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
print_mention_catch_exec
};
+static void
+create_syscall_event_catchpoint (int tempflag, struct syscall_filter *filter,
+ struct breakpoint_ops *ops)
+{
+ struct breakpoint *b =
+ create_catchpoint_without_mention (tempflag, NULL, ops);
+
+ b->syscalls_to_be_caught = filter;
+ /* We still don't know the syscall that will be caught :-). */
+ b->syscall_number = UNKNOWN_SYSCALL;
+
+ /* 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)
{
@@ -6659,6 +6940,122 @@ 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)
+{
+ struct syscall_filter *iter = *(struct syscall_filter **) arg;
+ while (iter)
+ {
+ struct syscall_filter *next = iter->next;
+ xfree (iter);
+ iter = next;
+ }
+}
+
+/* Splits the argument using space as delimiter. Returns an xmalloc'd
+ filter list, or NULL if no filtering is required. */
+static struct syscall_filter *
+catch_syscall_split_args (char *arg)
+{
+ struct syscall_filter *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_filter *new_filter;
+ 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')
+ {
+ gdbarch_get_syscall_by_number (current_gdbarch,
+ 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. */
+ gdbarch_get_syscall_by_name (current_gdbarch, 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. */
+ new_filter = XNEW (struct syscall_filter);
+ new_filter->syscall = s.number;
+ new_filter->next = result;
+ result = new_filter;
+ }
+
+ 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;
+ struct syscall_filter *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. */
+ gdbarch_get_syscall_by_number (current_gdbarch, 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
@@ -7125,6 +7522,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?
@@ -8032,6 +8430,56 @@ 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)
+ {
+ struct syscall_filter *iter;
+ for (iter = bp->syscalls_to_be_caught; iter; iter = iter->next)
+ if (syscall_number == iter->syscall)
+ return 1;
+ }
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Complete syscall names. Used by "catch syscall". */
+static char **
+catch_syscall_completer (char *text, char *word)
+{
+ const char **list =
+ gdbarch_get_syscall_names (current_gdbarch);
+ return (list == NULL) ? NULL : complete_on_enum (list, text, word);
+}
+
\f
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
@@ -8064,6 +8512,7 @@ static void
add_catch_command (char *name, char *docstring,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element *command),
+ char ** (*completion_function) (char *text, char *word),
void *user_data_catch,
void *user_data_tcatch)
{
@@ -8073,11 +8522,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, completion_function);
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, completion_function);
}
void
@@ -8352,36 +8803,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 b2db9eb..d176177 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:
@@ -337,6 +338,17 @@ enum watchpoint_triggered
watch_triggered_yes
};
+/* A syscall filter is represented as a linked list of syscall
+ numbers. */
+struct syscall_filter
+{
+ /* The system call to accept. */
+ int syscall;
+
+ /* The next filter. */
+ struct syscall_filter *next;
+};
+
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);
@@ -442,6 +454,20 @@ struct breakpoint
triggered. */
char *exec_pathname;
+ /* Syscall number used for the 'catch syscall' feature.
+ If no syscall has been called, its value is UNKNOWN_SYSCALL.
+ Otherwise, it holds the system call number in the target.
+
+ This field is only valid immediately after this catchpoint has
+ triggered. */
+ int syscall_number;
+
+ /* 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. */
+ struct syscall_filter *syscalls_to_be_caught;
+
/* Methods associated with this breakpoint. */
struct breakpoint_ops *ops;
@@ -782,6 +808,8 @@ extern void enable_watchpoints_after_interactive_call_stop (void);
extern enum command_control_type commands_from_control_command
(char *arg, struct command_line *cmd);
+extern void clear_syscall_catchpoints_info (void);
+
extern void clear_breakpoint_hit_counts (void);
extern int get_number (char **);
@@ -856,6 +884,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/defs.h b/gdb/defs.h
index 209b11d..92bbe5a 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -151,6 +151,9 @@ extern int dbx_commands;
/* System root path, used to find libraries etc. */
extern char *gdb_sysroot;
+/* GDB datadir, used to store data files. */
+extern char *gdb_datadir;
+
/* Search path for separate debug files. */
extern char *debug_file_directory;
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index c328a2b..48aa420 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -240,6 +240,11 @@ struct gdbarch
gdbarch_target_signal_from_host_ftype *target_signal_from_host;
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_record_special_symbol_ftype *record_special_symbol;
+ gdbarch_get_syscall_number_ftype *get_syscall_number;
+ gdbarch_get_syscall_by_number_ftype *get_syscall_by_number;
+ gdbarch_get_syscall_by_name_ftype *get_syscall_by_name;
+ gdbarch_get_syscall_names_ftype *get_syscall_names;
+ const char * xml_syscall_filename;
int has_global_solist;
};
@@ -372,6 +377,11 @@ struct gdbarch startup_gdbarch =
default_target_signal_from_host, /* target_signal_from_host */
default_target_signal_to_host, /* target_signal_to_host */
0, /* record_special_symbol */
+ 0, /* get_syscall_number */
+ 0, /* get_syscall_by_number */
+ 0, /* get_syscall_by_name */
+ 0, /* get_syscall_names */
+ 0, /* xml_syscall_filename */
0, /* has_global_solist */
/* startup_gdbarch() */
};
@@ -625,6 +635,11 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of target_signal_from_host, invalid_p == 0 */
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of record_special_symbol, has predicate */
+ /* Skip verify of get_syscall_number, has predicate */
+ /* Skip verify of get_syscall_by_number, has predicate */
+ /* Skip verify of get_syscall_by_name, has predicate */
+ /* Skip verify of get_syscall_names, has predicate */
+ /* Skip verify of xml_syscall_filename, invalid_p == 0 */
/* Skip verify of has_global_solist, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
@@ -835,6 +850,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: get_longjmp_target = <%s>\n",
host_address_to_string (gdbarch->get_longjmp_target));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_by_name_p() = %d\n",
+ gdbarch_get_syscall_by_name_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_by_name = <0x%lx>\n",
+ (long) gdbarch->get_syscall_by_name);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_by_number_p() = %d\n",
+ gdbarch_get_syscall_by_number_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_by_number = <0x%lx>\n",
+ (long) gdbarch->get_syscall_by_number);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_names_p() = %d\n",
+ gdbarch_get_syscall_names_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_names = <0x%lx>\n",
+ (long) gdbarch->get_syscall_names);
+ 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 = <0x%lx>\n",
+ (long) gdbarch->get_syscall_number);
+ fprintf_unfiltered (file,
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
@@ -1098,6 +1137,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: write_pc = <%s>\n",
host_address_to_string (gdbarch->write_pc));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: xml_syscall_filename = %s\n",
+ gdbarch->xml_syscall_filename);
if (gdbarch->dump_tdep != NULL)
gdbarch->dump_tdep (gdbarch, file);
}
@@ -3244,6 +3286,119 @@ 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_get_syscall_by_number_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_by_number != NULL;
+}
+
+void
+gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_by_number != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_number called\n");
+ gdbarch->get_syscall_by_number (gdbarch, syscall_number, s);
+}
+
+void
+set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_by_number_ftype get_syscall_by_number)
+{
+ gdbarch->get_syscall_by_number = get_syscall_by_number;
+}
+
+int
+gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_by_name != NULL;
+}
+
+void
+gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_by_name != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_name called\n");
+ gdbarch->get_syscall_by_name (gdbarch, syscall_name, s);
+}
+
+void
+set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_by_name_ftype get_syscall_by_name)
+{
+ gdbarch->get_syscall_by_name = get_syscall_by_name;
+}
+
+int
+gdbarch_get_syscall_names_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_names != NULL;
+}
+
+const char **
+gdbarch_get_syscall_names (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_names != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_names called\n");
+ return gdbarch->get_syscall_names (gdbarch);
+}
+
+void
+set_gdbarch_get_syscall_names (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_names_ftype get_syscall_names)
+{
+ gdbarch->get_syscall_names = get_syscall_names;
+}
+
+const char *
+gdbarch_xml_syscall_filename (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of xml_syscall_filename, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_xml_syscall_filename called\n");
+ return gdbarch->xml_syscall_filename;
+}
+
+void
+set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch,
+ const char * xml_syscall_filename)
+{
+ gdbarch->xml_syscall_filename = xml_syscall_filename;
+}
+
+int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 35f8a36..dd9950d 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;
@@ -811,6 +812,47 @@ 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);
+/* Functions 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);
+
+/* Fills the struct syscall (passed as argument) with the corresponding
+ system call represented by syscall_number. */
+
+extern int gdbarch_get_syscall_by_number_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_get_syscall_by_number_ftype) (struct gdbarch *gdbarch, int syscall_number, struct syscall *s);
+extern void gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s);
+extern void set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, gdbarch_get_syscall_by_number_ftype *get_syscall_by_number);
+
+/* Fills the struct syscall (passed as argument) with the corresponding
+ system call represented by syscall_name. */
+
+extern int gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_get_syscall_by_name_ftype) (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s);
+extern void gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s);
+extern void set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, gdbarch_get_syscall_by_name_ftype *get_syscall_by_name);
+
+/* Returns the array containing the syscall names for the architecture. */
+
+extern int gdbarch_get_syscall_names_p (struct gdbarch *gdbarch);
+
+typedef const char ** (gdbarch_get_syscall_names_ftype) (struct gdbarch *gdbarch);
+extern const char ** gdbarch_get_syscall_names (struct gdbarch *gdbarch);
+extern void set_gdbarch_get_syscall_names (struct gdbarch *gdbarch, gdbarch_get_syscall_names_ftype *get_syscall_names);
+
+/* Stores the name of syscall's XML file. Contains NULL if the file
+ was not set. */
+
+extern const char * gdbarch_xml_syscall_filename (struct gdbarch *gdbarch);
+extern void set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch, const char * xml_syscall_filename);
+
/* 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
@@ -820,6 +862,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 dc8fb08..953a30b 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -708,6 +708,26 @@ m:int:target_signal_to_host:enum target_signal ts:ts::default_target_signal_to_h
# Record architecture-specific information from the symbol table.
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+# Functions for the 'catch syscall' feature.
+
+# Get architecture-specific system calls information from registers.
+M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+
+# Fills the struct syscall (passed as argument) with the corresponding
+# system call represented by syscall_number.
+M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
+
+# Fills the struct syscall (passed as argument) with the corresponding
+# system call represented by syscall_name.
+M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
+
+# Returns the array containing the syscall names for the architecture.
+M:const char **:get_syscall_names:void:
+
+# Stores the name of syscall's XML file. Contains NULL if the file
+# was not set.
+v:const char *:xml_syscall_filename:::0:0::0:gdbarch->xml_syscall_filename
+
# 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
@@ -826,6 +846,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;
@@ -895,6 +916,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/inf-child.c b/gdb/inf-child.c
index 2e95c9b..25fcd8a 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -145,6 +145,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;
@@ -187,6 +196,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 538816d..3e34e25 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -352,13 +352,19 @@ static void
inf_ptrace_resume (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 (target_passed_by_entrypoint () > 0
+ && 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/infcmd.c b/gdb/infcmd.c
index a0189c8..84d0aa4 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -466,6 +466,11 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
init_wait_for_inferior ();
clear_breakpoint_hit_counts ();
+ /* If we already caught a syscall catchpoint, then reset its
+ syscall_number information because we are starting all over
+ again. */
+ clear_syscall_catchpoints_info ();
+
/* Clean up any leftovers from other runs. Some other things from
this function should probably be moved into target_pre_inferior. */
target_pre_inferior (from_tty);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2b74beb..a991b9e 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1046,7 +1046,7 @@ a command like `return' or `jump' to continue execution."));
}
}
- /* 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)
{
@@ -1069,6 +1069,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;
}
@@ -1509,7 +1514,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 ();
@@ -2109,6 +2114,50 @@ 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);
+ if (catch_syscall_enabled () > 0
+ && catching_syscall_number (syscall_number) > 0)
+ {
+ 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. */
@@ -2403,9 +2452,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
@@ -2415,9 +2466,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)
@@ -5054,6 +5106,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 9a7e39c..1d0f66f 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -676,6 +676,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
@@ -683,6 +684,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
+ linux_enable_tracesysgood (ptid);
}
static int
@@ -4160,6 +4162,7 @@ linux_target_install_ops (struct target_ops *t)
t->to_follow_fork = linux_child_follow_fork;
t->to_find_memory_regions = linux_nat_find_memory_regions;
t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+ t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
super_xfer_partial = t->to_xfer_partial;
t->to_xfer_partial = linux_xfer_partial;
diff --git a/gdb/main.c b/gdb/main.c
index 0eb9596..a4405e7 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -62,6 +62,9 @@ int dbx_commands = 0;
/* System root path, used to find libraries etc. */
char *gdb_sysroot = 0;
+/* GDB datadir, used to store data files. */
+char *gdb_datadir = 0;
+
struct ui_file *gdb_stdout;
struct ui_file *gdb_stderr;
struct ui_file *gdb_stdlog;
@@ -274,6 +277,40 @@ captured_main (void *data)
}
}
+#ifdef GDB_DATADIR_RELOCATABLE
+ gdb_datadir = make_relative_prefix (argv[0], BINDIR, GDB_DATADIR);
+ if (gdb_datadir)
+ {
+ struct stat s;
+ int res = 0;
+
+ if (stat (gdb_datadir, &s) == 0)
+ if (S_ISDIR (s.st_mode))
+ res = 1;
+
+ if (res == 0)
+ {
+ xfree (gdb_datadir);
+ gdb_datadir = xstrdup (GDB_DATADIR);
+ }
+ }
+ else
+ gdb_datadir = xstrdup (GDB_DATADIR);
+#else
+ gdb_datadir = xstrdup (GDB_DATADIR);
+#endif /* GDB_DATADIR_RELOCATABLE */
+
+ /* Canonicalize the GDB's datadir path. */
+ if (*gdb_datadir)
+ {
+ char *canon_debug = lrealpath (gdb_datadir);
+ if (canon_debug)
+ {
+ xfree (gdb_datadir);
+ gdb_datadir = canon_debug;
+ }
+ }
+
/* There will always be an interpreter. Either the one passed into
this captured main, or one specified by the user at start up, or
the console. Initialize the interpreter to the one requested by
diff --git a/gdb/maint.c b/gdb/maint.c
index 489234c..fae0724 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -906,4 +906,12 @@ When enabled GDB is profiled."),
show_maintenance_profile_p,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
+ add_setshow_filename_cmd ("gdb_datadir", class_maintenance,
+ &gdb_datadir, _("Set GDB's datadir path."),
+ _("Show GDB's datadir path."),
+ _("\
+When set, GDB uses the specified path to search for data files."),
+ NULL, NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
}
diff --git a/gdb/target.c b/gdb/target.c
index 78a0a1b..91ca86b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -456,6 +456,8 @@ update_current_target (void)
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
+ INHERIT (to_passed_by_entrypoint, t);
+ INHERIT (to_set_syscall_catchpoint, t);
INHERIT (to_has_exited, t);
/* Do no inherit to_mourn_inferiour. */
INHERIT (to_can_run, t);
@@ -611,9 +613,15 @@ update_current_target (void)
de_fault (to_insert_exec_catchpoint,
(void (*) (int))
tcomplain);
+ de_fault (to_passed_by_entrypoint,
+ (int (*) (void))
+ tcomplain);
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);
@@ -2640,6 +2648,12 @@ debug_to_wait (ptid_t ptid, struct target_waitstatus *status)
case TARGET_WAITKIND_EXECD:
fprintf_unfiltered (gdb_stdlog, "execd\n");
break;
+ case TARGET_WAITKIND_SYSCALL_ENTRY:
+ fprintf_unfiltered (gdb_stdlog, "entered syscall\n");
+ break;
+ case TARGET_WAITKIND_SYSCALL_RETURN:
+ fprintf_unfiltered (gdb_stdlog, "exited syscall\n");
+ break;
case TARGET_WAITKIND_SPURIOUS:
fprintf_unfiltered (gdb_stdlog, "spurious\n");
break;
diff --git a/gdb/target.h b/gdb/target.h
index 188c9a4..cda6be9 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -139,18 +139,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 name. */
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;
+ };
+
/* Possible types of events that the inferior handler will have to
deal with. */
enum inferior_event_type
@@ -392,6 +408,8 @@ 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_passed_by_entrypoint) (void);
+ 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);
@@ -725,6 +743,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 *);
@@ -883,6 +903,21 @@ int target_follow_fork (int follow_child);
#define target_remove_exec_catchpoint(pid) \
(*current_target.to_remove_exec_catchpoint) (pid)
+/* Has the inferior already passed through its entrypoint? */
+#define target_passed_by_entrypoint() \
+ (*current_target.to_passed_by_entrypoint) ()
+
+/* 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. */
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-01-26 4:56 ` Sérgio Durigan Júnior
@ 2009-01-26 17:04 ` Sérgio Durigan Júnior
2009-02-01 19:33 ` Daniel Jacobowitz
0 siblings, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-01-26 17:04 UTC (permalink / raw)
To: Pedro Alves; +Cc: gdb-patches, teawater
[-- Attachment #1: Type: text/plain, Size: 483 bytes --]
Ops, I did a little mistake in the patch and it wasn't passing the
testsuite. Now it's fixed. Please consider this last version.
Thanks,
On Mon, 2009-01-26 at 02:55 -0200, Sérgio Durigan Júnior wrote:
> On Mon, 2009-01-26 at 00:53 +0000, Pedro Alves wrote:
>
> > Could you please combine this into full sentences, please?
>
> Done :-). Patch attached. Thanks!
>
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
[-- Attachment #2: catch-syscall-arch-indep.patch --]
[-- Type: text/x-patch, Size: 48485 bytes --]
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 65bbca9..c8474ac 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -191,6 +191,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
static void insert_breakpoint_locations (void);
+static int syscall_catchpoint_p (struct breakpoint *b);
+
static const char *
bpdisp_text (enum bpdisp disp)
{
@@ -341,6 +343,18 @@ set_breakpoint_count (int num)
value_from_longest (builtin_type_int32, (LONGEST) num));
}
+/* Used in run_command to reset syscall catchpoints fields. */
+
+void
+clear_syscall_catchpoints_info (void)
+{
+ struct breakpoint *b;
+
+ ALL_BREAKPOINTS (b)
+ if (syscall_catchpoint_p (b))
+ b->syscall_number = UNKNOWN_SYSCALL;
+}
+
/* Used in run_command to zero the hit count when a new run starts. */
void
@@ -4135,6 +4149,8 @@ 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->syscall_number = UNKNOWN_SYSCALL;
b->ops = NULL;
b->condition_not_parsed = 0;
@@ -4654,7 +4670,241 @@ 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. */
+static int *syscalls_counts;
+
+/* Number of system entries in SYSCALLS_COUNTS. */
+static int syscalls_size;
+
+/* 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
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ if (iter->syscall >= syscalls_size)
+ {
+ syscalls_counts = xrealloc (syscalls_counts,
+ (iter->syscall + 1) * sizeof (int));
+ memset (&syscalls_counts[syscalls_size], 0,
+ (iter->syscall + 1 - syscalls_size) * sizeof (int));
+ }
+ ++syscalls_counts[iter->syscall];
+ }
+ }
+
+ target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ syscalls_size,
+ 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
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ if (iter->syscall >= syscalls_size)
+ {
+ /* Shouldn't happen. */
+ continue;
+ }
+ --syscalls_counts[iter->syscall];
+ }
+ }
+
+ return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
+ total_syscalls_count != 0,
+ any_syscall_count,
+ syscalls_size,
+ 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)
+ {
+ struct syscall_filter *iter;
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ if (syscall_number == iter->syscall)
+ break;
+ /* Not the same. */
+ if (!iter)
+ return 0;
+ }
+
+ /* It's the same syscall. We can update the breakpoint struct
+ with the correct information. */
+ b->syscall_number = syscall_number;
+
+ 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;
+
+ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s);
+
+ get_last_target_status (&ptid, &last);
+
+ annotate_catchpoint (b->number);
+
+ if (s.name == NULL)
+ syscall_id = xstrprintf ("%d", b->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
+ 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;
+ struct syscall s;
+
+ gdbarch_get_syscall_by_number (current_gdbarch, b->syscall_number, &s);
+
+ 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 \"");
+ if (b->syscall_number != UNKNOWN_SYSCALL)
+ {
+ if (s.name)
+ ui_out_field_string (uiout, "what", s.name);
+ else
+ ui_out_field_int (uiout, "what", b->syscall_number);
+ }
+ 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)
+ {
+ struct syscall_filter *iter;
+ printf_filtered (_("Catchpoint %d (syscall(s)"), b->number);
+ for (iter = b->syscalls_to_be_caught; iter; iter = iter->next)
+ {
+ struct syscall s;
+ gdbarch_get_syscall_by_number (current_gdbarch, iter->syscall, &s);
+
+ if (s.name)
+ printf_filtered (" '%s'", s.name);
+ else
+ printf_filtered (" %d", iter->syscall);
+ }
+ 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.
@@ -4662,16 +4912,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);
@@ -4685,6 +4932,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);
@@ -4769,6 +5033,23 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
print_mention_catch_exec
};
+static void
+create_syscall_event_catchpoint (int tempflag, struct syscall_filter *filter,
+ struct breakpoint_ops *ops)
+{
+ struct breakpoint *b =
+ create_catchpoint_without_mention (tempflag, NULL, ops);
+
+ b->syscalls_to_be_caught = filter;
+ /* We still don't know the syscall that will be caught :-). */
+ b->syscall_number = UNKNOWN_SYSCALL;
+
+ /* 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)
{
@@ -6659,6 +6940,122 @@ 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)
+{
+ struct syscall_filter *iter = *(struct syscall_filter **) arg;
+ while (iter)
+ {
+ struct syscall_filter *next = iter->next;
+ xfree (iter);
+ iter = next;
+ }
+}
+
+/* Splits the argument using space as delimiter. Returns an xmalloc'd
+ filter list, or NULL if no filtering is required. */
+static struct syscall_filter *
+catch_syscall_split_args (char *arg)
+{
+ struct syscall_filter *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_filter *new_filter;
+ 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')
+ {
+ gdbarch_get_syscall_by_number (current_gdbarch,
+ 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. */
+ gdbarch_get_syscall_by_name (current_gdbarch, 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. */
+ new_filter = XNEW (struct syscall_filter);
+ new_filter->syscall = s.number;
+ new_filter->next = result;
+ result = new_filter;
+ }
+
+ 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;
+ struct syscall_filter *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. */
+ gdbarch_get_syscall_by_number (current_gdbarch, 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
@@ -7125,6 +7522,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?
@@ -8032,6 +8430,56 @@ 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)
+ {
+ struct syscall_filter *iter;
+ for (iter = bp->syscalls_to_be_caught; iter; iter = iter->next)
+ if (syscall_number == iter->syscall)
+ return 1;
+ }
+ else
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Complete syscall names. Used by "catch syscall". */
+static char **
+catch_syscall_completer (char *text, char *word)
+{
+ const char **list =
+ gdbarch_get_syscall_names (current_gdbarch);
+ return (list == NULL) ? NULL : complete_on_enum (list, text, word);
+}
+
\f
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
@@ -8064,6 +8512,7 @@ static void
add_catch_command (char *name, char *docstring,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element *command),
+ char ** (*completion_function) (char *text, char *word),
void *user_data_catch,
void *user_data_tcatch)
{
@@ -8073,11 +8522,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, completion_function);
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, completion_function);
}
void
@@ -8352,36 +8803,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 b2db9eb..d176177 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:
@@ -337,6 +338,17 @@ enum watchpoint_triggered
watch_triggered_yes
};
+/* A syscall filter is represented as a linked list of syscall
+ numbers. */
+struct syscall_filter
+{
+ /* The system call to accept. */
+ int syscall;
+
+ /* The next filter. */
+ struct syscall_filter *next;
+};
+
typedef struct bp_location *bp_location_p;
DEF_VEC_P(bp_location_p);
@@ -442,6 +454,20 @@ struct breakpoint
triggered. */
char *exec_pathname;
+ /* Syscall number used for the 'catch syscall' feature.
+ If no syscall has been called, its value is UNKNOWN_SYSCALL.
+ Otherwise, it holds the system call number in the target.
+
+ This field is only valid immediately after this catchpoint has
+ triggered. */
+ int syscall_number;
+
+ /* 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. */
+ struct syscall_filter *syscalls_to_be_caught;
+
/* Methods associated with this breakpoint. */
struct breakpoint_ops *ops;
@@ -782,6 +808,8 @@ extern void enable_watchpoints_after_interactive_call_stop (void);
extern enum command_control_type commands_from_control_command
(char *arg, struct command_line *cmd);
+extern void clear_syscall_catchpoints_info (void);
+
extern void clear_breakpoint_hit_counts (void);
extern int get_number (char **);
@@ -856,6 +884,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/defs.h b/gdb/defs.h
index 209b11d..92bbe5a 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -151,6 +151,9 @@ extern int dbx_commands;
/* System root path, used to find libraries etc. */
extern char *gdb_sysroot;
+/* GDB datadir, used to store data files. */
+extern char *gdb_datadir;
+
/* Search path for separate debug files. */
extern char *debug_file_directory;
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index c328a2b..48aa420 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -240,6 +240,11 @@ struct gdbarch
gdbarch_target_signal_from_host_ftype *target_signal_from_host;
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_record_special_symbol_ftype *record_special_symbol;
+ gdbarch_get_syscall_number_ftype *get_syscall_number;
+ gdbarch_get_syscall_by_number_ftype *get_syscall_by_number;
+ gdbarch_get_syscall_by_name_ftype *get_syscall_by_name;
+ gdbarch_get_syscall_names_ftype *get_syscall_names;
+ const char * xml_syscall_filename;
int has_global_solist;
};
@@ -372,6 +377,11 @@ struct gdbarch startup_gdbarch =
default_target_signal_from_host, /* target_signal_from_host */
default_target_signal_to_host, /* target_signal_to_host */
0, /* record_special_symbol */
+ 0, /* get_syscall_number */
+ 0, /* get_syscall_by_number */
+ 0, /* get_syscall_by_name */
+ 0, /* get_syscall_names */
+ 0, /* xml_syscall_filename */
0, /* has_global_solist */
/* startup_gdbarch() */
};
@@ -625,6 +635,11 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of target_signal_from_host, invalid_p == 0 */
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of record_special_symbol, has predicate */
+ /* Skip verify of get_syscall_number, has predicate */
+ /* Skip verify of get_syscall_by_number, has predicate */
+ /* Skip verify of get_syscall_by_name, has predicate */
+ /* Skip verify of get_syscall_names, has predicate */
+ /* Skip verify of xml_syscall_filename, invalid_p == 0 */
/* Skip verify of has_global_solist, invalid_p == 0 */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
@@ -835,6 +850,30 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: get_longjmp_target = <%s>\n",
host_address_to_string (gdbarch->get_longjmp_target));
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_by_name_p() = %d\n",
+ gdbarch_get_syscall_by_name_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_by_name = <0x%lx>\n",
+ (long) gdbarch->get_syscall_by_name);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_by_number_p() = %d\n",
+ gdbarch_get_syscall_by_number_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_by_number = <0x%lx>\n",
+ (long) gdbarch->get_syscall_by_number);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_get_syscall_names_p() = %d\n",
+ gdbarch_get_syscall_names_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: get_syscall_names = <0x%lx>\n",
+ (long) gdbarch->get_syscall_names);
+ 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 = <0x%lx>\n",
+ (long) gdbarch->get_syscall_number);
+ fprintf_unfiltered (file,
"gdbarch_dump: has_global_solist = %s\n",
plongest (gdbarch->has_global_solist));
fprintf_unfiltered (file,
@@ -1098,6 +1137,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: write_pc = <%s>\n",
host_address_to_string (gdbarch->write_pc));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: xml_syscall_filename = %s\n",
+ gdbarch->xml_syscall_filename);
if (gdbarch->dump_tdep != NULL)
gdbarch->dump_tdep (gdbarch, file);
}
@@ -3244,6 +3286,119 @@ 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_get_syscall_by_number_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_by_number != NULL;
+}
+
+void
+gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_by_number != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_number called\n");
+ gdbarch->get_syscall_by_number (gdbarch, syscall_number, s);
+}
+
+void
+set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_by_number_ftype get_syscall_by_number)
+{
+ gdbarch->get_syscall_by_number = get_syscall_by_number;
+}
+
+int
+gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_by_name != NULL;
+}
+
+void
+gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_by_name != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_by_name called\n");
+ gdbarch->get_syscall_by_name (gdbarch, syscall_name, s);
+}
+
+void
+set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_by_name_ftype get_syscall_by_name)
+{
+ gdbarch->get_syscall_by_name = get_syscall_by_name;
+}
+
+int
+gdbarch_get_syscall_names_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->get_syscall_names != NULL;
+}
+
+const char **
+gdbarch_get_syscall_names (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->get_syscall_names != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_names called\n");
+ return gdbarch->get_syscall_names (gdbarch);
+}
+
+void
+set_gdbarch_get_syscall_names (struct gdbarch *gdbarch,
+ gdbarch_get_syscall_names_ftype get_syscall_names)
+{
+ gdbarch->get_syscall_names = get_syscall_names;
+}
+
+const char *
+gdbarch_xml_syscall_filename (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ /* Skip verify of xml_syscall_filename, invalid_p == 0 */
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_xml_syscall_filename called\n");
+ return gdbarch->xml_syscall_filename;
+}
+
+void
+set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch,
+ const char * xml_syscall_filename)
+{
+ gdbarch->xml_syscall_filename = xml_syscall_filename;
+}
+
+int
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{
gdb_assert (gdbarch != NULL);
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index 35f8a36..dd9950d 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;
@@ -811,6 +812,47 @@ 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);
+/* Functions 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);
+
+/* Fills the struct syscall (passed as argument) with the corresponding
+ system call represented by syscall_number. */
+
+extern int gdbarch_get_syscall_by_number_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_get_syscall_by_number_ftype) (struct gdbarch *gdbarch, int syscall_number, struct syscall *s);
+extern void gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, int syscall_number, struct syscall *s);
+extern void set_gdbarch_get_syscall_by_number (struct gdbarch *gdbarch, gdbarch_get_syscall_by_number_ftype *get_syscall_by_number);
+
+/* Fills the struct syscall (passed as argument) with the corresponding
+ system call represented by syscall_name. */
+
+extern int gdbarch_get_syscall_by_name_p (struct gdbarch *gdbarch);
+
+typedef void (gdbarch_get_syscall_by_name_ftype) (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s);
+extern void gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, const char *syscall_name, struct syscall *s);
+extern void set_gdbarch_get_syscall_by_name (struct gdbarch *gdbarch, gdbarch_get_syscall_by_name_ftype *get_syscall_by_name);
+
+/* Returns the array containing the syscall names for the architecture. */
+
+extern int gdbarch_get_syscall_names_p (struct gdbarch *gdbarch);
+
+typedef const char ** (gdbarch_get_syscall_names_ftype) (struct gdbarch *gdbarch);
+extern const char ** gdbarch_get_syscall_names (struct gdbarch *gdbarch);
+extern void set_gdbarch_get_syscall_names (struct gdbarch *gdbarch, gdbarch_get_syscall_names_ftype *get_syscall_names);
+
+/* Stores the name of syscall's XML file. Contains NULL if the file
+ was not set. */
+
+extern const char * gdbarch_xml_syscall_filename (struct gdbarch *gdbarch);
+extern void set_gdbarch_xml_syscall_filename (struct gdbarch *gdbarch, const char * xml_syscall_filename);
+
/* 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
@@ -820,6 +862,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 dc8fb08..953a30b 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -708,6 +708,26 @@ m:int:target_signal_to_host:enum target_signal ts:ts::default_target_signal_to_h
# Record architecture-specific information from the symbol table.
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
+# Functions for the 'catch syscall' feature.
+
+# Get architecture-specific system calls information from registers.
+M:LONGEST:get_syscall_number:ptid_t ptid:ptid
+
+# Fills the struct syscall (passed as argument) with the corresponding
+# system call represented by syscall_number.
+M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
+
+# Fills the struct syscall (passed as argument) with the corresponding
+# system call represented by syscall_name.
+M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
+
+# Returns the array containing the syscall names for the architecture.
+M:const char **:get_syscall_names:void:
+
+# Stores the name of syscall's XML file. Contains NULL if the file
+# was not set.
+v:const char *:xml_syscall_filename:::0:0::0:gdbarch->xml_syscall_filename
+
# 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
@@ -826,6 +846,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;
@@ -895,6 +916,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/inf-child.c b/gdb/inf-child.c
index 2e95c9b..25fcd8a 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -145,6 +145,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;
@@ -187,6 +196,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 538816d..3e34e25 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -352,13 +352,19 @@ static void
inf_ptrace_resume (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 (target_passed_by_entrypoint () > 0
+ && 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/infcmd.c b/gdb/infcmd.c
index a0189c8..84d0aa4 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -466,6 +466,11 @@ run_command_1 (char *args, int from_tty, int tbreak_at_main)
init_wait_for_inferior ();
clear_breakpoint_hit_counts ();
+ /* If we already caught a syscall catchpoint, then reset its
+ syscall_number information because we are starting all over
+ again. */
+ clear_syscall_catchpoints_info ();
+
/* Clean up any leftovers from other runs. Some other things from
this function should probably be moved into target_pre_inferior. */
target_pre_inferior (from_tty);
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 2b74beb..a991b9e 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -1046,7 +1046,7 @@ a command like `return' or `jump' to continue execution."));
}
}
- /* 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)
{
@@ -1069,6 +1069,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;
}
@@ -1509,7 +1514,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 ();
@@ -2109,6 +2114,50 @@ 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);
+ if (catch_syscall_enabled () > 0
+ && catching_syscall_number (syscall_number) > 0)
+ {
+ 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. */
@@ -2403,9 +2452,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
@@ -2415,9 +2466,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)
@@ -5054,6 +5106,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 9a7e39c..1d0f66f 100644
--- a/gdb/linux-nat.c
+++ b/gdb/linux-nat.c
@@ -676,6 +676,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
@@ -683,6 +684,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
+ linux_enable_tracesysgood (ptid);
}
static int
@@ -4160,6 +4162,7 @@ linux_target_install_ops (struct target_ops *t)
t->to_follow_fork = linux_child_follow_fork;
t->to_find_memory_regions = linux_nat_find_memory_regions;
t->to_make_corefile_notes = linux_nat_make_corefile_notes;
+ t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
super_xfer_partial = t->to_xfer_partial;
t->to_xfer_partial = linux_xfer_partial;
diff --git a/gdb/main.c b/gdb/main.c
index 0eb9596..a4405e7 100644
--- a/gdb/main.c
+++ b/gdb/main.c
@@ -62,6 +62,9 @@ int dbx_commands = 0;
/* System root path, used to find libraries etc. */
char *gdb_sysroot = 0;
+/* GDB datadir, used to store data files. */
+char *gdb_datadir = 0;
+
struct ui_file *gdb_stdout;
struct ui_file *gdb_stderr;
struct ui_file *gdb_stdlog;
@@ -274,6 +277,40 @@ captured_main (void *data)
}
}
+#ifdef GDB_DATADIR_RELOCATABLE
+ gdb_datadir = make_relative_prefix (argv[0], BINDIR, GDB_DATADIR);
+ if (gdb_datadir)
+ {
+ struct stat s;
+ int res = 0;
+
+ if (stat (gdb_datadir, &s) == 0)
+ if (S_ISDIR (s.st_mode))
+ res = 1;
+
+ if (res == 0)
+ {
+ xfree (gdb_datadir);
+ gdb_datadir = xstrdup (GDB_DATADIR);
+ }
+ }
+ else
+ gdb_datadir = xstrdup (GDB_DATADIR);
+#else
+ gdb_datadir = xstrdup (GDB_DATADIR);
+#endif /* GDB_DATADIR_RELOCATABLE */
+
+ /* Canonicalize the GDB's datadir path. */
+ if (*gdb_datadir)
+ {
+ char *canon_debug = lrealpath (gdb_datadir);
+ if (canon_debug)
+ {
+ xfree (gdb_datadir);
+ gdb_datadir = canon_debug;
+ }
+ }
+
/* There will always be an interpreter. Either the one passed into
this captured main, or one specified by the user at start up, or
the console. Initialize the interpreter to the one requested by
diff --git a/gdb/maint.c b/gdb/maint.c
index 489234c..fae0724 100644
--- a/gdb/maint.c
+++ b/gdb/maint.c
@@ -906,4 +906,12 @@ When enabled GDB is profiled."),
show_maintenance_profile_p,
&maintenance_set_cmdlist,
&maintenance_show_cmdlist);
+ add_setshow_filename_cmd ("gdb_datadir", class_maintenance,
+ &gdb_datadir, _("Set GDB's datadir path."),
+ _("Show GDB's datadir path."),
+ _("\
+When set, GDB uses the specified path to search for data files."),
+ NULL, NULL,
+ &maintenance_set_cmdlist,
+ &maintenance_show_cmdlist);
}
diff --git a/gdb/target.c b/gdb/target.c
index 78a0a1b..91ca86b 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -456,6 +456,8 @@ update_current_target (void)
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
+ INHERIT (to_passed_by_entrypoint, t);
+ INHERIT (to_set_syscall_catchpoint, t);
INHERIT (to_has_exited, t);
/* Do no inherit to_mourn_inferiour. */
INHERIT (to_can_run, t);
@@ -611,9 +613,15 @@ update_current_target (void)
de_fault (to_insert_exec_catchpoint,
(void (*) (int))
tcomplain);
+ de_fault (to_passed_by_entrypoint,
+ (int (*) (void))
+ tcomplain);
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);
@@ -2640,6 +2648,12 @@ debug_to_wait (ptid_t ptid, struct target_waitstatus *status)
case TARGET_WAITKIND_EXECD:
fprintf_unfiltered (gdb_stdlog, "execd\n");
break;
+ case TARGET_WAITKIND_SYSCALL_ENTRY:
+ fprintf_unfiltered (gdb_stdlog, "entered syscall\n");
+ break;
+ case TARGET_WAITKIND_SYSCALL_RETURN:
+ fprintf_unfiltered (gdb_stdlog, "exited syscall\n");
+ break;
case TARGET_WAITKIND_SPURIOUS:
fprintf_unfiltered (gdb_stdlog, "spurious\n");
break;
diff --git a/gdb/target.h b/gdb/target.h
index 188c9a4..cda6be9 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -139,18 +139,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 name. */
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;
+ };
+
/* Possible types of events that the inferior handler will have to
deal with. */
enum inferior_event_type
@@ -392,6 +408,8 @@ 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_passed_by_entrypoint) (void);
+ 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);
@@ -725,6 +743,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 *);
@@ -883,6 +903,21 @@ int target_follow_fork (int follow_child);
#define target_remove_exec_catchpoint(pid) \
(*current_target.to_remove_exec_catchpoint) (pid)
+/* Has the inferior already passed through its entrypoint? */
+#define target_passed_by_entrypoint() \
+ (*current_target.to_passed_by_entrypoint) ()
+
+/* 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. */
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-01-26 17:04 ` Sérgio Durigan Júnior
@ 2009-02-01 19:33 ` Daniel Jacobowitz
2009-02-25 21:44 ` Sérgio Durigan Júnior
0 siblings, 1 reply; 19+ messages in thread
From: Daniel Jacobowitz @ 2009-02-01 19:33 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: Pedro Alves, gdb-patches, teawater
Hi Sergio,
On Mon, Jan 26, 2009 at 03:02:34PM -0200, Sérgio Durigan Júnior wrote:
> +/* Used in run_command to reset syscall catchpoints fields. */
> +
> +void
> +clear_syscall_catchpoints_info (void)
> +{
> + struct breakpoint *b;
> +
> + ALL_BREAKPOINTS (b)
> + if (syscall_catchpoint_p (b))
> + b->syscall_number = UNKNOWN_SYSCALL;
> +}
> +
> /* Used in run_command to zero the hit count when a new run starts. */
>
> void
I see that the other catchpoints put mutable data in struct breakpoint
too. But it's really not a good idea :-(
In non-stop GDB, suppose we have two threads running. They make
different system calls and stop at the catchpoint. There's only one
'struct breakpoint', though, so do we report that they've both made
the same system call even though they might not have?
Can this go somewhere else? There's already a copy in the waitstatus,
maybe it can stay there if we copy the whole waitstatus into 'struct
thread_info', instead of copying just stop_signal.
> + get_last_target_status (&ptid, &last);
> +
> + annotate_catchpoint (b->number);
> +
> + if (s.name == NULL)
> + syscall_id = xstrprintf ("%d", b->syscall_number);
> + else
> + syscall_id = xstrprintf ("'%s'", s.name);
For instance, here we've got the waitstatus in addition to the breakpoint.
> @@ -4654,7 +4670,241 @@ 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. */
> +static int *syscalls_counts;
> +
> +/* Number of system entries in SYSCALLS_COUNTS. */
> +static int syscalls_size;
> +
> +/* This counts all syscall catch requests, so we can readily determine
> + if any catching is necessary. */
> +static int total_syscalls_count;
At some point, this information should be per-process. That can be a
future enhancement though. Just because we want to trace system calls
in one inferior does't mean we need to use PTRACE_SYSCALL in the
other.
> +/* Implement the "print_one" breakpoint_ops method for syscall
> + catchpoints. */
> +
> +static void
> +print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr)
> +{
Have you tried hitting a syscall catchpoint in MI mode, and is the
output anything useful?
> + 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);
I don't think this warning is useful; if they're entering numbers,
hopefully they know what they're doing.
> @@ -8352,36 +8803,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);
Careful about spaces vs tabs; in general, you should not have any
sequence of eight spaces in an added line in a patch.
> @@ -337,6 +338,17 @@ enum watchpoint_triggered
> watch_triggered_yes
> };
>
> +/* A syscall filter is represented as a linked list of syscall
> + numbers. */
> +struct syscall_filter
> +{
> + /* The system call to accept. */
> + int syscall;
> +
> + /* The next filter. */
> + struct syscall_filter *next;
> +};
> +
> typedef struct bp_location *bp_location_p;
> DEF_VEC_P(bp_location_p);
>
Does this need to be a linked list? Both this, and syscall_counts /
syscall_size, could be represented as VEC(int) (basically the same as
a C++ std::vector). That will simplify the code a bit.
> +# Fills the struct syscall (passed as argument) with the corresponding
> +# system call represented by syscall_number.
> +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> +
> +# Fills the struct syscall (passed as argument) with the corresponding
> +# system call represented by syscall_name.
> +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> +
> +# Returns the array containing the syscall names for the architecture.
> +M:const char **:get_syscall_names:void:
If every target is going to use XML for this, these three do not need
to be gdbarch methods and the support code can move from linux-tdep.c
to xml-syscall.c.
> + if (target_passed_by_entrypoint () > 0
> + && catch_syscall_enabled () > 0)
> + request = PT_SYSCALL;
> + else
> + request = PT_CONTINUE;
Why is target_passed_by_entrypoint still necessary? If we understand
why, I think there'll be some other more appropriate flag. Is it to
avoid using PTRACE_SYSCALL when the shell is running, before the
application starts?
> @@ -2109,6 +2114,50 @@ 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)
A debug_infrun message here that logs the syscall number could be very
handy during debugging.
> diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> index 9a7e39c..1d0f66f 100644
> --- a/gdb/linux-nat.c
> +++ b/gdb/linux-nat.c
> @@ -676,6 +676,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
> @@ -683,6 +684,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
> {
> linux_enable_event_reporting (ptid);
> check_for_thread_db ();
> + linux_enable_tracesysgood (ptid);
> }
>
> static int
> @@ -4160,6 +4162,7 @@ linux_target_install_ops (struct target_ops *t)
> t->to_follow_fork = linux_child_follow_fork;
> t->to_find_memory_regions = linux_nat_find_memory_regions;
> t->to_make_corefile_notes = linux_nat_make_corefile_notes;
> + t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
>
> super_xfer_partial = t->to_xfer_partial;
> t->to_xfer_partial = linux_xfer_partial;
These bits must be for another patch in the series :-)
> diff --git a/gdb/main.c b/gdb/main.c
> index 0eb9596..a4405e7 100644
> --- a/gdb/main.c
> +++ b/gdb/main.c
> @@ -62,6 +62,9 @@ int dbx_commands = 0;
> /* System root path, used to find libraries etc. */
> char *gdb_sysroot = 0;
>
> +/* GDB datadir, used to store data files. */
> +char *gdb_datadir = 0;
> +
This is an example of a piece of the patch which could be separated
out easily. Locating a data directory is logically independent of
system call tracing.
> diff --git a/gdb/maint.c b/gdb/maint.c
> index 489234c..fae0724 100644
> --- a/gdb/maint.c
> +++ b/gdb/maint.c
> @@ -906,4 +906,12 @@ When enabled GDB is profiled."),
> show_maintenance_profile_p,
> &maintenance_set_cmdlist,
> &maintenance_show_cmdlist);
> + add_setshow_filename_cmd ("gdb_datadir", class_maintenance,
> + &gdb_datadir, _("Set GDB's datadir path."),
> + _("Show GDB's datadir path."),
> + _("\
> +When set, GDB uses the specified path to search for data files."),
> + NULL, NULL,
> + &maintenance_set_cmdlist,
> + &maintenance_show_cmdlist);
> }
Just "datadir" (gdb_ is obvious, since this is GDB :-). Or
"data-directory", which will be easier to understand for users, I
think.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-02-01 19:33 ` Daniel Jacobowitz
@ 2009-02-25 21:44 ` Sérgio Durigan Júnior
2009-02-28 0:44 ` Daniel Jacobowitz
0 siblings, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-02-25 21:44 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, gdb-patches, teawater
Hi Daniel,
A few questions before I'm able to resubmit the patch. Thanks for your
review, by the way.
On Sun, 2009-02-01 at 14:33 -0500, Daniel Jacobowitz wrote:
> Hi Sergio,
>
> On Mon, Jan 26, 2009 at 03:02:34PM -0200, Sérgio Durigan Júnior wrote:
> > +/* Used in run_command to reset syscall catchpoints fields. */
> > +
> > +void
> > +clear_syscall_catchpoints_info (void)
> > +{
> > + struct breakpoint *b;
> > +
> > + ALL_BREAKPOINTS (b)
> > + if (syscall_catchpoint_p (b))
> > + b->syscall_number = UNKNOWN_SYSCALL;
> > +}
> > +
> > /* Used in run_command to zero the hit count when a new run starts. */
> >
> > void
>
> I see that the other catchpoints put mutable data in struct breakpoint
> too. But it's really not a good idea :-(
>
> In non-stop GDB, suppose we have two threads running. They make
> different system calls and stop at the catchpoint. There's only one
> 'struct breakpoint', though, so do we report that they've both made
> the same system call even though they might not have?
>
> Can this go somewhere else? There's already a copy in the waitstatus,
> maybe it can stay there if we copy the whole waitstatus into 'struct
> thread_info', instead of copying just stop_signal.
I'm not sure I understood what you said, so please correct me if I'm
wrong. IIUC, you want me to create another field in 'struct
thread_info', and this field would be a 'struct target_waitstatus',
right? This is because you think I could copy the whole 'struct
target_waitstatus' in 'deal_with_syscall_event', and use it someplace
else. Is it right? If it is, I have a question: would I have access to
the current 'struct thread_info' inside breakpoint.c?
> > + get_last_target_status (&ptid, &last);
> > +
> > + annotate_catchpoint (b->number);
> > +
> > + if (s.name == NULL)
> > + syscall_id = xstrprintf ("%d", b->syscall_number);
> > + else
> > + syscall_id = xstrprintf ("'%s'", s.name);
>
> For instance, here we've got the waitstatus in addition to the breakpoint.
That's what confused me. I didn't get if you want me to use 'struct
thread_info' or 'struct target_waitstatus' to hold the syscall_number
info :-).
> > +/* Implement the "print_one" breakpoint_ops method for syscall
> > + catchpoints. */
> > +
> > +static void
> > +print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr)
> > +{
>
> Have you tried hitting a syscall catchpoint in MI mode, and is the
> output anything useful?
No, unfortunately I haven't. Actually, I must first learn how to use the
MI interface, but that should not be hard :-).
> > + 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);
>
> I don't think this warning is useful; if they're entering numbers,
> hopefully they know what they're doing.
Yeah, it's because of the "hopefully" part that I decided to issue this
warning. But that's not a big deal; I'll remove.
> > +# Fills the struct syscall (passed as argument) with the corresponding
> > +# system call represented by syscall_number.
> > +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> > +
> > +# Fills the struct syscall (passed as argument) with the corresponding
> > +# system call represented by syscall_name.
> > +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> > +
> > +# Returns the array containing the syscall names for the architecture.
> > +M:const char **:get_syscall_names:void:
>
> If every target is going to use XML for this, these three do not need
> to be gdbarch methods and the support code can move from linux-tdep.c
> to xml-syscall.c.
As far as I understood (from our discussion a few months ago), not every
target is supposed to use the XML for syscalls. That's specially true
for embedded systems and/or architectures for which the XML file is
missing (for some obscure reason, don't know). That's why I thought it
would be better not to generalize.
> > + if (target_passed_by_entrypoint () > 0
> > + && catch_syscall_enabled () > 0)
> > + request = PT_SYSCALL;
> > + else
> > + request = PT_CONTINUE;
>
> Why is target_passed_by_entrypoint still necessary? If we understand
> why, I think there'll be some other more appropriate flag. Is it to
> avoid using PTRACE_SYSCALL when the shell is running, before the
> application starts?
It's been a long time since I added this check, but as far as I
remember, that's exactly the reason. I tried to remove this, and the
testcase simply freezes. Do you have another idea? :-)
> > diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> > index 9a7e39c..1d0f66f 100644
> > --- a/gdb/linux-nat.c
> > +++ b/gdb/linux-nat.c
> > @@ -676,6 +676,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
> > @@ -683,6 +684,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
> > {
> > linux_enable_event_reporting (ptid);
> > check_for_thread_db ();
> > + linux_enable_tracesysgood (ptid);
> > }
> >
> > static int
> > @@ -4160,6 +4162,7 @@ linux_target_install_ops (struct target_ops *t)
> > t->to_follow_fork = linux_child_follow_fork;
> > t->to_find_memory_regions = linux_nat_find_memory_regions;
> > t->to_make_corefile_notes = linux_nat_make_corefile_notes;
> > + t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
> >
> > super_xfer_partial = t->to_xfer_partial;
> > t->to_xfer_partial = linux_xfer_partial;
>
> These bits must be for another patch in the series :-)
I'm sorry, I didn't understand what you meant by that :-(. These
modifications are all architecture-independent, so this is the right
place for them right?
> > diff --git a/gdb/main.c b/gdb/main.c
> > index 0eb9596..a4405e7 100644
> > --- a/gdb/main.c
> > +++ b/gdb/main.c
> > @@ -62,6 +62,9 @@ int dbx_commands = 0;
> > /* System root path, used to find libraries etc. */
> > char *gdb_sysroot = 0;
> >
> > +/* GDB datadir, used to store data files. */
> > +char *gdb_datadir = 0;
> > +
>
> This is an example of a piece of the patch which could be separated
> out easily. Locating a data directory is logically independent of
> system call tracing.
You're right, I'll send another patch (i.e., another thread) in order to
add these modifications.
Well, I think that's it. Thanks in advance for your attention.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-02-25 21:44 ` Sérgio Durigan Júnior
@ 2009-02-28 0:44 ` Daniel Jacobowitz
2009-03-08 18:16 ` Sérgio Durigan Júnior
2009-03-29 21:16 ` Sérgio Durigan Júnior
0 siblings, 2 replies; 19+ messages in thread
From: Daniel Jacobowitz @ 2009-02-28 0:44 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: Pedro Alves, gdb-patches, teawater
On Wed, Feb 25, 2009 at 08:26:29AM -0300, Sérgio Durigan Júnior wrote:
> I'm not sure I understood what you said, so please correct me if I'm
> wrong. IIUC, you want me to create another field in 'struct
> thread_info', and this field would be a 'struct target_waitstatus',
> right? This is because you think I could copy the whole 'struct
> target_waitstatus' in 'deal_with_syscall_event', and use it someplace
> else. Is it right? If it is, I have a question: would I have access to
> the current 'struct thread_info' inside breakpoint.c?
The copy in to the thread is not syscall-specific, so that's not where
it should go. Maybe in infrun.c below this?
/* Cache the last pid/waitstatus. */
target_last_wait_ptid = ecs->ptid;
target_last_waitstatus = ecs->ws;
...
ecs->event_thread = find_thread_pid (ecs->ptid);
> > > + get_last_target_status (&ptid, &last);
> > > +
> > > + annotate_catchpoint (b->number);
> > > +
> > > + if (s.name == NULL)
> > > + syscall_id = xstrprintf ("%d", b->syscall_number);
> > > + else
> > > + syscall_id = xstrprintf ("'%s'", s.name);
> >
> > For instance, here we've got the waitstatus in addition to the breakpoint.
>
> That's what confused me. I didn't get if you want me to use 'struct
> thread_info' or 'struct target_waitstatus' to hold the syscall_number
> info :-).
It doesn't matter - as long as you don't put it in the breakpoint, and
it comes from somewhere thread-specific.
> > > +/* Implement the "print_one" breakpoint_ops method for syscall
> > > + catchpoints. */
> > > +
> > > +static void
> > > +print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr)
> > > +{
> >
> > Have you tried hitting a syscall catchpoint in MI mode, and is the
> > output anything useful?
>
> No, unfortunately I haven't. Actually, I must first learn how to use the
> MI interface, but that should not be hard :-).
I'd suggest doing that as part of this submission so that we know
you're on the right track. It isn't too hard; you can start by
looking at the test logs from gdb.mi tests, if that helps.
> > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > +# system call represented by syscall_number.
> > > +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> > > +
> > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > +# system call represented by syscall_name.
> > > +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> > > +
> > > +# Returns the array containing the syscall names for the architecture.
> > > +M:const char **:get_syscall_names:void:
> >
> > If every target is going to use XML for this, these three do not need
> > to be gdbarch methods and the support code can move from linux-tdep.c
> > to xml-syscall.c.
>
> As far as I understood (from our discussion a few months ago), not every
> target is supposed to use the XML for syscalls. That's specially true
> for embedded systems and/or architectures for which the XML file is
> missing (for some obscure reason, don't know). That's why I thought it
> would be better not to generalize.
I don't think this is a big deal. If it is, we can handle it the same
way as for target-descriptions: pre-compile them into GDB.
> > > + if (target_passed_by_entrypoint () > 0
> > > + && catch_syscall_enabled () > 0)
> > > + request = PT_SYSCALL;
> > > + else
> > > + request = PT_CONTINUE;
> >
> > Why is target_passed_by_entrypoint still necessary? If we understand
> > why, I think there'll be some other more appropriate flag. Is it to
> > avoid using PTRACE_SYSCALL when the shell is running, before the
> > application starts?
>
> It's been a long time since I added this check, but as far as I
> remember, that's exactly the reason. I tried to remove this, and the
> testcase simply freezes. Do you have another idea? :-)
Not sure that the flag exists any more, but you're trying to avoid it
when called by startup_inferior. I suppose you could use the
inferior_created observer (not new_inferior! The distinction is not
too clear in the manual but that one is too early). The problem is,
again, that this flag needs to be per-inferior.
Pedro, any thoughts?
>
> > > diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> > > index 9a7e39c..1d0f66f 100644
> > > --- a/gdb/linux-nat.c
> > > +++ b/gdb/linux-nat.c
> > > @@ -676,6 +676,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
> > > @@ -683,6 +684,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
> > > {
> > > linux_enable_event_reporting (ptid);
> > > check_for_thread_db ();
> > > + linux_enable_tracesysgood (ptid);
> > > }
> > >
> > > static int
> > > @@ -4160,6 +4162,7 @@ linux_target_install_ops (struct target_ops *t)
> > > t->to_follow_fork = linux_child_follow_fork;
> > > t->to_find_memory_regions = linux_nat_find_memory_regions;
> > > t->to_make_corefile_notes = linux_nat_make_corefile_notes;
> > > + t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
> > >
> > > super_xfer_partial = t->to_xfer_partial;
> > > t->to_xfer_partial = linux_xfer_partial;
> >
> > These bits must be for another patch in the series :-)
>
> I'm sorry, I didn't understand what you meant by that :-(. These
> modifications are all architecture-independent, so this is the right
> place for them right?
No - since they're specific to Linux. Also, I don't think they'll
compile at this point, you haven't added the function yet.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-02-28 0:44 ` Daniel Jacobowitz
@ 2009-03-08 18:16 ` Sérgio Durigan Júnior
2009-03-09 13:19 ` Daniel Jacobowitz
2009-03-29 21:16 ` Sérgio Durigan Júnior
1 sibling, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-03-08 18:16 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, gdb-patches
Hi Daniel,
Thanks for your comments.
On Fri, 2009-02-27 at 17:11 -0500, Daniel Jacobowitz wrote:
> > > > +/* Implement the "print_one" breakpoint_ops method for syscall
> > > > + catchpoints. */
> > > > +
> > > > +static void
> > > > +print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr)
> > > > +{
> > >
> > > Have you tried hitting a syscall catchpoint in MI mode, and is the
> > > output anything useful?
> >
> > No, unfortunately I haven't. Actually, I must first learn how to use the
> > MI interface, but that should not be hard :-).
>
> I'd suggest doing that as part of this submission so that we know
> you're on the right track. It isn't too hard; you can start by
> looking at the test logs from gdb.mi tests, if that helps.
All right, I'll do that today.
> > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > +# system call represented by syscall_number.
> > > > +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> > > > +
> > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > +# system call represented by syscall_name.
> > > > +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> > > > +
> > > > +# Returns the array containing the syscall names for the architecture.
> > > > +M:const char **:get_syscall_names:void:
> > >
> > > If every target is going to use XML for this, these three do not need
> > > to be gdbarch methods and the support code can move from linux-tdep.c
> > > to xml-syscall.c.
> >
> > As far as I understood (from our discussion a few months ago), not every
> > target is supposed to use the XML for syscalls. That's specially true
> > for embedded systems and/or architectures for which the XML file is
> > missing (for some obscure reason, don't know). That's why I thought it
> > would be better not to generalize.
>
> I don't think this is a big deal. If it is, we can handle it the same
> way as for target-descriptions: pre-compile them into GDB.
So I won't modify anything, ok?
> > > > + if (target_passed_by_entrypoint () > 0
> > > > + && catch_syscall_enabled () > 0)
> > > > + request = PT_SYSCALL;
> > > > + else
> > > > + request = PT_CONTINUE;
> > >
> > > Why is target_passed_by_entrypoint still necessary? If we understand
> > > why, I think there'll be some other more appropriate flag. Is it to
> > > avoid using PTRACE_SYSCALL when the shell is running, before the
> > > application starts?
> >
> > It's been a long time since I added this check, but as far as I
> > remember, that's exactly the reason. I tried to remove this, and the
> > testcase simply freezes. Do you have another idea? :-)
>
> Not sure that the flag exists any more, but you're trying to avoid it
> when called by startup_inferior. I suppose you could use the
> inferior_created observer (not new_inferior! The distinction is not
> too clear in the manual but that one is too early). The problem is,
> again, that this flag needs to be per-inferior.
>
> Pedro, any thoughts?
What do you mean by "Not sure that the flag exists any more"? Also, I'm
waiting for Pedro's reply.
> > > > diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c
> > > > index 9a7e39c..1d0f66f 100644
> > > > --- a/gdb/linux-nat.c
> > > > +++ b/gdb/linux-nat.c
> > > > @@ -676,6 +676,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
> > > > @@ -683,6 +684,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
> > > > {
> > > > linux_enable_event_reporting (ptid);
> > > > check_for_thread_db ();
> > > > + linux_enable_tracesysgood (ptid);
> > > > }
> > > >
> > > > static int
> > > > @@ -4160,6 +4162,7 @@ linux_target_install_ops (struct target_ops *t)
> > > > t->to_follow_fork = linux_child_follow_fork;
> > > > t->to_find_memory_regions = linux_nat_find_memory_regions;
> > > > t->to_make_corefile_notes = linux_nat_make_corefile_notes;
> > > > + t->to_passed_by_entrypoint = linux_passed_by_entrypoint;
> > > >
> > > > super_xfer_partial = t->to_xfer_partial;
> > > > t->to_xfer_partial = linux_xfer_partial;
> > >
> > > These bits must be for another patch in the series :-)
> >
> > I'm sorry, I didn't understand what you meant by that :-(. These
> > modifications are all architecture-independent, so this is the right
> > place for them right?
>
> No - since they're specific to Linux. Also, I don't think they'll
> compile at this point, you haven't added the function yet.
Well, I know it's a shame, but the patches for catch syscall don't
compile alone at all. You must have all four patches in order to get
things working, and I haven't even tested if the patches can be compiled
independently. However, you're right regarding this piece of code: it
should be placed in other patch.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-08 18:16 ` Sérgio Durigan Júnior
@ 2009-03-09 13:19 ` Daniel Jacobowitz
2009-03-09 14:09 ` Sérgio Durigan Júnior
2009-03-09 18:31 ` Pedro Alves
0 siblings, 2 replies; 19+ messages in thread
From: Daniel Jacobowitz @ 2009-03-09 13:19 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: Pedro Alves, gdb-patches
On Sun, Mar 08, 2009 at 04:15:58PM -0300, Sérgio Durigan Júnior wrote:
> > > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > > +# system call represented by syscall_number.
> > > > > +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> > > > > +
> > > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > > +# system call represented by syscall_name.
> > > > > +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> > > > > +
> > > > > +# Returns the array containing the syscall names for the architecture.
> > > > > +M:const char **:get_syscall_names:void:
> > > >
> > > > If every target is going to use XML for this, these three do not need
> > > > to be gdbarch methods and the support code can move from linux-tdep.c
> > > > to xml-syscall.c.
> > >
> > > As far as I understood (from our discussion a few months ago), not every
> > > target is supposed to use the XML for syscalls. That's specially true
> > > for embedded systems and/or architectures for which the XML file is
> > > missing (for some obscure reason, don't know). That's why I thought it
> > > would be better not to generalize.
> >
> > I don't think this is a big deal. If it is, we can handle it the same
> > way as for target-descriptions: pre-compile them into GDB.
>
> So I won't modify anything, ok?
Sorry, I was unclear - I still suggest that you drop the extra gdbarch
methods and rearrange. There's nothing Linux-specific about what you
have.
> > Not sure that the flag exists any more, but you're trying to avoid it
> > when called by startup_inferior. I suppose you could use the
> > inferior_created observer (not new_inferior! The distinction is not
> > too clear in the manual but that one is too early). The problem is,
> > again, that this flag needs to be per-inferior.
> >
> > Pedro, any thoughts?
>
> What do you mean by "Not sure that the flag exists any more"? Also, I'm
> waiting for Pedro's reply.
There used to be a global variable for this, but I believe it was
removed.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-09 13:19 ` Daniel Jacobowitz
@ 2009-03-09 14:09 ` Sérgio Durigan Júnior
2009-03-09 18:39 ` Pedro Alves
2009-03-09 18:31 ` Pedro Alves
1 sibling, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-03-09 14:09 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, gdb-patches
On Mon, 2009-03-09 at 09:18 -0400, Daniel Jacobowitz wrote:
> On Sun, Mar 08, 2009 at 04:15:58PM -0300, Sérgio Durigan Júnior wrote:
> > > > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > > > +# system call represented by syscall_number.
> > > > > > +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> > > > > > +
> > > > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > > > +# system call represented by syscall_name.
> > > > > > +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> > > > > > +
> > > > > > +# Returns the array containing the syscall names for the architecture.
> > > > > > +M:const char **:get_syscall_names:void:
> > > > >
> > > > > If every target is going to use XML for this, these three do not need
> > > > > to be gdbarch methods and the support code can move from linux-tdep.c
> > > > > to xml-syscall.c.
> > > >
> > > > As far as I understood (from our discussion a few months ago), not every
> > > > target is supposed to use the XML for syscalls. That's specially true
> > > > for embedded systems and/or architectures for which the XML file is
> > > > missing (for some obscure reason, don't know). That's why I thought it
> > > > would be better not to generalize.
> > >
> > > I don't think this is a big deal. If it is, we can handle it the same
> > > way as for target-descriptions: pre-compile them into GDB.
> >
> > So I won't modify anything, ok?
>
> Sorry, I was unclear - I still suggest that you drop the extra gdbarch
> methods and rearrange. There's nothing Linux-specific about what you
> have.
>
> > > Not sure that the flag exists any more, but you're trying to avoid it
> > > when called by startup_inferior. I suppose you could use the
> > > inferior_created observer (not new_inferior! The distinction is not
> > > too clear in the manual but that one is too early). The problem is,
> > > again, that this flag needs to be per-inferior.
> > >
> > > Pedro, any thoughts?
> >
> > What do you mean by "Not sure that the flag exists any more"? Also, I'm
> > waiting for Pedro's reply.
>
> There used to be a global variable for this, but I believe it was
> removed.
Hmm, right. I need to make a correction about an information I gave you.
I tried to remove the call to target_passed_by_entrypoint, i.e., leaving
the code like this:
if (catch_syscall_enabled () > 0) ...
What happens is that the code does not freeze. GDB still works with
this, and as far as I could investigate it shows everything fine.
Therefore, I think this function is not needed at all.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-09 13:19 ` Daniel Jacobowitz
2009-03-09 14:09 ` Sérgio Durigan Júnior
@ 2009-03-09 18:31 ` Pedro Alves
1 sibling, 0 replies; 19+ messages in thread
From: Pedro Alves @ 2009-03-09 18:31 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Sérgio Durigan Júnior, gdb-patches
On Monday 09 March 2009 13:18:56, Daniel Jacobowitz wrote:
> > > Not sure that the flag exists any more, but you're trying to avoid it
> > > when called by startup_inferior. I suppose you could use the
> > > inferior_created observer (not new_inferior! The distinction is not
> > > too clear in the manual but that one is too early). The problem is,
> > > again, that this flag needs to be per-inferior.
> > >
> > > Pedro, any thoughts?
Makes sense to me.
Alternatively, can we use inf->stop_soon != STOP_QUIETLY for this?
This flag is already per-inferior. The only small problem is, since
startup_inferior was rewritten to not use wait_for_inferior, we're not
setting stop_soon = STOP_QUIETLY while in there anymore. We could
bring that bit back again. Just something like setting stop_soon = STOP_QUIETLY
on entry to startup_inferior, and clear it on exit to NO_STOP_QUIETLY on
exit.
--
Pedro Alves
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-09 14:09 ` Sérgio Durigan Júnior
@ 2009-03-09 18:39 ` Pedro Alves
2009-03-09 18:56 ` Daniel Jacobowitz
0 siblings, 1 reply; 19+ messages in thread
From: Pedro Alves @ 2009-03-09 18:39 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: Daniel Jacobowitz, gdb-patches
On Monday 09 March 2009 15:09:24, Sérgio Durigan Júnior wrote:
> if (catch_syscall_enabled () > 0) ...
>
> What happens is that the code does not freeze. GDB still works with
> this, and as far as I could investigate it shows everything fine.
> Therefore, I think this function is not needed at all.
Oh, was that because you're only enabling PTRACE_O_TRACESYSGOOD
after startup_inferior is finished, in linux_child_post_startup_inferior,
and, PT_SYSCALL just behaves as PT_CONTINUE in that case? That
would make sense to me.
--
Pedro Alves
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-09 18:39 ` Pedro Alves
@ 2009-03-09 18:56 ` Daniel Jacobowitz
0 siblings, 0 replies; 19+ messages in thread
From: Daniel Jacobowitz @ 2009-03-09 18:56 UTC (permalink / raw)
To: Pedro Alves; +Cc: Sérgio Durigan Júnior, gdb-patches
On Mon, Mar 09, 2009 at 06:39:49PM +0000, Pedro Alves wrote:
> On Monday 09 March 2009 15:09:24, Sérgio Durigan Júnior wrote:
> > if (catch_syscall_enabled () > 0) ...
> >
> > What happens is that the code does not freeze. GDB still works with
> > this, and as far as I could investigate it shows everything fine.
> > Therefore, I think this function is not needed at all.
>
> Oh, was that because you're only enabling PTRACE_O_TRACESYSGOOD
> after startup_inferior is finished, in linux_child_post_startup_inferior,
> and, PT_SYSCALL just behaves as PT_CONTINUE in that case? That
> would make sense to me.
No - without PTRACE_O_TRACESYSGOOD, PT_SYSCALL reports a SIGTRAP on
each syscall entry or exit. With it, it reports 0x80 | SIGTRAP.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-02-28 0:44 ` Daniel Jacobowitz
2009-03-08 18:16 ` Sérgio Durigan Júnior
@ 2009-03-29 21:16 ` Sérgio Durigan Júnior
2009-03-31 16:39 ` Daniel Jacobowitz
1 sibling, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-03-29 21:16 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, gdb-patches, teawater
Hi Daniel,
On Fri, 2009-02-27 at 17:11 -0500, Daniel Jacobowitz wrote:
> > > > +/* Implement the "print_one" breakpoint_ops method for syscall
> > > > + catchpoints. */
> > > > +
> > > > +static void
> > > > +print_one_catch_syscall (struct breakpoint *b, CORE_ADDR *last_addr)
> > > > +{
> > >
> > > Have you tried hitting a syscall catchpoint in MI mode, and is the
> > > output anything useful?
> >
> > No, unfortunately I haven't. Actually, I must first learn how to use the
> > MI interface, but that should not be hard :-).
>
> I'd suggest doing that as part of this submission so that we know
> you're on the right track. It isn't too hard; you can start by
> looking at the test logs from gdb.mi tests, if that helps.
I finally had time to test this. In the example below, I tried to catch
the syscall "chroot" using the same testcase used in the
catch-syscall.exp test, and the output is:
(gdb)
maint set data-directory ./gdb
&"maint set data-directory ./gdb\n"
^done
(gdb)
catch syscall chroot
&"catch syscall chroot\n"
~"Catchpoint 1 (syscall(s) 'chroot')\n"
^done
(gdb)
run
&"run\n"
~"Starting
program: /tmp/test-syscall/gdb/testsuite/gdb.base/catch-syscall \n"
=thread-group-created,id="1392"
=thread-created,id="1",group-id="1392"
^running
*running,thread-id="all"
(gdb)
=library-loaded,id="/lib/ld-linux.so.2",target-name="/lib/ld-linux.so.2",host-name="/lib/ld-linux.so.2",symbols-loaded="0"
=library-loaded,id="/lib/libm.so.6",target-name="/lib/libm.so.6",host-name="/lib/libm.so.6",symbols-loaded="0"
=library-loaded,id="/lib/libc.so.6",target-name="/lib/libc.so.6",host-name="/lib/libc.so.6",symbols-loaded="0"
~"\n"
~"Catchpoint 1 (call to syscall 'chroot'), 0xffffe424 in
__kernel_vsyscall ()\n"
~"0xffffe424 <__kernel_vsyscall+16>:\tpop %ebp\n"
*stopped,frame={addr="0xffffe424",func="__kernel_vsyscall",args=[]},thread-id="1",stopped-threads="all"
(gdb)
continue
&"continue\n"
~"Continuing.\n"
^running
*running,thread-id="all"
(gdb)
~"\n"
~"Catchpoint 1 (returned from syscall 'chroot'), 0xffffe424 in
__kernel_vsyscall ()\n"
~"0xffffe424 <__kernel_vsyscall+16>:\tpop %ebp\n"
*stopped,frame={addr="0xffffe424",func="__kernel_vsyscall",args=[]},thread-id="1",stopped-threads="all"
So, what do you think of it? Analyzing it, I think it's not so useful
except for the (obvious) part ~"Catchpoint 1 ...".
> > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > +# system call represented by syscall_number.
> > > > +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> > > > +
> > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > +# system call represented by syscall_name.
> > > > +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> > > > +
> > > > +# Returns the array containing the syscall names for the architecture.
> > > > +M:const char **:get_syscall_names:void:
> > >
> > > If every target is going to use XML for this, these three do not need
> > > to be gdbarch methods and the support code can move from linux-tdep.c
> > > to xml-syscall.c.
> >
> > As far as I understood (from our discussion a few months ago), not every
> > target is supposed to use the XML for syscalls. That's specially true
> > for embedded systems and/or architectures for which the XML file is
> > missing (for some obscure reason, don't know). That's why I thought it
> > would be better not to generalize.
>
> I don't think this is a big deal. If it is, we can handle it the same
> way as for target-descriptions: pre-compile them into GDB.
With this you mean that I should remove the methods from gdbarch?
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-29 21:16 ` Sérgio Durigan Júnior
@ 2009-03-31 16:39 ` Daniel Jacobowitz
2009-04-09 19:29 ` Sérgio Durigan Júnior
2009-04-15 23:12 ` Sérgio Durigan Júnior
0 siblings, 2 replies; 19+ messages in thread
From: Daniel Jacobowitz @ 2009-03-31 16:39 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: Pedro Alves, gdb-patches, teawater
On Sun, Mar 29, 2009 at 03:50:26PM -0300, Sérgio Durigan Júnior wrote:
> ~"Catchpoint 1 (call to syscall 'chroot'), 0xffffe424 in
> __kernel_vsyscall ()\n"
> ~"0xffffe424 <__kernel_vsyscall+16>:\tpop %ebp\n"
> *stopped,frame={addr="0xffffe424",func="__kernel_vsyscall",args=[]},thread-id="1",stopped-threads="all"
> So, what do you think of it? Analyzing it, I think it's not so useful
> except for the (obvious) part ~"Catchpoint 1 ...".
Right. There ought to be a new reason="..." entry; search for
EXEC_ASYNC_BREAKPOINT_HIT. There should probably be some semantic
fields, too, like "old" for watchpoints.
> > > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > > +# system call represented by syscall_number.
> > > > > +M:void:get_syscall_by_number:int syscall_number, struct syscall *s:syscall_number, s
> > > > > +
> > > > > +# Fills the struct syscall (passed as argument) with the corresponding
> > > > > +# system call represented by syscall_name.
> > > > > +M:void:get_syscall_by_name:const char *syscall_name, struct syscall *s:syscall_name, s
> > > > > +
> > > > > +# Returns the array containing the syscall names for the architecture.
> > > > > +M:const char **:get_syscall_names:void:
> > > >
> > > > If every target is going to use XML for this, these three do not need
> > > > to be gdbarch methods and the support code can move from linux-tdep.c
> > > > to xml-syscall.c.
> > >
> > > As far as I understood (from our discussion a few months ago), not every
> > > target is supposed to use the XML for syscalls. That's specially true
> > > for embedded systems and/or architectures for which the XML file is
> > > missing (for some obscure reason, don't know). That's why I thought it
> > > would be better not to generalize.
> >
> > I don't think this is a big deal. If it is, we can handle it the same
> > way as for target-descriptions: pre-compile them into GDB.
>
> With this you mean that I should remove the methods from gdbarch?
Yes, that's what I mean.
The way I think about this is that every gdbarch routine is a way for
some architecture to handle things differently. If we can make every
architecture work the same way, we should do that instead.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-31 16:39 ` Daniel Jacobowitz
@ 2009-04-09 19:29 ` Sérgio Durigan Júnior
2009-04-09 19:36 ` Daniel Jacobowitz
2009-04-15 23:12 ` Sérgio Durigan Júnior
1 sibling, 1 reply; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-04-09 19:29 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, gdb-patches
Hi Daniel,
On Tue, 2009-03-31 at 11:44 -0400, Daniel Jacobowitz wrote:
> On Sun, Mar 29, 2009 at 03:50:26PM -0300, Sérgio Durigan Júnior wrote:
> > ~"Catchpoint 1 (call to syscall 'chroot'), 0xffffe424 in
> > __kernel_vsyscall ()\n"
> > ~"0xffffe424 <__kernel_vsyscall+16>:\tpop %ebp\n"
> > *stopped,frame={addr="0xffffe424",func="__kernel_vsyscall",args=[]},thread-id="1",stopped-threads="all"
>
> > So, what do you think of it? Analyzing it, I think it's not so useful
> > except for the (obvious) part ~"Catchpoint 1 ...".
>
> Right. There ought to be a new reason="..." entry; search for
> EXEC_ASYNC_BREAKPOINT_HIT. There should probably be some semantic
> fields, too, like "old" for watchpoints.
I'm sorry about taking so long to reply your messages, but I'm really
busy with other things here. By the way, that's one of the reasons why
I'm asking this...
Well, I perfectly understand when you (or anyone else here in GDB) ask
me to implement something else in the catch syscall patch, after all
it's important to have a good code in GDB's codebase. But honestly, this
time I think you're exaggerating a little. I know that it would be cool
to have the MI support in the catch syscall feature, and I myself plan
to implement this support in a future not so distant; however, and
specially because I'm very busy these days, I won't be able to dedicate
enough time in order to get it ready for GDB 7.0, and IMHO the catch
syscall would be a *nice* feature to have in this release.
So this is my opinion about this: I have the complete catch syscall
patch here (the only thing that's missing is the MI support), so what do
you think if we just push this patch upstream as-is (which is: in a
pretty good shape, as far as I understood the others developers' --
including yours -- comments), and postpone this MI support? I think I
should be able to sit down and implement this support until the end of
this semester, is it good for you?
Well, thanks for your time, for your valuable reviews about my code, and
for your patience. Please consider my proposal and let me know what you
think about it.
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-04-09 19:29 ` Sérgio Durigan Júnior
@ 2009-04-09 19:36 ` Daniel Jacobowitz
2009-04-09 20:21 ` Sérgio Durigan Júnior
0 siblings, 1 reply; 19+ messages in thread
From: Daniel Jacobowitz @ 2009-04-09 19:36 UTC (permalink / raw)
To: Sérgio Durigan Júnior; +Cc: Pedro Alves, gdb-patches
On Thu, Apr 09, 2009 at 04:29:33PM -0300, Sérgio Durigan Júnior wrote:
> So this is my opinion about this: I have the complete catch syscall
> patch here (the only thing that's missing is the MI support), so what do
> you think if we just push this patch upstream as-is (which is: in a
> pretty good shape, as far as I understood the others developers' --
> including yours -- comments), and postpone this MI support? I think I
> should be able to sit down and implement this support until the end of
> this semester, is it good for you?
Yes, that's fine. If someone else needs it, they'll fill it in.
--
Daniel Jacobowitz
CodeSourcery
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-04-09 19:36 ` Daniel Jacobowitz
@ 2009-04-09 20:21 ` Sérgio Durigan Júnior
0 siblings, 0 replies; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-04-09 20:21 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, gdb-patches
On Thu, 2009-04-09 at 15:35 -0400, Daniel Jacobowitz wrote:
> On Thu, Apr 09, 2009 at 04:29:33PM -0300, Sérgio Durigan Júnior wrote:
> > So this is my opinion about this: I have the complete catch syscall
> > patch here (the only thing that's missing is the MI support), so what do
> > you think if we just push this patch upstream as-is (which is: in a
> > pretty good shape, as far as I understood the others developers' --
> > including yours -- comments), and postpone this MI support? I think I
> > should be able to sit down and implement this support until the end of
> > this semester, is it good for you?
>
> Yes, that's fine. If someone else needs it, they'll fill it in.
Thank you very much, Daniel. I'll prepare the patch for resubmission as
soon as I get some free time here :-).
Regards,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part
2009-03-31 16:39 ` Daniel Jacobowitz
2009-04-09 19:29 ` Sérgio Durigan Júnior
@ 2009-04-15 23:12 ` Sérgio Durigan Júnior
1 sibling, 0 replies; 19+ messages in thread
From: Sérgio Durigan Júnior @ 2009-04-15 23:12 UTC (permalink / raw)
To: Daniel Jacobowitz; +Cc: Pedro Alves, gdb-patches
Hi Daniel,
I forgot to ask one more thing. Here it goes.
On Tue, 2009-03-31 at 11:44 -0400, Daniel Jacobowitz wrote:
> > With this you mean that I should remove the methods from gdbarch?
>
> Yes, that's what I mean.
>
> The way I think about this is that every gdbarch routine is a way for
> some architecture to handle things differently. If we can make every
> architecture work the same way, we should do that instead.
Right, I'm already removing the code from gdbarch, but I'm facing a
problem that I'm unable to solve. Basically, I have a method in gdbarch
called gdbarch_xml_syscall_filename, which returns the name of the XML
that is going to be used. I need this because the XML file is different
for each supported arch.
The thing is that if I remove this, I can't think in a good way to
retrieve this filename. Is it ok to keep this single method inside
gdbarch?
Thanks,
--
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2009-04-15 23:12 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2009-01-26 0:31 [PATCH 1/4] catch syscall -- try 4 -- Architecture-independent part Sérgio Durigan Júnior
2009-01-26 0:51 ` Pedro Alves
2009-01-26 4:56 ` Sérgio Durigan Júnior
2009-01-26 17:04 ` Sérgio Durigan Júnior
2009-02-01 19:33 ` Daniel Jacobowitz
2009-02-25 21:44 ` Sérgio Durigan Júnior
2009-02-28 0:44 ` Daniel Jacobowitz
2009-03-08 18:16 ` Sérgio Durigan Júnior
2009-03-09 13:19 ` Daniel Jacobowitz
2009-03-09 14:09 ` Sérgio Durigan Júnior
2009-03-09 18:39 ` Pedro Alves
2009-03-09 18:56 ` Daniel Jacobowitz
2009-03-09 18:31 ` Pedro Alves
2009-03-29 21:16 ` Sérgio Durigan Júnior
2009-03-31 16:39 ` Daniel Jacobowitz
2009-04-09 19:29 ` Sérgio Durigan Júnior
2009-04-09 19:36 ` Daniel Jacobowitz
2009-04-09 20:21 ` Sérgio Durigan Júnior
2009-04-15 23:12 ` Sérgio Durigan Júnior
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox