This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[2/10] RFC: add "catch rethrow"


PR 12824 notices that "catch throw" does not handle re-throws.

I thought this is best done with a new subcommand, as it is much less
common to want to catch re-throws.

This patch implements the feature in a straightforward way.

Built and regtested on x86-64 Fedora 16.
New test case included.

Tom

	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.texinfo (Set Catchpoints): Reorganize exception
	catchpoints.  Document "catch rethrow".
	(Debugging C Plus Plus): Mention "catch rethrow".

	* gdb.cp/exception.exp: Add "catch rethrow" tests.
---
 gdb/NEWS                           |    3 +
 gdb/breakpoint.c                   |   93 +++++++++++++++++++++++++++++-------
 gdb/doc/gdb.texinfo                |   61 ++++++++++++++---------
 gdb/testsuite/gdb.cp/exception.exp |   33 ++++++-------
 4 files changed, 132 insertions(+), 58 deletions(-)

diff --git a/gdb/NEWS b/gdb/NEWS
index 0877aa2..6984390 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -81,6 +81,9 @@ Lynx 178 PowerPC		powerpc-*-lynx*178
 
 * New commands (for set/show, see "New options" below)
 
+catch rethrow
+  Like "catch throw", but catches a re-thrown exception.
+
 catch signal 
   Catch signals.  This is similar to "handle", but allows commands and
   conditions to be attached.
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index fb57a57..6682ec2 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -86,6 +86,7 @@
 enum exception_event_kind
 {
   EX_EVENT_THROW,
+  EX_EVENT_RETHROW,
   EX_EVENT_CATCH
 };
 
@@ -11543,16 +11544,30 @@ catch_exec_command_1 (char *arg, int from_tty,
   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
 print_it_exception_catchpoint (bpstat bs)
 {
   struct ui_out *uiout = current_uiout;
   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);
 
-  bp_throw = strstr (b->addr_string, "throw") != NULL;
   if (b->loc->address != b->loc->requested_address)
     breakpoint_adjustment_warning (b->loc->requested_address,
 	                           b->loc->address,
@@ -11564,8 +11579,9 @@ print_it_exception_catchpoint (bpstat bs)
   if (!ui_out_is_mi_like_p (uiout))
     ui_out_field_int (uiout, "bkptno", b->number);
   ui_out_text (uiout,
-	       bp_throw ? " (exception thrown), "
-		        : " (exception caught), ");
+	       (kind == EX_EVENT_THROW ? " (exception thrown), "
+		: (kind == EX_EVENT_CATCH ? " (exception caught), "
+		   : " (exception rethrown), ")));
   if (ui_out_is_mi_like_p (uiout))
     {
       ui_out_field_string (uiout, "reason", 
@@ -11582,6 +11598,7 @@ print_one_exception_catchpoint (struct breakpoint *b,
 {
   struct value_print_options opts;
   struct ui_out *uiout = current_uiout;
+  enum exception_event_kind kind = classify_exception_breakpoint (b);
 
   get_user_print_options (&opts);
   if (opts.addressprint)
@@ -11596,17 +11613,26 @@ print_one_exception_catchpoint (struct breakpoint *b,
   annotate_field (5);
   if (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");
       if (ui_out_is_mi_like_p (uiout))
 	ui_out_field_string (uiout, "catch-type", "throw");
-    }
-  else
-    {
+      break;
+
+    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");
       if (ui_out_is_mi_like_p (uiout))
 	ui_out_field_string (uiout, "catch-type", "catch");
+      break;
     }
 }
 
@@ -11615,15 +11641,15 @@ print_mention_exception_catchpoint (struct breakpoint *b)
 {
   struct ui_out *uiout = current_uiout;
   int bp_temp;
-  int bp_throw;
+  enum exception_event_kind kind = classify_exception_breakpoint (b);
 
   bp_temp = b->disposition == disp_del;
-  bp_throw = strstr (b->addr_string, "throw") != NULL;
   ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
 			      : _("Catchpoint "));
   ui_out_field_int (uiout, "bkptno", b->number);
-  ui_out_text (uiout, bp_throw ? _(" (throw)")
-			       : _(" (catch)"));
+  ui_out_text (uiout, (kind == EX_EVENT_THROW ? _(" (throw)")
+		       : (kind == EX_EVENT_CATCH ? _(" (catch)")
+			  : _(" (rethrow)"))));
 }
 
 /* Implement the "print_recreate" breakpoint_ops method for throw and
@@ -11634,12 +11660,22 @@ print_recreate_exception_catchpoint (struct breakpoint *b,
 				     struct ui_file *fp)
 {
   int bp_temp;
-  int bp_throw;
+  enum exception_event_kind kind = classify_exception_breakpoint (b);
 
   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_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);
 }
 
@@ -11653,8 +11689,13 @@ handle_gnu_v3_exceptions (int tempflag, char *cond_string,
  
   if (ex_event == EX_EVENT_CATCH)
     trigger_func_name = "__cxa_begin_catch";
+  else if (ex_event == EX_EVENT_RETHROW)
+    trigger_func_name = "__cxa_rethrow";
   else
-    trigger_func_name = "__cxa_throw";
+    {
+      gdb_assert (ex_event == EX_EVENT_THROW);
+      trigger_func_name = "__cxa_throw";
+    }
 
   create_breakpoint (get_current_arch (),
 		     trigger_func_name, cond_string, -1, NULL,
@@ -11688,7 +11729,8 @@ catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
     error (_("Junk at end of arguments."));
 
   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"));
 
   if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
@@ -11717,6 +11759,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);
 }
 
+/* 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
 init_ada_exception_breakpoint (struct breakpoint *b,
 			       struct gdbarch *gdbarch,
@@ -16305,6 +16358,12 @@ Catch an exception, when thrown."),
                      NULL,
 		     CATCH_PERMANENT,
 		     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."),
 		     catch_fork_command_1,
                      NULL,
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 181e5cc..3ec005d 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -4052,13 +4052,46 @@ shared library.  Use the @code{catch} command to set a catchpoint.
 @kindex catch
 @item catch @var{event}
 Stop when @var{event} occurs.  @var{event} can be any of the following:
+
 @table @code
 @item throw
+@itemx rethrow
+@itemx catch
 @cindex stop on C@t{++} exceptions
-The throwing of a C@t{++} exception.
+The throwing, re-throwing, or catching of a C@t{++} exception.
+
+There are currently some limitations to C@t{++} exception handling in
+@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 catch
-The catching of a C@t{++} exception.
+@item
+You cannot install an exception handler interactively.
+@end itemize
 
 @item exception
 @cindex Ada exception catching
@@ -4268,27 +4301,6 @@ automatically deleted after the first time the event is caught.
 
 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
 @subsection Deleting Breakpoints
@@ -13283,6 +13295,7 @@ classes.
 
 @cindex C@t{++} exception handling
 @item catch throw
+@itemx catch rethrow
 @itemx catch catch
 Debug C@t{++} exception handling using these commands.  @xref{Set
 Catchpoints, , Setting Catchpoints}.
diff --git a/gdb/testsuite/gdb.cp/exception.exp b/gdb/testsuite/gdb.cp/exception.exp
index 3d3114e..04c1c10 100644
--- a/gdb/testsuite/gdb.cp/exception.exp
+++ b/gdb/testsuite/gdb.cp/exception.exp
@@ -56,6 +56,11 @@ gdb_test "catch catch" "Catchpoint \[0-9\]+ \\(catch\\)" \
 gdb_test "catch throw" "Catchpoint \[0-9\]+ \\(throw\\)" \
     "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.
 # 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_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_4_bp   "3${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception rethrow"
 
 set name "info breakpoints (before inferior run)"
 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
     }
     -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 ok 0
 gdb_run_cmd
 gdb_test_multiple "" "Run to main" {
-    -re "Temporary breakpoint 3,.*$gdb_prompt $" {
+    -re "Temporary breakpoint 4,.*$gdb_prompt $" {
 	pass "Run to main"
 	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_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_4_bp   "3${ws}breakpoint${ws}keep${ws}y${ws}$addr${ws}exception rethrow"
 
 set name "info breakpoints (after inferior run)"
 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
     }
     -re ".*$gdb_prompt $"
@@ -209,16 +216,8 @@ gdb_test_multiple "backtrace" $name {
 # Continue to breakpoint on catcher.
 gdb_test "continue" ".*catcher \\(x=13\\).*" "continue to catcher for the second time"
 
-# That is all for now.
-# 
-# The original code had:
-#
-#    continue to re-throw ; backtrace
-#    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
+
+# Continue to the re-throw.
+
+gdb_test "continue" "Catchpoint \[0-9\]+.*exception rethrown.*" \
+    "continue to rethrow"
-- 
1.7.7.6


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]