2008-04-07 Pedro Alves * breakpoint.c (update_breakpoints_after_exec): Delete bp_longjmp and bp_longjmp_resume breakpoints. (breakpoint_address_is_meaningful): Claim bp_longjmp_resume as meaningful. (create_longjmp_breakpoint): Don't create bp_longjmp_resume breakpoints. Create bp_longjmp breakpoints as momentary breakpoints. (enable_longjmp_breakpoint): Delete. (set_longjmp_breakpoint): New. (disable_longjmp_breakpoint): Delete. (delete_longjmp_breakpoint_thread, delete_longjmp_breakpoint): New. (set_longjmp_resume_breakpoint): Delete. (set_momentary_breakpoint_at_pc): New. (breakpoint_re_set_one): Don't delete bp_longjmp and bp_longjmp_resume breakpoints. (breakpoint_re_set): Don't create longjmp and longjmp-resume breakpoints. * infrun.c (step_resume_breakpoint): Add comment. (struct execution_control_state): Delete handling_longjmp member. (init_execution_control_state). Don't clear handling_longjmp. (context_switch): Don't context switch handling_longjmp. (handle_inferior_event): If handling a bp_longjmp breakpoint, create a bp_longjmp_resume breakpoint, and set it as current step_resume_breakpoint, then step over the longjmp breakpoint. If handling a bp_longjmp_resume breakpoint, don't delete the longjmp breakpoint, delete the longjmp-resume breakpoint, and stop stepping. (currently_stepping): Remove handling_longjmp from expression. (insert_step_resume_breakpoint_at_sal): Update comment. (insert_longjmp_resume_breakpoint): New. * breakpoint.h (set_momentary_breakpoint_at_pc): Declare. (enable_longjmp_breakpoint, disable_longjmp_breakpoint): Delete declarations. (set_longjmp_breakpoint, delete_longjmp_breakpoint) (delete_longjmp_breakpoint_thread): Declare. (set_longjmp_resume_breakpoint): Delete declaration. * gdbthread.h (save_infrun_state): Remove handling_longjmp parameter. (load_infrun_state): Delete *handling_longjmp parameter. * thread.c (save_infrun_state): Remove handling_longjmp parameter. Update body. (load_infrun_state): Delete *handling_longjmp parameter. Update body. * infcmd.c Include "gdbthread.h". (disable_longjmp_breakpoint_cleanup): Delete. (delete_longjmp_breakpoint_cleanup): New. (step_1): Call set_longjmp_breakpoint instead of enable_longjmp_breakpoint. Use delete_longjmp_breakpoint_cleanup instead of disable_longjmp_breakpoint_cleanup when making cleanup. * Makefile.in (infcmd.o): Update. --- gdb/Makefile.in | 2 gdb/breakpoint.c | 112 +++++++++++++++++++++---------------------------------- gdb/breakpoint.h | 9 ++-- gdb/gdbthread.h | 3 - gdb/infcmd.c | 26 ++++++++++-- gdb/infrun.c | 86 +++++++++++++++++++++++++++++------------- gdb/thread.c | 4 - 7 files changed, 131 insertions(+), 111 deletions(-) Index: src/gdb/breakpoint.c =================================================================== --- src.orig/gdb/breakpoint.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/breakpoint.c 2008-04-07 02:28:24.000000000 +0100 @@ -149,8 +149,6 @@ static int watchpoint_check (void *); static void maintenance_info_breakpoints (char *, int); -static void create_longjmp_breakpoint (char *); - static void create_overlay_event_breakpoint (char *); static int hw_breakpoint_used_count (void); @@ -1430,6 +1428,14 @@ update_breakpoints_after_exec (void) continue; } + /* Longjmp and longjmp-resume breakpoints are also meaningless + after an exec. */ + if (b->type == bp_longjmp || b->type == bp_longjmp_resume) + { + delete_breakpoint (b); + continue; + } + /* Don't delete an exec catchpoint, because else the inferior won't stop when it ought! @@ -3968,7 +3974,6 @@ set_default_breakpoint (int valid, CORE_ bp_read_watchpoint bp_access_watchpoint bp_catch_exec - bp_longjmp_resume bp_catch_fork bp_catch_vork */ @@ -3982,7 +3987,6 @@ breakpoint_address_is_meaningful (struct && type != bp_read_watchpoint && type != bp_access_watchpoint && type != bp_catch_exec - && type != bp_longjmp_resume && type != bp_catch_fork && type != bp_catch_vfork); } @@ -4349,20 +4353,9 @@ create_longjmp_breakpoint (char *func_na struct breakpoint *b; struct minimal_symbol *m; - if (func_name == NULL) - b = create_internal_breakpoint (0, bp_longjmp_resume); - else - { - if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL) - return; - - b = create_internal_breakpoint (SYMBOL_VALUE_ADDRESS (m), bp_longjmp); - } - - b->enable_state = bp_disabled; - b->silent = 1; - if (func_name) - b->addr_string = xstrdup (func_name); + if ((m = lookup_minimal_symbol_text (func_name, NULL)) == NULL) + return; + set_momentary_breakpoint_at_pc (SYMBOL_VALUE_ADDRESS (m), bp_longjmp); } /* Call this routine when stepping and nexting to enable a breakpoint @@ -4370,30 +4363,31 @@ create_longjmp_breakpoint (char *func_na set_longjmp_resume_breakpoint() to figure out where we are going. */ void -enable_longjmp_breakpoint (void) +set_longjmp_breakpoint (void) { struct breakpoint *b; - ALL_BREAKPOINTS (b) - if (b->type == bp_longjmp) + if (gdbarch_get_longjmp_target_p (current_gdbarch)) { - b->enable_state = bp_enabled; - check_duplicates (b); + create_longjmp_breakpoint ("longjmp"); + create_longjmp_breakpoint ("_longjmp"); + create_longjmp_breakpoint ("siglongjmp"); + create_longjmp_breakpoint ("_siglongjmp"); } } +/* Delete all longjmp breakpoints from PTID. */ void -disable_longjmp_breakpoint (void) +delete_longjmp_breakpoint (int thread) { - struct breakpoint *b; + struct breakpoint *b, *temp; - ALL_BREAKPOINTS (b) - if (b->type == bp_longjmp - || b->type == bp_longjmp_resume) - { - b->enable_state = bp_disabled; - check_duplicates (b); - } + ALL_BREAKPOINTS_SAFE (b, temp) + if (b->type == bp_longjmp) + { + if (b->thread == thread) + delete_breakpoint (b); + } } static void @@ -4679,30 +4673,6 @@ hw_watchpoint_used_count (enum bptype ty return i; } -/* Call this after hitting the longjmp() breakpoint. Use this to set - a new breakpoint at the target of the jmp_buf. - - FIXME - This ought to be done by setting a temporary breakpoint - that gets deleted automatically... */ - -void -set_longjmp_resume_breakpoint (CORE_ADDR pc, struct frame_id frame_id) -{ - struct breakpoint *b; - - ALL_BREAKPOINTS (b) - if (b->type == bp_longjmp_resume) - { - b->loc->requested_address = pc; - b->loc->address = adjust_breakpoint_address (b->loc->requested_address, - b->type); - b->enable_state = bp_enabled; - b->frame_id = frame_id; - check_duplicates (b); - return; - } -} - void disable_watchpoints_before_interactive_call_start (void) { @@ -4764,6 +4734,19 @@ set_momentary_breakpoint (struct symtab_ return b; } + +struct breakpoint * +set_momentary_breakpoint_at_pc (CORE_ADDR pc, enum bptype type) +{ + struct symtab_and_line sal; + + sal = find_pc_line (pc, 0); + sal.pc = pc; + sal.section = find_pc_overlay (pc); + sal.explicit_pc = 1; + + return set_momentary_breakpoint (sal, null_frame_id, type); +} /* Tell the user we have just set a breakpoint B. */ @@ -7423,10 +7406,8 @@ breakpoint_re_set_one (void *bint) default: printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type); /* fall through */ - /* Delete longjmp and overlay event breakpoints; they will be - reset later by breakpoint_re_set. */ - case bp_longjmp: - case bp_longjmp_resume: + /* Delete overlay event breakpoints; they will be reset later by + breakpoint_re_set. */ case bp_overlay_event: delete_breakpoint (b); break; @@ -7448,6 +7429,8 @@ breakpoint_re_set_one (void *bint) case bp_watchpoint_scope: case bp_call_dummy: case bp_step_resume: + case bp_longjmp: + case bp_longjmp_resume: break; } @@ -7475,15 +7458,6 @@ breakpoint_re_set (void) } set_language (save_language); input_radix = save_input_radix; - - if (gdbarch_get_longjmp_target_p (current_gdbarch)) - { - create_longjmp_breakpoint ("longjmp"); - create_longjmp_breakpoint ("_longjmp"); - create_longjmp_breakpoint ("siglongjmp"); - create_longjmp_breakpoint ("_siglongjmp"); - create_longjmp_breakpoint (NULL); - } create_overlay_event_breakpoint ("_ovly_debug_event"); } Index: src/gdb/infrun.c =================================================================== --- src.orig/gdb/infrun.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/infrun.c 2008-04-07 02:41:01.000000000 +0100 @@ -271,6 +271,7 @@ struct regcache *stop_registers; static int stop_print_frame; +/* Step-resume or longjmp-resume breakpoint. */ static struct breakpoint *step_resume_breakpoint = NULL; /* This is a cached copy of the pid/waitstatus of the last event @@ -947,7 +948,6 @@ struct execution_control_state struct symtab_and_line sal; int current_line; struct symtab *current_symtab; - int handling_longjmp; /* FIXME */ ptid_t ptid; ptid_t saved_inferior_ptid; int step_after_step_resume_breakpoint; @@ -969,6 +969,8 @@ static void insert_step_resume_breakpoin static void insert_step_resume_breakpoint_at_caller (struct frame_info *); static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, struct frame_id sr_id); +static void insert_longjmp_resume_breakpoint (CORE_ADDR); + static void stop_stepping (struct execution_control_state *ecs); static void prepare_to_wait (struct execution_control_state *ecs); static void keep_going (struct execution_control_state *ecs); @@ -1118,7 +1120,6 @@ init_execution_control_state (struct exe ecs->stepping_over_breakpoint = 0; ecs->random_signal = 0; ecs->step_after_step_resume_breakpoint = 0; - ecs->handling_longjmp = 0; /* FIXME */ ecs->stepping_through_solib_after_catch = 0; ecs->stepping_through_solib_catchpoints = NULL; ecs->sal = find_pc_line (prev_pc, 0); @@ -1173,7 +1174,7 @@ context_switch (struct execution_control stepping_over_breakpoint, step_resume_breakpoint, step_range_start, step_range_end, &step_frame_id, - ecs->handling_longjmp, ecs->stepping_over_breakpoint, + ecs->stepping_over_breakpoint, ecs->stepping_through_solib_after_catch, ecs->stepping_through_solib_catchpoints, ecs->current_line, ecs->current_symtab); @@ -1183,7 +1184,7 @@ context_switch (struct execution_control &stepping_over_breakpoint, &step_resume_breakpoint, &step_range_start, &step_range_end, &step_frame_id, - &ecs->handling_longjmp, &ecs->stepping_over_breakpoint, + &ecs->stepping_over_breakpoint, &ecs->stepping_through_solib_after_catch, &ecs->stepping_through_solib_catchpoints, &ecs->current_line, &ecs->current_symtab); @@ -2106,38 +2107,50 @@ process_event_stop_test: switch (what.main_action) { case BPSTAT_WHAT_SET_LONGJMP_RESUME: - /* If we hit the breakpoint at longjmp, disable it for the - duration of this command. Then, install a temporary - breakpoint at the target of the jmp_buf. */ - if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n"); - disable_longjmp_breakpoint (); + /* If we hit the breakpoint at longjmp while stepping, we + install a momentary breakpoint at the target of the + jmp_buf. */ + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME\n"); + + ecs->stepping_over_breakpoint = 1; + if (!gdbarch_get_longjmp_target_p (current_gdbarch) || !gdbarch_get_longjmp_target (current_gdbarch, get_current_frame (), &jmp_buf_pc)) { + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, "\ +infrun: BPSTAT_WHAT_SET_LONGJMP_RESUME (!gdbarch_get_longjmp_target)\n"); keep_going (ecs); return; } - /* Need to blow away step-resume breakpoint, as it - interferes with us */ + /* We're going to replace the current step-resume breakpoint + with a longjmp-resume breakpoint. */ if (step_resume_breakpoint != NULL) - { - delete_step_resume_breakpoint (&step_resume_breakpoint); - } + delete_step_resume_breakpoint (&step_resume_breakpoint); + + /* Insert a breakpoint at resume address. */ + insert_longjmp_resume_breakpoint (jmp_buf_pc); - set_longjmp_resume_breakpoint (jmp_buf_pc, null_frame_id); - ecs->handling_longjmp = 1; /* FIXME */ keep_going (ecs); return; case BPSTAT_WHAT_CLEAR_LONGJMP_RESUME: if (debug_infrun) - fprintf_unfiltered (gdb_stdlog, "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n"); - disable_longjmp_breakpoint (); - ecs->handling_longjmp = 0; /* FIXME */ - break; + fprintf_unfiltered (gdb_stdlog, + "infrun: BPSTAT_WHAT_CLEAR_LONGJMP_RESUME\n"); + + gdb_assert (step_resume_breakpoint != NULL); + delete_step_resume_breakpoint (&step_resume_breakpoint); + + stop_step = 1; + print_stop_reason (END_STEPPING_RANGE, 0); + stop_stepping (ecs); + return; case BPSTAT_WHAT_SINGLE: if (debug_infrun) @@ -2704,9 +2717,8 @@ process_event_stop_test: static int currently_stepping (struct execution_control_state *ecs) { - return ((!ecs->handling_longjmp - && ((step_range_end && step_resume_breakpoint == NULL) - || stepping_over_breakpoint)) + return (((step_range_end && step_resume_breakpoint == NULL) + || stepping_over_breakpoint) || ecs->stepping_through_solib_after_catch || bpstat_should_step ()); } @@ -2793,8 +2805,8 @@ static void insert_step_resume_breakpoint_at_sal (struct symtab_and_line sr_sal, struct frame_id sr_id) { - /* There should never be more than one step-resume breakpoint per - thread, so we should never be setting a new + /* There should never be more than one step-resume or longjmp-resume + breakpoint per thread, so we should never be setting a new step_resume_breakpoint when one is already active. */ gdb_assert (step_resume_breakpoint == NULL); @@ -2862,6 +2874,28 @@ insert_step_resume_breakpoint_at_caller insert_step_resume_breakpoint_at_sal (sr_sal, frame_unwind_id (next_frame)); } +/* Insert a "longjmp-resume" breakpoint at PC. This is used to set a + new breakpoint at the target of a jmp_buf. The handling of + longjmp-resume uses the same mechanisms used for handling + "step-resume" breakpoints. */ + +static void +insert_longjmp_resume_breakpoint (CORE_ADDR pc) +{ + /* There should never be more than one step-resume or longjmp-resume + breakpoint per thread, so we should never be setting a new + longjmp_resume_breakpoint when one is already active. */ + gdb_assert (step_resume_breakpoint == NULL); + + if (debug_infrun) + fprintf_unfiltered (gdb_stdlog, + "infrun: inserting longjmp-resume breakpoint at 0x%s\n", + paddr_nz (pc)); + + step_resume_breakpoint = + set_momentary_breakpoint_at_pc (pc, bp_longjmp_resume); +} + static void stop_stepping (struct execution_control_state *ecs) { Index: src/gdb/breakpoint.h =================================================================== --- src.orig/gdb/breakpoint.h 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/breakpoint.h 2008-04-07 02:28:24.000000000 +0100 @@ -686,6 +686,9 @@ extern int ep_is_exception_catchpoint (s extern struct breakpoint *set_momentary_breakpoint (struct symtab_and_line, struct frame_id, enum bptype); +extern struct breakpoint *set_momentary_breakpoint_at_pc + (CORE_ADDR pc, enum bptype type); + extern void set_ignore_count (int, int, int); extern void set_default_breakpoint (int, CORE_ADDR, struct symtab *, int); @@ -756,12 +759,12 @@ extern void update_breakpoints_after_exe inferior_ptid. */ extern int detach_breakpoints (int); -extern void enable_longjmp_breakpoint (void); -extern void disable_longjmp_breakpoint (void); +extern void set_longjmp_breakpoint (void); +extern void delete_longjmp_breakpoint (int thread); + extern void enable_overlay_breakpoints (void); extern void disable_overlay_breakpoints (void); -extern void set_longjmp_resume_breakpoint (CORE_ADDR, struct frame_id); /* These functions respectively disable or reenable all currently enabled watchpoints. When disabled, the watchpoints are marked call_disabled. When reenabled, they are marked enabled. Index: src/gdb/gdbthread.h =================================================================== --- src.orig/gdb/gdbthread.h 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/gdbthread.h 2008-04-07 02:28:24.000000000 +0100 @@ -50,7 +50,6 @@ struct thread_info int current_line; struct symtab *current_symtab; int trap_expected; - int handling_longjmp; int stepping_over_breakpoint; /* This is set TRUE when a catchpoint of a shared library event @@ -123,7 +122,6 @@ extern void save_infrun_state (ptid_t pt CORE_ADDR step_range_start, CORE_ADDR step_range_end, const struct frame_id *step_frame_id, - int handling_longjmp, int another_trap, int stepping_through_solib_after_catch, bpstat stepping_through_solib_catchpoints, @@ -139,7 +137,6 @@ extern void load_infrun_state (ptid_t pt CORE_ADDR *step_range_start, CORE_ADDR *step_range_end, struct frame_id *step_frame_id, - int *handling_longjmp, int *another_trap, int *stepping_through_solib_affter_catch, bpstat *stepping_through_solib_catchpoints, Index: src/gdb/thread.c =================================================================== --- src.orig/gdb/thread.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/thread.c 2008-04-07 02:28:24.000000000 +0100 @@ -316,7 +316,6 @@ load_infrun_state (ptid_t ptid, CORE_ADDR *step_range_start, CORE_ADDR *step_range_end, struct frame_id *step_frame_id, - int *handling_longjmp, int *stepping_over_breakpoint, int *stepping_through_solib_after_catch, bpstat *stepping_through_solib_catchpoints, @@ -337,7 +336,6 @@ load_infrun_state (ptid_t ptid, *step_range_start = tp->step_range_start; *step_range_end = tp->step_range_end; *step_frame_id = tp->step_frame_id; - *handling_longjmp = tp->handling_longjmp; *stepping_over_breakpoint = tp->stepping_over_breakpoint; *stepping_through_solib_after_catch = tp->stepping_through_solib_after_catch; @@ -357,7 +355,6 @@ save_infrun_state (ptid_t ptid, CORE_ADDR step_range_start, CORE_ADDR step_range_end, const struct frame_id *step_frame_id, - int handling_longjmp, int stepping_over_breakpoint, int stepping_through_solib_after_catch, bpstat stepping_through_solib_catchpoints, @@ -378,7 +375,6 @@ save_infrun_state (ptid_t ptid, tp->step_range_start = step_range_start; tp->step_range_end = step_range_end; tp->step_frame_id = (*step_frame_id); - tp->handling_longjmp = handling_longjmp; tp->stepping_over_breakpoint = stepping_over_breakpoint; tp->stepping_through_solib_after_catch = stepping_through_solib_after_catch; tp->stepping_through_solib_catchpoints = stepping_through_solib_catchpoints; Index: src/gdb/infcmd.c =================================================================== --- src.orig/gdb/infcmd.c 2008-04-07 02:24:30.000000000 +0100 +++ src/gdb/infcmd.c 2008-04-07 02:28:24.000000000 +0100 @@ -49,6 +49,7 @@ #include "target-descriptions.h" #include "user-regs.h" #include "exceptions.h" +#include "gdbthread.h" /* Functions exported for general use, in inferior.h: */ @@ -689,9 +690,11 @@ nexti_command (char *count_string, int f } static void -disable_longjmp_breakpoint_cleanup (void *ignore) +delete_longjmp_breakpoint_cleanup (void *arg) { - disable_longjmp_breakpoint (); + int thread = * (int *) arg; + xfree (arg); + delete_longjmp_breakpoint (thread); } static void @@ -724,11 +727,24 @@ step_1 (int skip_subroutines, int single if (!single_inst || skip_subroutines) /* leave si command alone */ { - enable_longjmp_breakpoint (); + struct cleanup *old_chain; + int *thread; + + thread = xmalloc (sizeof (int)); + old_chain = make_cleanup (xfree, thread); + + if (in_thread_list (inferior_ptid)) + *thread = pid_to_thread_id (inferior_ptid); + else + *thread = -1; + + set_longjmp_breakpoint (); + + discard_cleanups (old_chain); if (!target_can_async_p ()) - cleanups = make_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); + cleanups = make_cleanup (delete_longjmp_breakpoint_cleanup, thread); else - make_exec_cleanup (disable_longjmp_breakpoint_cleanup, 0 /*ignore*/); + make_exec_cleanup (delete_longjmp_breakpoint_cleanup, thread); } /* In synchronous case, all is well, just use the regular for loop. */ Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2008-04-07 02:28:11.000000000 +0100 +++ src/gdb/Makefile.in 2008-04-07 02:41:05.000000000 +0100 @@ -2291,7 +2291,7 @@ infcmd.o: infcmd.c $(defs_h) $(gdb_strin $(objfiles_h) $(completer_h) $(ui_out_h) $(event_top_h) \ $(parser_defs_h) $(regcache_h) $(reggroups_h) $(block_h) \ $(solib_h) $(gdb_assert_h) $(observer_h) $(target_descriptions_h) \ - $(user_regs_h) $(exceptions_h) + $(user_regs_h) $(exceptions_h) $(gdbthread_h) inf-loop.o: inf-loop.c $(defs_h) $(inferior_h) $(target_h) $(event_loop_h) \ $(event_top_h) $(inf_loop_h) $(remote_h) $(exceptions_h) \ $(language_h)