From aa7d318d60c595f97230f45575c882c73f7bdcf7 Mon Sep 17 00:00:00 2001 From: Tom Tromey Date: Thu, 25 Mar 2010 20:48:53 +0000 Subject: [PATCH] PR gdb/11327, PR gdb/11328, PR breakpoints/11368: * infrun.c (handle_inferior_event): Change initialization of stop_stack_dummy. (handle_inferior_event): Change assignment to stop_stack_dummy. (normal_stop): Update use of stop_stack_dummy. (struct inferior_status) : Change type. * inferior.h (stop_stack_dummy): Update. * infcmd.c (stop_stack_dummy): Change type. * infcall.c (cleanup_delete_std_terminate_breakpoint): New function. (call_function_by_hand): Call set_std_terminate_breakpoint. Rewrite std::terminate handling. * breakpoint.h (enum bptype) : New. (enum stop_stack_kind): New. (struct bpstat_what) : Change type. (set_std_terminate_breakpoint, delete_std_terminate_breakpoint): Declare. * breakpoint.c (create_std_terminate_master_breakpoint): New function. (update_breakpoints_after_exec): Handle bp_std_terminate_master. Call create_std_terminate_master_breakpoint. (print_it_typical): Handle new breakpoint kinds. (bpstat_stop_status): Handle bp_std_terminate_master. (bpstat_what): Correctly set call_dummy field. Handle bp_std_terminate_master and bp_std_terminate. (print_one_breakpoint_location): Update. (allocate_bp_location): Update. (set_std_terminate_breakpoint): New function. (delete_std_terminate_breakpoint): Likewise. (create_thread_event_breakpoint): Update. (delete_command): Update. (breakpoint_re_set_one): Update. (breakpoint_re_set): Call create_std_terminate_master_breakpoint. --- gdb/ChangeLog | 37 ++++++++++++++++++++ gdb/breakpoint.c | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++--- gdb/breakpoint.h | 26 +++++++++++++- gdb/infcall.c | 69 +++++++++++++++---------------------- gdb/infcmd.c | 2 +- gdb/inferior.h | 2 +- gdb/infrun.c | 8 ++--- 7 files changed, 192 insertions(+), 53 deletions(-) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index d3ecb91..d2c44c0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,40 @@ +2010-03-25 Tom Tromey + + PR gdb/11327, PR gdb/11328, PR breakpoints/11368: + * infrun.c (handle_inferior_event): Change initialization of + stop_stack_dummy. + (handle_inferior_event): Change assignment to stop_stack_dummy. + (normal_stop): Update use of stop_stack_dummy. + (struct inferior_status) : Change type. + * inferior.h (stop_stack_dummy): Update. + * infcmd.c (stop_stack_dummy): Change type. + * infcall.c (cleanup_delete_std_terminate_breakpoint): New + function. + (call_function_by_hand): Call set_std_terminate_breakpoint. + Rewrite std::terminate handling. + * breakpoint.h (enum bptype) : New. + (enum stop_stack_kind): New. + (struct bpstat_what) : Change type. + (set_std_terminate_breakpoint, delete_std_terminate_breakpoint): + Declare. + * breakpoint.c (create_std_terminate_master_breakpoint): New + function. + (update_breakpoints_after_exec): Handle bp_std_terminate_master. + Call create_std_terminate_master_breakpoint. + (print_it_typical): Handle new breakpoint kinds. + (bpstat_stop_status): Handle bp_std_terminate_master. + (bpstat_what): Correctly set call_dummy field. Handle + bp_std_terminate_master and bp_std_terminate. + (print_one_breakpoint_location): Update. + (allocate_bp_location): Update. + (set_std_terminate_breakpoint): New function. + (delete_std_terminate_breakpoint): Likewise. + (create_thread_event_breakpoint): Update. + (delete_command): Update. + (breakpoint_re_set_one): Update. + (breakpoint_re_set): Call create_std_terminate_master_breakpoint. + 2010-03-25 Jan Kratochvil * symfile.c (build_section_addr_info_from_bfd): New. diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 2cc1f08..ded2a55 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -2157,6 +2157,41 @@ create_longjmp_master_breakpoint (char *func_name) do_cleanups (old_chain); } +/* Create a master std::terminate breakpoint. The actual function + looked for is named FUNC_NAME. */ +static void +create_std_terminate_master_breakpoint (const char *func_name) +{ + struct program_space *pspace; + struct objfile *objfile; + struct cleanup *old_chain; + + old_chain = save_current_program_space (); + + ALL_PSPACES (pspace) + ALL_OBJFILES (objfile) + { + struct breakpoint *b; + struct minimal_symbol *m; + + set_current_program_space (pspace); + + m = lookup_minimal_symbol (func_name, NULL, objfile); + if (m == NULL || (MSYMBOL_TYPE (m) != mst_text + && MSYMBOL_TYPE (m) != mst_file_text)) + continue; + + b = create_internal_breakpoint (get_objfile_arch (objfile), + SYMBOL_VALUE_ADDRESS (m), + bp_std_terminate_master); + b->addr_string = xstrdup (func_name); + b->enable_state = bp_disabled; + } + update_global_location_list (1); + + do_cleanups (old_chain); +} + void update_breakpoints_after_exec (void) { @@ -2198,7 +2233,7 @@ update_breakpoints_after_exec (void) /* Thread event breakpoints must be set anew after an exec(), as must overlay event and longjmp master breakpoints. */ if (b->type == bp_thread_event || b->type == bp_overlay_event - || b->type == bp_longjmp_master) + || b->type == bp_longjmp_master || b->type == bp_std_terminate_master) { delete_breakpoint (b); continue; @@ -2274,6 +2309,7 @@ update_breakpoints_after_exec (void) create_longjmp_master_breakpoint ("_longjmp"); create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp"); + create_std_terminate_master_breakpoint ("std::terminate()"); } int @@ -3202,6 +3238,12 @@ print_it_typical (bpstat bs) result = PRINT_NOTHING; break; + case bp_std_terminate_master: + /* These should never be enabled. */ + printf_filtered (_("std::terminate Master Breakpoint: gdb should not stop!\n")); + result = PRINT_NOTHING; + break; + case bp_watchpoint: case bp_hardware_watchpoint: annotate_watchpoint (b->number); @@ -3292,6 +3334,7 @@ print_it_typical (bpstat bs) case bp_step_resume: case bp_watchpoint_scope: case bp_call_dummy: + case bp_std_terminate: case bp_tracepoint: case bp_fast_tracepoint: case bp_jit_event: @@ -4035,7 +4078,8 @@ bpstat_stop_status (struct address_space *aspace, continue; if (b->type == bp_thread_event || b->type == bp_overlay_event - || b->type == bp_longjmp_master) + || b->type == bp_longjmp_master + || b->type == bp_std_terminate_master) /* We do not stop for these. */ bs->stop = 0; else @@ -4245,7 +4289,7 @@ bpstat_what (bpstat bs) enum bpstat_what_main_action current_action = BPSTAT_WHAT_KEEP_CHECKING; struct bpstat_what retval; - retval.call_dummy = 0; + retval.call_dummy = STOP_NONE; for (; bs != NULL; bs = bs->next) { enum class bs_class = no_effect; @@ -4318,6 +4362,7 @@ bpstat_what (bpstat bs) case bp_thread_event: case bp_overlay_event: case bp_longjmp_master: + case bp_std_terminate_master: bs_class = bp_nostop; break; case bp_catchpoint: @@ -4337,7 +4382,13 @@ bpstat_what (bpstat bs) /* Make sure the action is stop (silent or noisy), so infrun.c pops the dummy frame. */ bs_class = bp_silent; - retval.call_dummy = 1; + retval.call_dummy = STOP_STACK_DUMMY; + break; + case bp_std_terminate: + /* Make sure the action is stop (silent or noisy), + so infrun.c pops the dummy frame. */ + bs_class = bp_silent; + retval.call_dummy = STOP_STD_TERMINATE; break; case bp_tracepoint: case bp_fast_tracepoint: @@ -4465,10 +4516,12 @@ print_one_breakpoint_location (struct breakpoint *b, {bp_step_resume, "step resume"}, {bp_watchpoint_scope, "watchpoint scope"}, {bp_call_dummy, "call dummy"}, + {bp_std_terminate, "std::terminate"}, {bp_shlib_event, "shlib events"}, {bp_thread_event, "thread events"}, {bp_overlay_event, "overlay events"}, {bp_longjmp_master, "longjmp master"}, + {bp_std_terminate_master, "std::terminate master"}, {bp_catchpoint, "catchpoint"}, {bp_tracepoint, "tracepoint"}, {bp_fast_tracepoint, "fast tracepoint"}, @@ -4596,10 +4649,12 @@ print_one_breakpoint_location (struct breakpoint *b, case bp_step_resume: case bp_watchpoint_scope: case bp_call_dummy: + case bp_std_terminate: case bp_shlib_event: case bp_thread_event: case bp_overlay_event: case bp_longjmp_master: + case bp_std_terminate_master: case bp_tracepoint: case bp_fast_tracepoint: case bp_jit_event: @@ -5235,11 +5290,13 @@ allocate_bp_location (struct breakpoint *bpt) case bp_step_resume: case bp_watchpoint_scope: case bp_call_dummy: + case bp_std_terminate: case bp_shlib_event: case bp_thread_event: case bp_overlay_event: case bp_jit_event: case bp_longjmp_master: + case bp_std_terminate_master: loc->loc_type = bp_loc_software_breakpoint; break; case bp_hardware_breakpoint: @@ -5492,6 +5549,33 @@ disable_overlay_breakpoints (void) } } +/* Set an active std::terminate breakpoint for each std::terminate + master breakpoint. */ +void +set_std_terminate_breakpoint (void) +{ + struct breakpoint *b, *temp; + + ALL_BREAKPOINTS_SAFE (b, temp) + if (b->pspace == current_program_space + && b->type == bp_std_terminate_master) + { + struct breakpoint *clone = clone_momentary_breakpoint (b); + clone->type = bp_std_terminate; + } +} + +/* Delete all the std::terminate breakpoints. */ +void +delete_std_terminate_breakpoint (void) +{ + struct breakpoint *b, *temp; + + ALL_BREAKPOINTS_SAFE (b, temp) + if (b->type == bp_std_terminate) + delete_breakpoint (b); +} + struct breakpoint * create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address) { @@ -6537,12 +6621,14 @@ mention (struct breakpoint *b) case bp_longjmp_resume: case bp_step_resume: case bp_call_dummy: + case bp_std_terminate: case bp_watchpoint_scope: case bp_shlib_event: case bp_thread_event: case bp_overlay_event: case bp_jit_event: case bp_longjmp_master: + case bp_std_terminate_master: break; } @@ -9222,11 +9308,13 @@ delete_command (char *arg, int from_tty) ALL_BREAKPOINTS (b) { if (b->type != bp_call_dummy + && b->type != bp_std_terminate && b->type != bp_shlib_event && b->type != bp_jit_event && b->type != bp_thread_event && b->type != bp_overlay_event && b->type != bp_longjmp_master + && b->type != bp_std_terminate_master && b->number >= 0) { breaks_to_delete = 1; @@ -9241,11 +9329,13 @@ delete_command (char *arg, int from_tty) ALL_BREAKPOINTS_SAFE (b, temp) { if (b->type != bp_call_dummy + && b->type != bp_std_terminate && b->type != bp_shlib_event && b->type != bp_thread_event && b->type != bp_jit_event && b->type != bp_overlay_event && b->type != bp_longjmp_master + && b->type != bp_std_terminate_master && b->number >= 0) delete_breakpoint (b); } @@ -9556,6 +9646,7 @@ breakpoint_re_set_one (void *bint) reset later by breakpoint_re_set. */ case bp_overlay_event: case bp_longjmp_master: + case bp_std_terminate_master: delete_breakpoint (b); break; @@ -9575,6 +9666,7 @@ breakpoint_re_set_one (void *bint) case bp_finish: case bp_watchpoint_scope: case bp_call_dummy: + case bp_std_terminate: case bp_step_resume: case bp_longjmp: case bp_longjmp_resume: @@ -9620,6 +9712,7 @@ breakpoint_re_set (void) create_longjmp_master_breakpoint ("_longjmp"); create_longjmp_master_breakpoint ("siglongjmp"); create_longjmp_master_breakpoint ("_siglongjmp"); + create_std_terminate_master_breakpoint ("std::terminate()"); } /* Reset the thread number of this breakpoint: diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index 197bbc4..98a7157 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -83,6 +83,10 @@ enum bptype of scope (with hardware support for watchpoints)). */ bp_call_dummy, + /* A breakpoint set on std::terminate, that is used to catch + otherwise uncaught exceptions thrown during an inferior call. */ + bp_std_terminate, + /* Some dynamic linkers (HP, maybe Solaris) can arrange for special code in the inferior to run when significant events occur in the dynamic linker (for example a library is loaded or unloaded). @@ -118,6 +122,9 @@ enum bptype bp_longjmp_master, + /* Master copies of std::terminate breakpoints. */ + bp_std_terminate_master, + bp_catchpoint, bp_tracepoint, @@ -609,6 +616,20 @@ enum bpstat_what_main_action BPSTAT_WHAT_LAST }; +/* An enum indicating the kind of "stack dummy" stop. This is a bit + of a misnomer because only one kind of truly a stack dummy. */ +enum stop_stack_kind + { + /* We didn't stop at a stack dummy breakpoint. */ + STOP_NONE = 0, + + /* Stopped at a stack dummy. */ + STOP_STACK_DUMMY, + + /* Stopped at std::terminate. */ + STOP_STD_TERMINATE + }; + struct bpstat_what { enum bpstat_what_main_action main_action; @@ -617,7 +638,7 @@ struct bpstat_what of BPSTAT_WHAT_STOP_SILENT or BPSTAT_WHAT_STOP_NOISY (the concept of continuing from a call dummy without popping the frame is not a useful one). */ - int call_dummy; + enum stop_stack_kind call_dummy; }; /* The possible return values for print_bpstat, print_it_normal, @@ -865,6 +886,9 @@ extern void delete_longjmp_breakpoint (int thread); extern void enable_overlay_breakpoints (void); extern void disable_overlay_breakpoints (void); +extern void set_std_terminate_breakpoint (void); +extern void delete_std_terminate_breakpoint (void); + /* These functions respectively disable or reenable all currently enabled watchpoints. When disabled, the watchpoints are marked call_disabled. When reenabled, they are marked enabled. diff --git a/gdb/infcall.c b/gdb/infcall.c index d6a8de3..b603cf6 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -403,6 +403,13 @@ run_inferior_call (struct thread_info *call_thread, CORE_ADDR real_pc) return e; } +/* A cleanup function that calls delete_std_terminate_breakpoint. */ +static void +cleanup_delete_std_terminate_breakpoint (void *ignore) +{ + delete_std_terminate_breakpoint (); +} + /* All this stuff with a dummy frame may seem unnecessarily complicated (why not just save registers in GDB?). The purpose of pushing a dummy frame which looks just like a real frame is so that if you call a @@ -440,9 +447,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) struct cleanup *args_cleanup; struct frame_info *frame; struct gdbarch *gdbarch; - struct breakpoint *terminate_bp = NULL; - struct minimal_symbol *tm; - struct cleanup *terminate_bp_cleanup = NULL; + struct cleanup *terminate_bp_cleanup; ptid_t call_thread_ptid; struct gdb_exception e; const char *name; @@ -757,13 +762,7 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) call. Place a momentary breakpoint in the std::terminate function and if triggered in the call, rewind. */ if (unwind_on_terminating_exception_p) - { - struct minimal_symbol *tm = lookup_minimal_symbol ("std::terminate()", - NULL, NULL); - if (tm != NULL) - terminate_bp = set_momentary_breakpoint_at_pc - (gdbarch, SYMBOL_VALUE_ADDRESS (tm), bp_breakpoint); - } + set_std_terminate_breakpoint (); /* Everything's ready, push all the info needed to restore the caller (and identify the dummy-frame) onto the dummy-frame @@ -776,8 +775,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) discard_cleanups (inf_status_cleanup); /* Register a clean-up for unwind_on_terminating_exception_breakpoint. */ - if (terminate_bp) - terminate_bp_cleanup = make_cleanup_delete_breakpoint (terminate_bp); + terminate_bp_cleanup = make_cleanup (cleanup_delete_std_terminate_breakpoint, + NULL); /* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - If you're looking to implement asynchronous dummy-frames, then @@ -878,7 +877,7 @@ When the function is done executing, GDB will silently stop."), name); } - if (stopped_by_random_signal || !stop_stack_dummy) + if (stopped_by_random_signal || stop_stack_dummy != STOP_STACK_DUMMY) { const char *name = get_function_name (funaddr, name_buf, sizeof (name_buf)); @@ -932,30 +931,17 @@ When the function is done executing, GDB will silently stop."), } } - if (!stop_stack_dummy) + if (stop_stack_dummy == STOP_STD_TERMINATE) { + /* We must get back to the frame we were before the dummy + call. */ + dummy_frame_pop (dummy_id); - /* Check if unwind on terminating exception behaviour is on. */ - if (unwind_on_terminating_exception_p) - { - /* Check that the breakpoint is our special std::terminate - breakpoint. If it is, we do not want to kill the inferior - in an inferior function call. Rewind, and warn the - user. */ - - if (terminate_bp != NULL - && (inferior_thread ()->stop_bpstat->breakpoint_at->address - == terminate_bp->loc->address)) - { - /* We must get back to the frame we were before the - dummy call. */ - dummy_frame_pop (dummy_id); - - /* We also need to restore inferior status to that before the - dummy call. */ - restore_inferior_status (inf_status); - - error (_("\ + /* We also need to restore inferior status to that before + the dummy call. */ + restore_inferior_status (inf_status); + + error (_("\ The program being debugged entered a std::terminate call, most likely\n\ caused by an unhandled C++ exception. GDB blocked this call in order\n\ to prevent the program from being terminated, and has restored the\n\ @@ -963,9 +949,11 @@ context to its original state before the call.\n\ To change this behaviour use \"set unwind-on-terminating-exception off\".\n\ Evaluation of the expression containing the function (%s)\n\ will be abandoned."), - name); - } - } + name); + } + else if (stop_stack_dummy == STOP_NONE) + { + /* We hit a breakpoint inside the FUNCTION. Keep the dummy frame, the user may want to examine its state. Discard inferior status, we're not at the same point @@ -992,10 +980,7 @@ When the function is done executing, GDB will silently stop."), internal_error (__FILE__, __LINE__, _("... should not be here")); } - /* If we get here and the std::terminate() breakpoint has been set, - it has to be cleaned manually. */ - if (terminate_bp) - do_cleanups (terminate_bp_cleanup); + do_cleanups (terminate_bp_cleanup); /* If we get here the called FUNCTION ran to completion, and the dummy frame has already been popped. */ diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 174acde..db2232d 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -155,7 +155,7 @@ int breakpoint_proceeded; /* Nonzero if stopped due to completion of a stack dummy routine. */ -int stop_stack_dummy; +enum stop_stack_kind stop_stack_dummy; /* Nonzero if stopped due to a random (unexpected) signal in inferior process. */ diff --git a/gdb/inferior.h b/gdb/inferior.h index dc87a9e..17b2c6f 100644 --- a/gdb/inferior.h +++ b/gdb/inferior.h @@ -297,7 +297,7 @@ extern CORE_ADDR stop_pc; /* Nonzero if stopped due to completion of a stack dummy routine. */ -extern int stop_stack_dummy; +extern enum stop_stack_kind stop_stack_dummy; /* Nonzero if program stopped due to a random (unexpected) signal in inferior process. */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 4bfe546..5f58759 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -2904,7 +2904,7 @@ handle_inferior_event (struct execution_control_state *ecs) target_last_waitstatus = ecs->ws; /* Always clear state belonging to the previous time we stopped. */ - stop_stack_dummy = 0; + stop_stack_dummy = STOP_NONE; /* If it's a new process, add it to the thread database */ @@ -3970,7 +3970,7 @@ process_event_stop_test: if (what.call_dummy) { - stop_stack_dummy = 1; + stop_stack_dummy = what.call_dummy; } switch (what.main_action) @@ -5460,7 +5460,7 @@ Further execution is probably impossible.\n")); stop_registers = regcache_dup (get_current_regcache ()); } - if (stop_stack_dummy) + if (stop_stack_dummy == STOP_STACK_DUMMY) { /* Pop the empty frame that contains the stack dummy. This also restores inferior state prior to the call @@ -6038,7 +6038,7 @@ struct inferior_status { bpstat stop_bpstat; int stop_step; - int stop_stack_dummy; + enum stop_stack_kind stop_stack_dummy; int stopped_by_random_signal; int stepping_over_breakpoint; CORE_ADDR step_range_start; -- 2.7.4