From 75cd8a288787550a58c9dd3a7db1b5b0c99c587f Mon Sep 17 00:00:00 2001 From: Kevin Pouget Date: Fri, 6 Jan 2012 14:14:49 +0100 Subject: [PATCH] better exception support --- gdb/arm-linux-tdep.c | 2 +- gdb/breakpoint.c | 68 +++++++++++---- gdb/breakpoint.h | 13 ++- gdb/elfread.c | 3 +- gdb/infcall.c | 3 +- gdb/infcmd.c | 9 +- gdb/infrun.c | 46 +++++++--- gdb/python/py-finishbreakpoint.c | 96 +++++++++++++------- gdb/python/python.c | 6 ++ gdb/python/python.h | 2 + gdb/testsuite/gdb.python/py-finish-breakpoint2.exp | 22 ++++- 11 files changed, 194 insertions(+), 76 deletions(-) diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c index ac4860c..8479839 100644 --- a/gdb/arm-linux-tdep.c +++ b/gdb/arm-linux-tdep.c @@ -935,7 +935,7 @@ arm_linux_copy_svc (struct gdbarch *gdbarch, struct regcache *regs, { inferior_thread ()->control.step_resume_breakpoint = set_momentary_breakpoint (gdbarch, sal, get_frame_id (frame), - bp_step_resume); + bp_step_resume, /* nostop */ 0); /* We need to make sure we actually insert the momentary breakpoint set above. */ diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c index 6bcedc4..e578aed 100644 --- a/gdb/breakpoint.c +++ b/gdb/breakpoint.c @@ -257,6 +257,7 @@ static struct breakpoint_ops internal_breakpoint_ops; /* Momentary breakpoints class type. */ static struct breakpoint_ops momentary_breakpoint_ops; +static struct breakpoint_ops momentary_nostop_breakpoint_ops; /* The breakpoint_ops structure to be used in regular user created breakpoints. */ @@ -4308,6 +4309,7 @@ bpstat_what (bpstat bs_head) retval.main_action = BPSTAT_WHAT_KEEP_CHECKING; retval.call_dummy = STOP_NONE; retval.is_longjmp = 0; + retval.is_nostop = 0; for (bs = bs_head; bs != NULL; bs = bs->next) { @@ -4364,6 +4366,8 @@ bpstat_what (bpstat bs_head) case bp_exception: this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME; retval.is_longjmp = bptype == bp_longjmp; + retval.is_nostop = + momentary_breakpoint_is_nostop (bs->breakpoint_at); break; case bp_longjmp_resume: case bp_exception_resume: @@ -5902,13 +5906,18 @@ make_breakpoint_permanent (struct breakpoint *b) /* Call this routine when stepping and nexting to enable a breakpoint if we do a longjmp() or 'throw' in TP. FRAME is the frame which - initiated the operation. */ + initiated the operation. If the flag NOSTOP is set, the execution will + not be stopped upon hitting the breakpoint, but internal functions can be + triggered. */ void -set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame) +set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame, + int nostop) { struct breakpoint *b, *b_tmp; int thread = tp->num; + struct breakpoint_ops *ops = (nostop ? &momentary_nostop_breakpoint_ops + : &momentary_breakpoint_ops); /* To avoid having to rescan all objfile symbols at every step, we maintain a list of continually-inserted but always disabled @@ -5922,8 +5931,7 @@ set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame) enum bptype type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception; struct breakpoint *clone; - clone = momentary_breakpoint_from_master (b, type, - &momentary_breakpoint_ops); + clone = momentary_breakpoint_from_master (b, type, ops); clone->thread = thread; } @@ -7045,21 +7053,24 @@ enable_breakpoints_after_startup (void) } -/* Set a breakpoint that will evaporate an end of command - at address specified by SAL. - Restrict it to frame FRAME if FRAME is nonzero. */ +/* Set a breakpoint that will evaporate an end of command at address specified + by SAL. Restrict it to frame FRAME if FRAME is nonzero. Will not request + execution stop if NOSTOP is set. */ struct breakpoint * set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal, - struct frame_id frame_id, enum bptype type) + struct frame_id frame_id, enum bptype type, + int nostop) { struct breakpoint *b; + struct breakpoint_ops *ops = (nostop ? &momentary_nostop_breakpoint_ops + : &momentary_breakpoint_ops); /* If FRAME_ID is valid, it should be a real frame, not an inlined one. */ gdb_assert (!frame_id_inlined_p (frame_id)); - b = set_raw_breakpoint (gdbarch, sal, type, &momentary_breakpoint_ops); + b = set_raw_breakpoint (gdbarch, sal, type, ops); b->enable_state = bp_enabled; b->disposition = disp_donttouch; b->frame_id = frame_id; @@ -7127,7 +7138,7 @@ clone_momentary_breakpoint (struct breakpoint *orig) struct breakpoint * set_momentary_breakpoint_at_pc (struct gdbarch *gdbarch, CORE_ADDR pc, - enum bptype type) + enum bptype type, int nostop) { struct symtab_and_line sal; @@ -7136,7 +7147,16 @@ set_momentary_breakpoint_at_pc (struct gdbarch *gdbarch, CORE_ADDR pc, sal.section = find_pc_overlay (pc); sal.explicit_pc = 1; - return set_momentary_breakpoint (gdbarch, sal, null_frame_id, type); + return set_momentary_breakpoint (gdbarch, sal, null_frame_id, type, nostop); +} + +/* Return 1 if the momentary breakpoint BP was created with the NOSTOP + flag. */ + +int +momentary_breakpoint_is_nostop (struct breakpoint *bp) +{ + return bp->ops == &momentary_nostop_breakpoint_ops; } @@ -9549,13 +9569,14 @@ until_break_command (char *arg, int from_tty, int anywhere) /* If the user told us to continue until a specified location, we don't specify a frame at which we need to stop. */ breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal, - null_frame_id, bp_until); + null_frame_id, bp_until, + /* nostop */ 0); else /* Otherwise, specify the selected frame, because we want to stop only at the very same frame. */ breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal, get_stack_frame_id (frame), - bp_until); + bp_until, /* nostop */ 0); old_chain = make_cleanup_delete_breakpoint (breakpoint); @@ -9572,10 +9593,11 @@ until_break_command (char *arg, int from_tty, int anywhere) breakpoint2 = set_momentary_breakpoint (frame_unwind_caller_arch (frame), sal, frame_unwind_caller_id (frame), - bp_until); + bp_until, /* nostop */ 0); make_cleanup_delete_breakpoint (breakpoint2); - set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame)); + set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame), + /* nostop */ 0); make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); } @@ -11176,11 +11198,19 @@ momentary_bkpt_re_set (struct breakpoint *b) } static void -momentary_bkpt_check_status (bpstat bs) +momentary_stop_bkpt_check_status (bpstat bs) { /* Nothing. The point of these breakpoints is causing a stop. */ } +static void +momentary_nostop_bkpt_check_status (bpstat bs) +{ + /* Don't stop, just trigger internal mechanisms. */ + bs->stop = 0; + bs->print = 0; +} + static enum print_stop_action momentary_bkpt_print_it (bpstat bs) { @@ -13480,10 +13510,14 @@ initialize_breakpoint_ops (void) ops = &momentary_breakpoint_ops; *ops = bkpt_base_breakpoint_ops; ops->re_set = momentary_bkpt_re_set; - ops->check_status = momentary_bkpt_check_status; + ops->check_status = momentary_stop_bkpt_check_status; ops->print_it = momentary_bkpt_print_it; ops->print_mention = momentary_bkpt_print_mention; + ops = &momentary_nostop_breakpoint_ops; + *ops = momentary_breakpoint_ops; + ops->check_status = momentary_nostop_bkpt_check_status; + /* GNU v3 exception catchpoints. */ ops = &gnu_v3_exception_catchpoint_ops; *ops = bkpt_breakpoint_ops; diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h index c1d3be9..1b6cabd 100644 --- a/gdb/breakpoint.h +++ b/gdb/breakpoint.h @@ -836,6 +836,11 @@ struct bpstat_what BPSTAT_WHAT_CLEAR_LONGJMP_RESUME. True if we are handling a longjmp, false if we are handling an exception. */ int is_longjmp; + + /* Used for BPSTAT_WHAT_SET_LONGJMP_RESUME and + BPSTAT_WHAT_CLEAR_LONGJMP_RESUME. True if we are handling a + nostop momentary breakpoint. */ + int is_nostop; }; /* The possible return values for print_bpstat, print_it_normal, @@ -1029,13 +1034,15 @@ extern void breakpoint_re_set (void); extern void breakpoint_re_set_thread (struct breakpoint *); extern struct breakpoint *set_momentary_breakpoint - (struct gdbarch *, struct symtab_and_line, struct frame_id, enum bptype); + (struct gdbarch *, struct symtab_and_line, struct frame_id, enum bptype, + int nostop); extern struct breakpoint *set_momentary_breakpoint_at_pc - (struct gdbarch *, CORE_ADDR pc, enum bptype type); + (struct gdbarch *, CORE_ADDR pc, enum bptype type, int nostop); extern struct breakpoint *clone_momentary_breakpoint (struct breakpoint *bpkt); +extern int momentary_breakpoint_is_nostop (struct breakpoint *bp); extern void set_ignore_count (int, int, int); extern void breakpoint_init_inferior (enum inf_context); @@ -1163,7 +1170,7 @@ extern int detach_breakpoints (int); extern void breakpoint_program_space_exit (struct program_space *pspace); extern void set_longjmp_breakpoint (struct thread_info *tp, - struct frame_id frame); + struct frame_id frame, int nostop); extern void delete_longjmp_breakpoint (int thread); extern void enable_overlay_breakpoints (void); diff --git a/gdb/elfread.c b/gdb/elfread.c index ddae099..6315323 100644 --- a/gdb/elfread.c +++ b/gdb/elfread.c @@ -993,7 +993,8 @@ elf_gnu_ifunc_resolver_stop (struct breakpoint *b) sal.explicit_pc = 1; b_return = set_momentary_breakpoint (get_frame_arch (prev_frame), sal, prev_frame_id, - bp_gnu_ifunc_resolver_return); + bp_gnu_ifunc_resolver_return, + /* nostop */ 0); /* Add new b_return to the ring list b->related_breakpoint. */ gdb_assert (b_return->related_breakpoint == b_return); diff --git a/gdb/infcall.c b/gdb/infcall.c index 9af56ba..cca13b2 100644 --- a/gdb/infcall.c +++ b/gdb/infcall.c @@ -782,7 +782,8 @@ call_function_by_hand (struct value *function, int nargs, struct value **args) /* Sanity. The exact same SP value is returned by PUSH_DUMMY_CALL, saved as the dummy-frame TOS, and used by dummy_id to form the frame ID's stack address. */ - bpt = set_momentary_breakpoint (gdbarch, sal, dummy_id, bp_call_dummy); + bpt = set_momentary_breakpoint (gdbarch, sal, dummy_id, bp_call_dummy, + /* nostop */ 0); bpt->disposition = disp_del; } diff --git a/gdb/infcmd.c b/gdb/infcmd.c index 75dc55b..5c8c9f2 100644 --- a/gdb/infcmd.c +++ b/gdb/infcmd.c @@ -889,7 +889,8 @@ step_1 (int skip_subroutines, int single_inst, char *count_string) if (in_thread_list (inferior_ptid)) thread = pid_to_thread_id (inferior_ptid); - set_longjmp_breakpoint (tp, get_frame_id (get_current_frame ())); + set_longjmp_breakpoint (tp, get_frame_id (get_current_frame ()), + /* nostop */ 0); make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); } @@ -1327,7 +1328,7 @@ until_next_command (int from_tty) tp->step_multi = 0; /* Only one call to proceed */ - set_longjmp_breakpoint (tp, get_frame_id (frame)); + set_longjmp_breakpoint (tp, get_frame_id (frame), /* nostop */ 0); old_chain = make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); proceed ((CORE_ADDR) -1, TARGET_SIGNAL_DEFAULT, 1); @@ -1649,11 +1650,11 @@ finish_forward (struct symbol *function, struct frame_info *frame) breakpoint = set_momentary_breakpoint (gdbarch, sal, get_stack_frame_id (frame), - bp_finish); + bp_finish, /* nostop */ 0); old_chain = make_cleanup_delete_breakpoint (breakpoint); - set_longjmp_breakpoint (tp, get_frame_id (frame)); + set_longjmp_breakpoint (tp, get_frame_id (frame), /* from_py*/ 0); make_cleanup (delete_longjmp_breakpoint_cleanup, &thread); /* We want stop_registers, please... */ diff --git a/gdb/infrun.c b/gdb/infrun.c index 24d2720..dbe062a 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -55,6 +55,7 @@ #include "continuations.h" #include "interps.h" #include "skip.h" +#include "python/python.h" /* Prototypes for local functions */ @@ -104,7 +105,8 @@ static void insert_hp_step_resume_breakpoint_at_frame (struct frame_info *); static void insert_step_resume_breakpoint_at_caller (struct frame_info *); -static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR); +static void insert_longjmp_resume_breakpoint (struct gdbarch *, CORE_ADDR, + int); /* When set, stop the 'step' command if we enter a function which has no line number information. The normal behavior is that we step @@ -2379,7 +2381,8 @@ static void handle_step_into_function (struct gdbarch *gdbarch, static void handle_step_into_function_backward (struct gdbarch *gdbarch, struct execution_control_state *ecs); static void check_exception_resume (struct execution_control_state *, - struct frame_info *, struct symbol *); + struct frame_info *, struct symbol *, + int nostop); static void stop_stepping (struct execution_control_state *ecs); static void prepare_to_wait (struct execution_control_state *ecs); @@ -4388,6 +4391,7 @@ process_event_stop_test: { CORE_ADDR jmp_buf_pc; struct bpstat_what what; + int nostop; what = bpstat_what (ecs->event_thread->control.stop_bpstat); @@ -4434,14 +4438,15 @@ process_event_stop_test: delete_step_resume_breakpoint (ecs->event_thread); /* Insert a breakpoint at resume address. */ - insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc); + insert_longjmp_resume_breakpoint (gdbarch, jmp_buf_pc, + what.is_nostop); } else { struct symbol *func = get_frame_function (frame); if (func) - check_exception_resume (ecs, frame, func); + check_exception_resume (ecs, frame, func, what.is_nostop); } keep_going (ecs); return; @@ -4455,6 +4460,8 @@ process_event_stop_test: { gdb_assert (ecs->event_thread->control.step_resume_breakpoint != NULL); + nostop = momentary_breakpoint_is_nostop ( + ecs->event_thread->control.step_resume_breakpoint); delete_step_resume_breakpoint (ecs->event_thread); } else @@ -4476,6 +4483,8 @@ process_event_stop_test: gdb_assert (ecs->event_thread->control.exception_resume_breakpoint != NULL); + nostop = momentary_breakpoint_is_nostop ( + ecs->event_thread->control.exception_resume_breakpoint); delete_exception_resume_breakpoint (ecs->event_thread); if (init_frame) @@ -4500,6 +4509,12 @@ process_event_stop_test: delete_step_resume_breakpoint (ecs->event_thread); } + /* Notify Python that an exception/longjmp occured. */ + gdbpy_bpfinish_handle_exception (); + + if (nostop) + break; + ecs->event_thread->control.stop_step = 1; print_end_stepping_range_reason (); stop_stepping (ecs); @@ -5385,7 +5400,8 @@ insert_step_resume_breakpoint_at_sal_1 (struct gdbarch *gdbarch, paddress (gdbarch, sr_sal.pc)); inferior_thread ()->control.step_resume_breakpoint - = set_momentary_breakpoint (gdbarch, sr_sal, sr_id, sr_type); + = set_momentary_breakpoint (gdbarch, sr_sal, sr_id, sr_type, + /* nostop */ 0); } void @@ -5466,7 +5482,8 @@ insert_step_resume_breakpoint_at_caller (struct frame_info *next_frame) "step-resume" breakpoints. */ static void -insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc) +insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc, + int nostop) { /* There should never be more than one step-resume or longjmp-resume breakpoint per thread, so we should never be setting a new @@ -5479,20 +5496,23 @@ insert_longjmp_resume_breakpoint (struct gdbarch *gdbarch, CORE_ADDR pc) paddress (gdbarch, pc)); inferior_thread ()->control.step_resume_breakpoint = - set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume); + set_momentary_breakpoint_at_pc (gdbarch, pc, bp_longjmp_resume, + nostop); } /* Insert an exception resume breakpoint. TP is the thread throwing the exception. The block B is the block of the unwinder debug hook function. FRAME is the frame corresponding to the call to this function. SYM is the symbol of the function argument holding the - target PC of the exception. */ + target PC of the exception. The breakpoint will not stop the execution + if the flag NOSTOP is set. */ static void insert_exception_resume_breakpoint (struct thread_info *tp, struct block *b, struct frame_info *frame, - struct symbol *sym) + struct symbol *sym, + int nostop) { volatile struct gdb_exception e; @@ -5517,7 +5537,8 @@ insert_exception_resume_breakpoint (struct thread_info *tp, (unsigned long) handler); bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame), - handler, bp_exception_resume); + handler, bp_exception_resume, + nostop); bp->thread = tp->num; inferior_thread ()->control.exception_resume_breakpoint = bp; } @@ -5530,7 +5551,8 @@ insert_exception_resume_breakpoint (struct thread_info *tp, static void check_exception_resume (struct execution_control_state *ecs, - struct frame_info *frame, struct symbol *func) + struct frame_info *frame, struct symbol *func, + int nostop) { volatile struct gdb_exception e; @@ -5566,7 +5588,7 @@ check_exception_resume (struct execution_control_state *ecs, else { insert_exception_resume_breakpoint (ecs->event_thread, - b, frame, sym); + b, frame, sym, nostop); break; } } diff --git a/gdb/python/py-finishbreakpoint.c b/gdb/python/py-finishbreakpoint.c index bfbf9c3..621a155 100644 --- a/gdb/python/py-finishbreakpoint.c +++ b/gdb/python/py-finishbreakpoint.c @@ -298,6 +298,10 @@ bpfinishpy_init (PyObject *self, PyObject *args, PyObject *kwargs) /* Bind the breakpoint with the current program space. */ self_bpfinish->py_bp.bp->pspace = current_program_space; + /* Set a watchdog on longjmp/exception. It will trigger + `gdbpy_bpfinish_handle_exception' if necessary. */ + set_longjmp_breakpoint (inferior_thread (), frame_id, /* nostop */ 1); + return 0; invalid_frame: @@ -327,45 +331,74 @@ bpfinishpy_out_of_scope (struct finish_breakpoint_object *bpfinish_obj) delete_breakpoint (bpfinish_obj->py_bp.bp); } -/* Callback for `bpfinishpy_detect_out_scope'. Triggers Python's - `B->out_of_scope' function if B is a FinishBreakpoint out of its scope. */ +/* Triggers Python's `B->out_of_scope' function if B is a FinishBreakpoint + out of its scope. If INC_CURRENT is set, being on the initial frame will + trigger the callback as well. */ static int -bpfinishpy_detect_out_scope_cb (struct breakpoint *b, void *args) +bpfinishpy_detect_out_scope (struct breakpoint *b, int inc_current) { volatile struct gdb_exception except; - struct breakpoint *bp_stopped = (struct breakpoint *) args; - PyObject *py_bp = (PyObject *) b->py_bp_object; + struct finish_breakpoint_object *finish_bp = + (struct finish_breakpoint_object *) b->py_bp_object; struct gdbarch *garch = b->gdbarch ? b->gdbarch : get_current_arch (); - /* Trigger out_of_scope if this is a FinishBreakpoint and its frame is - not anymore in the current callstack. */ - if (py_bp != NULL && b->py_bp_object->is_finish_bp) + /* Ensure that B is a FinishBreakpoint and we're stopped in its inferior. */ + if (finish_bp != NULL && finish_bp->py_bp.is_finish_bp + && b->pspace == current_inferior ()->pspace) { - struct finish_breakpoint_object *finish_bp = - (struct finish_breakpoint_object *) py_bp; - - /* Check scope if not currently stopped at the FinishBreakpoint. */ - if (b != bp_stopped) + TRY_CATCH (except, RETURN_MASK_ALL) { - TRY_CATCH (except, RETURN_MASK_ALL) - { - if (b->pspace == current_inferior ()->pspace - && (!target_has_registers - || frame_find_by_id (b->frame_id) == NULL)) - bpfinishpy_out_of_scope (finish_bp); - } - if (except.reason < 0) - { - gdbpy_convert_exception (except); - gdbpy_print_stack (); - } + /* Trigger the callback if the initial frame no longer exists or, + if INC_CURRENT is set, if we're back on the initial frame, or if + the inferior no longer exists. */ + int is_current = 0; + + if (inc_current && target_has_registers) + is_current = frame_id_eq (get_frame_id (get_current_frame ()), + b->frame_id); + + if (!target_has_registers + || frame_find_by_id (b->frame_id) == NULL + || is_current) + bpfinishpy_out_of_scope (finish_bp); + } + if (except.reason < 0) + { + gdbpy_convert_exception (except); + gdbpy_print_stack (); } } return 0; } +/* Callback for bpfinishpy_handle_stop. Check scope of B if not + currently stopped on it. */ + +static int +bpfinishpy_detect_out_scope_bp_cb (struct breakpoint *b, void *args) +{ + struct breakpoint *bp_stopped = (struct breakpoint *) args; + + if (bp_stopped != b) + bpfinishpy_detect_out_scope (b, 0); + + return 0; +} + +/* Callback for bpfinishpy_handle_exception. Force out_of_scope if stopped + in the initial frame. */ + +static int +bpfinishpy_detect_out_scope_exception_cb (struct breakpoint *b, void *args) +{ + bpfinishpy_detect_out_scope (b, 1); + + return 0; +} + + /* Attached to `stop' notifications, check if the execution has run out of the scope of any FinishBreakpoint before it has been hit. */ @@ -375,22 +408,22 @@ bpfinishpy_handle_stop (struct bpstats *bs, int print_frame) struct cleanup *cleanup = ensure_python_env (get_current_arch (), current_language); - iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, + iterate_over_breakpoints (bpfinishpy_detect_out_scope_bp_cb, bs == NULL ? NULL : bs->breakpoint_at); do_cleanups (cleanup); } -/* Attached to `exit' notifications, triggers all the necessary out of +/* Called when an exception is caught, triggers the necessary out of scope notifications. */ -static void -bpfinishpy_handle_exit (struct inferior *inf) +void +gdbpy_bpfinish_handle_exception (void) { - struct cleanup *cleanup = ensure_python_env (target_gdbarch, + struct cleanup *cleanup = ensure_python_env (get_current_arch (), current_language); - iterate_over_breakpoints (bpfinishpy_detect_out_scope_cb, NULL); + iterate_over_breakpoints (bpfinishpy_detect_out_scope_exception_cb, NULL); do_cleanups (cleanup); } @@ -408,7 +441,6 @@ gdbpy_initialize_finishbreakpoints (void) (PyObject *) &finish_breakpoint_object_type); observer_attach_normal_stop (bpfinishpy_handle_stop); - observer_attach_inferior_exit (bpfinishpy_handle_exit); } static PyGetSetDef finish_breakpoint_object_getset[] = { diff --git a/gdb/python/python.c b/gdb/python/python.c index 5212d4e..a786a55 100644 --- a/gdb/python/python.c +++ b/gdb/python/python.c @@ -1101,6 +1101,12 @@ gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj) "scripting is not supported.")); } +void +gdbpy_bpfinish_handle_exception (void) +{ + /* Nothing. */ +} + #endif /* HAVE_PYTHON */ diff --git a/gdb/python/python.h b/gdb/python/python.h index 9e461f7..8afe28f 100644 --- a/gdb/python/python.h +++ b/gdb/python/python.h @@ -47,4 +47,6 @@ int gdbpy_should_stop (struct breakpoint_object *bp_obj); int gdbpy_breakpoint_has_py_cond (struct breakpoint_object *bp_obj); +void gdbpy_bpfinish_handle_exception (void); + #endif /* GDB_PYTHON_H */ diff --git a/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp b/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp index 9e65d6c..ffa4f62 100644 --- a/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp +++ b/gdb/testsuite/gdb.python/py-finish-breakpoint2.exp @@ -50,18 +50,30 @@ if ![runto_main] then { # Check FinishBreakpoints against C++ exceptions # -gdb_breakpoint [gdb_get_line_number "Break after exception 2"] - gdb_test "source $pyfile" ".*Python script imported.*" \ "import python scripts" gdb_breakpoint "throw_exception_1" +gdb_test "python watch = gdb.Breakpoint (\"[gdb_get_line_number "Break after exception 1"]\")" \ + "Breakpoint.*" "set watchdog breakpoint after exception handler" gdb_test "continue" "Breakpoint .*throw_exception_1.*" "run to exception 1" -gdb_test "python print len(gdb.breakpoints())" "3" "check BP count" +gdb_test "python print len(gdb.breakpoints ())" "3" "check BP count" gdb_test "python ExceptionFinishBreakpoint(gdb.newest_frame())" "init ExceptionFinishBreakpoint" "set FinishBP after the exception" -gdb_test "continue" ".*stopped at ExceptionFinishBreakpoint.*" "check FinishBreakpoint in catch()" -gdb_test "python print len(gdb.breakpoints())" "3" "check finish BP removal" + +set test "don't catch FinishBreakpoint with exception" +gdb_test_multiple "continue" $test { + -re "stopped at ExceptionFinishBreakpoint.*$gdb_prompt $" { + xfail $test + } + -re "exception did not finish.*Breakpoint .* Break after exception 1.*$gdb_prompt $" { + pass $test + + gdb_test "python print len(gdb.breakpoints())" "3" "check finish BP removal" + } +} + +gdb_py_test_silent_cmd "python watch.delete ()" "delete watchdog breakpoint" 0 gdb_test "continue" ".*Breakpoint.* throw_exception_1.*" "continue to second exception" gdb_test "python ExceptionFinishBreakpoint(gdb.newest_frame())" "init ExceptionFinishBreakpoint" "set FinishBP after the exception" -- 1.7.6.5