do_cleanups (old_chain);
}
+/* Install a master breakpoint on the unwinder's debug hook. */
+
+void
+create_exception_master_breakpoint (void)
+{
+ struct objfile *objfile;
+
+ ALL_OBJFILES (objfile)
+ {
+ struct minimal_symbol *debug_hook;
+
+ debug_hook = lookup_minimal_symbol ("_Unwind_DebugHook", NULL, objfile);
+ if (debug_hook != NULL)
+ {
+ struct breakpoint *b;
+ CORE_ADDR addr = SYMBOL_VALUE_ADDRESS (debug_hook);
+ struct gdbarch *gdbarch = get_objfile_arch (objfile);
+
+ addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
+ ¤t_target);
+ b = create_internal_breakpoint (gdbarch, addr, bp_exception_master);
+ b->addr_string = xstrdup ("_Unwind_DebugHook");
+ b->enable_state = bp_disabled;
+ }
+ }
+
+ update_global_location_list (1);
+}
+
void
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_std_terminate_master)
+ || b->type == bp_longjmp_master || b->type == bp_std_terminate_master
+ || b->type == bp_exception_master)
{
delete_breakpoint (b);
continue;
/* Longjmp and longjmp-resume breakpoints are also meaningless
after an exec. */
- if (b->type == bp_longjmp || b->type == bp_longjmp_resume)
+ if (b->type == bp_longjmp || b->type == bp_longjmp_resume
+ || b->type == bp_exception || b->type == bp_exception_resume)
{
delete_breakpoint (b);
continue;
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
create_std_terminate_master_breakpoint ("std::terminate()");
+ create_exception_master_breakpoint ();
}
int
result = PRINT_NOTHING;
break;
+ case bp_exception_master:
+ /* These should never be enabled. */
+ printf_filtered (_("Exception Master Breakpoint: gdb should not stop!\n"));
+ result = PRINT_NOTHING;
+ break;
+
case bp_watchpoint:
case bp_hardware_watchpoint:
annotate_watchpoint (b->number);
case bp_none:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
if (b->type == bp_thread_event || b->type == bp_overlay_event
|| b->type == bp_longjmp_master
- || b->type == bp_std_terminate_master)
+ || b->type == bp_std_terminate_master
+ || b->type == bp_exception_master)
/* We do not stop for these. */
bs->stop = 0;
else
retval.main_action = BPSTAT_WHAT_KEEP_CHECKING;
retval.call_dummy = STOP_NONE;
+ retval.is_longjmp = 0;
for (; bs != NULL; bs = bs->next)
{
}
break;
case bp_longjmp:
+ case bp_exception:
this_action = BPSTAT_WHAT_SET_LONGJMP_RESUME;
+ retval.is_longjmp = bptype == bp_longjmp;
break;
case bp_longjmp_resume:
+ case bp_exception_resume:
this_action = BPSTAT_WHAT_CLEAR_LONGJMP_RESUME;
+ retval.is_longjmp = bptype == bp_longjmp_resume;
break;
case bp_step_resume:
if (bs->stop)
case bp_overlay_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
this_action = BPSTAT_WHAT_SINGLE;
break;
case bp_catchpoint:
{bp_access_watchpoint, "acc watchpoint"},
{bp_longjmp, "longjmp"},
{bp_longjmp_resume, "longjmp resume"},
+ {bp_exception, "exception"},
+ {bp_exception_resume, "exception resume"},
{bp_step_resume, "step resume"},
{bp_watchpoint_scope, "watchpoint scope"},
{bp_call_dummy, "call dummy"},
{bp_overlay_event, "overlay events"},
{bp_longjmp_master, "longjmp master"},
{bp_std_terminate_master, "std::terminate master"},
+ {bp_exception_master, "exception master"},
{bp_catchpoint, "catchpoint"},
{bp_tracepoint, "tracepoint"},
{bp_fast_tracepoint, "fast tracepoint"},
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_overlay_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
case bp_tracepoint:
case bp_fast_tracepoint:
case bp_static_tracepoint:
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_watchpoint_scope:
case bp_call_dummy:
case bp_jit_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
loc->loc_type = bp_loc_software_breakpoint;
break;
case bp_hardware_breakpoint:
}
/* Call this routine when stepping and nexting to enable a breakpoint
- if we do a longjmp() in THREAD. When we hit that breakpoint, call
- set_longjmp_resume_breakpoint() to figure out where we are going. */
+ if we do a longjmp() or 'throw' in TP. FRAME is the frame which
+ initiated the operation. */
void
-set_longjmp_breakpoint (int thread)
+set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
{
struct breakpoint *b, *temp;
+ int thread = tp->num;
/* To avoid having to rescan all objfile symbols at every step,
we maintain a list of continually-inserted but always disabled
clones of those and enable them for the requested thread. */
ALL_BREAKPOINTS_SAFE (b, temp)
if (b->pspace == current_program_space
- && b->type == bp_longjmp_master)
+ && (b->type == bp_longjmp_master
+ || b->type == bp_exception_master))
{
struct breakpoint *clone = clone_momentary_breakpoint (b);
- clone->type = bp_longjmp;
+ clone->type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
clone->thread = thread;
}
+
+ tp->initiating_frame = frame;
}
/* Delete all longjmp breakpoints from THREAD. */
struct breakpoint *b, *temp;
ALL_BREAKPOINTS_SAFE (b, temp)
- if (b->type == bp_longjmp)
+ if (b->type == bp_longjmp || b->type == bp_exception)
{
if (b->thread == thread)
delete_breakpoint (b);
case bp_finish:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_step_resume:
case bp_call_dummy:
case bp_std_terminate:
case bp_jit_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
break;
}
{
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2;
+ int thread_num;
};
/* This function is called by fetch_inferior_event via the
delete_breakpoint (a->breakpoint);
if (a->breakpoint2)
delete_breakpoint (a->breakpoint2);
+ delete_longjmp_breakpoint (a->thread_num);
}
void
struct breakpoint *breakpoint;
struct breakpoint *breakpoint2 = NULL;
struct cleanup *old_chain;
+ int thread;
+ struct thread_info *tp;
clear_proceed_status ();
old_chain = make_cleanup_delete_breakpoint (breakpoint);
+ tp = inferior_thread ();
+ thread = tp->num;
+
/* Keep within the current frame, or in frames called by the current
one. */
frame_unwind_caller_id (frame),
bp_until);
make_cleanup_delete_breakpoint (breakpoint2);
+
+ set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame));
+ make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
}
proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
args->breakpoint = breakpoint;
args->breakpoint2 = breakpoint2;
+ args->thread_num = thread;
discard_cleanups (old_chain);
add_continuation (inferior_thread (),
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
&& b->type != bp_std_terminate_master
+ && b->type != bp_exception_master
&& b->number >= 0)
{
breaks_to_delete = 1;
&& b->type != bp_overlay_event
&& b->type != bp_longjmp_master
&& b->type != bp_std_terminate_master
+ && b->type != bp_exception_master
&& b->number >= 0)
delete_breakpoint (b);
}
case bp_overlay_event:
case bp_longjmp_master:
case bp_std_terminate_master:
+ case bp_exception_master:
delete_breakpoint (b);
break;
case bp_step_resume:
case bp_longjmp:
case bp_longjmp_resume:
+ case bp_exception:
+ case bp_exception_resume:
case bp_jit_event:
break;
}
create_longjmp_master_breakpoint ("siglongjmp");
create_longjmp_master_breakpoint ("_siglongjmp");
create_std_terminate_master_breakpoint ("std::terminate()");
+ create_exception_master_breakpoint ();
}
\f
/* Reset the thread number of this breakpoint: