PR c++/12824:

* NEWS: Update.
	* breakpoint.c (enum exception_event_kind) <EX_EVENT_RETHROW>:
	New constant.
	(classify_exception_breakpoint): New function.
	(print_it_exception_catchpoint, print_one_exception_catchpoint)
	(print_mention_exception_catchpoint)
	(print_recreate_exception_catchpoint, handle_gnu_v3_exceptions)
	(catch_exception_command_1): Handle "rethrow" catchpoint.
	(catch_rethrow_command): New function.
	(_initialize_breakpoint): Add "catch rethrow" command.
gdb/doc
	* gdb.texinfo (Set Catchpoints): Reorganize exception
	catchpoints.  Document "catch rethrow".
	(Debugging C Plus Plus): Mention "catch rethrow".
gdb/testsuite
	* gdb.cp/exception.exp: Add "catch rethrow" tests.
This commit is contained in:
Tom Tromey 2013-04-15 17:27:44 +00:00
parent 02ae6bada6
commit 591f19e89b
7 changed files with 156 additions and 58 deletions

View File

@ -1,3 +1,17 @@
2013-04-15 Tom Tromey <tromey@redhat.com>
PR c++/12824:
* NEWS: Update.
* breakpoint.c (enum exception_event_kind) <EX_EVENT_RETHROW>:
New constant.
(classify_exception_breakpoint): New function.
(print_it_exception_catchpoint, print_one_exception_catchpoint)
(print_mention_exception_catchpoint)
(print_recreate_exception_catchpoint, handle_gnu_v3_exceptions)
(catch_exception_command_1): Handle "rethrow" catchpoint.
(catch_rethrow_command): New function.
(_initialize_breakpoint): Add "catch rethrow" command.
2013-04-15 Pierre Muller <muller@sourceware.org> 2013-04-15 Pierre Muller <muller@sourceware.org>
* contrib/ari/gdb_ari.sh (write_pc rule): Do not consider * contrib/ari/gdb_ari.sh (write_pc rule): Do not consider

View File

@ -151,6 +151,9 @@ Tilera TILE-Gx GNU/Linux tilegx*-*-linux
* New commands (for set/show, see "New options" below) * New commands (for set/show, see "New options" below)
catch rethrow
Like "catch throw", but catches a re-thrown exception.
catch signal catch signal
Catch signals. This is similar to "handle", but allows commands and Catch signals. This is similar to "handle", but allows commands and
conditions to be attached. conditions to be attached.

View File

@ -86,6 +86,7 @@
enum exception_event_kind enum exception_event_kind
{ {
EX_EVENT_THROW, EX_EVENT_THROW,
EX_EVENT_RETHROW,
EX_EVENT_CATCH EX_EVENT_CATCH
}; };
@ -11570,16 +11571,30 @@ catch_exec_command_1 (char *arg, int from_tty,
install_breakpoint (0, &c->base, 1); install_breakpoint (0, &c->base, 1);
} }
/* A helper function that returns a value indicating the kind of the
exception catchpoint B. */
static enum exception_event_kind
classify_exception_breakpoint (struct breakpoint *b)
{
if (strstr (b->addr_string, "catch") != NULL)
return EX_EVENT_CATCH;
else if (strstr (b->addr_string, "rethrow") != NULL)
return EX_EVENT_RETHROW;
else
return EX_EVENT_THROW;
}
static enum print_stop_action static enum print_stop_action
print_it_exception_catchpoint (bpstat bs) print_it_exception_catchpoint (bpstat bs)
{ {
struct ui_out *uiout = current_uiout; struct ui_out *uiout = current_uiout;
struct breakpoint *b = bs->breakpoint_at; struct breakpoint *b = bs->breakpoint_at;
int bp_temp, bp_throw; int bp_temp;
enum exception_event_kind kind = classify_exception_breakpoint (b);
annotate_catchpoint (b->number); annotate_catchpoint (b->number);
bp_throw = strstr (b->addr_string, "throw") != NULL;
if (b->loc->address != b->loc->requested_address) if (b->loc->address != b->loc->requested_address)
breakpoint_adjustment_warning (b->loc->requested_address, breakpoint_adjustment_warning (b->loc->requested_address,
b->loc->address, b->loc->address,
@ -11591,8 +11606,9 @@ print_it_exception_catchpoint (bpstat bs)
if (!ui_out_is_mi_like_p (uiout)) if (!ui_out_is_mi_like_p (uiout))
ui_out_field_int (uiout, "bkptno", b->number); ui_out_field_int (uiout, "bkptno", b->number);
ui_out_text (uiout, ui_out_text (uiout,
bp_throw ? " (exception thrown), " (kind == EX_EVENT_THROW ? " (exception thrown), "
: " (exception caught), "); : (kind == EX_EVENT_CATCH ? " (exception caught), "
: " (exception rethrown), ")));
if (ui_out_is_mi_like_p (uiout)) if (ui_out_is_mi_like_p (uiout))
{ {
ui_out_field_string (uiout, "reason", ui_out_field_string (uiout, "reason",
@ -11609,6 +11625,7 @@ print_one_exception_catchpoint (struct breakpoint *b,
{ {
struct value_print_options opts; struct value_print_options opts;
struct ui_out *uiout = current_uiout; struct ui_out *uiout = current_uiout;
enum exception_event_kind kind = classify_exception_breakpoint (b);
get_user_print_options (&opts); get_user_print_options (&opts);
if (opts.addressprint) if (opts.addressprint)
@ -11623,17 +11640,26 @@ print_one_exception_catchpoint (struct breakpoint *b,
annotate_field (5); annotate_field (5);
if (b->loc) if (b->loc)
*last_loc = b->loc; *last_loc = b->loc;
if (strstr (b->addr_string, "throw") != NULL)
switch (kind)
{ {
case EX_EVENT_THROW:
ui_out_field_string (uiout, "what", "exception throw"); ui_out_field_string (uiout, "what", "exception throw");
if (ui_out_is_mi_like_p (uiout)) if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "catch-type", "throw"); ui_out_field_string (uiout, "catch-type", "throw");
} break;
else
{ case EX_EVENT_RETHROW:
ui_out_field_string (uiout, "what", "exception rethrow");
if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "catch-type", "rethrow");
break;
case EX_EVENT_CATCH:
ui_out_field_string (uiout, "what", "exception catch"); ui_out_field_string (uiout, "what", "exception catch");
if (ui_out_is_mi_like_p (uiout)) if (ui_out_is_mi_like_p (uiout))
ui_out_field_string (uiout, "catch-type", "catch"); ui_out_field_string (uiout, "catch-type", "catch");
break;
} }
} }
@ -11642,15 +11668,15 @@ print_mention_exception_catchpoint (struct breakpoint *b)
{ {
struct ui_out *uiout = current_uiout; struct ui_out *uiout = current_uiout;
int bp_temp; int bp_temp;
int bp_throw; enum exception_event_kind kind = classify_exception_breakpoint (b);
bp_temp = b->disposition == disp_del; bp_temp = b->disposition == disp_del;
bp_throw = strstr (b->addr_string, "throw") != NULL;
ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ") ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
: _("Catchpoint ")); : _("Catchpoint "));
ui_out_field_int (uiout, "bkptno", b->number); ui_out_field_int (uiout, "bkptno", b->number);
ui_out_text (uiout, bp_throw ? _(" (throw)") ui_out_text (uiout, (kind == EX_EVENT_THROW ? _(" (throw)")
: _(" (catch)")); : (kind == EX_EVENT_CATCH ? _(" (catch)")
: _(" (rethrow)"))));
} }
/* Implement the "print_recreate" breakpoint_ops method for throw and /* Implement the "print_recreate" breakpoint_ops method for throw and
@ -11661,12 +11687,22 @@ print_recreate_exception_catchpoint (struct breakpoint *b,
struct ui_file *fp) struct ui_file *fp)
{ {
int bp_temp; int bp_temp;
int bp_throw; enum exception_event_kind kind = classify_exception_breakpoint (b);
bp_temp = b->disposition == disp_del; bp_temp = b->disposition == disp_del;
bp_throw = strstr (b->addr_string, "throw") != NULL;
fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch "); fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
fprintf_unfiltered (fp, bp_throw ? "throw" : "catch"); switch (kind)
{
case EX_EVENT_THROW:
fprintf_unfiltered (fp, "throw");
break;
case EX_EVENT_CATCH:
fprintf_unfiltered (fp, "catch");
break;
case EX_EVENT_RETHROW:
fprintf_unfiltered (fp, "rethrow");
break;
}
print_recreate_thread (b, fp); print_recreate_thread (b, fp);
} }
@ -11680,8 +11716,13 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_string,
if (ex_event == EX_EVENT_CATCH) if (ex_event == EX_EVENT_CATCH)
trigger_func_name = "__cxa_begin_catch"; trigger_func_name = "__cxa_begin_catch";
else if (ex_event == EX_EVENT_RETHROW)
trigger_func_name = "__cxa_rethrow";
else else
trigger_func_name = "__cxa_throw"; {
gdb_assert (ex_event == EX_EVENT_THROW);
trigger_func_name = "__cxa_throw";
}
create_breakpoint (get_current_arch (), create_breakpoint (get_current_arch (),
trigger_func_name, cond_string, -1, NULL, trigger_func_name, cond_string, -1, NULL,
@ -11715,7 +11756,8 @@ catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
error (_("Junk at end of arguments.")); error (_("Junk at end of arguments."));
if (ex_event != EX_EVENT_THROW if (ex_event != EX_EVENT_THROW
&& ex_event != EX_EVENT_CATCH) && ex_event != EX_EVENT_CATCH
&& ex_event != EX_EVENT_RETHROW)
error (_("Unsupported or unknown exception event; cannot catch it")); error (_("Unsupported or unknown exception event; cannot catch it"));
if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty)) if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
@ -11744,6 +11786,17 @@ catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty); catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
} }
/* Implementation of "catch rethrow" command. */
static void
catch_rethrow_command (char *arg, int from_tty,
struct cmd_list_element *command)
{
int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
catch_exception_command_1 (EX_EVENT_RETHROW, arg, tempflag, from_tty);
}
void void
init_ada_exception_breakpoint (struct breakpoint *b, init_ada_exception_breakpoint (struct breakpoint *b,
struct gdbarch *gdbarch, struct gdbarch *gdbarch,
@ -16355,6 +16408,12 @@ Catch an exception, when thrown."),
NULL, NULL,
CATCH_PERMANENT, CATCH_PERMANENT,
CATCH_TEMPORARY); CATCH_TEMPORARY);
add_catch_command ("rethrow", _("\
Catch an exception, when rethrown."),
catch_rethrow_command,
NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("fork", _("Catch calls to fork."), add_catch_command ("fork", _("Catch calls to fork."),
catch_fork_command_1, catch_fork_command_1,
NULL, NULL,

View File

@ -1,3 +1,9 @@
2013-04-15 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Set Catchpoints): Reorganize exception
catchpoints. Document "catch rethrow".
(Debugging C Plus Plus): Mention "catch rethrow".
2013-04-15 Tom Tromey <tromey@redhat.com> 2013-04-15 Tom Tromey <tromey@redhat.com>
* gdb.texinfo (Set Catchpoints): Remove obsolete text. * gdb.texinfo (Set Catchpoints): Remove obsolete text.

View File

@ -4072,13 +4072,46 @@ shared library. Use the @code{catch} command to set a catchpoint.
@kindex catch @kindex catch
@item catch @var{event} @item catch @var{event}
Stop when @var{event} occurs. @var{event} can be any of the following: Stop when @var{event} occurs. @var{event} can be any of the following:
@table @code @table @code
@item throw @item throw
@itemx rethrow
@itemx catch
@cindex stop on C@t{++} exceptions @cindex stop on C@t{++} exceptions
The throwing of a C@t{++} exception. The throwing, re-throwing, or catching of a C@t{++} exception.
@item catch There are currently some limitations to C@t{++} exception handling in
The catching of a C@t{++} exception. @value{GDBN}:
@itemize @bullet
@item
The support for these commands is system-dependent. Currently, only
systems using the @samp{gnu-v3} C@t{++} ABI (@pxref{ABI}) are
supported.
@item
When an exception-related catchpoint is hit, @value{GDBN} stops at a
location in the system library which implements runtime exception
support for C@t{++}, usually @code{libstdc++}. You can use @code{up}
(@pxref{Selection}) to get to your code.
@item
If you call a function interactively, @value{GDBN} normally returns
control to you when the function has finished executing. If the call
raises an exception, however, the call may bypass the mechanism that
returns control to you and cause your program either to abort or to
simply continue running until it hits a breakpoint, catches a signal
that @value{GDBN} is listening for, or exits. This is the case even if
you set a catchpoint for the exception; catchpoints on exceptions are
disabled within interactive calls. @xref{Calling}, for information on
controlling this with @code{set unwind-on-terminating-exception}.
@item
You cannot raise an exception interactively.
@item
You cannot install an exception handler interactively.
@end itemize
@item exception @item exception
@cindex Ada exception catching @cindex Ada exception catching
@ -4288,27 +4321,6 @@ automatically deleted after the first time the event is caught.
Use the @code{info break} command to list the current catchpoints. Use the @code{info break} command to list the current catchpoints.
There are currently some limitations to C@t{++} exception handling
(@code{catch throw} and @code{catch catch}) in @value{GDBN}:
@itemize @bullet
@item
If you call a function interactively, @value{GDBN} normally returns
control to you when the function has finished executing. If the call
raises an exception, however, the call may bypass the mechanism that
returns control to you and cause your program either to abort or to
simply continue running until it hits a breakpoint, catches a signal
that @value{GDBN} is listening for, or exits. This is the case even if
you set a catchpoint for the exception; catchpoints on exceptions are
disabled within interactive calls.
@item
You cannot raise an exception interactively.
@item
You cannot install an exception handler interactively.
@end itemize
@node Delete Breaks @node Delete Breaks
@subsection Deleting Breakpoints @subsection Deleting Breakpoints
@ -13508,6 +13520,7 @@ classes.
@cindex C@t{++} exception handling @cindex C@t{++} exception handling
@item catch throw @item catch throw
@itemx catch rethrow
@itemx catch catch @itemx catch catch
Debug C@t{++} exception handling using these commands. @xref{Set Debug C@t{++} exception handling using these commands. @xref{Set
Catchpoints, , Setting Catchpoints}. Catchpoints, , Setting Catchpoints}.

View File

@ -1,3 +1,7 @@
2013-04-15 Tom Tromey <tromey@redhat.com>
* gdb.cp/exception.exp: Add "catch rethrow" tests.
2013-04-13 Yao Qi <yao@codesourcery.com> 2013-04-13 Yao Qi <yao@codesourcery.com>
* gdb.base/completion.exp: Test completion of command * gdb.base/completion.exp: Test completion of command

View File

@ -56,6 +56,11 @@ gdb_test "catch catch" "Catchpoint \[0-9\]+ \\(catch\\)" \
gdb_test "catch throw" "Catchpoint \[0-9\]+ \\(throw\\)" \ gdb_test "catch throw" "Catchpoint \[0-9\]+ \\(throw\\)" \
"catch throw (before inferior run)" "catch throw (before inferior run)"
# Set a rethrow catchpoint
gdb_test "catch rethrow" "Catchpoint \[0-9\]+ \\(rethrow\\)" \
"catch rethrow (before inferior run)"
# The catchpoints should be listed in the list of breakpoints. # The catchpoints should be listed in the list of breakpoints.
# In case of a statically linked test, we won't have a pending breakpoint. # In case of a statically linked test, we won't have a pending breakpoint.
@ -66,10 +71,11 @@ set addr "\(<PENDING>|$hex\)"
set re_head "Num${ws}Type${ws}Disp${ws}Enb${ws}Address${ws}What" set re_head "Num${ws}Type${ws}Disp${ws}Enb${ws}Address${ws}What"
set re_2_bp "1${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception catch" set re_2_bp "1${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception catch"
set re_3_bp "2${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception throw" set re_3_bp "2${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception throw"
set re_4_bp "3${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception rethrow"
set name "info breakpoints (before inferior run)" set name "info breakpoints (before inferior run)"
gdb_test_multiple "info breakpoints" $name { gdb_test_multiple "info breakpoints" $name {
-re "$re_head${ws}$re_2_bp${ws}$re_3_bp\r\n$gdb_prompt $" { -re "$re_head${ws}$re_2_bp${ws}$re_3_bp${ws}$re_4_bp\r\n$gdb_prompt $" {
pass $name pass $name
} }
-re ".*$gdb_prompt $" -re ".*$gdb_prompt $"
@ -78,13 +84,13 @@ gdb_test_multiple "info breakpoints" $name {
} }
} }
gdb_test "tbreak main" "Temporary breakpoint 3.*" \ gdb_test "tbreak main" "Temporary breakpoint 4.*" \
"Set temporary breakpoint at main" "Set temporary breakpoint at main"
set ok 0 set ok 0
gdb_run_cmd gdb_run_cmd
gdb_test_multiple "" "Run to main" { gdb_test_multiple "" "Run to main" {
-re "Temporary breakpoint 3,.*$gdb_prompt $" { -re "Temporary breakpoint 4,.*$gdb_prompt $" {
pass "Run to main" pass "Run to main"
set ok 1 set ok 1
} }
@ -98,10 +104,11 @@ set addr "$hex"
set re_head "Num${ws}Type${ws}Disp${ws}Enb${ws}Address${ws}What" set re_head "Num${ws}Type${ws}Disp${ws}Enb${ws}Address${ws}What"
set re_2_bp "1${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception catch" set re_2_bp "1${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception catch"
set re_3_bp "2${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception throw" set re_3_bp "2${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception throw"
set re_4_bp "3${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception rethrow"
set name "info breakpoints (after inferior run)" set name "info breakpoints (after inferior run)"
gdb_test_multiple "info breakpoints" $name { gdb_test_multiple "info breakpoints" $name {
-re "$re_head${ws}$re_2_bp${ws}$re_3_bp\r\n$gdb_prompt $" { -re "$re_head${ws}$re_2_bp${ws}$re_3_bp${ws}$re_4_bp\r\n$gdb_prompt $" {
pass $name pass $name
} }
-re ".*$gdb_prompt $" -re ".*$gdb_prompt $"
@ -209,16 +216,8 @@ gdb_test_multiple "backtrace" $name {
# Continue to breakpoint on catcher. # Continue to breakpoint on catcher.
gdb_test "continue" ".*catcher \\(x=13\\).*" "continue to catcher for the second time" gdb_test "continue" ".*catcher \\(x=13\\).*" "continue to catcher for the second time"
# That is all for now.
# # Continue to the re-throw.
# The original code had:
# gdb_test "continue" "Catchpoint \[0-9\]+.*exception rethrown.*" \
# continue to re-throw ; backtrace "continue to rethrow"
# continue to catch ; backtrace
# continue to throw out of main
#
# The problem is that "re-throw" does not show a throw; only a catch.
# I do not know if this is because of a bug, or because the generated
# code is optimized for a throw into the same function.
#
# -- chastain 2004-01-09