From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 26338 invoked by alias); 30 Sep 2008 18:12:50 -0000 Received: (qmail 25999 invoked by uid 22791); 30 Sep 2008 18:12:44 -0000 X-Spam-Check-By: sourceware.org Received: from igw2.br.ibm.com (HELO igw2.br.ibm.com) (32.104.18.25) by sourceware.org (qpsmtpd/0.31) with ESMTP; Tue, 30 Sep 2008 18:11:55 +0000 Received: from mailhub3.br.ibm.com (mailhub3 [9.18.232.110]) by igw2.br.ibm.com (Postfix) with ESMTP id 3090E17F4FD for ; Tue, 30 Sep 2008 14:55:55 -0300 (BRT) Received: from d24av01.br.ibm.com (d24av01.br.ibm.com [9.18.232.46]) by mailhub3.br.ibm.com (8.13.8/8.13.8/NCO v8.7) with ESMTP id m8UIBuf21622146 for ; Tue, 30 Sep 2008 15:11:56 -0300 Received: from d24av01.br.ibm.com (loopback [127.0.0.1]) by d24av01.br.ibm.com (8.12.11.20060308/8.13.3) with ESMTP id m8UIBm3B028866 for ; Tue, 30 Sep 2008 15:11:48 -0300 Received: from [9.18.238.184] (IBM-708585AE534-009018238184.br.ibm.com [9.18.238.184]) by d24av01.br.ibm.com (8.12.11.20060308/8.12.11) with ESMTP id m8UIBmwa028862 for ; Tue, 30 Sep 2008 15:11:48 -0300 Subject: [PATCH 1/4] 'catch syscall' feature -- Architecture-independent part From: =?ISO-8859-1?Q?S=E9rgio?= Durigan =?ISO-8859-1?Q?J=FAnior?= To: gdb-patches@sourceware.org Content-Type: text/plain; charset=ISO-8859-1 Date: Tue, 30 Sep 2008 18:12:00 -0000 Message-Id: <1222798409.30389.23.camel@miki> Mime-Version: 1.0 X-Mailer: Evolution 2.22.3.1 Content-Transfer-Encoding: 8bit X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2008-09/txt/msg00584.txt.bz2 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 * 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", ""); + 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 + + 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 ". + + 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 <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. */