aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhil Muldoon <pmuldoon@redhat.com>2009-06-15 12:11:37 +0000
committerPhil Muldoon <pmuldoon@redhat.com>2009-06-15 12:11:37 +0000
commit7cd1089b09663f833a90a4536db2ffad3591636b (patch)
treeea5adc0bb69efa19f2aa28a7687493bfdf7f7dfe /gdb/infcall.c
parent PR 10263 (diff)
downloadbinutils-gdb-7cd1089b09663f833a90a4536db2ffad3591636b.tar.gz
binutils-gdb-7cd1089b09663f833a90a4536db2ffad3591636b.tar.bz2
binutils-gdb-7cd1089b09663f833a90a4536db2ffad3591636b.zip
2009-06-15 Phil Muldoon <pmuldoon@redhat.com>
* infcall.c (show_unwind_on_terminating_exception_p): New function. (call_function_by_hand): Create breakpoint and clean-up call for std::terminate.breakpoint. Add unwind_on_terminating_exception_p gate. Pop frame on breakpoint hit. (_initialize_infcall): Add add_setshow_boolean_cmd for unwind-on-terminating-exception. testsuite/ 2009-06-15 Phil Muldoon <pmuldoon@redhat.com> * gdb.cp/gdb2495.cc: New file. * gdb.cp/gdb2495.exp: New file. doc/ 2009-06-15 Phil Muldoon <pmuldoon@redhat.com> * doc/gdb.texinfo (Calling): Document set-unwind-on-terminating-exception usage.
Diffstat (limited to 'gdb/infcall.c')
-rw-r--r--gdb/infcall.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/gdb/infcall.c b/gdb/infcall.c
index 193a15b5975..416219e0381 100644
--- a/gdb/infcall.c
+++ b/gdb/infcall.c
@@ -98,6 +98,30 @@ Unwinding of stack if a signal is received while in a call dummy is %s.\n"),
value);
}
+/* This boolean tells what gdb should do if a std::terminate call is
+ made while in a function called from gdb (call dummy).
+ As the confines of a single dummy stack prohibit out-of-frame
+ handlers from handling a raised exception, and as out-of-frame
+ handlers are common in C++, this can lead to no handler being found
+ by the unwinder, and a std::terminate call. This is a false positive.
+ If set, gdb unwinds the stack and restores the context to what it
+ was before the call.
+
+ The default is to unwind the frame if a std::terminate call is
+ made. */
+
+static int unwind_on_terminating_exception_p = 1;
+
+static void
+show_unwind_on_terminating_exception_p (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+
+{
+ fprintf_filtered (file, _("\
+Unwind stack if a C++ exception is unhandled while in a call dummy is %s.\n"),
+ value);
+}
/* Perform the standard coercions that are specified
for arguments to be passed to C or Ada functions.
@@ -416,6 +440,8 @@ 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;
ptid_t call_thread_ptid;
struct gdb_exception e;
const char *name;
@@ -716,6 +742,27 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
bpt->disposition = disp_del;
}
+ /* Create a breakpoint in std::terminate.
+ If a C++ exception is raised in the dummy-frame, and the
+ exception handler is (normally, and expected to be) out-of-frame,
+ the default C++ handler will (wrongly) be called in an inferior
+ function call. This is wrong, as an exception can be normally
+ and legally handled out-of-frame. The confines of the dummy frame
+ prevent the unwinder from finding the correct handler (or any
+ handler, unless it is in-frame). The default handler calls
+ std::terminate. This will kill the inferior. Assert that
+ terminate should never be called in an inferior function
+ 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
+ (SYMBOL_VALUE_ADDRESS (tm), bp_breakpoint);
+ }
+
/* Everything's ready, push all the info needed to restore the
caller (and identify the dummy-frame) onto the dummy-frame
stack. */
@@ -726,6 +773,10 @@ call_function_by_hand (struct value *function, int nargs, struct value **args)
or discard it. */
discard_cleanups (inf_status_cleanup);
+ /* Register a clean-up for unwind_on_terminating_exception_breakpoint. */
+ if (terminate_bp)
+ make_cleanup_delete_breakpoint (terminate_bp);
+
/* - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP - SNIP -
If you're looking to implement asynchronous dummy-frames, then
just below is the place to chop this function in two.. */
@@ -881,6 +932,38 @@ When the function is done executing, GDB will silently stop."),
if (!stop_stack_dummy)
{
+
+ /* 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 (_("\
+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\
+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);
+ }
+ }
/* 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
@@ -989,4 +1072,19 @@ The default is to stop in the frame where the signal was received."),
NULL,
show_unwind_on_signal_p,
&setlist, &showlist);
+
+ add_setshow_boolean_cmd ("unwind-on-terminating-exception", no_class,
+ &unwind_on_terminating_exception_p, _("\
+Set unwinding of stack if std::terminate is called while in call dummy."), _("\
+Show unwinding of stack if std::terminate() is called while in a call dummy."), _("\
+The unwind on terminating exception flag lets the user determine\n\
+what gdb should do if a std::terminate() call is made from the\n\
+default exception handler. If set, gdb unwinds the stack and restores\n\
+the context to what it was before the call. If unset, gdb allows the\n\
+std::terminate call to proceed.\n\
+The default is to unwind the frame."),
+ NULL,
+ show_unwind_on_terminating_exception_p,
+ &setlist, &showlist);
+
}