This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 1/4] 'catch syscall' feature -- Architecture-independent part
- From: Sérgio Durigan Júnior <sergiodj at linux dot vnet dot ibm dot com>
- To: gdb-patches at sourceware dot org
- Date: Tue, 30 Sep 2008 15:13:29 -0300
- Subject: [PATCH 1/4] 'catch syscall' feature -- Architecture-independent part
This is 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
2008-09-29 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
* breakpoint.c (clear_syscall_catchpoints_info): New.
(insert_catchpoint): Add syscall catchpoint case.
(insert_bp_location): Add syscall catchpoint for checking.
(remove_breakpoint): Removing syscall catchpoint.
(ep_is_catchpoint): Adding syscall catchpoint for checking.
(print_it_typical): Included syscall catchpoint code for
printing. Also, handle the case of the breakpoint at the
entrypoint.
(bpstat_check_location): Add syscall catchpoint handler.
(bpstat_what): Add the entry breakpoint case.
(print_one_breakpoint): Add syscall catchpoint and entry
breakpoint.
(user_settable_breakpoint): Add syscall catchpoint.
(breakpoint_address_is_meaningful): Likewise.
(adjust_breakpoint_address): Likewise.
(allocate_bp_location): Add syscall catchpoint and entry
breakpoint.
(set_raw_breakpoint_without_location): Zeroing fields related
to syscall catchpoint.
(create_entry_breakpoint): New.
(create_syscall_event_catchpoint): New.
(mention): Add syscall catchpoint and entry breakpoint.
(catch_syscall_command_1): New.
(delete_command): Add syscall catchpoint and entry breakpoint.
(breakpoint_re_set_one): Likewise.
(disable_command): Add syscall catchpoint.
(enable_command): Likewise.
(is_syscall_catchpoint_enabled): New.
(catch_syscall_enabled): New.
(catching_syscall_number): New.
* breakpoint.h (enum bptype): Add syscall catchpoint and entry
breakpoint types.
(struct breakpoint): Add field 'syscall_number' (used to know
which syscall triggered the catchpoint) and
'syscall_to_be_caught' (used to know which syscall we are trying
to catch).
(enum bpstat_what_main_action): Add BPSTAT_WHAT_ENTRY_BREAKPOINT,
used to identify wheter we hit an entry breakpoint.
(clear_syscall_catchpoints_info): New.
(catch_syscall_enabled): New.
(catching_syscall_number): New.
(create_entry_breakpoint): New.
* gdbarch.c: Regenerate.
* gdbarch.h: Regenerate.
* gdbarch.sh: Add syscall catchpoint functions to gdbarch.
(get_syscall_number): New.
(syscall_name_from_number): New.
(syscall_number_from_name): New.
* gdbthread.h (struct thread_info): Add field 'syscall_state',
used to know if we are calling or returning from a syscall.
* inf-child.c (inf_child_insert_syscall_catchpoint): New.
(inf_child_remove_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.
* 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 target_ops): Add ops for syscall catchpoint and entry
breakpoint.
(inferior_has_called_syscall): New.
(target_passed_by_entrypoint): New.
(target_insert_syscall_catchpoint): New.
(target_remove_syscall_catchpoint): New.
(target_enable_tracesysgood): New.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 6e863d7..7f9cc49 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -404,6 +404,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 (b->type == bp_catch_syscall)
+ b->syscall_number = UNKNOWN_SYSCALL;
+}
+
/* Used in run_command to zero the hit count when a new run starts. */
void
@@ -810,6 +822,9 @@ insert_catchpoint (struct ui_out *uo, void *args)
case bp_catch_exec:
target_insert_exec_catchpoint (PIDGET (inferior_ptid));
break;
+ case bp_catch_syscall:
+ target_insert_syscall_catchpoint (PIDGET (inferior_ptid));
+ break;
default:
internal_error (__FILE__, __LINE__, _("unknown breakpoint type"));
break;
@@ -1250,7 +1265,8 @@ Note: automatically using hardware breakpoints for read-only addresses.\n"));
else if (bpt->owner->type == bp_catch_fork
|| bpt->owner->type == bp_catch_vfork
- || bpt->owner->type == bp_catch_exec)
+ || bpt->owner->type == bp_catch_exec
+ || bpt->owner->type == bp_catch_syscall)
{
struct gdb_exception e = catch_exception (uiout, insert_catchpoint,
bpt->owner, RETURN_MASK_ERROR);
@@ -1708,6 +1724,9 @@ remove_breakpoint (struct bp_location *b, insertion_state_t is)
case bp_catch_exec:
val = target_remove_exec_catchpoint (PIDGET (inferior_ptid));
break;
+ case bp_catch_syscall:
+ val = target_remove_syscall_catchpoint (PIDGET (inferior_ptid));
+ break;
default:
warning (_("Internal error, %s line %d."), __FILE__, __LINE__);
break;
@@ -1957,7 +1976,8 @@ ep_is_catchpoint (struct breakpoint *ep)
|| (ep->type == bp_catch_unload)
|| (ep->type == bp_catch_fork)
|| (ep->type == bp_catch_vfork)
- || (ep->type == bp_catch_exec);
+ || (ep->type == bp_catch_exec)
+ || (ep->type == bp_catch_syscall);
/* ??rehrauer: Add more kinds here, as are implemented... */
}
@@ -2278,6 +2298,13 @@ print_it_typical (bpstat bs)
struct cleanup *old_chain, *ui_out_chain;
struct breakpoint *b;
const struct bp_location *bl;
+ /* Used for "catch syscall".
+
+ This is 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". */
+ struct thread_info *th_info = find_thread_pid (inferior_ptid);
struct ui_stream *stb;
int bp_temp = 0;
stb = ui_out_stream_new (uiout);
@@ -2329,6 +2356,14 @@ print_it_typical (bpstat bs)
return PRINT_NOTHING;
break;
+ case bp_entry_breakpoint:
+ /* Not sure how we will get here.
+ GDB should not stop for these breakpoints. */
+ internal_error (__FILE__, __LINE__,
+ _("Entry Breakpoint: gdb should not stop!\n"));
+ return PRINT_NOTHING;
+ break;
+
case bp_overlay_event:
/* By analogy with the thread event, GDB should not stop for these. */
printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n"));
@@ -2375,6 +2410,17 @@ print_it_typical (bpstat bs)
return PRINT_SRC_AND_LOC;
break;
+ case bp_catch_syscall:
+ annotate_catchpoint (b->number);
+ printf_filtered (_("\nCatchpoint %d (%s syscall '%s ()'), "),
+ b->number,
+ (th_info->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY)
+ ? "called" : "returned from",
+ gdbarch_syscall_name_from_number (current_gdbarch,
+ b->syscall_number));
+ return PRINT_SRC_AND_LOC;
+ break;
+
case bp_watchpoint:
case bp_hardware_watchpoint:
annotate_watchpoint (b->number);
@@ -2795,7 +2841,8 @@ bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr)
&& b->type != bp_hardware_breakpoint
&& b->type != bp_catch_fork
&& b->type != bp_catch_vfork
- && b->type != bp_catch_exec) /* a non-watchpoint bp */
+ && b->type != bp_catch_exec
+ && b->type != bp_catch_syscall) /* a non-watchpoint bp */
{
if (bl->address != bp_addr) /* address doesn't match */
return 0;
@@ -2869,6 +2916,25 @@ bpstat_check_location (const struct bp_location *bl, CORE_ADDR bp_addr)
&& !inferior_has_execd (inferior_ptid, &b->exec_pathname))
return 0;
+ /* 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. */
+ if (b->type == bp_catch_syscall)
+ {
+ int syscall_number;
+ if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
+ return 0;
+ /* Now, checking if the syscall is the same. */
+ if (b->syscall_to_be_caught != CATCHING_ANY_SYSCALL
+ && b->syscall_to_be_caught != syscall_number)
+ /* Not the same. */
+ return 0;
+
+ /* It's the same syscall. We can update the breakpoint struct
+ with the correct information. */
+ b->syscall_number = syscall_number;
+ }
+
return 1;
}
@@ -3212,6 +3278,9 @@ bpstat_what (bpstat bs)
/* We caught a shared library event. */
catch_shlib_event,
+ /* We are in a entry breakpoint. */
+ entry_breakpoint,
+
/* This is just used to count how many enums there are. */
class_last
};
@@ -3228,6 +3297,7 @@ bpstat_what (bpstat bs)
#define sr BPSTAT_WHAT_STEP_RESUME
#define shl BPSTAT_WHAT_CHECK_SHLIBS
#define shlr BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK
+#define entrybp BPSTAT_WHAT_ENTRY_BREAKPOINT
/* "Can't happen." Might want to print an error message.
abort() is not out of the question, but chances are GDB is just
@@ -3272,30 +3342,33 @@ bpstat_what (bpstat bs)
table[(int) class_last][(int) BPSTAT_WHAT_LAST] =
{
/* old action */
- /* kc ss sn sgl slr clr sr shl shlr
+ /* kc ss sn sgl slr clr sr shl shlr entrybp
*/
/*no_effect */
- {kc, ss, sn, sgl, slr, clr, sr, shl, shlr},
+ {kc, ss, sn, sgl, slr, clr, sr, shl, shlr, shlr},
/*wp_silent */
- {ss, ss, sn, ss, ss, ss, sr, shl, shlr},
+ {ss, ss, sn, ss, ss, ss, sr, shl, shlr, shlr},
/*wp_noisy */
- {sn, sn, sn, sn, sn, sn, sr, shl, shlr},
+ {sn, sn, sn, sn, sn, sn, sr, shl, shlr, shlr},
/*bp_nostop */
- {sgl, ss, sn, sgl, slr, slr, sr, shl, shlr},
+ {sgl, ss, sn, sgl, slr, slr, sr, shl, shlr, shlr},
/*bp_silent */
- {ss, ss, sn, ss, ss, ss, sr, shl, shlr},
+ {ss, ss, sn, ss, ss, ss, sr, shl, shlr, shlr},
/*bp_noisy */
- {sn, sn, sn, sn, sn, sn, sr, shl, shlr},
+ {sn, sn, sn, sn, sn, sn, sr, shl, shlr, shlr},
/*long_jump */
- {slr, ss, sn, slr, slr, err, sr, shl, shlr},
+ {slr, ss, sn, slr, slr, err, sr, shl, shlr, shlr},
/*long_resume */
- {clr, ss, sn, err, err, err, sr, shl, shlr},
+ {clr, ss, sn, err, err, err, sr, shl, shlr, shlr},
/*step_resume */
- {sr, sr, sr, sr, sr, sr, sr, sr, sr},
+ {sr, sr, sr, sr, sr, sr, sr, sr, sr, sr},
/*shlib */
- {shl, shl, shl, shl, shl, shl, sr, shl, shlr},
+ {shl, shl, shl, shl, shl, shl, sr, shl, shlr, shl},
/*catch_shlib */
- {shlr, shlr, shlr, shlr, shlr, shlr, sr, shlr, shlr}
+ {shlr, shlr, shlr, shlr, shlr, shlr, sr, shlr, shlr, shlr},
+/* entry_breakpoint */
+ {entrybp, entrybp, entrybp, entrybp, entrybp, entrybp, sr, entrybp,
+ entrybp, entrybp}
};
#undef kc
@@ -3309,6 +3382,7 @@ bpstat_what (bpstat bs)
#undef ts
#undef shl
#undef shlr
+#undef entrybp
enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING;
struct bpstat_what retval;
@@ -3396,6 +3470,7 @@ bpstat_what (bpstat bs)
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
+ case bp_catch_syscall:
if (bs->stop)
{
if (bs->print)
@@ -3414,6 +3489,12 @@ bpstat_what (bpstat bs)
bs_class = bp_silent;
retval.call_dummy = 1;
break;
+ case bp_entry_breakpoint:
+ if (bs->stop)
+ bs_class = entry_breakpoint;
+ else
+ bs_class = no_effect;
+ break;
}
current_action = table[(int) bs_class][(int) current_action];
}
@@ -3577,7 +3658,9 @@ print_one_breakpoint_location (struct breakpoint *b,
{bp_catch_unload, "catch unload"},
{bp_catch_fork, "catch fork"},
{bp_catch_vfork, "catch vfork"},
- {bp_catch_exec, "catch exec"}
+ {bp_catch_exec, "catch exec"},
+ {bp_catch_syscall, "catch syscall"},
+ {bp_entry_breakpoint, "entry breakpoint"}
};
static char bpenables[] = "nynny";
@@ -3743,6 +3826,23 @@ print_one_breakpoint_location (struct breakpoint *b,
}
break;
+ case bp_catch_syscall:
+ /* 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 (addressprint)
+ ui_out_field_skip (uiout, "addr");
+ annotate_field (5);
+ ui_out_text (uiout, "syscall \"");
+ if (b->syscall_number != UNKNOWN_SYSCALL)
+ ui_out_field_string (uiout, "what",
+ gdbarch_syscall_name_from_number (current_gdbarch,
+ b->syscall_number));
+ else
+ ui_out_field_string (uiout, "what", "<unknown syscall>");
+ ui_out_text (uiout, "\" ");
+ break;
+
case bp_breakpoint:
case bp_hardware_breakpoint:
case bp_until:
@@ -3755,6 +3855,7 @@ print_one_breakpoint_location (struct breakpoint *b,
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
+ case bp_entry_breakpoint:
if (addressprint)
{
annotate_field (4);
@@ -3944,6 +4045,7 @@ user_settable_breakpoint (const struct breakpoint *b)
|| b->type == bp_catch_fork
|| b->type == bp_catch_vfork
|| b->type == bp_catch_exec
+ || b->type == bp_catch_syscall
|| b->type == bp_hardware_breakpoint
|| b->type == bp_watchpoint
|| b->type == bp_read_watchpoint
@@ -4150,6 +4252,7 @@ set_default_breakpoint (int valid, CORE_ADDR addr, struct symtab *symtab,
bp_hardware_watchpoint
bp_read_watchpoint
bp_access_watchpoint
+ bp_catch_syscall
bp_catch_exec
bp_catch_fork
bp_catch_vork */
@@ -4163,6 +4266,7 @@ breakpoint_address_is_meaningful (struct breakpoint *bpt)
&& type != bp_hardware_watchpoint
&& type != bp_read_watchpoint
&& type != bp_access_watchpoint
+ && type != bp_catch_syscall
&& type != bp_catch_exec
&& type != bp_catch_fork
&& type != bp_catch_vfork);
@@ -4282,7 +4386,8 @@ adjust_breakpoint_address (CORE_ADDR bpaddr, enum bptype bptype)
|| bptype == bp_access_watchpoint
|| bptype == bp_catch_fork
|| bptype == bp_catch_vfork
- || bptype == bp_catch_exec)
+ || bptype == bp_catch_exec
+ || bptype == bp_catch_syscall)
{
/* Watchpoints and the various bp_catch_* eventpoints should not
have their addresses modified. */
@@ -4333,6 +4438,7 @@ allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type)
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_shlib_event:
+ case bp_entry_breakpoint:
case bp_thread_event:
case bp_overlay_event:
case bp_catch_load:
@@ -4351,6 +4457,7 @@ allocate_bp_location (struct breakpoint *bpt, enum bptype bp_type)
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
+ case bp_catch_syscall:
loc->loc_type = bp_loc_other;
break;
default:
@@ -4396,6 +4503,8 @@ set_raw_breakpoint_without_location (enum bptype bptype)
b->triggered_dll_pathname = NULL;
b->forked_inferior_pid = null_ptid;
b->exec_pathname = NULL;
+ b->syscall_to_be_caught = CATCHING_ANY_SYSCALL;
+ b->syscall_number = UNKNOWN_SYSCALL;
b->ops = NULL;
b->condition_not_parsed = 0;
@@ -4618,6 +4727,31 @@ disable_overlay_breakpoints (void)
}
}
+int
+create_entry_breakpoint ()
+{
+ CORE_ADDR taddr, entry_addr;
+ struct breakpoint *b;
+
+ taddr = entry_point_address ();
+ /* Make certain that the address points at real code, and not a
+ function descriptor. */
+ entry_addr = gdbarch_convert_from_func_ptr_addr (current_gdbarch, taddr,
+ ¤t_target);
+
+ /* Setting the breakpoint */
+ b = create_internal_breakpoint (entry_addr, bp_entry_breakpoint);
+
+ b->enable_state = bp_enabled;
+ b->disposition = disp_del;
+ /* addr_string has to be used or breakpoint_re_set will delete me. */
+ b->addr_string = xstrprintf ("AT_ENTRY (0x%s)", paddr (entry_addr));
+
+ update_global_location_list (1);
+
+ return 1;
+}
+
struct breakpoint *
create_thread_event_breakpoint (CORE_ADDR address)
{
@@ -4817,6 +4951,31 @@ create_exec_event_catchpoint (int tempflag, char *cond_string)
mention (b);
}
+static void
+create_syscall_event_catchpoint (int tempflag, int syscall_number)
+{
+ struct symtab_and_line sal;
+ struct breakpoint *b;
+ int thread = -1; /* All threads. */
+
+ init_sal (&sal);
+
+ b = set_raw_breakpoint (sal, bp_catch_syscall);
+ set_breakpoint_count (breakpoint_count + 1);
+ b->number = breakpoint_count;
+ b->cond_string = NULL;
+ b->thread = thread;
+ b->syscall_to_be_caught = syscall_number;
+ /* We still don't know the syscall that will be caught :-). */
+ b->syscall_number = UNKNOWN_SYSCALL;
+ b->addr_string = NULL;
+ b->enable_state = bp_enabled;
+ b->disposition = tempflag ? disp_del : disp_donttouch;
+ update_global_location_list (1);
+
+ mention (b);
+}
+
static int
hw_breakpoint_used_count (void)
{
@@ -5034,6 +5193,16 @@ mention (struct breakpoint *b)
printf_filtered (_("Catchpoint %d (exec)"),
b->number);
break;
+ case bp_catch_syscall:
+ if (b->syscall_to_be_caught != CATCHING_ANY_SYSCALL)
+ printf_filtered (_("Catchpoint %d (syscall '%s ()')"),
+ b->number,
+ gdbarch_syscall_name_from_number (current_gdbarch,
+ b->syscall_to_be_caught));
+ else
+ printf_filtered (_("Catchpoint %d (syscall)"),
+ b->number);
+ break;
case bp_until:
case bp_finish:
@@ -5045,6 +5214,7 @@ mention (struct breakpoint *b)
case bp_shlib_event:
case bp_thread_event:
case bp_overlay_event:
+ case bp_entry_breakpoint:
break;
}
@@ -6795,6 +6965,36 @@ catch_ada_exception_command (char *arg, int from_tty,
from_tty);
}
+/* Implement the "catch syscall" command. */
+
+static void
+catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
+{
+ int tempflag;
+ int syscall_number = CATCHING_ANY_SYSCALL;
+
+ tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+ ep_skip_leading_whitespace (&arg);
+
+ /* The allowed syntax is:
+ catch syscall
+ catch syscall <name>
+
+ Let's check if there's a syscall name. */
+
+ if (arg != NULL)
+ {
+ syscall_number = gdbarch_syscall_number_from_name (current_gdbarch,
+ (const char *) arg);
+ if (syscall_number == UNKNOWN_SYSCALL)
+ error (_("Invalid syscall name '%s'."), arg);
+ }
+
+ /* Now let's create the catchpoint */
+ create_syscall_event_catchpoint (tempflag, syscall_number);
+}
+
/* Implement the "catch assert" command. */
static void
@@ -7312,6 +7512,7 @@ delete_command (char *arg, int from_tty)
b->type != bp_shlib_event &&
b->type != bp_thread_event &&
b->type != bp_overlay_event &&
+ b->type != bp_entry_breakpoint &&
b->number >= 0)
{
breaks_to_delete = 1;
@@ -7329,6 +7530,7 @@ delete_command (char *arg, int from_tty)
b->type != bp_shlib_event &&
b->type != bp_thread_event &&
b->type != bp_overlay_event &&
+ b->type != bp_entry_breakpoint &&
b->number >= 0)
delete_breakpoint (b);
}
@@ -7620,6 +7822,7 @@ breakpoint_re_set_one (void *bint)
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
+ case bp_catch_syscall:
break;
default:
@@ -7639,6 +7842,9 @@ breakpoint_re_set_one (void *bint)
Once it is set up, we do not want to touch it. */
case bp_thread_event:
+ /* Same for this one */
+ case bp_entry_breakpoint:
+
/* Keep temporary breakpoints, which can be encountered when we step
over a dlopen call and SOLIB_ADD is resetting the breakpoints.
Otherwise these should have been blown away via the cleanup chain
@@ -7893,6 +8099,7 @@ disable_command (char *args, int from_tty)
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
+ case bp_catch_syscall:
case bp_hardware_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
@@ -8027,6 +8234,7 @@ enable_command (char *args, int from_tty)
case bp_catch_fork:
case bp_catch_vfork:
case bp_catch_exec:
+ case bp_catch_syscall:
case bp_hardware_breakpoint:
case bp_watchpoint:
case bp_hardware_watchpoint:
@@ -8209,6 +8417,45 @@ 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 (bp->type == bp_catch_syscall
+ && bp->enable_state != bp_disabled
+ && bp->enable_state != bp_call_disabled)
+ return 1;
+ else
+ return 0;
+}
+
+int
+catch_syscall_enabled (void)
+{
+ struct breakpoint *bp;
+
+ ALL_BREAKPOINTS (bp)
+ if (is_syscall_catchpoint_enabled (bp))
+ return 1;
+
+ return 0;
+}
+
+int
+catching_syscall_number (int syscall_number)
+{
+ struct breakpoint *bp;
+
+ ALL_BREAKPOINTS (bp)
+ if (is_syscall_catchpoint_enabled (bp))
+ if (bp->syscall_to_be_caught == syscall_number
+ || bp->syscall_to_be_caught == CATCHING_ANY_SYSCALL)
+ return 1;
+
+ return 0;
+}
+
/* This help string is used for the break, hbreak, tbreak and thbreak commands.
It is defined as a macro to prevent duplication.
@@ -8549,6 +8796,12 @@ With an argument, catch only exceptions with the given name."),
catch_exec_command_1,
CATCH_PERMANENT,
CATCH_TEMPORARY);
+ add_catch_command ("syscall", _("\
+Catch calls to syscalls.\n\
+With an argument, catch only calls of that syscall."),
+ catch_syscall_command_1,
+ CATCH_PERMANENT,
+ CATCH_TEMPORARY);
add_catch_command ("load", _("\
Catch library loads.\n\
With an argument, catch only loads of that library."),
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index db6e972..bc3de7f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -33,6 +33,11 @@ struct block;
#define BREAKPOINT_MAX 16
+
+/* A number to represent wether we are catching any syscalls. */
+
+#define CATCHING_ANY_SYSCALL (-1)
+
/* Type of breakpoint. */
/* FIXME In the future, we should fold all other breakpoint-like things into
here. This includes:
@@ -127,6 +132,14 @@ enum bptype
bp_catch_fork,
bp_catch_vfork,
bp_catch_exec,
+
+ /* This is not really a breakpoint, but the catchpoint which implements
+ the "catch syscall" functionality. */
+ bp_catch_syscall,
+
+ /* This type is used to signal an internal breakpoint located at
+ the AT_ENTRY address. */
+ bp_entry_breakpoint,
};
/* States of enablement of breakpoint. */
@@ -455,6 +468,21 @@ 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;
+
+ /* This field is used when we are "filtering" the syscalls
+ (i.e., when the user types "catch syscall <SYSCALL_NAME>".
+
+ It stores the syscall number in case we are in the "filter mode",
+ or CATCHING_ANY_SYSCALL otherwise. */
+ int syscall_to_be_caught;
+
/* Methods associated with this breakpoint. */
struct breakpoint_ops *ops;
@@ -536,6 +564,10 @@ enum bpstat_what_main_action
resume out of the dynamic linker's callback, stop and print. */
BPSTAT_WHAT_CHECK_SHLIBS_RESUME_FROM_HOOK,
+ /* This internal breakpoint is used syscall catchpoints only after the
+ shell and the dynamic linker have already ran. */
+ BPSTAT_WHAT_ENTRY_BREAKPOINT,
+
/* This is just used to keep track of how many enums there are. */
BPSTAT_WHAT_LAST
};
@@ -805,6 +837,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 **);
@@ -884,4 +918,26 @@ 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);
+
+/* Function used to set an internal breakpoint at the AT_ENTRY
+ (a.k.a. the entry point of the inferior).
+
+ This is currently needed for us to know when to start setting
+ up catchpoints for syscalls in the inferior. If we don't do that,
+ then we would set a "catch syscall" too early, which would
+ catch syscalls from ld.so and/or libc (and we don't want that).
+
+ Returns zero if there was an error setting this breakpoint,
+ or 1 if everything went OK. */
+extern int create_entry_breakpoint (void);
+
+
#endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index aa9a455..f4b3dec 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -240,6 +240,9 @@ 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_syscall_name_from_number_ftype *syscall_name_from_number;
+ gdbarch_syscall_number_from_name_ftype *syscall_number_from_name;
};
@@ -371,6 +374,9 @@ 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, /* syscall_name_from_number */
+ 0, /* syscall_number_from_name */
/* startup_gdbarch() */
};
@@ -623,6 +629,9 @@ 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 syscall_name_from_number, has predicate */
+ /* Skip verify of syscall_number_from_name, has predicate */
buf = ui_file_xstrdup (log, &dummy);
make_cleanup (xfree, buf);
if (strlen (buf) > 0)
@@ -832,6 +841,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: get_longjmp_target = <0x%lx>\n",
(long) gdbarch->get_longjmp_target);
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: have_nonsteppable_watchpoint = %s\n",
plongest (gdbarch->have_nonsteppable_watchpoint));
fprintf_unfiltered (file,
@@ -1051,6 +1066,18 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
"gdbarch_dump: static_transform_name = <0x%lx>\n",
(long) gdbarch->static_transform_name);
fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_syscall_name_from_number_p() = %d\n",
+ gdbarch_syscall_name_from_number_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: syscall_name_from_number = <0x%lx>\n",
+ (long) gdbarch->syscall_name_from_number);
+ fprintf_unfiltered (file,
+ "gdbarch_dump: gdbarch_syscall_number_from_name_p() = %d\n",
+ gdbarch_syscall_number_from_name_p (gdbarch));
+ fprintf_unfiltered (file,
+ "gdbarch_dump: syscall_number_from_name = <0x%lx>\n",
+ (long) gdbarch->syscall_number_from_name);
+ fprintf_unfiltered (file,
"gdbarch_dump: target_desc = %s\n",
plongest ((long) gdbarch->target_desc));
fprintf_unfiltered (file,
@@ -3237,6 +3264,78 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch,
gdbarch->record_special_symbol = record_special_symbol;
}
+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_syscall_name_from_number_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->syscall_name_from_number != NULL;
+}
+
+const char *
+gdbarch_syscall_name_from_number (struct gdbarch *gdbarch, int syscall_number)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->syscall_name_from_number != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_syscall_name_from_number called\n");
+ return gdbarch->syscall_name_from_number (gdbarch, syscall_number);
+}
+
+void
+set_gdbarch_syscall_name_from_number (struct gdbarch *gdbarch,
+ gdbarch_syscall_name_from_number_ftype syscall_name_from_number)
+{
+ gdbarch->syscall_name_from_number = syscall_name_from_number;
+}
+
+int
+gdbarch_syscall_number_from_name_p (struct gdbarch *gdbarch)
+{
+ gdb_assert (gdbarch != NULL);
+ return gdbarch->syscall_number_from_name != NULL;
+}
+
+int
+gdbarch_syscall_number_from_name (struct gdbarch *gdbarch, const char *syscall_name)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->syscall_number_from_name != NULL);
+ if (gdbarch_debug >= 2)
+ fprintf_unfiltered (gdb_stdlog, "gdbarch_syscall_number_from_name called\n");
+ return gdbarch->syscall_number_from_name (gdbarch, syscall_name);
+}
+
+void
+set_gdbarch_syscall_number_from_name (struct gdbarch *gdbarch,
+ gdbarch_syscall_number_from_name_ftype syscall_number_from_name)
+{
+ gdbarch->syscall_number_from_name = syscall_number_from_name;
+}
+
/* Keep a registry of per-architecture data-pointers required by GDB
modules. */
diff --git a/gdb/gdbarch.h b/gdb/gdbarch.h
index bc8298d..a2b4468 100644
--- a/gdb/gdbarch.h
+++ b/gdb/gdbarch.h
@@ -811,6 +811,37 @@ 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);
+
+/* Translate a syscall number to its corresponding name. */
+
+extern int gdbarch_syscall_name_from_number_p (struct gdbarch *gdbarch);
+
+typedef const char * (gdbarch_syscall_name_from_number_ftype) (struct gdbarch *gdbarch, int syscall_number);
+extern const char * gdbarch_syscall_name_from_number (struct gdbarch *gdbarch, int syscall_number);
+extern void set_gdbarch_syscall_name_from_number (struct gdbarch *gdbarch, gdbarch_syscall_name_from_number_ftype *syscall_name_from_number);
+
+/* Translate a syscall name to its corresponding number.
+
+ This function must return the syscall number if found, or
+ UNKNOWN_SYSCALL if not found. */
+
+extern int gdbarch_syscall_number_from_name_p (struct gdbarch *gdbarch);
+
+typedef int (gdbarch_syscall_number_from_name_ftype) (struct gdbarch *gdbarch, const char *syscall_name);
+extern int gdbarch_syscall_number_from_name (struct gdbarch *gdbarch, const char *syscall_name);
+extern void set_gdbarch_syscall_number_from_name (struct gdbarch *gdbarch, gdbarch_syscall_number_from_name_ftype *syscall_number_from_name);
+
+/* 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 0c513a5..684bb8c 100755
--- a/gdb/gdbarch.sh
+++ b/gdb/gdbarch.sh
@@ -707,6 +707,20 @@ 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
+
+# Translate a syscall number to its corresponding name.
+M:const char *:syscall_name_from_number:int syscall_number:syscall_number
+
+# Translate a syscall name to its corresponding number.
+#
+# This function must return the syscall number if found, or
+# UNKNOWN_SYSCALL if not found.
+M:int:syscall_number_from_name:const char *syscall_name:syscall_name
EOF
}
@@ -888,6 +902,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/gdbthread.h b/gdb/gdbthread.h
index 0fb53fb..85245ca 100644
--- a/gdb/gdbthread.h
+++ b/gdb/gdbthread.h
@@ -170,6 +170,13 @@ struct thread_info
/* Private data used by the target vector implementation. */
struct private_thread_info *private;
+
+ /* Signal wether we are in a SYSCALL_ENTRY or
+ in a SYSCALL_RETURN event.
+ Values:
+ - TARGET_WAITKIND_SYSCALL_ENTRY
+ - TARGET_WAITKIND_SYSCALL_RETURN */
+ int syscall_state;
};
/* Create an empty thread list, or empty the existing one. */
diff --git a/gdb/inf-child.c b/gdb/inf-child.c
index 8da25f4..058cb34 100644
--- a/gdb/inf-child.c
+++ b/gdb/inf-child.c
@@ -144,6 +144,21 @@ inf_child_remove_exec_catchpoint (int pid)
return 0;
}
+static void
+inf_child_insert_syscall_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of syscall
+ events. */
+}
+
+static int
+inf_child_remove_syscall_catchpoint (int pid)
+{
+ /* This version of Unix doesn't support notification of syscall
+ events. */
+ return 0;
+}
+
static int
inf_child_can_run (void)
{
@@ -187,6 +202,8 @@ 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_insert_syscall_catchpoint = inf_child_insert_syscall_catchpoint;
+ t->to_remove_syscall_catchpoint = inf_child_remove_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 57af79a..65e7acd 100644
--- a/gdb/inf-ptrace.c
+++ b/gdb/inf-ptrace.c
@@ -355,13 +355,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 6ed6341..09d4d9b 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -450,6 +450,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 4b4df8f..9c5efef 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -964,7 +964,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)
{
@@ -980,6 +980,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;
}
@@ -1386,7 +1391,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 ();
@@ -1831,6 +1836,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. */
@@ -2119,9 +2168,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
@@ -2131,9 +2182,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)
@@ -2951,6 +3003,16 @@ infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n");
}
break;
+ case BPSTAT_WHAT_ENTRY_BREAKPOINT:
+ /* We hit the AT_ENTRY breakpoint, and now we have to enable
+ the PTRACE_O_TRACESYSGOOD option in the inferior *if* we
+ are catching syscalls. */
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_ENTRY_BREAKPOINT\n");
+ target_enable_tracesysgood (ecs->ptid);
+ ecs->event_thread->stepping_over_breakpoint = 1;
+ break;
+
case BPSTAT_WHAT_LAST:
/* Not a real code, but listed here to shut up gcc -Wall. */
@@ -4563,6 +4625,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/target.c b/gdb/target.c
index a509c17..39a92b5 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -426,6 +426,10 @@ 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_insert_syscall_catchpoint, t);
+ INHERIT (to_remove_syscall_catchpoint, t);
+ INHERIT (to_enable_tracesysgood, t);
INHERIT (to_has_exited, t);
INHERIT (to_mourn_inferior, t);
INHERIT (to_can_run, t);
@@ -581,9 +585,21 @@ 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_insert_syscall_catchpoint,
+ (void (*) (int))
+ tcomplain);
+ de_fault (to_remove_syscall_catchpoint,
+ (int (*) (int))
+ tcomplain);
+ de_fault (to_enable_tracesysgood,
+ (void (*) (ptid_t))
+ tcomplain);
de_fault (to_has_exited,
(int (*) (int, int, int *))
return_zero);
@@ -2532,6 +2548,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 067c031..6e379d3 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -135,14 +135,15 @@ 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;
};
@@ -393,6 +394,10 @@ 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);
+ void (*to_insert_syscall_catchpoint) (int);
+ int (*to_remove_syscall_catchpoint) (int);
+ void (*to_enable_tracesysgood) (ptid_t);
int (*to_has_exited) (int, int, int *);
void (*to_mourn_inferior) (void);
int (*to_can_run) (void);
@@ -708,6 +713,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 *);
@@ -867,6 +874,24 @@ 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 functions */
+
+#define target_insert_syscall_catchpoint(pid) \
+ (*current_target.to_insert_syscall_catchpoint) (pid)
+
+#define target_remove_syscall_catchpoint(pid) \
+ (*current_target.to_remove_syscall_catchpoint) (pid)
+
+/* Enable PTRACE_O_TRACESYSGOOD in the inferior.
+ This is mainly used for the "catch syscall" feature. */
+
+#define target_enable_tracesysgood(ptid) \
+ (*current_target.to_enable_tracesysgood) (ptid)
+
/* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the
exit code of PID, if any. */