+/* 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. */
+
+static void
+insert_exception_resume_breakpoint (struct thread_info *tp,
+ struct block *b,
+ struct frame_info *frame,
+ struct symbol *sym)
+{
+ struct gdb_exception e;
+
+ /* We want to ignore errors here. */
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ struct symbol *vsym;
+ struct value *value;
+ CORE_ADDR handler;
+ struct breakpoint *bp;
+
+ vsym = lookup_symbol (SYMBOL_LINKAGE_NAME (sym), b, VAR_DOMAIN, NULL);
+ value = read_var_value (vsym, frame);
+ /* If the value was optimized out, revert to the old behavior. */
+ if (! value_optimized_out (value))
+ {
+ handler = value_as_address (value);
+
+ if (debug_infrun)
+ fprintf_unfiltered (gdb_stdlog,
+ "infrun: exception resume at %lx\n",
+ (unsigned long) handler);
+
+ bp = set_momentary_breakpoint_at_pc (get_frame_arch (frame),
+ handler, bp_exception_resume);
+ bp->thread = tp->num;
+ inferior_thread ()->control.exception_resume_breakpoint = bp;
+ }
+ }
+}
+
+/* This is called when an exception has been intercepted. Check to
+ see whether the exception's destination is of interest, and if so,
+ set an exception resume breakpoint there. */
+
+static void
+check_exception_resume (struct execution_control_state *ecs,
+ struct frame_info *frame, struct symbol *func)
+{
+ struct gdb_exception e;
+
+ TRY_CATCH (e, RETURN_MASK_ERROR)
+ {
+ struct block *b;
+ struct dict_iterator iter;
+ struct symbol *sym;
+ int argno = 0;
+
+ /* The exception breakpoint is a thread-specific breakpoint on
+ the unwinder's debug hook, declared as:
+
+ void _Unwind_DebugHook (void *cfa, void *handler);
+
+ The CFA argument indicates the frame to which control is
+ about to be transferred. HANDLER is the destination PC.
+
+ We ignore the CFA and set a temporary breakpoint at HANDLER.
+ This is not extremely efficient but it avoids issues in gdb
+ with computing the DWARF CFA, and it also works even in weird
+ cases such as throwing an exception from inside a signal
+ handler. */
+
+ b = SYMBOL_BLOCK_VALUE (func);
+ ALL_BLOCK_SYMBOLS (b, iter, sym)
+ {
+ if (!SYMBOL_IS_ARGUMENT (sym))
+ continue;
+
+ if (argno == 0)
+ ++argno;
+ else
+ {
+ insert_exception_resume_breakpoint (ecs->event_thread,
+ b, frame, sym);
+ break;
+ }
+ }
+ }
+}
+