Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH] gdb/mi: New commands to catch C++ exceptions
@ 2019-05-09  0:05 Andrew Burgess
  2019-05-09 21:50 ` Tom Tromey
                   ` (2 more replies)
  0 siblings, 3 replies; 9+ messages in thread
From: Andrew Burgess @ 2019-05-09  0:05 UTC (permalink / raw)
  To: gdb-patches; +Cc: Andrew Burgess

Adds some MI commands to catch C++ exceptions.  These are
-catch-throw, -catch-rethrow, and -catch-catch, these all correspond
to the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.

Each MI command takes two optional arguments, '-t' has the effect of
calling 'tcatch' instead of 'catch', for example:

   -catch-throw -t

Is the same as:

   (gdb) tcatch throw

There is also a '-r REGEXP' argument that can supply a regexp to match
against the exception type, so:

   -catch-catch -r PATTERN

Is the same as:

   (gdb) catch catch PATTERN

gdb/ChangeLog:

	* NEWS: Mention new MI commands.
	* break-catch-throw.c (enum exception_event_kind): Move to
	breakpoint.h.
	(catch_exception_command_1): Rename to...
	(catch_exception_event): ...this, make non-static, update header
	command, and change some parameter types.
	(catch_catch_command): Update for changes to
	catch_exception_command_1.
	(catch_throw_command): Likewise.
	(catch_rethrow_command): Likewise.
	* breakpoint.c (enum exception_event_kind): Delete.
	* breakpoint.h (enum exception_event_kind): Moved here from
	break-catch-throw.c.
	(catch_exception_event): Declare.
	* mi/mi-cmd-catch.c (mi_cmd_catch_exception_event): New function.
	(mi_cmd_catch_throw): New function.
	(mi_cmd_catch_rethrow): New function.
	(mi_cmd_catch_catch): New function.
	* mi/mi-cmds.c (mi_cmds): Add 'catch-throw', 'catch-rethrow', and
	'catch-catch' entries.
	* mi/mi-cmds.h (mi_cmd_catch_throw): Declare.
	(mi_cmd_catch_rethrow): Declare.
	(mi_cmd_catch_catch): Declare.

gdb/doc/ChangeLog:

	* gdb.texinfo (GDB/MI Catchpoint Commands): Add menu entry to new
	node.
	(C++ Exception GDB/MI Catchpoint Commands): New node to describe
	new MI commands.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-catch-cpp-exceptions.cc: New file.
	* gdb.mi/mi-catch-cpp-exceptions.exp: New file.
	* lib/mi-support.exp (mi_expect_stop): Handle 'exception-caught'
	as a stop reason.
---
 gdb/ChangeLog                                    |  26 +++
 gdb/NEWS                                         |   4 +
 gdb/break-catch-throw.c                          |  30 ++--
 gdb/breakpoint.c                                 |   8 -
 gdb/breakpoint.h                                 |  19 +++
 gdb/doc/ChangeLog                                |   7 +
 gdb/doc/gdb.texinfo                              | 125 ++++++++++++++
 gdb/mi/mi-cmd-catch.c                            |  70 ++++++++
 gdb/mi/mi-cmds.c                                 |   6 +
 gdb/mi/mi-cmds.h                                 |   3 +
 gdb/testsuite/ChangeLog                          |   7 +
 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc  |  73 ++++++++
 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp | 202 +++++++++++++++++++++++
 gdb/testsuite/lib/mi-support.exp                 |  11 +-
 14 files changed, 560 insertions(+), 31 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
 create mode 100644 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 288615b8cd3..e350a18f1f2 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -27,6 +27,10 @@
      'array_indexes', 'symbols', 'unions', 'deref_refs', 'actual_objects',
      'static_members', 'max_elements', 'repeat_threshold', and 'format'.
 
+* MI changes
+
+  ** New command -catch-throw, -catch-rethrow, and -catch-catch.
+
 * New commands
 
 set may-call-functions [on|off]
diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index a221cb31518..bb9507ee45b 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -37,14 +37,6 @@
 #include "cp-support.h"
 #include "location.h"
 
-/* Enums for exception-handling support.  */
-enum exception_event_kind
-{
-  EX_EVENT_THROW,
-  EX_EVENT_RETHROW,
-  EX_EVENT_CATCH
-};
-
 /* Each spot where we may place an exception-related catchpoint has
    two names: the SDT probe point and the function name.  This
    structure holds both.  */
@@ -420,13 +412,11 @@ extract_exception_regexp (const char **string)
   return std::string ();
 }
 
-/* Deal with "catch catch", "catch throw", and "catch rethrow"
-   commands.  */
+/* See breakpoint.h.  */
 
-static void
-catch_exception_command_1 (enum exception_event_kind ex_event,
-			   const char *arg,
-			   int tempflag, int from_tty)
+void
+catch_exception_event (enum exception_event_kind ex_event,
+		       const char *arg, bool tempflag, int from_tty)
 {
   const char *cond_string = NULL;
 
@@ -456,9 +446,9 @@ static void
 catch_catch_command (const char *arg, int from_tty,
 		     struct cmd_list_element *command)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-  catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
+  catch_exception_event (EX_EVENT_CATCH, arg, tempflag, from_tty);
 }
 
 /* Implementation of "catch throw" command.  */
@@ -467,9 +457,9 @@ static void
 catch_throw_command (const char *arg, int from_tty,
 		     struct cmd_list_element *command)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-  catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
+  catch_exception_event (EX_EVENT_THROW, arg, tempflag, from_tty);
 }
 
 /* Implementation of "catch rethrow" command.  */
@@ -478,9 +468,9 @@ static void
 catch_rethrow_command (const char *arg, int from_tty,
 		       struct cmd_list_element *command)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-  catch_exception_command_1 (EX_EVENT_RETHROW, arg, tempflag, from_tty);
+  catch_exception_event (EX_EVENT_RETHROW, arg, tempflag, from_tty);
 }
 
 \f
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index f6d2f36d0a4..0d678587aa4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -85,14 +85,6 @@
 #include "common/array-view.h"
 #include "common/gdb_optional.h"
 
-/* Enums for exception-handling support.  */
-enum exception_event_kind
-{
-  EX_EVENT_THROW,
-  EX_EVENT_RETHROW,
-  EX_EVENT_CATCH
-};
-
 /* Prototypes for local functions.  */
 
 static void map_breakpoint_numbers (const char *,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index a91e3e334cf..7c2c3899b48 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -42,6 +42,16 @@ struct linespec_result;
 struct linespec_sals;
 struct inferior;
 
+/* Enum for exception-handling support in 'catch throw', 'catch rethrow',
+   'catch catch' and the MI equivalent.  */
+
+enum exception_event_kind
+{
+  EX_EVENT_THROW,
+  EX_EVENT_RETHROW,
+  EX_EVENT_CATCH
+};
+
 /* Why are we removing the breakpoint from the target?  */
 
 enum remove_bp_reason
@@ -1670,4 +1680,13 @@ extern void print_breakpoint (breakpoint *bp);
 /* Command element for the 'commands' command.  */
 extern cmd_list_element *commands_cmd_element;
 
+/* Deal with "catch catch", "catch throw", and "catch rethrow" commands and
+   the MI equivalents.  Sets up to catch events of type EX_EVENT.  When
+   TEMPFLAG is true only the next matching event is caught after which the
+   catch-point is deleted.  If REGEX is not NULL then only exceptions whose
+   type name matches REGEX will trigger the event.  */
+
+void catch_exception_event (enum exception_event_kind ex_event,
+			    const char *regex, bool tempflag, int from_tty);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b7f3b271d1f..16a775c226e 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -29406,6 +29406,7 @@
 @menu
 * Shared Library GDB/MI Catchpoint Commands::
 * Ada Exception GDB/MI Catchpoint Commands::
+* C++ Exception GDB/MI Catchpoint Commands::
 @end menu
 
 @node Shared Library GDB/MI Catchpoint Commands
@@ -29605,6 +29606,130 @@
 (gdb)
 @end smallexample
 
+@node C++ Exception GDB/MI Catchpoint Commands
+@subsection C++ Exception @sc{gdb/mi} Catchpoints
+
+The following @sc{gdb/mi} commands can be used to create catchpoints
+that stop the execution when C++ exceptions are being throw, rethrown,
+or caught..
+
+@subheading The @code{-catch-throw} Command
+@findex -catch-throw
+
+@subsubheading Synopsis
+
+@smallexample
+ -catch-throw [ -t ] [ -r @var{regexp}]
+@end smallexample
+
+Catch the throwing of a C@t{++} exception.  If @var{regexp} is given
+then only exceptions whose type matches the regular expression will be
+caught.
+
+If @samp{-t} is given then the catchpoint is enabled only for one
+stop, the catchpoint is automatically deleted after the first event is
+caught.
+
+The possible optional parameters for this command are:
+
+@table @samp
+@item -r @var{regexp}
+Use @var{regexp} to match against the exception type.
+@item -t
+Create a temporary catchpoint.
+@end table
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{catch throw}
+and @samp{tcatch throw}.
+
+@subsubheading Example
+
+@smallexample
+-catch-throw -r exception_type
+^done,bkptno="1"
+(gdb)
+@end smallexample
+
+@subheading The @code{-catch-rethrow} Command
+@findex -catch-rethrow
+
+@subsubheading Synopsis
+
+@smallexample
+ -catch-rethrow [ -t ] [ -r @var{regexp}]
+@end smallexample
+
+Catch the rethrowing of a C@t{++} exception.  If @var{regexp} is given
+then only exceptions whose type matches the regular expression will be
+caught.
+
+If @samp{-t} is given then the catchpoint is enabled only for one
+stop, the catchpoint is automatically deleted after the first event is
+caught.
+
+The possible optional parameters for this command are:
+
+@table @samp
+@item -r @var{regexp}
+Use @var{regexp} to match against the exception type.
+@item -t
+Create a temporary catchpoint.
+@end table
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{catch rethrow}
+and @samp{tcatch rethrow}.
+
+@subsubheading Example
+
+@smallexample
+-catch-rethrow -r exception_type
+^done,bkptno="1"
+(gdb)
+@end smallexample
+
+@subheading The @code{-catch-catch} Command
+@findex -catch-catch
+
+@subsubheading Synopsis
+
+@smallexample
+ -catch-catch [ -t ] [ -r @var{regexp}]
+@end smallexample
+
+Catch the catching of a C@t{++} exception.  If @var{regexp} is given
+then only exceptions whose type matches the regular expression will be
+caught.
+
+If @samp{-t} is given then the catchpoint is enabled only for one
+stop, the catchpoint is automatically deleted after the first event is
+caught.
+
+The possible optional parameters for this command are:
+
+@table @samp
+@item -r @var{regexp}
+Use @var{regexp} to match against the exception type.
+@item -t
+Create a temporary catchpoint.
+@end table
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{catch catch}
+and @samp{tcatch catch}.
+
+@subsubheading Example
+
+@smallexample
+-catch-catch -r exception_type
+^done,bkptno="1"
+(gdb)
+@end smallexample
+
 @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @node GDB/MI Program Context
 @section @sc{gdb/mi}  Program Context
diff --git a/gdb/mi/mi-cmd-catch.c b/gdb/mi/mi-cmd-catch.c
index 87929c48ca4..282ce67c738 100644
--- a/gdb/mi/mi-cmd-catch.c
+++ b/gdb/mi/mi-cmd-catch.c
@@ -288,3 +288,73 @@ mi_cmd_catch_unload (const char *cmd, char *argv[], int argc)
   mi_catch_load_unload (0, argv, argc);
 }
 
+/* Core handler for -catch-throw, -catch-rethrow, and -catch-catch
+   commands.  The argument handling for all of these is identical, we just
+   pass KIND through to GDB's core to select the correct event type.  */
+
+static void
+mi_cmd_catch_exception_event (enum exception_event_kind kind,
+			      const char *cmd, char *argv[], int argc)
+{
+  char *regex = NULL;
+  bool temp = false;
+  int oind = 0;
+  char *oarg;
+  enum opt
+    {
+      OPT_TEMP,
+      OPT_REGEX,
+    };
+  static const struct mi_opt opts[] =
+    {
+      { "t", OPT_TEMP, 0 },
+      { "r", OPT_REGEX, 1 },
+      { 0, 0, 0 }
+    };
+
+  for (;;)
+    {
+      int opt = mi_getopt (cmd, argc, argv, opts,
+                           &oind, &oarg);
+
+      if (opt < 0)
+        break;
+
+      switch ((enum opt) opt)
+        {
+        case OPT_TEMP:
+          temp = true;
+          break;
+        case OPT_REGEX:
+	  regex = oarg;
+          break;
+        }
+    }
+
+  catch_exception_event (kind, regex, temp, 0 /* from_tty */);
+}
+
+/* Handler for -catch-throw.  */
+
+void
+mi_cmd_catch_throw (const char *cmd, char *argv[], int argc)
+{
+  mi_cmd_catch_exception_event (EX_EVENT_THROW, cmd, argv, argc);
+}
+
+/* Handler for -catch-rethrow.  */
+
+void
+mi_cmd_catch_rethrow (const char *cmd, char *argv[], int argc)
+{
+  mi_cmd_catch_exception_event (EX_EVENT_RETHROW, cmd, argv, argc);
+}
+
+/* Handler for -catch-catch.  */
+
+void
+mi_cmd_catch_catch (const char *cmd, char *argv[], int argc)
+{
+  mi_cmd_catch_exception_event (EX_EVENT_CATCH, cmd, argv, argc);
+}
+
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index fe30ac2e822..cd2ffa5fc37 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -75,6 +75,12 @@ static struct mi_cmd mi_cmds[] =
                    &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI_1 ("catch-unload", mi_cmd_catch_unload,
                    &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("catch-throw", mi_cmd_catch_throw,
+                   &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("catch-rethrow", mi_cmd_catch_rethrow,
+                   &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("catch-catch", mi_cmd_catch_catch,
+                   &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI ("data-disassemble", mi_cmd_disassemble),
   DEF_MI_CMD_MI ("data-evaluate-expression", mi_cmd_data_evaluate_expression),
   DEF_MI_CMD_MI ("data-list-changed-registers",
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 7b22ce78134..5a8e99bd33c 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -44,6 +44,9 @@ extern mi_cmd_argv_ftype mi_cmd_catch_exception;
 extern mi_cmd_argv_ftype mi_cmd_catch_handlers;
 extern mi_cmd_argv_ftype mi_cmd_catch_load;
 extern mi_cmd_argv_ftype mi_cmd_catch_unload;
+extern mi_cmd_argv_ftype mi_cmd_catch_throw;
+extern mi_cmd_argv_ftype mi_cmd_catch_rethrow;
+extern mi_cmd_argv_ftype mi_cmd_catch_catch;
 extern mi_cmd_argv_ftype mi_cmd_disassemble;
 extern mi_cmd_argv_ftype mi_cmd_data_evaluate_expression;
 extern mi_cmd_argv_ftype mi_cmd_data_list_register_names;
diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
new file mode 100644
index 00000000000..cacda4653a9
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
@@ -0,0 +1,73 @@
+/* Copyright 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class my_exception
+{
+private:
+  int m_value;
+
+public:
+  my_exception (int v)
+    : m_value (v)
+  {
+    /* Nothing.  */
+  }
+};
+
+void
+bar ()
+{
+  my_exception ex (4);
+  throw ex;	/* Throw 1.  */
+}
+
+void
+foo ()
+{
+  for (int i = 0; i < 2; ++i)
+    {
+      try
+	{
+	  bar ();
+	}
+      catch (const my_exception &ex)	/* Catch 1.  */
+	{
+	  if (i == 1)
+	    throw;	/* Throw 2.  */
+	}
+    }
+}
+
+int
+main ()
+{
+  for (int i = 0; i < 2; ++i)
+    {
+      try
+	{
+	  foo ();
+	}
+      catch (const my_exception &ex)	/* Catch 2.  */
+	{
+	  if (i == 1)
+	    return 1;	/* Stop here.  */
+	}
+    }
+
+  return 0;
+}
+
diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
new file mode 100644
index 00000000000..160dd570616
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
@@ -0,0 +1,202 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the -catch-throw, -catch-rethrow, and -catch-catch MI commands.
+
+if { [skip_cplus_tests] } { continue }
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile .cc
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+    untested "failed to compile"
+    return -1
+}
+
+# Grab some line numbers we'll need.
+set catch_1_lineno [gdb_get_line_number "Catch 1"]
+set catch_2_lineno [gdb_get_line_number "Catch 2"]
+set throw_1_lineno [gdb_get_line_number "Throw 1"]
+set throw_2_lineno [gdb_get_line_number "Throw 2"]
+set main_lineno [gdb_get_line_number "Stop here"]
+
+# Restart this test, load the test binary and set a breakpoint in
+# main.
+proc restart_for_test {} {
+    global srcdir subdir binfile srcfile
+    global main_lineno
+
+    if {[mi_gdb_start]} {
+	continue
+    }
+
+    mi_delete_breakpoints
+    mi_gdb_reinitialize_dir $srcdir/$subdir
+    mi_gdb_load ${binfile}
+
+    mi_runto main
+
+    mi_create_breakpoint \
+	"$srcfile:${main_lineno}" "break before exiting program" \
+	-disp keep -func "main.*" \
+	-file ".*mi-catch-cpp-exceptions.cc" -line ${main_lineno}
+}
+
+# Issue an -exec-continue then wait for GDB to catch a C++ exception
+# event in FUNC on LINE.  Use TESTNAME to make tests unique.
+proc continue_to_next_exception { func line testname } {
+    global hex
+
+    mi_send_resuming_command "exec-continue" \
+	"exec-continue"
+    mi_expect_stop "exception-caught" ".*" ".*" ".*" ".*" \
+	{} "run until an exception is caught: $testname"
+    mi_gdb_test "-stack-list-frames 1 1" \
+	"\\^done,stack=\\\[frame=\{level=\"1\",addr=\"$hex\",func=\"${func}\",.*,line=\"${line}\".*\}\\\]" \
+	"check previous frame: $testname"
+}
+
+# Issue an -exec-continue and stop at the breakpoint in main.
+proc continue_to_breakpoint_in_main {} {
+    global main_lineno
+
+    mi_send_resuming_command "exec-continue" "exec-continue to main"
+    mi_expect_stop "breakpoint-hit" "main" ".*" ".*" "${main_lineno}" \
+	{.* disp="keep"} "run until breakpoint in main"
+}
+
+# Ensure that -catch-throw will catch only throws and nothing else.
+with_test_prefix "-catch-throw" {
+    restart_for_test
+    mi_gdb_test "-catch-throw" \
+	"^done,bkptno=\"$decimal\""
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4"
+    continue_to_breakpoint_in_main
+}
+
+# Ensure that -catch-rethrow catches only rethrows and nothing else.
+with_test_prefix "-catch-rethrow" {
+    restart_for_test
+    mi_gdb_test "-catch-rethrow" \
+	"^done,bkptno=\"$decimal\""
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2"
+    continue_to_breakpoint_in_main
+}
+
+# Ensure that -catch-catch catches only catch points, and nothing
+# else.
+with_test_prefix "-catch-catch" {
+    restart_for_test
+    mi_gdb_test "-catch-catch" \
+	"^done,bkptno=\"$decimal\""
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 3"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 6"
+    continue_to_breakpoint_in_main
+}
+
+# Now check that all of the command with a regexp that doesn't match,
+# don't trigger.
+with_test_prefix "all with invalid regexp" {
+    restart_for_test
+    mi_gdb_test "-catch-throw -r blahblah" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-rethrow -r woofwoof" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-catch -r miowmiow" \
+	"^done,bkptno=\"$decimal\""
+
+    # Would like to use 'continue_to_breakpoint_in_main' here, if
+    # there wasn't a bug that requires a use of kfail.
+
+    mi_send_resuming_command "exec-continue" \
+	"exec-continue"
+    set testname "run until breakpoint in main"
+    gdb_expect {
+	-re "could not find minimal symbol for typeinfo address.*$mi_gdb_prompt$" {
+	    kfail "gdb/24541" "${testname}"
+	}
+	-re "\\*stopped,reason=\"breakpoint-hit\".*func=\"main\".*line=\"${main_lineno}\".*$mi_gdb_prompt$" {
+	    pass "${testname}"
+	}
+	timeout {
+	    fail "${testname} (timeout)"
+	}
+    }
+}
+
+# Now check that all of the commands with a regexp that does match,
+# still trigger.
+with_test_prefix "all with valid regexp" {
+    restart_for_test
+    mi_gdb_test "-catch-throw -r my_ex" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-rethrow -r _except" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-catch -r my_exception" \
+	"^done,bkptno=\"$decimal\""
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 3"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 6"
+    continue_to_breakpoint_in_main
+}
+
+# Check that the temporary switch works on its own.
+with_test_prefix "all with -t" {
+    restart_for_test
+    mi_gdb_test "-catch-throw -t" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-rethrow -t" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-catch -t" \
+	"^done,bkptno=\"$decimal\""
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_breakpoint_in_main
+}
+
+# Check that the temporary switch works when used with a regexp.
+restart_for_test
+with_test_prefix "all with -t and regexp" {
+    mi_gdb_test "-catch-throw -t -r my_ex" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-rethrow -t -r _except" \
+	"^done,bkptno=\"$decimal\""
+    mi_gdb_test "-catch-catch -t -r my_exception" \
+	"^done,bkptno=\"$decimal\""
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_breakpoint_in_main
+}
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index a58c4f6e119..8c2c7c84eda 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1221,10 +1221,15 @@ proc mi_expect_stop { reason func args file line extra test } {
     set args "\\\[$args\\\]"
 
     set bn ""
+    set ebn ""
     if { $reason == "breakpoint-hit" } {
 	set bn {bkptno="[0-9]+",}
     } elseif { $reason == "solib-event" } {
 	set bn ".*"
+    } elseif { $reason == "exception-caught" } {
+	set ebn {bkptno="[0-9]+",}
+	set bn ".*"
+	set reason "breakpoint-hit"
     }
 
     set r ""
@@ -1235,9 +1240,9 @@ proc mi_expect_stop { reason func args file line extra test } {
 
     set a $after_reason
 
-    verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
+    verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
     gdb_expect {
-	-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
+	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
 	    pass "$test"
 	    if {[array names expect_out "2,string"] != ""} {
 		return $expect_out(2,string)
@@ -1245,7 +1250,7 @@ proc mi_expect_stop { reason func args file line extra test } {
 	    # No debug info available but $file does match.
 	    return 0
 	}
-	-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\",arch=\"$any\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
+	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\",arch=\"$any\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
 	    verbose -log "got $expect_out(buffer)"
 	    fail "$test (stopped at wrong place)"
 	    return -1
-- 
2.14.5


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] gdb/mi: New commands to catch C++ exceptions
  2019-05-09  0:05 [PATCH] gdb/mi: New commands to catch C++ exceptions Andrew Burgess
@ 2019-05-09 21:50 ` Tom Tromey
  2019-05-10  7:01 ` Eli Zaretskii
  2019-05-11 23:46 ` [PATCHv2] " Andrew Burgess
  2 siblings, 0 replies; 9+ messages in thread
From: Tom Tromey @ 2019-05-09 21:50 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

>>>>> "Andrew" == Andrew Burgess <andrew.burgess@embecosm.com> writes:

Andrew> Adds some MI commands to catch C++ exceptions.  These are
Andrew> -catch-throw, -catch-rethrow, and -catch-catch, these all correspond
Andrew> to the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.

Thanks for the patch.

I read through this and it all seems good to me (of course Eli will have
to approve the docs).

I had one tiny nit.

Andrew> +void catch_exception_event (enum exception_event_kind ex_event,
Andrew> +			    const char *regex, bool tempflag, int from_tty);

The style in breakpoint.h seems to be to use "extern void ...".

Tom


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH] gdb/mi: New commands to catch C++ exceptions
  2019-05-09  0:05 [PATCH] gdb/mi: New commands to catch C++ exceptions Andrew Burgess
  2019-05-09 21:50 ` Tom Tromey
@ 2019-05-10  7:01 ` Eli Zaretskii
  2019-05-11 23:46 ` [PATCHv2] " Andrew Burgess
  2 siblings, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2019-05-10  7:01 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Cc: Andrew Burgess <andrew.burgess@embecosm.com>
> Date: Thu,  9 May 2019 01:05:00 +0100
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 288615b8cd3..e350a18f1f2 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -27,6 +27,10 @@
>       'array_indexes', 'symbols', 'unions', 'deref_refs', 'actual_objects',
>       'static_members', 'max_elements', 'repeat_threshold', and 'format'.
>  
> +* MI changes
> +
> +  ** New command -catch-throw, -catch-rethrow, and -catch-catch.
            ^^^^^^^
That should be "commands", right?

> +@node C++ Exception GDB/MI Catchpoint Commands
> +@subsection C++ Exception @sc{gdb/mi} Catchpoints

@node cannot have markup, but @subsection can.  Our convention is to
use C@t{++} for "C++", as that makes it look prettier in print.
Please use this markup in @subsection and elsewhere in the text.

> +@smallexample
> + -catch-throw [ -t ] [ -r @var{regexp}]
> +@end smallexample
> +
> +Catch the throwing of a C@t{++} exception.

"Catch the throwing" is ambiguous, because the meaning of "catch" here
is unclear.  The section of the manual that describes the
corresponding CLI commands uses a more clear description: "Stop when
@var{event} occurs."  So I suggest to use the same:

  Stop when the debuggee throws a C@t{++} exception.

>                                               If @var{regexp} is given
> +then only exceptions whose type matches the regular expression will be
> +caught.

A comma is missing after "given".

> +If @samp{-t} is given then the catchpoint is enabled only for one

Likewise.

> +stop, the catchpoint is automatically deleted after the first event is
> +caught.

Again, please don't use "caught", but instead "after stopping once for
the event."

> +The possible optional parameters for this command are:
> +
> +@table @samp
> +@item -r @var{regexp}
> +Use @var{regexp} to match against the exception type.
> +@item -t
> +Create a temporary catchpoint.
> +@end table

This part sounds like a repetition to me.

> +@subsubheading @value{GDBN} Command
> +
> +The corresponding @value{GDBN} commands are @samp{catch throw}
> +and @samp{tcatch throw}.

Please add a cross-reference to where these CLI commands are
described.

> +@subsubheading Example
> +
> +@smallexample
> +-catch-throw -r exception_type
> +^done,bkptno="1"
> +(gdb)
> +@end smallexample

IMO, this example is not useful, because it doesn't show the effect of
the used features.  How about adding the output when the program is
stopped because it throws a matching exception?  Then you'd be able to
show that the type is matched as a regexp, not as a literal string.

> +@smallexample
> + -catch-rethrow [ -t ] [ -r @var{regexp}]
> +@end smallexample
> +
> +Catch the rethrowing of a C@t{++} exception.  If @var{regexp} is given
   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
"Stop when a C@t{++} exception is re-thrown."

A comma is missing after "given".

> +If @samp{-t} is given then the catchpoint is enabled only for one

Likewise.

> +The possible optional parameters for this command are:
> +
> +@table @samp
> +@item -r @var{regexp}
> +Use @var{regexp} to match against the exception type.
> +@item -t
> +Create a temporary catchpoint.
> +@end table

Repetition again.

> +@subsubheading @value{GDBN} Command
> +
> +The corresponding @value{GDBN} commands are @samp{catch rethrow}
> +and @samp{tcatch rethrow}.

Again, please add a cross-reference.

> +@smallexample
> +-catch-rethrow -r exception_type
> +^done,bkptno="1"
> +(gdb)
> +@end smallexample

Same comment as for the previous example.

> +@smallexample
> + -catch-catch [ -t ] [ -r @var{regexp}]
> +@end smallexample
> +
> +Catch the catching of a C@t{++} exception.  If @var{regexp} is given

Same comments as above.

Btw, as the text you use to describe all 3 commands is extremely
similar, maybe you should describe them in a single subheading,
instead of copying the same text 3 times?

Thanks.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCHv2] gdb/mi: New commands to catch C++ exceptions
  2019-05-09  0:05 [PATCH] gdb/mi: New commands to catch C++ exceptions Andrew Burgess
  2019-05-09 21:50 ` Tom Tromey
  2019-05-10  7:01 ` Eli Zaretskii
@ 2019-05-11 23:46 ` Andrew Burgess
  2019-05-12  4:09   ` Eli Zaretskii
  2019-06-15 22:34   ` Andrew Burgess
  2 siblings, 2 replies; 9+ messages in thread
From: Andrew Burgess @ 2019-05-11 23:46 UTC (permalink / raw)
  To: gdb-patches; +Cc: Eli Zaretskii, Tom Tromey, Andrew Burgess

Eli,

This iteration includes updated documentation that fixes almost all of
the issues you raised.  The only thing I haven't done is collapse all
of the command sub-sections into a single sub-section.  I looked
through most of the existing MI commands and they all seem to be one
command per sub-section, so I wasn't entirely sure how to layout a
merged entry, nor if a merged entry was inline with the style for MI
commands.

---

I have also tweaked the code a little in this version, the changes
around how a catchpoint is reported when it is initially setup has
changed, the output is not more inline with other breakpoints.  See
the changes in print_mention_exception_catchpoint, and the new
scoped_restore restore_breakpoint_reporting in
mi_cmd_catch_exception_event.  Otherwise the code is unchanged.

Thanks,
Andrew

---

Adds some MI commands to catch C++ exceptions.  The new commands are
-catch-throw, -catch-rethrow, and -catch-catch, these all correspond
to the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.

Each MI command takes two optional arguments, '-t' has the effect of
calling 'tcatch' instead of 'catch', for example:

   (gdb)
   -catch-throw -t

Is the same as:

   (gdb) tcatch throw

There is also a '-r REGEXP' argument that can supply a regexp to match
against the exception type, so:

   (gdb)
   -catch-catch -r PATTERN

Is the same as:

   (gdb) catch catch PATTERN

The change in print_mention_exception_catchpoint might seem a little
strange; changing the output from using ui_out::field_int and
ui_out::text to using  ui_out::message.

The print_mention_exception_catchpoint is used as the 'print_mention'
method for the exception catchpoint breakpoint object.  Most of the
other 'print_mention' methods (see breakpoint.c) use either
printf_filtered, of ui_out::message.  Using field_int was causing an
unexpected field to be added to the MI output.  Here's the output
without the change in print_mention_exception_catchpoint:

    (gdb)
    -catch-throw
    ^done,bkptno="1",bkpt={number="1",type="breakpoint",disp="keep",
                           enabled="y",addr="0x00000000004006c0",
                           what="exception throw",catch-type="throw",
                           thread-groups=["i1"],times="0"}

Notice the breakpoint number appears in both the 'bkptno' field, and
the 'number' field within the 'bkpt' tuple.  Here's the output with
the change in print_mention_exception_catchpoint:

    (gdb)
    -catch-throw
    ^done,bkpt={number="1",type="breakpoint",disp="keep",
                enabled="y",addr="0x00000000004006c0",
                what="exception throw",catch-type="throw",
                thread-groups=["i1"],times="0"}

gdb/ChangeLog:

	* NEWS: Mention new MI commands.
	* break-catch-throw.c (enum exception_event_kind): Move to
	breakpoint.h.
	(print_mention_exception_catchpoint): Output text as a single
	message.
	(catch_exception_command_1): Rename to...
	(catch_exception_event): ...this, make non-static, update header
	command, and change some parameter types.
	(catch_catch_command): Update for changes to
	catch_exception_command_1.
	(catch_throw_command): Likewise.
	(catch_rethrow_command): Likewise.
	* breakpoint.c (enum exception_event_kind): Delete.
	* breakpoint.h (enum exception_event_kind): Moved here from
	break-catch-throw.c.
	(catch_exception_event): Declare.
	* mi/mi-cmd-catch.c (mi_cmd_catch_exception_event): New function.
	(mi_cmd_catch_throw): New function.
	(mi_cmd_catch_rethrow): New function.
	(mi_cmd_catch_catch): New function.
	* mi/mi-cmds.c (mi_cmds): Add 'catch-throw', 'catch-rethrow', and
	'catch-catch' entries.
	* mi/mi-cmds.h (mi_cmd_catch_throw): Declare.
	(mi_cmd_catch_rethrow): Declare.
	(mi_cmd_catch_catch): Declare.

gdb/doc/ChangeLog:

	* gdb.texinfo (GDB/MI Catchpoint Commands): Add menu entry to new
	node.
	(C++ Exception GDB/MI Catchpoint Commands): New node to describe
	new MI commands.

gdb/testsuite/ChangeLog:

	* gdb.mi/mi-catch-cpp-exceptions.cc: New file.
	* gdb.mi/mi-catch-cpp-exceptions.exp: New file.
	* lib/mi-support.exp (mi_expect_stop): Handle 'exception-caught'
	as a stop reason.
---
 gdb/ChangeLog                                    |  28 ++++
 gdb/NEWS                                         |   4 +
 gdb/break-catch-throw.c                          |  42 ++---
 gdb/breakpoint.c                                 |   8 -
 gdb/breakpoint.h                                 |  20 +++
 gdb/doc/ChangeLog                                |   7 +
 gdb/doc/gdb.texinfo                              | 140 ++++++++++++++++
 gdb/mi/mi-cmd-catch.c                            |  71 ++++++++
 gdb/mi/mi-cmds.c                                 |   6 +
 gdb/mi/mi-cmds.h                                 |   3 +
 gdb/testsuite/ChangeLog                          |   7 +
 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc  |  73 +++++++++
 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp | 197 +++++++++++++++++++++++
 gdb/testsuite/lib/mi-support.exp                 |  11 +-
 14 files changed, 580 insertions(+), 37 deletions(-)
 create mode 100644 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
 create mode 100644 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp

diff --git a/gdb/NEWS b/gdb/NEWS
index 288615b8cd3..3377940e2b2 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -27,6 +27,10 @@
      'array_indexes', 'symbols', 'unions', 'deref_refs', 'actual_objects',
      'static_members', 'max_elements', 'repeat_threshold', and 'format'.
 
+* MI changes
+
+  ** New commands -catch-throw, -catch-rethrow, and -catch-catch.
+
 * New commands
 
 set may-call-functions [on|off]
diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
index a221cb31518..107ac74f5cc 100644
--- a/gdb/break-catch-throw.c
+++ b/gdb/break-catch-throw.c
@@ -37,14 +37,6 @@
 #include "cp-support.h"
 #include "location.h"
 
-/* Enums for exception-handling support.  */
-enum exception_event_kind
-{
-  EX_EVENT_THROW,
-  EX_EVENT_RETHROW,
-  EX_EVENT_CATCH
-};
-
 /* Each spot where we may place an exception-related catchpoint has
    two names: the SDT probe point and the function name.  This
    structure holds both.  */
@@ -317,12 +309,12 @@ print_mention_exception_catchpoint (struct breakpoint *b)
   enum exception_event_kind kind = classify_exception_breakpoint (b);
 
   bp_temp = b->disposition == disp_del;
-  uiout->text (bp_temp ? _("Temporary catchpoint ")
-			      : _("Catchpoint "));
-  uiout->field_int ("bkptno", b->number);
-  uiout->text ((kind == EX_EVENT_THROW ? _(" (throw)")
-		       : (kind == EX_EVENT_CATCH ? _(" (catch)")
-			  : _(" (rethrow)"))));
+  uiout->message ("%s %d %s",
+		  (bp_temp ? _("Temporary catchpoint ") : _("Catchpoint")),
+		  b->number,
+		  (kind == EX_EVENT_THROW
+		   ? _("(throw)") : (kind == EX_EVENT_CATCH
+				     ? _("(catch)") : _("(rethrow)"))));
 }
 
 /* Implement the "print_recreate" breakpoint_ops method for throw and
@@ -420,13 +412,11 @@ extract_exception_regexp (const char **string)
   return std::string ();
 }
 
-/* Deal with "catch catch", "catch throw", and "catch rethrow"
-   commands.  */
+/* See breakpoint.h.  */
 
-static void
-catch_exception_command_1 (enum exception_event_kind ex_event,
-			   const char *arg,
-			   int tempflag, int from_tty)
+void
+catch_exception_event (enum exception_event_kind ex_event,
+		       const char *arg, bool tempflag, int from_tty)
 {
   const char *cond_string = NULL;
 
@@ -456,9 +446,9 @@ static void
 catch_catch_command (const char *arg, int from_tty,
 		     struct cmd_list_element *command)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-  catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
+  catch_exception_event (EX_EVENT_CATCH, arg, tempflag, from_tty);
 }
 
 /* Implementation of "catch throw" command.  */
@@ -467,9 +457,9 @@ static void
 catch_throw_command (const char *arg, int from_tty,
 		     struct cmd_list_element *command)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-  catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
+  catch_exception_event (EX_EVENT_THROW, arg, tempflag, from_tty);
 }
 
 /* Implementation of "catch rethrow" command.  */
@@ -478,9 +468,9 @@ static void
 catch_rethrow_command (const char *arg, int from_tty,
 		       struct cmd_list_element *command)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-  catch_exception_command_1 (EX_EVENT_RETHROW, arg, tempflag, from_tty);
+  catch_exception_event (EX_EVENT_RETHROW, arg, tempflag, from_tty);
 }
 
 \f
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 35da97bd041..7b0fbdd01be 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -85,14 +85,6 @@
 #include "common/array-view.h"
 #include "common/gdb_optional.h"
 
-/* Enums for exception-handling support.  */
-enum exception_event_kind
-{
-  EX_EVENT_THROW,
-  EX_EVENT_RETHROW,
-  EX_EVENT_CATCH
-};
-
 /* Prototypes for local functions.  */
 
 static void map_breakpoint_numbers (const char *,
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index a91e3e334cf..c404d0e8ee8 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -42,6 +42,16 @@ struct linespec_result;
 struct linespec_sals;
 struct inferior;
 
+/* Enum for exception-handling support in 'catch throw', 'catch rethrow',
+   'catch catch' and the MI equivalent.  */
+
+enum exception_event_kind
+{
+  EX_EVENT_THROW,
+  EX_EVENT_RETHROW,
+  EX_EVENT_CATCH
+};
+
 /* Why are we removing the breakpoint from the target?  */
 
 enum remove_bp_reason
@@ -1670,4 +1680,14 @@ extern void print_breakpoint (breakpoint *bp);
 /* Command element for the 'commands' command.  */
 extern cmd_list_element *commands_cmd_element;
 
+/* Deal with "catch catch", "catch throw", and "catch rethrow" commands and
+   the MI equivalents.  Sets up to catch events of type EX_EVENT.  When
+   TEMPFLAG is true only the next matching event is caught after which the
+   catch-point is deleted.  If REGEX is not NULL then only exceptions whose
+   type name matches REGEX will trigger the event.  */
+
+extern void catch_exception_event (enum exception_event_kind ex_event,
+				   const char *regex, bool tempflag,
+				   int from_tty);
+
 #endif /* !defined (BREAKPOINT_H) */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index b7f3b271d1f..14d834eb488 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -29406,6 +29406,7 @@
 @menu
 * Shared Library GDB/MI Catchpoint Commands::
 * Ada Exception GDB/MI Catchpoint Commands::
+* C++ Exception GDB/MI Catchpoint Commands::
 @end menu
 
 @node Shared Library GDB/MI Catchpoint Commands
@@ -29605,6 +29606,145 @@
 (gdb)
 @end smallexample
 
+@node C++ Exception GDB/MI Catchpoint Commands
+@subsection C@t{++} Exception @sc{gdb/mi} Catchpoints
+
+The following @sc{gdb/mi} commands can be used to create catchpoints
+that stop the execution when C@t{++} exceptions are being throw, rethrown,
+or caught..
+
+@subheading The @code{-catch-throw} Command
+@findex -catch-throw
+
+@subsubheading Synopsis
+
+@smallexample
+ -catch-throw [ -t ] [ -r @var{regexp}]
+@end smallexample
+
+Stop when the debuggee throws a C@t{++} exception.  If @var{regexp} is
+given, then only exceptions whose type matches the regular expression
+will be caught.
+
+If @samp{-t} is given, then the catchpoint is enabled only for one
+stop, the catchpoint is automatically deleted after stopping once for
+the event.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{catch throw}
+and @samp{tcatch throw} (@pxref{Set Catchpoints}).
+
+@subsubheading Example
+
+@smallexample
+-catch-throw -r exception_type
+^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+  addr="0x00000000004006c0",what="exception throw",
+  catch-type="throw",thread-groups=["i1"],
+  regexp="exception_type",times="0"@}
+(gdb)
+-exec-run
+^running
+(gdb)
+~"\n"
+~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed
+  in __cxa_throw () from /lib64/libstdc++.so.6\n"
+*stopped,bkptno="1",reason="breakpoint-hit",disp="keep",
+  frame=@{addr="0x00007ffff7ae00ed",func="__cxa_throw",
+  args=[],from="/lib64/libstdc++.so.6",arch="i386:x86-64"@},
+  thread-id="1",stopped-threads="all",core="6"
+(gdb)
+@end smallexample
+
+@subheading The @code{-catch-rethrow} Command
+@findex -catch-rethrow
+
+@subsubheading Synopsis
+
+@smallexample
+ -catch-rethrow [ -t ] [ -r @var{regexp}]
+@end smallexample
+
+Stop when a C@t{++} exception is re-thrown.  If @var{regexp} is given,
+then only exceptions whose type matches the regular expression will be
+caught.
+
+If @samp{-t} is given, then the catchpoint is enabled only for one
+stop, the catchpoint is automatically deleted after the first event is
+caught.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{catch rethrow}
+and @samp{tcatch rethrow} (@pxref{Set Catchpoints}).
+
+@subsubheading Example
+
+@smallexample
+-catch-rethrow -r exception_type
+^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+  addr="0x00000000004006c0",what="exception rethrow",
+  catch-type="rethrow",thread-groups=["i1"],
+  regexp="exception_type",times="0"@}
+(gdb)
+-exec-run
+^running
+(gdb)
+~"\n"
+~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed
+  in __cxa_throw () from /lib64/libstdc++.so.6\n"
+*stopped,bkptno="1",reason="breakpoint-hit",disp="keep",
+  frame=@{addr="0x00007ffff7ae00ed",func="__cxa_throw",
+  args=[],from="/lib64/libstdc++.so.6",arch="i386:x86-64"@},
+  thread-id="1",stopped-threads="all",core="6"
+(gdb)
+@end smallexample
+
+@subheading The @code{-catch-catch} Command
+@findex -catch-catch
+
+@subsubheading Synopsis
+
+@smallexample
+ -catch-catch [ -t ] [ -r @var{regexp}]
+@end smallexample
+
+Stop when the debuggee catches a C@t{++} exception.  If @var{regexp}
+is given, then only exceptions whose type matches the regular
+expression will be caught.
+
+If @samp{-t} is given, then the catchpoint is enabled only for one
+stop, the catchpoint is automatically deleted after the first event is
+caught.
+
+@subsubheading @value{GDBN} Command
+
+The corresponding @value{GDBN} commands are @samp{catch catch}
+and @samp{tcatch catch} (@pxref{Set Catchpoints}).
+
+@subsubheading Example
+
+@smallexample
+-catch-catch -r exception_type
+^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
+  addr="0x00000000004006c0",what="exception catch",
+  catch-type="catch",thread-groups=["i1"],
+  regexp="exception_type",times="0"@}
+(gdb)
+-exec-run
+^running
+(gdb)
+~"\n"
+~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed
+  in __cxa_throw () from /lib64/libstdc++.so.6\n"
+*stopped,bkptno="1",reason="breakpoint-hit",disp="keep",
+  frame=@{addr="0x00007ffff7ae00ed",func="__cxa_throw",
+  args=[],from="/lib64/libstdc++.so.6",arch="i386:x86-64"@},
+  thread-id="1",stopped-threads="all",core="6"
+(gdb)
+@end smallexample
+
 @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @node GDB/MI Program Context
 @section @sc{gdb/mi}  Program Context
diff --git a/gdb/mi/mi-cmd-catch.c b/gdb/mi/mi-cmd-catch.c
index 87929c48ca4..a044fe4472c 100644
--- a/gdb/mi/mi-cmd-catch.c
+++ b/gdb/mi/mi-cmd-catch.c
@@ -288,3 +288,74 @@ mi_cmd_catch_unload (const char *cmd, char *argv[], int argc)
   mi_catch_load_unload (0, argv, argc);
 }
 
+/* Core handler for -catch-throw, -catch-rethrow, and -catch-catch
+   commands.  The argument handling for all of these is identical, we just
+   pass KIND through to GDB's core to select the correct event type.  */
+
+static void
+mi_cmd_catch_exception_event (enum exception_event_kind kind,
+			      const char *cmd, char *argv[], int argc)
+{
+  char *regex = NULL;
+  bool temp = false;
+  int oind = 0;
+  char *oarg;
+  enum opt
+    {
+      OPT_TEMP,
+      OPT_REGEX,
+    };
+  static const struct mi_opt opts[] =
+    {
+      { "t", OPT_TEMP, 0 },
+      { "r", OPT_REGEX, 1 },
+      { 0, 0, 0 }
+    };
+
+  for (;;)
+    {
+      int opt = mi_getopt (cmd, argc, argv, opts,
+                           &oind, &oarg);
+
+      if (opt < 0)
+        break;
+
+      switch ((enum opt) opt)
+        {
+        case OPT_TEMP:
+          temp = true;
+          break;
+        case OPT_REGEX:
+	  regex = oarg;
+          break;
+        }
+    }
+
+  scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
+  catch_exception_event (kind, regex, temp, 0 /* from_tty */);
+}
+
+/* Handler for -catch-throw.  */
+
+void
+mi_cmd_catch_throw (const char *cmd, char *argv[], int argc)
+{
+  mi_cmd_catch_exception_event (EX_EVENT_THROW, cmd, argv, argc);
+}
+
+/* Handler for -catch-rethrow.  */
+
+void
+mi_cmd_catch_rethrow (const char *cmd, char *argv[], int argc)
+{
+  mi_cmd_catch_exception_event (EX_EVENT_RETHROW, cmd, argv, argc);
+}
+
+/* Handler for -catch-catch.  */
+
+void
+mi_cmd_catch_catch (const char *cmd, char *argv[], int argc)
+{
+  mi_cmd_catch_exception_event (EX_EVENT_CATCH, cmd, argv, argc);
+}
+
diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
index fe30ac2e822..cd2ffa5fc37 100644
--- a/gdb/mi/mi-cmds.c
+++ b/gdb/mi/mi-cmds.c
@@ -75,6 +75,12 @@ static struct mi_cmd mi_cmds[] =
                    &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI_1 ("catch-unload", mi_cmd_catch_unload,
                    &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("catch-throw", mi_cmd_catch_throw,
+                   &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("catch-rethrow", mi_cmd_catch_rethrow,
+                   &mi_suppress_notification.breakpoint),
+  DEF_MI_CMD_MI_1 ("catch-catch", mi_cmd_catch_catch,
+                   &mi_suppress_notification.breakpoint),
   DEF_MI_CMD_MI ("data-disassemble", mi_cmd_disassemble),
   DEF_MI_CMD_MI ("data-evaluate-expression", mi_cmd_data_evaluate_expression),
   DEF_MI_CMD_MI ("data-list-changed-registers",
diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
index 7b22ce78134..5a8e99bd33c 100644
--- a/gdb/mi/mi-cmds.h
+++ b/gdb/mi/mi-cmds.h
@@ -44,6 +44,9 @@ extern mi_cmd_argv_ftype mi_cmd_catch_exception;
 extern mi_cmd_argv_ftype mi_cmd_catch_handlers;
 extern mi_cmd_argv_ftype mi_cmd_catch_load;
 extern mi_cmd_argv_ftype mi_cmd_catch_unload;
+extern mi_cmd_argv_ftype mi_cmd_catch_throw;
+extern mi_cmd_argv_ftype mi_cmd_catch_rethrow;
+extern mi_cmd_argv_ftype mi_cmd_catch_catch;
 extern mi_cmd_argv_ftype mi_cmd_disassemble;
 extern mi_cmd_argv_ftype mi_cmd_data_evaluate_expression;
 extern mi_cmd_argv_ftype mi_cmd_data_list_register_names;
diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
new file mode 100644
index 00000000000..cacda4653a9
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
@@ -0,0 +1,73 @@
+/* Copyright 2019 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+class my_exception
+{
+private:
+  int m_value;
+
+public:
+  my_exception (int v)
+    : m_value (v)
+  {
+    /* Nothing.  */
+  }
+};
+
+void
+bar ()
+{
+  my_exception ex (4);
+  throw ex;	/* Throw 1.  */
+}
+
+void
+foo ()
+{
+  for (int i = 0; i < 2; ++i)
+    {
+      try
+	{
+	  bar ();
+	}
+      catch (const my_exception &ex)	/* Catch 1.  */
+	{
+	  if (i == 1)
+	    throw;	/* Throw 2.  */
+	}
+    }
+}
+
+int
+main ()
+{
+  for (int i = 0; i < 2; ++i)
+    {
+      try
+	{
+	  foo ();
+	}
+      catch (const my_exception &ex)	/* Catch 2.  */
+	{
+	  if (i == 1)
+	    return 1;	/* Stop here.  */
+	}
+    }
+
+  return 0;
+}
+
diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
new file mode 100644
index 00000000000..b5dfbe68c1a
--- /dev/null
+++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
@@ -0,0 +1,197 @@
+# Copyright 2019 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test the -catch-throw, -catch-rethrow, and -catch-catch MI commands.
+
+if { [skip_cplus_tests] } { continue }
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+standard_testfile .cc
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
+    untested "failed to compile"
+    return -1
+}
+
+# Grab some line numbers we'll need.
+set catch_1_lineno [gdb_get_line_number "Catch 1"]
+set catch_2_lineno [gdb_get_line_number "Catch 2"]
+set throw_1_lineno [gdb_get_line_number "Throw 1"]
+set throw_2_lineno [gdb_get_line_number "Throw 2"]
+set main_lineno [gdb_get_line_number "Stop here"]
+
+# Restart this test, load the test binary and set a breakpoint in
+# main.
+proc restart_for_test {} {
+    global srcdir subdir binfile srcfile
+    global main_lineno
+
+    if {[mi_gdb_start]} {
+	continue
+    }
+
+    mi_delete_breakpoints
+    mi_gdb_reinitialize_dir $srcdir/$subdir
+    mi_gdb_load ${binfile}
+
+    mi_runto main
+
+    mi_create_breakpoint \
+	"$srcfile:${main_lineno}" "break before exiting program" \
+	-disp keep -func "main.*" \
+	-file ".*mi-catch-cpp-exceptions.cc" -line ${main_lineno}
+}
+
+# Issue an -exec-continue then wait for GDB to catch a C++ exception
+# event in FUNC on LINE.  Use TESTNAME to make tests unique.
+proc continue_to_next_exception { func line testname } {
+    global hex
+
+    mi_send_resuming_command "exec-continue" \
+	"exec-continue"
+    mi_expect_stop "exception-caught" ".*" ".*" ".*" ".*" \
+	{} "run until an exception is caught: $testname"
+    mi_gdb_test "-stack-list-frames 1 1" \
+	"\\^done,stack=\\\[frame=\{level=\"1\",addr=\"$hex\",func=\"${func}\",.*,line=\"${line}\".*\}\\\]" \
+	"check previous frame: $testname"
+}
+
+# Issue an -exec-continue and stop at the breakpoint in main.
+proc continue_to_breakpoint_in_main {} {
+    global main_lineno
+
+    mi_send_resuming_command "exec-continue" "exec-continue to main"
+    mi_expect_stop "breakpoint-hit" "main" ".*" ".*" "${main_lineno}" \
+	{.* disp="keep"} "run until breakpoint in main"
+}
+
+# TYPE is one of throw, rethrow, or catch.  This proc creates a catch
+# point using -catch-TYPE.  The optional string EXTRA is any extra
+# arguments to pass when setting up the catchpoint.
+proc setup_catchpoint {type {extra ""}} {
+    global decimal
+    mi_gdb_test "-catch-${type} ${extra}" \
+	"\\^done,bkpt=\{number=\"$decimal\".*what=\"exception ${type}\",catch-type=\"${type}\".*\}" \
+	"Setup -catch-${type}"
+}
+
+# Ensure that -catch-throw will catch only throws and nothing else.
+with_test_prefix "-catch-throw" {
+    restart_for_test
+    setup_catchpoint "throw"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4"
+    continue_to_breakpoint_in_main
+}
+
+# Ensure that -catch-rethrow catches only rethrows and nothing else.
+with_test_prefix "-catch-rethrow" {
+    restart_for_test
+    setup_catchpoint "rethrow"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2"
+    continue_to_breakpoint_in_main
+}
+
+# Ensure that -catch-catch catches only catch points, and nothing
+# else.
+with_test_prefix "-catch-catch" {
+    restart_for_test
+    setup_catchpoint "catch"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 3"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 6"
+    continue_to_breakpoint_in_main
+}
+
+# Now check that all of the command with a regexp that doesn't match,
+# don't trigger.
+with_test_prefix "all with invalid regexp" {
+    restart_for_test
+    setup_catchpoint "throw" "-r blahblah"
+    setup_catchpoint "rethrow" "-r woofwoof"
+    setup_catchpoint "catch" "-r miowmiow"
+
+    # Would like to use 'continue_to_breakpoint_in_main' here, if
+    # there wasn't a bug that requires a use of kfail.
+
+    mi_send_resuming_command "exec-continue" \
+	"exec-continue"
+    set testname "run until breakpoint in main"
+    gdb_expect {
+	-re "could not find minimal symbol for typeinfo address.*$mi_gdb_prompt$" {
+	    kfail "gdb/24541" "${testname}"
+	}
+	-re "\\*stopped,reason=\"breakpoint-hit\".*func=\"main\".*line=\"${main_lineno}\".*$mi_gdb_prompt$" {
+	    pass "${testname}"
+	}
+	timeout {
+	    fail "${testname} (timeout)"
+	}
+    }
+}
+
+# Now check that all of the commands with a regexp that does match,
+# still trigger.
+with_test_prefix "all with valid regexp" {
+    restart_for_test
+    setup_catchpoint "throw" "-r my_ex"
+    setup_catchpoint "rethrow" "-r _except"
+    setup_catchpoint "catch" "-r my_exception"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 3"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2"
+    continue_to_next_exception "main" "${catch_2_lineno}" "catch 6"
+    continue_to_breakpoint_in_main
+}
+
+# Check that the temporary switch works on its own.
+with_test_prefix "all with -t" {
+    restart_for_test
+    setup_catchpoint "throw" "-t"
+    setup_catchpoint "rethrow" "-t"
+    setup_catchpoint "catch" "-t"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_breakpoint_in_main
+}
+
+# Check that the temporary switch works when used with a regexp.
+restart_for_test
+with_test_prefix "all with -t and regexp" {
+    setup_catchpoint "throw" "-t -r my_ex"
+    setup_catchpoint "rethrow" "-t -r _except"
+    setup_catchpoint "catch" "-t -r my_exception"
+    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
+    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
+    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
+    continue_to_breakpoint_in_main
+}
diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
index a58c4f6e119..8c2c7c84eda 100644
--- a/gdb/testsuite/lib/mi-support.exp
+++ b/gdb/testsuite/lib/mi-support.exp
@@ -1221,10 +1221,15 @@ proc mi_expect_stop { reason func args file line extra test } {
     set args "\\\[$args\\\]"
 
     set bn ""
+    set ebn ""
     if { $reason == "breakpoint-hit" } {
 	set bn {bkptno="[0-9]+",}
     } elseif { $reason == "solib-event" } {
 	set bn ".*"
+    } elseif { $reason == "exception-caught" } {
+	set ebn {bkptno="[0-9]+",}
+	set bn ".*"
+	set reason "breakpoint-hit"
     }
 
     set r ""
@@ -1235,9 +1240,9 @@ proc mi_expect_stop { reason func args file line extra test } {
 
     set a $after_reason
 
-    verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
+    verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
     gdb_expect {
-	-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
+	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
 	    pass "$test"
 	    if {[array names expect_out "2,string"] != ""} {
 		return $expect_out(2,string)
@@ -1245,7 +1250,7 @@ proc mi_expect_stop { reason func args file line extra test } {
 	    # No debug info available but $file does match.
 	    return 0
 	}
-	-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\",arch=\"$any\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
+	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\",arch=\"$any\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
 	    verbose -log "got $expect_out(buffer)"
 	    fail "$test (stopped at wrong place)"
 	    return -1
-- 
2.14.5


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv2] gdb/mi: New commands to catch C++ exceptions
  2019-05-11 23:46 ` [PATCHv2] " Andrew Burgess
@ 2019-05-12  4:09   ` Eli Zaretskii
  2019-06-15 22:34   ` Andrew Burgess
  1 sibling, 0 replies; 9+ messages in thread
From: Eli Zaretskii @ 2019-05-12  4:09 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches, tom

> From: Andrew Burgess <andrew.burgess@embecosm.com>
> Cc: Eli Zaretskii <eliz@gnu.org>,
> 	Tom Tromey <tom@tromey.com>,
> 	Andrew Burgess <andrew.burgess@embecosm.com>
> Date: Sun, 12 May 2019 00:46:46 +0100
> 
> Eli,
> 
> This iteration includes updated documentation that fixes almost all of
> the issues you raised.  The only thing I haven't done is collapse all
> of the command sub-sections into a single sub-section.  I looked
> through most of the existing MI commands and they all seem to be one
> command per sub-section, so I wasn't entirely sure how to layout a
> merged entry, nor if a merged entry was inline with the style for MI
> commands.

Understood.

> +The following @sc{gdb/mi} commands can be used to create catchpoints
> +that stop the execution when C@t{++} exceptions are being throw, rethrown,
> +or caught..
            ^^
Extra period.

> +@smallexample
> +-catch-throw -r exception_type
> +^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
> +  addr="0x00000000004006c0",what="exception throw",
> +  catch-type="throw",thread-groups=["i1"],
> +  regexp="exception_type",times="0"@}
> +(gdb)
> +-exec-run
> +^running
> +(gdb)
> +~"\n"
> +~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed
> +  in __cxa_throw () from /lib64/libstdc++.so.6\n"
> +*stopped,bkptno="1",reason="breakpoint-hit",disp="keep",
> +  frame=@{addr="0x00007ffff7ae00ed",func="__cxa_throw",
> +  args=[],from="/lib64/libstdc++.so.6",arch="i386:x86-64"@},
> +  thread-id="1",stopped-threads="all",core="6"
> +(gdb)
> +@end smallexample

So what GDB shows when the catchpoint triggers doesn't include the
exception's type, is that right?  That's a pity; I expected it to show
the type, which could then be compared against the regexp.  Oh well.

> +~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed

It says "thrown" both for "throw" and "rethrow"?  So there's no way to
distinguish between these two?

> +~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed

And the same here? not "exception caught"?

The documentation parts are OK, thanks.


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv2] gdb/mi: New commands to catch C++ exceptions
  2019-05-11 23:46 ` [PATCHv2] " Andrew Burgess
  2019-05-12  4:09   ` Eli Zaretskii
@ 2019-06-15 22:34   ` Andrew Burgess
  2019-06-16 13:14     ` Tom de Vries
  1 sibling, 1 reply; 9+ messages in thread
From: Andrew Burgess @ 2019-06-15 22:34 UTC (permalink / raw)
  To: gdb-patches

* Andrew Burgess <andrew.burgess@embecosm.com> [2019-05-12 00:46:46 +0100]:

> Eli,
> 
> This iteration includes updated documentation that fixes almost all of
> the issues you raised.  The only thing I haven't done is collapse all
> of the command sub-sections into a single sub-section.  I looked
> through most of the existing MI commands and they all seem to be one
> command per sub-section, so I wasn't entirely sure how to layout a
> merged entry, nor if a merged entry was inline with the style for MI
> commands.
> 
> ---
> 
> I have also tweaked the code a little in this version, the changes
> around how a catchpoint is reported when it is initially setup has
> changed, the output is not more inline with other breakpoints.  See
> the changes in print_mention_exception_catchpoint, and the new
> scoped_restore restore_breakpoint_reporting in
> mi_cmd_catch_exception_event.  Otherwise the code is unchanged.
> 
> Thanks,
> Andrew
> 
> ---
> 
> Adds some MI commands to catch C++ exceptions.  The new commands are
> -catch-throw, -catch-rethrow, and -catch-catch, these all correspond
> to the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.
> 
> Each MI command takes two optional arguments, '-t' has the effect of
> calling 'tcatch' instead of 'catch', for example:
> 
>    (gdb)
>    -catch-throw -t
> 
> Is the same as:
> 
>    (gdb) tcatch throw
> 
> There is also a '-r REGEXP' argument that can supply a regexp to match
> against the exception type, so:
> 
>    (gdb)
>    -catch-catch -r PATTERN
> 
> Is the same as:
> 
>    (gdb) catch catch PATTERN
> 
> The change in print_mention_exception_catchpoint might seem a little
> strange; changing the output from using ui_out::field_int and
> ui_out::text to using  ui_out::message.
> 
> The print_mention_exception_catchpoint is used as the 'print_mention'
> method for the exception catchpoint breakpoint object.  Most of the
> other 'print_mention' methods (see breakpoint.c) use either
> printf_filtered, of ui_out::message.  Using field_int was causing an
> unexpected field to be added to the MI output.  Here's the output
> without the change in print_mention_exception_catchpoint:
> 
>     (gdb)
>     -catch-throw
>     ^done,bkptno="1",bkpt={number="1",type="breakpoint",disp="keep",
>                            enabled="y",addr="0x00000000004006c0",
>                            what="exception throw",catch-type="throw",
>                            thread-groups=["i1"],times="0"}
> 
> Notice the breakpoint number appears in both the 'bkptno' field, and
> the 'number' field within the 'bkpt' tuple.  Here's the output with
> the change in print_mention_exception_catchpoint:
> 
>     (gdb)
>     -catch-throw
>     ^done,bkpt={number="1",type="breakpoint",disp="keep",
>                 enabled="y",addr="0x00000000004006c0",
>                 what="exception throw",catch-type="throw",
>                 thread-groups=["i1"],times="0"}
> 
> gdb/ChangeLog:
> 
> 	* NEWS: Mention new MI commands.
> 	* break-catch-throw.c (enum exception_event_kind): Move to
> 	breakpoint.h.
> 	(print_mention_exception_catchpoint): Output text as a single
> 	message.
> 	(catch_exception_command_1): Rename to...
> 	(catch_exception_event): ...this, make non-static, update header
> 	command, and change some parameter types.
> 	(catch_catch_command): Update for changes to
> 	catch_exception_command_1.
> 	(catch_throw_command): Likewise.
> 	(catch_rethrow_command): Likewise.
> 	* breakpoint.c (enum exception_event_kind): Delete.
> 	* breakpoint.h (enum exception_event_kind): Moved here from
> 	break-catch-throw.c.
> 	(catch_exception_event): Declare.
> 	* mi/mi-cmd-catch.c (mi_cmd_catch_exception_event): New function.
> 	(mi_cmd_catch_throw): New function.
> 	(mi_cmd_catch_rethrow): New function.
> 	(mi_cmd_catch_catch): New function.
> 	* mi/mi-cmds.c (mi_cmds): Add 'catch-throw', 'catch-rethrow', and
> 	'catch-catch' entries.
> 	* mi/mi-cmds.h (mi_cmd_catch_throw): Declare.
> 	(mi_cmd_catch_rethrow): Declare.
> 	(mi_cmd_catch_catch): Declare.
> 
> gdb/doc/ChangeLog:
> 
> 	* gdb.texinfo (GDB/MI Catchpoint Commands): Add menu entry to new
> 	node.
> 	(C++ Exception GDB/MI Catchpoint Commands): New node to describe
> 	new MI commands.
> 
> gdb/testsuite/ChangeLog:
> 
> 	* gdb.mi/mi-catch-cpp-exceptions.cc: New file.
> 	* gdb.mi/mi-catch-cpp-exceptions.exp: New file.
> 	* lib/mi-support.exp (mi_expect_stop): Handle 'exception-caught'
> 	as a stop reason.

I've now pushed this patch with the doc fixes that Eli suggested.

Thanks,
Andrew





> ---
>  gdb/ChangeLog                                    |  28 ++++
>  gdb/NEWS                                         |   4 +
>  gdb/break-catch-throw.c                          |  42 ++---
>  gdb/breakpoint.c                                 |   8 -
>  gdb/breakpoint.h                                 |  20 +++
>  gdb/doc/ChangeLog                                |   7 +
>  gdb/doc/gdb.texinfo                              | 140 ++++++++++++++++
>  gdb/mi/mi-cmd-catch.c                            |  71 ++++++++
>  gdb/mi/mi-cmds.c                                 |   6 +
>  gdb/mi/mi-cmds.h                                 |   3 +
>  gdb/testsuite/ChangeLog                          |   7 +
>  gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc  |  73 +++++++++
>  gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp | 197 +++++++++++++++++++++++
>  gdb/testsuite/lib/mi-support.exp                 |  11 +-
>  14 files changed, 580 insertions(+), 37 deletions(-)
>  create mode 100644 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
>  create mode 100644 gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
> 
> diff --git a/gdb/NEWS b/gdb/NEWS
> index 288615b8cd3..3377940e2b2 100644
> --- a/gdb/NEWS
> +++ b/gdb/NEWS
> @@ -27,6 +27,10 @@
>       'array_indexes', 'symbols', 'unions', 'deref_refs', 'actual_objects',
>       'static_members', 'max_elements', 'repeat_threshold', and 'format'.
>  
> +* MI changes
> +
> +  ** New commands -catch-throw, -catch-rethrow, and -catch-catch.
> +
>  * New commands
>  
>  set may-call-functions [on|off]
> diff --git a/gdb/break-catch-throw.c b/gdb/break-catch-throw.c
> index a221cb31518..107ac74f5cc 100644
> --- a/gdb/break-catch-throw.c
> +++ b/gdb/break-catch-throw.c
> @@ -37,14 +37,6 @@
>  #include "cp-support.h"
>  #include "location.h"
>  
> -/* Enums for exception-handling support.  */
> -enum exception_event_kind
> -{
> -  EX_EVENT_THROW,
> -  EX_EVENT_RETHROW,
> -  EX_EVENT_CATCH
> -};
> -
>  /* Each spot where we may place an exception-related catchpoint has
>     two names: the SDT probe point and the function name.  This
>     structure holds both.  */
> @@ -317,12 +309,12 @@ print_mention_exception_catchpoint (struct breakpoint *b)
>    enum exception_event_kind kind = classify_exception_breakpoint (b);
>  
>    bp_temp = b->disposition == disp_del;
> -  uiout->text (bp_temp ? _("Temporary catchpoint ")
> -			      : _("Catchpoint "));
> -  uiout->field_int ("bkptno", b->number);
> -  uiout->text ((kind == EX_EVENT_THROW ? _(" (throw)")
> -		       : (kind == EX_EVENT_CATCH ? _(" (catch)")
> -			  : _(" (rethrow)"))));
> +  uiout->message ("%s %d %s",
> +		  (bp_temp ? _("Temporary catchpoint ") : _("Catchpoint")),
> +		  b->number,
> +		  (kind == EX_EVENT_THROW
> +		   ? _("(throw)") : (kind == EX_EVENT_CATCH
> +				     ? _("(catch)") : _("(rethrow)"))));
>  }
>  
>  /* Implement the "print_recreate" breakpoint_ops method for throw and
> @@ -420,13 +412,11 @@ extract_exception_regexp (const char **string)
>    return std::string ();
>  }
>  
> -/* Deal with "catch catch", "catch throw", and "catch rethrow"
> -   commands.  */
> +/* See breakpoint.h.  */
>  
> -static void
> -catch_exception_command_1 (enum exception_event_kind ex_event,
> -			   const char *arg,
> -			   int tempflag, int from_tty)
> +void
> +catch_exception_event (enum exception_event_kind ex_event,
> +		       const char *arg, bool tempflag, int from_tty)
>  {
>    const char *cond_string = NULL;
>  
> @@ -456,9 +446,9 @@ static void
>  catch_catch_command (const char *arg, int from_tty,
>  		     struct cmd_list_element *command)
>  {
> -  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
> +  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
>  
> -  catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
> +  catch_exception_event (EX_EVENT_CATCH, arg, tempflag, from_tty);
>  }
>  
>  /* Implementation of "catch throw" command.  */
> @@ -467,9 +457,9 @@ static void
>  catch_throw_command (const char *arg, int from_tty,
>  		     struct cmd_list_element *command)
>  {
> -  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
> +  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
>  
> -  catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
> +  catch_exception_event (EX_EVENT_THROW, arg, tempflag, from_tty);
>  }
>  
>  /* Implementation of "catch rethrow" command.  */
> @@ -478,9 +468,9 @@ static void
>  catch_rethrow_command (const char *arg, int from_tty,
>  		       struct cmd_list_element *command)
>  {
> -  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
> +  bool tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
>  
> -  catch_exception_command_1 (EX_EVENT_RETHROW, arg, tempflag, from_tty);
> +  catch_exception_event (EX_EVENT_RETHROW, arg, tempflag, from_tty);
>  }
>  
>  \f
> diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
> index 35da97bd041..7b0fbdd01be 100644
> --- a/gdb/breakpoint.c
> +++ b/gdb/breakpoint.c
> @@ -85,14 +85,6 @@
>  #include "common/array-view.h"
>  #include "common/gdb_optional.h"
>  
> -/* Enums for exception-handling support.  */
> -enum exception_event_kind
> -{
> -  EX_EVENT_THROW,
> -  EX_EVENT_RETHROW,
> -  EX_EVENT_CATCH
> -};
> -
>  /* Prototypes for local functions.  */
>  
>  static void map_breakpoint_numbers (const char *,
> diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
> index a91e3e334cf..c404d0e8ee8 100644
> --- a/gdb/breakpoint.h
> +++ b/gdb/breakpoint.h
> @@ -42,6 +42,16 @@ struct linespec_result;
>  struct linespec_sals;
>  struct inferior;
>  
> +/* Enum for exception-handling support in 'catch throw', 'catch rethrow',
> +   'catch catch' and the MI equivalent.  */
> +
> +enum exception_event_kind
> +{
> +  EX_EVENT_THROW,
> +  EX_EVENT_RETHROW,
> +  EX_EVENT_CATCH
> +};
> +
>  /* Why are we removing the breakpoint from the target?  */
>  
>  enum remove_bp_reason
> @@ -1670,4 +1680,14 @@ extern void print_breakpoint (breakpoint *bp);
>  /* Command element for the 'commands' command.  */
>  extern cmd_list_element *commands_cmd_element;
>  
> +/* Deal with "catch catch", "catch throw", and "catch rethrow" commands and
> +   the MI equivalents.  Sets up to catch events of type EX_EVENT.  When
> +   TEMPFLAG is true only the next matching event is caught after which the
> +   catch-point is deleted.  If REGEX is not NULL then only exceptions whose
> +   type name matches REGEX will trigger the event.  */
> +
> +extern void catch_exception_event (enum exception_event_kind ex_event,
> +				   const char *regex, bool tempflag,
> +				   int from_tty);
> +
>  #endif /* !defined (BREAKPOINT_H) */
> diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
> index b7f3b271d1f..14d834eb488 100644
> --- a/gdb/doc/gdb.texinfo
> +++ b/gdb/doc/gdb.texinfo
> @@ -29406,6 +29406,7 @@
>  @menu
>  * Shared Library GDB/MI Catchpoint Commands::
>  * Ada Exception GDB/MI Catchpoint Commands::
> +* C++ Exception GDB/MI Catchpoint Commands::
>  @end menu
>  
>  @node Shared Library GDB/MI Catchpoint Commands
> @@ -29605,6 +29606,145 @@
>  (gdb)
>  @end smallexample
>  
> +@node C++ Exception GDB/MI Catchpoint Commands
> +@subsection C@t{++} Exception @sc{gdb/mi} Catchpoints
> +
> +The following @sc{gdb/mi} commands can be used to create catchpoints
> +that stop the execution when C@t{++} exceptions are being throw, rethrown,
> +or caught..
> +
> +@subheading The @code{-catch-throw} Command
> +@findex -catch-throw
> +
> +@subsubheading Synopsis
> +
> +@smallexample
> + -catch-throw [ -t ] [ -r @var{regexp}]
> +@end smallexample
> +
> +Stop when the debuggee throws a C@t{++} exception.  If @var{regexp} is
> +given, then only exceptions whose type matches the regular expression
> +will be caught.
> +
> +If @samp{-t} is given, then the catchpoint is enabled only for one
> +stop, the catchpoint is automatically deleted after stopping once for
> +the event.
> +
> +@subsubheading @value{GDBN} Command
> +
> +The corresponding @value{GDBN} commands are @samp{catch throw}
> +and @samp{tcatch throw} (@pxref{Set Catchpoints}).
> +
> +@subsubheading Example
> +
> +@smallexample
> +-catch-throw -r exception_type
> +^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
> +  addr="0x00000000004006c0",what="exception throw",
> +  catch-type="throw",thread-groups=["i1"],
> +  regexp="exception_type",times="0"@}
> +(gdb)
> +-exec-run
> +^running
> +(gdb)
> +~"\n"
> +~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed
> +  in __cxa_throw () from /lib64/libstdc++.so.6\n"
> +*stopped,bkptno="1",reason="breakpoint-hit",disp="keep",
> +  frame=@{addr="0x00007ffff7ae00ed",func="__cxa_throw",
> +  args=[],from="/lib64/libstdc++.so.6",arch="i386:x86-64"@},
> +  thread-id="1",stopped-threads="all",core="6"
> +(gdb)
> +@end smallexample
> +
> +@subheading The @code{-catch-rethrow} Command
> +@findex -catch-rethrow
> +
> +@subsubheading Synopsis
> +
> +@smallexample
> + -catch-rethrow [ -t ] [ -r @var{regexp}]
> +@end smallexample
> +
> +Stop when a C@t{++} exception is re-thrown.  If @var{regexp} is given,
> +then only exceptions whose type matches the regular expression will be
> +caught.
> +
> +If @samp{-t} is given, then the catchpoint is enabled only for one
> +stop, the catchpoint is automatically deleted after the first event is
> +caught.
> +
> +@subsubheading @value{GDBN} Command
> +
> +The corresponding @value{GDBN} commands are @samp{catch rethrow}
> +and @samp{tcatch rethrow} (@pxref{Set Catchpoints}).
> +
> +@subsubheading Example
> +
> +@smallexample
> +-catch-rethrow -r exception_type
> +^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
> +  addr="0x00000000004006c0",what="exception rethrow",
> +  catch-type="rethrow",thread-groups=["i1"],
> +  regexp="exception_type",times="0"@}
> +(gdb)
> +-exec-run
> +^running
> +(gdb)
> +~"\n"
> +~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed
> +  in __cxa_throw () from /lib64/libstdc++.so.6\n"
> +*stopped,bkptno="1",reason="breakpoint-hit",disp="keep",
> +  frame=@{addr="0x00007ffff7ae00ed",func="__cxa_throw",
> +  args=[],from="/lib64/libstdc++.so.6",arch="i386:x86-64"@},
> +  thread-id="1",stopped-threads="all",core="6"
> +(gdb)
> +@end smallexample
> +
> +@subheading The @code{-catch-catch} Command
> +@findex -catch-catch
> +
> +@subsubheading Synopsis
> +
> +@smallexample
> + -catch-catch [ -t ] [ -r @var{regexp}]
> +@end smallexample
> +
> +Stop when the debuggee catches a C@t{++} exception.  If @var{regexp}
> +is given, then only exceptions whose type matches the regular
> +expression will be caught.
> +
> +If @samp{-t} is given, then the catchpoint is enabled only for one
> +stop, the catchpoint is automatically deleted after the first event is
> +caught.
> +
> +@subsubheading @value{GDBN} Command
> +
> +The corresponding @value{GDBN} commands are @samp{catch catch}
> +and @samp{tcatch catch} (@pxref{Set Catchpoints}).
> +
> +@subsubheading Example
> +
> +@smallexample
> +-catch-catch -r exception_type
> +^done,bkpt=@{number="1",type="breakpoint",disp="keep",enabled="y",
> +  addr="0x00000000004006c0",what="exception catch",
> +  catch-type="catch",thread-groups=["i1"],
> +  regexp="exception_type",times="0"@}
> +(gdb)
> +-exec-run
> +^running
> +(gdb)
> +~"\n"
> +~"Catchpoint 1 (exception thrown), 0x00007ffff7ae00ed
> +  in __cxa_throw () from /lib64/libstdc++.so.6\n"
> +*stopped,bkptno="1",reason="breakpoint-hit",disp="keep",
> +  frame=@{addr="0x00007ffff7ae00ed",func="__cxa_throw",
> +  args=[],from="/lib64/libstdc++.so.6",arch="i386:x86-64"@},
> +  thread-id="1",stopped-threads="all",core="6"
> +(gdb)
> +@end smallexample
> +
>  @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
>  @node GDB/MI Program Context
>  @section @sc{gdb/mi}  Program Context
> diff --git a/gdb/mi/mi-cmd-catch.c b/gdb/mi/mi-cmd-catch.c
> index 87929c48ca4..a044fe4472c 100644
> --- a/gdb/mi/mi-cmd-catch.c
> +++ b/gdb/mi/mi-cmd-catch.c
> @@ -288,3 +288,74 @@ mi_cmd_catch_unload (const char *cmd, char *argv[], int argc)
>    mi_catch_load_unload (0, argv, argc);
>  }
>  
> +/* Core handler for -catch-throw, -catch-rethrow, and -catch-catch
> +   commands.  The argument handling for all of these is identical, we just
> +   pass KIND through to GDB's core to select the correct event type.  */
> +
> +static void
> +mi_cmd_catch_exception_event (enum exception_event_kind kind,
> +			      const char *cmd, char *argv[], int argc)
> +{
> +  char *regex = NULL;
> +  bool temp = false;
> +  int oind = 0;
> +  char *oarg;
> +  enum opt
> +    {
> +      OPT_TEMP,
> +      OPT_REGEX,
> +    };
> +  static const struct mi_opt opts[] =
> +    {
> +      { "t", OPT_TEMP, 0 },
> +      { "r", OPT_REGEX, 1 },
> +      { 0, 0, 0 }
> +    };
> +
> +  for (;;)
> +    {
> +      int opt = mi_getopt (cmd, argc, argv, opts,
> +                           &oind, &oarg);
> +
> +      if (opt < 0)
> +        break;
> +
> +      switch ((enum opt) opt)
> +        {
> +        case OPT_TEMP:
> +          temp = true;
> +          break;
> +        case OPT_REGEX:
> +	  regex = oarg;
> +          break;
> +        }
> +    }
> +
> +  scoped_restore restore_breakpoint_reporting = setup_breakpoint_reporting ();
> +  catch_exception_event (kind, regex, temp, 0 /* from_tty */);
> +}
> +
> +/* Handler for -catch-throw.  */
> +
> +void
> +mi_cmd_catch_throw (const char *cmd, char *argv[], int argc)
> +{
> +  mi_cmd_catch_exception_event (EX_EVENT_THROW, cmd, argv, argc);
> +}
> +
> +/* Handler for -catch-rethrow.  */
> +
> +void
> +mi_cmd_catch_rethrow (const char *cmd, char *argv[], int argc)
> +{
> +  mi_cmd_catch_exception_event (EX_EVENT_RETHROW, cmd, argv, argc);
> +}
> +
> +/* Handler for -catch-catch.  */
> +
> +void
> +mi_cmd_catch_catch (const char *cmd, char *argv[], int argc)
> +{
> +  mi_cmd_catch_exception_event (EX_EVENT_CATCH, cmd, argv, argc);
> +}
> +
> diff --git a/gdb/mi/mi-cmds.c b/gdb/mi/mi-cmds.c
> index fe30ac2e822..cd2ffa5fc37 100644
> --- a/gdb/mi/mi-cmds.c
> +++ b/gdb/mi/mi-cmds.c
> @@ -75,6 +75,12 @@ static struct mi_cmd mi_cmds[] =
>                     &mi_suppress_notification.breakpoint),
>    DEF_MI_CMD_MI_1 ("catch-unload", mi_cmd_catch_unload,
>                     &mi_suppress_notification.breakpoint),
> +  DEF_MI_CMD_MI_1 ("catch-throw", mi_cmd_catch_throw,
> +                   &mi_suppress_notification.breakpoint),
> +  DEF_MI_CMD_MI_1 ("catch-rethrow", mi_cmd_catch_rethrow,
> +                   &mi_suppress_notification.breakpoint),
> +  DEF_MI_CMD_MI_1 ("catch-catch", mi_cmd_catch_catch,
> +                   &mi_suppress_notification.breakpoint),
>    DEF_MI_CMD_MI ("data-disassemble", mi_cmd_disassemble),
>    DEF_MI_CMD_MI ("data-evaluate-expression", mi_cmd_data_evaluate_expression),
>    DEF_MI_CMD_MI ("data-list-changed-registers",
> diff --git a/gdb/mi/mi-cmds.h b/gdb/mi/mi-cmds.h
> index 7b22ce78134..5a8e99bd33c 100644
> --- a/gdb/mi/mi-cmds.h
> +++ b/gdb/mi/mi-cmds.h
> @@ -44,6 +44,9 @@ extern mi_cmd_argv_ftype mi_cmd_catch_exception;
>  extern mi_cmd_argv_ftype mi_cmd_catch_handlers;
>  extern mi_cmd_argv_ftype mi_cmd_catch_load;
>  extern mi_cmd_argv_ftype mi_cmd_catch_unload;
> +extern mi_cmd_argv_ftype mi_cmd_catch_throw;
> +extern mi_cmd_argv_ftype mi_cmd_catch_rethrow;
> +extern mi_cmd_argv_ftype mi_cmd_catch_catch;
>  extern mi_cmd_argv_ftype mi_cmd_disassemble;
>  extern mi_cmd_argv_ftype mi_cmd_data_evaluate_expression;
>  extern mi_cmd_argv_ftype mi_cmd_data_list_register_names;
> diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
> new file mode 100644
> index 00000000000..cacda4653a9
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.cc
> @@ -0,0 +1,73 @@
> +/* Copyright 2019 Free Software Foundation, Inc.
> +
> +   This file is part of GDB.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +class my_exception
> +{
> +private:
> +  int m_value;
> +
> +public:
> +  my_exception (int v)
> +    : m_value (v)
> +  {
> +    /* Nothing.  */
> +  }
> +};
> +
> +void
> +bar ()
> +{
> +  my_exception ex (4);
> +  throw ex;	/* Throw 1.  */
> +}
> +
> +void
> +foo ()
> +{
> +  for (int i = 0; i < 2; ++i)
> +    {
> +      try
> +	{
> +	  bar ();
> +	}
> +      catch (const my_exception &ex)	/* Catch 1.  */
> +	{
> +	  if (i == 1)
> +	    throw;	/* Throw 2.  */
> +	}
> +    }
> +}
> +
> +int
> +main ()
> +{
> +  for (int i = 0; i < 2; ++i)
> +    {
> +      try
> +	{
> +	  foo ();
> +	}
> +      catch (const my_exception &ex)	/* Catch 2.  */
> +	{
> +	  if (i == 1)
> +	    return 1;	/* Stop here.  */
> +	}
> +    }
> +
> +  return 0;
> +}
> +
> diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
> new file mode 100644
> index 00000000000..b5dfbe68c1a
> --- /dev/null
> +++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
> @@ -0,0 +1,197 @@
> +# Copyright 2019 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Test the -catch-throw, -catch-rethrow, and -catch-catch MI commands.
> +
> +if { [skip_cplus_tests] } { continue }
> +
> +load_lib mi-support.exp
> +set MIFLAGS "-i=mi"
> +
> +standard_testfile .cc
> +
> +if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug c++}] != "" } {
> +    untested "failed to compile"
> +    return -1
> +}
> +
> +# Grab some line numbers we'll need.
> +set catch_1_lineno [gdb_get_line_number "Catch 1"]
> +set catch_2_lineno [gdb_get_line_number "Catch 2"]
> +set throw_1_lineno [gdb_get_line_number "Throw 1"]
> +set throw_2_lineno [gdb_get_line_number "Throw 2"]
> +set main_lineno [gdb_get_line_number "Stop here"]
> +
> +# Restart this test, load the test binary and set a breakpoint in
> +# main.
> +proc restart_for_test {} {
> +    global srcdir subdir binfile srcfile
> +    global main_lineno
> +
> +    if {[mi_gdb_start]} {
> +	continue
> +    }
> +
> +    mi_delete_breakpoints
> +    mi_gdb_reinitialize_dir $srcdir/$subdir
> +    mi_gdb_load ${binfile}
> +
> +    mi_runto main
> +
> +    mi_create_breakpoint \
> +	"$srcfile:${main_lineno}" "break before exiting program" \
> +	-disp keep -func "main.*" \
> +	-file ".*mi-catch-cpp-exceptions.cc" -line ${main_lineno}
> +}
> +
> +# Issue an -exec-continue then wait for GDB to catch a C++ exception
> +# event in FUNC on LINE.  Use TESTNAME to make tests unique.
> +proc continue_to_next_exception { func line testname } {
> +    global hex
> +
> +    mi_send_resuming_command "exec-continue" \
> +	"exec-continue"
> +    mi_expect_stop "exception-caught" ".*" ".*" ".*" ".*" \
> +	{} "run until an exception is caught: $testname"
> +    mi_gdb_test "-stack-list-frames 1 1" \
> +	"\\^done,stack=\\\[frame=\{level=\"1\",addr=\"$hex\",func=\"${func}\",.*,line=\"${line}\".*\}\\\]" \
> +	"check previous frame: $testname"
> +}
> +
> +# Issue an -exec-continue and stop at the breakpoint in main.
> +proc continue_to_breakpoint_in_main {} {
> +    global main_lineno
> +
> +    mi_send_resuming_command "exec-continue" "exec-continue to main"
> +    mi_expect_stop "breakpoint-hit" "main" ".*" ".*" "${main_lineno}" \
> +	{.* disp="keep"} "run until breakpoint in main"
> +}
> +
> +# TYPE is one of throw, rethrow, or catch.  This proc creates a catch
> +# point using -catch-TYPE.  The optional string EXTRA is any extra
> +# arguments to pass when setting up the catchpoint.
> +proc setup_catchpoint {type {extra ""}} {
> +    global decimal
> +    mi_gdb_test "-catch-${type} ${extra}" \
> +	"\\^done,bkpt=\{number=\"$decimal\".*what=\"exception ${type}\",catch-type=\"${type}\".*\}" \
> +	"Setup -catch-${type}"
> +}
> +
> +# Ensure that -catch-throw will catch only throws and nothing else.
> +with_test_prefix "-catch-throw" {
> +    restart_for_test
> +    setup_catchpoint "throw"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4"
> +    continue_to_breakpoint_in_main
> +}
> +
> +# Ensure that -catch-rethrow catches only rethrows and nothing else.
> +with_test_prefix "-catch-rethrow" {
> +    restart_for_test
> +    setup_catchpoint "rethrow"
> +    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
> +    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2"
> +    continue_to_breakpoint_in_main
> +}
> +
> +# Ensure that -catch-catch catches only catch points, and nothing
> +# else.
> +with_test_prefix "-catch-catch" {
> +    restart_for_test
> +    setup_catchpoint "catch"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2"
> +    continue_to_next_exception "main" "${catch_2_lineno}" "catch 3"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5"
> +    continue_to_next_exception "main" "${catch_2_lineno}" "catch 6"
> +    continue_to_breakpoint_in_main
> +}
> +
> +# Now check that all of the command with a regexp that doesn't match,
> +# don't trigger.
> +with_test_prefix "all with invalid regexp" {
> +    restart_for_test
> +    setup_catchpoint "throw" "-r blahblah"
> +    setup_catchpoint "rethrow" "-r woofwoof"
> +    setup_catchpoint "catch" "-r miowmiow"
> +
> +    # Would like to use 'continue_to_breakpoint_in_main' here, if
> +    # there wasn't a bug that requires a use of kfail.
> +
> +    mi_send_resuming_command "exec-continue" \
> +	"exec-continue"
> +    set testname "run until breakpoint in main"
> +    gdb_expect {
> +	-re "could not find minimal symbol for typeinfo address.*$mi_gdb_prompt$" {
> +	    kfail "gdb/24541" "${testname}"
> +	}
> +	-re "\\*stopped,reason=\"breakpoint-hit\".*func=\"main\".*line=\"${main_lineno}\".*$mi_gdb_prompt$" {
> +	    pass "${testname}"
> +	}
> +	timeout {
> +	    fail "${testname} (timeout)"
> +	}
> +    }
> +}
> +
> +# Now check that all of the commands with a regexp that does match,
> +# still trigger.
> +with_test_prefix "all with valid regexp" {
> +    restart_for_test
> +    setup_catchpoint "throw" "-r my_ex"
> +    setup_catchpoint "rethrow" "-r _except"
> +    setup_catchpoint "catch" "-r my_exception"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 2"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 2"
> +    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
> +    continue_to_next_exception "main" "${catch_2_lineno}" "catch 3"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 3"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 4"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 4"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 5"
> +    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 2"
> +    continue_to_next_exception "main" "${catch_2_lineno}" "catch 6"
> +    continue_to_breakpoint_in_main
> +}
> +
> +# Check that the temporary switch works on its own.
> +with_test_prefix "all with -t" {
> +    restart_for_test
> +    setup_catchpoint "throw" "-t"
> +    setup_catchpoint "rethrow" "-t"
> +    setup_catchpoint "catch" "-t"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
> +    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
> +    continue_to_breakpoint_in_main
> +}
> +
> +# Check that the temporary switch works when used with a regexp.
> +restart_for_test
> +with_test_prefix "all with -t and regexp" {
> +    setup_catchpoint "throw" "-t -r my_ex"
> +    setup_catchpoint "rethrow" "-t -r _except"
> +    setup_catchpoint "catch" "-t -r my_exception"
> +    continue_to_next_exception "bar" "${throw_1_lineno}" "throw 1"
> +    continue_to_next_exception "foo" "${catch_1_lineno}" "catch 1"
> +    continue_to_next_exception "foo" "${throw_2_lineno}" "rethrow 1"
> +    continue_to_breakpoint_in_main
> +}
> diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp
> index a58c4f6e119..8c2c7c84eda 100644
> --- a/gdb/testsuite/lib/mi-support.exp
> +++ b/gdb/testsuite/lib/mi-support.exp
> @@ -1221,10 +1221,15 @@ proc mi_expect_stop { reason func args file line extra test } {
>      set args "\\\[$args\\\]"
>  
>      set bn ""
> +    set ebn ""
>      if { $reason == "breakpoint-hit" } {
>  	set bn {bkptno="[0-9]+",}
>      } elseif { $reason == "solib-event" } {
>  	set bn ".*"
> +    } elseif { $reason == "exception-caught" } {
> +	set ebn {bkptno="[0-9]+",}
> +	set bn ".*"
> +	set reason "breakpoint-hit"
>      }
>  
>      set r ""
> @@ -1235,9 +1240,9 @@ proc mi_expect_stop { reason func args file line extra test } {
>  
>      set a $after_reason
>  
> -    verbose -log "mi_expect_stop: expecting: \\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
> +    verbose -log "mi_expect_stop: expecting: \\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"$line\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re"
>      gdb_expect {
> -	-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
> +	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$func\",args=$args,(?:file=\"$any$file\",fullname=\"${fullname_syntax}$file\",line=\"($line)\",arch=\"$any\"|from=\"$file\")\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    pass "$test"
>  	    if {[array names expect_out "2,string"] != ""} {
>  		return $expect_out(2,string)
> @@ -1245,7 +1250,7 @@ proc mi_expect_stop { reason func args file line extra test } {
>  	    # No debug info available but $file does match.
>  	    return 0
>  	}
> -	-re "\\*stopped,${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\",arch=\"$any\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
> +	-re "\\*stopped,${ebn}${r}${a}${bn}frame=\{addr=\"$hex\",func=\"$any\",args=\[\\\[\{\]$any\[\\\]\}\],file=\"$any\",fullname=\"${fullname_syntax}$any\",line=\"\[0-9\]*\",arch=\"$any\"\}$after_stopped,thread-id=\"$decimal\",stopped-threads=$any\r\n($thread_selected_re|$breakpoint_re)*$prompt_re" {
>  	    verbose -log "got $expect_out(buffer)"
>  	    fail "$test (stopped at wrong place)"
>  	    return -1
> -- 
> 2.14.5
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv2] gdb/mi: New commands to catch C++ exceptions
  2019-06-15 22:34   ` Andrew Burgess
@ 2019-06-16 13:14     ` Tom de Vries
  2019-06-16 15:30       ` Andrew Burgess
  0 siblings, 1 reply; 9+ messages in thread
From: Tom de Vries @ 2019-06-16 13:14 UTC (permalink / raw)
  To: Andrew Burgess, gdb-patches

On 16-06-19 00:34, Andrew Burgess wrote:
> * Andrew Burgess <andrew.burgess@embecosm.com> [2019-05-12 00:46:46 +0100]:
> 
>> Eli,
>>
>> This iteration includes updated documentation that fixes almost all of
>> the issues you raised.  The only thing I haven't done is collapse all
>> of the command sub-sections into a single sub-section.  I looked
>> through most of the existing MI commands and they all seem to be one
>> command per sub-section, so I wasn't entirely sure how to layout a
>> merged entry, nor if a merged entry was inline with the style for MI
>> commands.
>>
>> ---
>>
>> I have also tweaked the code a little in this version, the changes
>> around how a catchpoint is reported when it is initially setup has
>> changed, the output is not more inline with other breakpoints.  See
>> the changes in print_mention_exception_catchpoint, and the new
>> scoped_restore restore_breakpoint_reporting in
>> mi_cmd_catch_exception_event.  Otherwise the code is unchanged.
>>
>> Thanks,
>> Andrew
>>
>> ---
>>
>> Adds some MI commands to catch C++ exceptions.  The new commands are
>> -catch-throw, -catch-rethrow, and -catch-catch, these all correspond
>> to the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.
>>
>> Each MI command takes two optional arguments, '-t' has the effect of
>> calling 'tcatch' instead of 'catch', for example:
>>
>>    (gdb)
>>    -catch-throw -t
>>
>> Is the same as:
>>
>>    (gdb) tcatch throw
>>
>> There is also a '-r REGEXP' argument that can supply a regexp to match
>> against the exception type, so:
>>
>>    (gdb)
>>    -catch-catch -r PATTERN
>>
>> Is the same as:
>>
>>    (gdb) catch catch PATTERN
>>
>> The change in print_mention_exception_catchpoint might seem a little
>> strange; changing the output from using ui_out::field_int and
>> ui_out::text to using  ui_out::message.
>>
>> The print_mention_exception_catchpoint is used as the 'print_mention'
>> method for the exception catchpoint breakpoint object.  Most of the
>> other 'print_mention' methods (see breakpoint.c) use either
>> printf_filtered, of ui_out::message.  Using field_int was causing an
>> unexpected field to be added to the MI output.  Here's the output
>> without the change in print_mention_exception_catchpoint:
>>
>>     (gdb)
>>     -catch-throw
>>     ^done,bkptno="1",bkpt={number="1",type="breakpoint",disp="keep",
>>                            enabled="y",addr="0x00000000004006c0",
>>                            what="exception throw",catch-type="throw",
>>                            thread-groups=["i1"],times="0"}
>>
>> Notice the breakpoint number appears in both the 'bkptno' field, and
>> the 'number' field within the 'bkpt' tuple.  Here's the output with
>> the change in print_mention_exception_catchpoint:
>>
>>     (gdb)
>>     -catch-throw
>>     ^done,bkpt={number="1",type="breakpoint",disp="keep",
>>                 enabled="y",addr="0x00000000004006c0",
>>                 what="exception throw",catch-type="throw",
>>                 thread-groups=["i1"],times="0"}
>>
>> gdb/ChangeLog:
>>
>> 	* NEWS: Mention new MI commands.
>> 	* break-catch-throw.c (enum exception_event_kind): Move to
>> 	breakpoint.h.
>> 	(print_mention_exception_catchpoint): Output text as a single
>> 	message.
>> 	(catch_exception_command_1): Rename to...
>> 	(catch_exception_event): ...this, make non-static, update header
>> 	command, and change some parameter types.
>> 	(catch_catch_command): Update for changes to
>> 	catch_exception_command_1.
>> 	(catch_throw_command): Likewise.
>> 	(catch_rethrow_command): Likewise.
>> 	* breakpoint.c (enum exception_event_kind): Delete.
>> 	* breakpoint.h (enum exception_event_kind): Moved here from
>> 	break-catch-throw.c.
>> 	(catch_exception_event): Declare.
>> 	* mi/mi-cmd-catch.c (mi_cmd_catch_exception_event): New function.
>> 	(mi_cmd_catch_throw): New function.
>> 	(mi_cmd_catch_rethrow): New function.
>> 	(mi_cmd_catch_catch): New function.
>> 	* mi/mi-cmds.c (mi_cmds): Add 'catch-throw', 'catch-rethrow', and
>> 	'catch-catch' entries.
>> 	* mi/mi-cmds.h (mi_cmd_catch_throw): Declare.
>> 	(mi_cmd_catch_rethrow): Declare.
>> 	(mi_cmd_catch_catch): Declare.
>>
>> gdb/doc/ChangeLog:
>>
>> 	* gdb.texinfo (GDB/MI Catchpoint Commands): Add menu entry to new
>> 	node.
>> 	(C++ Exception GDB/MI Catchpoint Commands): New node to describe
>> 	new MI commands.
>>
>> gdb/testsuite/ChangeLog:
>>
>> 	* gdb.mi/mi-catch-cpp-exceptions.cc: New file.
>> 	* gdb.mi/mi-catch-cpp-exceptions.exp: New file.
>> 	* lib/mi-support.exp (mi_expect_stop): Handle 'exception-caught'
>> 	as a stop reason.
> 
> I've now pushed this patch with the doc fixes that Eli suggested.
> 

I've filed PR24686 - "FAIL: gdb.mi/mi-catch-cpp-exceptions.exp: all with
invalid regexp: run until breakpoint in main (timeout)"

Thanks,
- Tom


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv2] gdb/mi: New commands to catch C++ exceptions
  2019-06-16 13:14     ` Tom de Vries
@ 2019-06-16 15:30       ` Andrew Burgess
  2019-06-16 21:45         ` Tom de Vries
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Burgess @ 2019-06-16 15:30 UTC (permalink / raw)
  To: Tom de Vries; +Cc: gdb-patches

* Tom de Vries <tdevries@suse.de> [2019-06-16 15:14:06 +0200]:

> On 16-06-19 00:34, Andrew Burgess wrote:
> > * Andrew Burgess <andrew.burgess@embecosm.com> [2019-05-12 00:46:46 +0100]:
> > 
> >> Eli,
> >>
> >> This iteration includes updated documentation that fixes almost all of
> >> the issues you raised.  The only thing I haven't done is collapse all
> >> of the command sub-sections into a single sub-section.  I looked
> >> through most of the existing MI commands and they all seem to be one
> >> command per sub-section, so I wasn't entirely sure how to layout a
> >> merged entry, nor if a merged entry was inline with the style for MI
> >> commands.
> >>
> >> ---
> >>
> >> I have also tweaked the code a little in this version, the changes
> >> around how a catchpoint is reported when it is initially setup has
> >> changed, the output is not more inline with other breakpoints.  See
> >> the changes in print_mention_exception_catchpoint, and the new
> >> scoped_restore restore_breakpoint_reporting in
> >> mi_cmd_catch_exception_event.  Otherwise the code is unchanged.
> >>
> >> Thanks,
> >> Andrew
> >>
> >> ---
> >>
> >> Adds some MI commands to catch C++ exceptions.  The new commands are
> >> -catch-throw, -catch-rethrow, and -catch-catch, these all correspond
> >> to the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.
> >>
> >> Each MI command takes two optional arguments, '-t' has the effect of
> >> calling 'tcatch' instead of 'catch', for example:
> >>
> >>    (gdb)
> >>    -catch-throw -t
> >>
> >> Is the same as:
> >>
> >>    (gdb) tcatch throw
> >>
> >> There is also a '-r REGEXP' argument that can supply a regexp to match
> >> against the exception type, so:
> >>
> >>    (gdb)
> >>    -catch-catch -r PATTERN
> >>
> >> Is the same as:
> >>
> >>    (gdb) catch catch PATTERN
> >>
> >> The change in print_mention_exception_catchpoint might seem a little
> >> strange; changing the output from using ui_out::field_int and
> >> ui_out::text to using  ui_out::message.
> >>
> >> The print_mention_exception_catchpoint is used as the 'print_mention'
> >> method for the exception catchpoint breakpoint object.  Most of the
> >> other 'print_mention' methods (see breakpoint.c) use either
> >> printf_filtered, of ui_out::message.  Using field_int was causing an
> >> unexpected field to be added to the MI output.  Here's the output
> >> without the change in print_mention_exception_catchpoint:
> >>
> >>     (gdb)
> >>     -catch-throw
> >>     ^done,bkptno="1",bkpt={number="1",type="breakpoint",disp="keep",
> >>                            enabled="y",addr="0x00000000004006c0",
> >>                            what="exception throw",catch-type="throw",
> >>                            thread-groups=["i1"],times="0"}
> >>
> >> Notice the breakpoint number appears in both the 'bkptno' field, and
> >> the 'number' field within the 'bkpt' tuple.  Here's the output with
> >> the change in print_mention_exception_catchpoint:
> >>
> >>     (gdb)
> >>     -catch-throw
> >>     ^done,bkpt={number="1",type="breakpoint",disp="keep",
> >>                 enabled="y",addr="0x00000000004006c0",
> >>                 what="exception throw",catch-type="throw",
> >>                 thread-groups=["i1"],times="0"}
> >>
> >> gdb/ChangeLog:
> >>
> >> 	* NEWS: Mention new MI commands.
> >> 	* break-catch-throw.c (enum exception_event_kind): Move to
> >> 	breakpoint.h.
> >> 	(print_mention_exception_catchpoint): Output text as a single
> >> 	message.
> >> 	(catch_exception_command_1): Rename to...
> >> 	(catch_exception_event): ...this, make non-static, update header
> >> 	command, and change some parameter types.
> >> 	(catch_catch_command): Update for changes to
> >> 	catch_exception_command_1.
> >> 	(catch_throw_command): Likewise.
> >> 	(catch_rethrow_command): Likewise.
> >> 	* breakpoint.c (enum exception_event_kind): Delete.
> >> 	* breakpoint.h (enum exception_event_kind): Moved here from
> >> 	break-catch-throw.c.
> >> 	(catch_exception_event): Declare.
> >> 	* mi/mi-cmd-catch.c (mi_cmd_catch_exception_event): New function.
> >> 	(mi_cmd_catch_throw): New function.
> >> 	(mi_cmd_catch_rethrow): New function.
> >> 	(mi_cmd_catch_catch): New function.
> >> 	* mi/mi-cmds.c (mi_cmds): Add 'catch-throw', 'catch-rethrow', and
> >> 	'catch-catch' entries.
> >> 	* mi/mi-cmds.h (mi_cmd_catch_throw): Declare.
> >> 	(mi_cmd_catch_rethrow): Declare.
> >> 	(mi_cmd_catch_catch): Declare.
> >>
> >> gdb/doc/ChangeLog:
> >>
> >> 	* gdb.texinfo (GDB/MI Catchpoint Commands): Add menu entry to new
> >> 	node.
> >> 	(C++ Exception GDB/MI Catchpoint Commands): New node to describe
> >> 	new MI commands.
> >>
> >> gdb/testsuite/ChangeLog:
> >>
> >> 	* gdb.mi/mi-catch-cpp-exceptions.cc: New file.
> >> 	* gdb.mi/mi-catch-cpp-exceptions.exp: New file.
> >> 	* lib/mi-support.exp (mi_expect_stop): Handle 'exception-caught'
> >> 	as a stop reason.
> > 
> > I've now pushed this patch with the doc fixes that Eli suggested.
> > 
> 
> I've filed PR24686 - "FAIL: gdb.mi/mi-catch-cpp-exceptions.exp: all with
> invalid regexp: run until breakpoint in main (timeout)"

Thanks for reporting this.

I have pushed the patch below which I believe should change the FAIL
you are seeing into a KFAIL.

Let me know if this helps.

Thanks,
Andrew

--

commit 93cb9841d68263174a600dc70af742a8e2eabfc6
Author: Andrew Burgess <andrew.burgess@embecosm.com>
Date:   Sun Jun 16 16:17:59 2019 +0100

    gdb/testsuite: Improve detection of bug gdb/24541
    
    In bug gdb/24686 a testsuite failure was reported, this failure was
    actually just another instance of bug gdb/24541, however, due to the
    non-deterministic nature of bug gdb/24541 the testsuite pattern that
    was intended to catch this bug failed.
    
    This commit adds a second pattern to help detect gdb/24541, which
    should change the FAIL reported in gdb/24686 into a KFAIL.
    
    gdb/testsuite/ChangeLog:
    
            PR gdb/24686
            * gdb.mi/mi-catch-cpp-exceptions.exp: Add an extra pattern to
            improve detection of bug gdb/24541.

diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
index b5dfbe68c1a..fa5b11e3e58 100644
--- a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
+++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
@@ -141,6 +141,9 @@ with_test_prefix "all with invalid regexp" {
 	-re "could not find minimal symbol for typeinfo address.*$mi_gdb_prompt$" {
 	    kfail "gdb/24541" "${testname}"
 	}
+	-re "\\*stopped,bkptno=\"$decimal\",reason=\"breakpoint-hit\",disp=\"keep\".*func=\"__cxa_throw\".*$mi_gdb_prompt$" {
+	    kfail "gdb/24541" "${testname}"
+	}
 	-re "\\*stopped,reason=\"breakpoint-hit\".*func=\"main\".*line=\"${main_lineno}\".*$mi_gdb_prompt$" {
 	    pass "${testname}"
 	}


^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCHv2] gdb/mi: New commands to catch C++ exceptions
  2019-06-16 15:30       ` Andrew Burgess
@ 2019-06-16 21:45         ` Tom de Vries
  0 siblings, 0 replies; 9+ messages in thread
From: Tom de Vries @ 2019-06-16 21:45 UTC (permalink / raw)
  To: Andrew Burgess; +Cc: gdb-patches

On 16-06-19 17:29, Andrew Burgess wrote:
> * Tom de Vries <tdevries@suse.de> [2019-06-16 15:14:06 +0200]:
> 
>> On 16-06-19 00:34, Andrew Burgess wrote:
>>> * Andrew Burgess <andrew.burgess@embecosm.com> [2019-05-12 00:46:46 +0100]:
>>>
>>>> Eli,
>>>>
>>>> This iteration includes updated documentation that fixes almost all of
>>>> the issues you raised.  The only thing I haven't done is collapse all
>>>> of the command sub-sections into a single sub-section.  I looked
>>>> through most of the existing MI commands and they all seem to be one
>>>> command per sub-section, so I wasn't entirely sure how to layout a
>>>> merged entry, nor if a merged entry was inline with the style for MI
>>>> commands.
>>>>
>>>> ---
>>>>
>>>> I have also tweaked the code a little in this version, the changes
>>>> around how a catchpoint is reported when it is initially setup has
>>>> changed, the output is not more inline with other breakpoints.  See
>>>> the changes in print_mention_exception_catchpoint, and the new
>>>> scoped_restore restore_breakpoint_reporting in
>>>> mi_cmd_catch_exception_event.  Otherwise the code is unchanged.
>>>>
>>>> Thanks,
>>>> Andrew
>>>>
>>>> ---
>>>>
>>>> Adds some MI commands to catch C++ exceptions.  The new commands are
>>>> -catch-throw, -catch-rethrow, and -catch-catch, these all correspond
>>>> to the CLI commands 'catch throw', 'catch rethrow', and 'catch catch'.
>>>>
>>>> Each MI command takes two optional arguments, '-t' has the effect of
>>>> calling 'tcatch' instead of 'catch', for example:
>>>>
>>>>    (gdb)
>>>>    -catch-throw -t
>>>>
>>>> Is the same as:
>>>>
>>>>    (gdb) tcatch throw
>>>>
>>>> There is also a '-r REGEXP' argument that can supply a regexp to match
>>>> against the exception type, so:
>>>>
>>>>    (gdb)
>>>>    -catch-catch -r PATTERN
>>>>
>>>> Is the same as:
>>>>
>>>>    (gdb) catch catch PATTERN
>>>>
>>>> The change in print_mention_exception_catchpoint might seem a little
>>>> strange; changing the output from using ui_out::field_int and
>>>> ui_out::text to using  ui_out::message.
>>>>
>>>> The print_mention_exception_catchpoint is used as the 'print_mention'
>>>> method for the exception catchpoint breakpoint object.  Most of the
>>>> other 'print_mention' methods (see breakpoint.c) use either
>>>> printf_filtered, of ui_out::message.  Using field_int was causing an
>>>> unexpected field to be added to the MI output.  Here's the output
>>>> without the change in print_mention_exception_catchpoint:
>>>>
>>>>     (gdb)
>>>>     -catch-throw
>>>>     ^done,bkptno="1",bkpt={number="1",type="breakpoint",disp="keep",
>>>>                            enabled="y",addr="0x00000000004006c0",
>>>>                            what="exception throw",catch-type="throw",
>>>>                            thread-groups=["i1"],times="0"}
>>>>
>>>> Notice the breakpoint number appears in both the 'bkptno' field, and
>>>> the 'number' field within the 'bkpt' tuple.  Here's the output with
>>>> the change in print_mention_exception_catchpoint:
>>>>
>>>>     (gdb)
>>>>     -catch-throw
>>>>     ^done,bkpt={number="1",type="breakpoint",disp="keep",
>>>>                 enabled="y",addr="0x00000000004006c0",
>>>>                 what="exception throw",catch-type="throw",
>>>>                 thread-groups=["i1"],times="0"}
>>>>
>>>> gdb/ChangeLog:
>>>>
>>>> 	* NEWS: Mention new MI commands.
>>>> 	* break-catch-throw.c (enum exception_event_kind): Move to
>>>> 	breakpoint.h.
>>>> 	(print_mention_exception_catchpoint): Output text as a single
>>>> 	message.
>>>> 	(catch_exception_command_1): Rename to...
>>>> 	(catch_exception_event): ...this, make non-static, update header
>>>> 	command, and change some parameter types.
>>>> 	(catch_catch_command): Update for changes to
>>>> 	catch_exception_command_1.
>>>> 	(catch_throw_command): Likewise.
>>>> 	(catch_rethrow_command): Likewise.
>>>> 	* breakpoint.c (enum exception_event_kind): Delete.
>>>> 	* breakpoint.h (enum exception_event_kind): Moved here from
>>>> 	break-catch-throw.c.
>>>> 	(catch_exception_event): Declare.
>>>> 	* mi/mi-cmd-catch.c (mi_cmd_catch_exception_event): New function.
>>>> 	(mi_cmd_catch_throw): New function.
>>>> 	(mi_cmd_catch_rethrow): New function.
>>>> 	(mi_cmd_catch_catch): New function.
>>>> 	* mi/mi-cmds.c (mi_cmds): Add 'catch-throw', 'catch-rethrow', and
>>>> 	'catch-catch' entries.
>>>> 	* mi/mi-cmds.h (mi_cmd_catch_throw): Declare.
>>>> 	(mi_cmd_catch_rethrow): Declare.
>>>> 	(mi_cmd_catch_catch): Declare.
>>>>
>>>> gdb/doc/ChangeLog:
>>>>
>>>> 	* gdb.texinfo (GDB/MI Catchpoint Commands): Add menu entry to new
>>>> 	node.
>>>> 	(C++ Exception GDB/MI Catchpoint Commands): New node to describe
>>>> 	new MI commands.
>>>>
>>>> gdb/testsuite/ChangeLog:
>>>>
>>>> 	* gdb.mi/mi-catch-cpp-exceptions.cc: New file.
>>>> 	* gdb.mi/mi-catch-cpp-exceptions.exp: New file.
>>>> 	* lib/mi-support.exp (mi_expect_stop): Handle 'exception-caught'
>>>> 	as a stop reason.
>>>
>>> I've now pushed this patch with the doc fixes that Eli suggested.
>>>
>>
>> I've filed PR24686 - "FAIL: gdb.mi/mi-catch-cpp-exceptions.exp: all with
>> invalid regexp: run until breakpoint in main (timeout)"
> 
> Thanks for reporting this.
> 
> I have pushed the patch below which I believe should change the FAIL
> you are seeing into a KFAIL.
> 
> Let me know if this helps.
> 

Hi,

that works, I see a KFAIL now.

Thanks,
- Tom

> Thanks,
> Andrew
> 
> --
> 
> commit 93cb9841d68263174a600dc70af742a8e2eabfc6
> Author: Andrew Burgess <andrew.burgess@embecosm.com>
> Date:   Sun Jun 16 16:17:59 2019 +0100
> 
>     gdb/testsuite: Improve detection of bug gdb/24541
>     
>     In bug gdb/24686 a testsuite failure was reported, this failure was
>     actually just another instance of bug gdb/24541, however, due to the
>     non-deterministic nature of bug gdb/24541 the testsuite pattern that
>     was intended to catch this bug failed.
>     
>     This commit adds a second pattern to help detect gdb/24541, which
>     should change the FAIL reported in gdb/24686 into a KFAIL.
>     
>     gdb/testsuite/ChangeLog:
>     
>             PR gdb/24686
>             * gdb.mi/mi-catch-cpp-exceptions.exp: Add an extra pattern to
>             improve detection of bug gdb/24541.
> 
> diff --git a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
> index b5dfbe68c1a..fa5b11e3e58 100644
> --- a/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
> +++ b/gdb/testsuite/gdb.mi/mi-catch-cpp-exceptions.exp
> @@ -141,6 +141,9 @@ with_test_prefix "all with invalid regexp" {
>  	-re "could not find minimal symbol for typeinfo address.*$mi_gdb_prompt$" {
>  	    kfail "gdb/24541" "${testname}"
>  	}
> +	-re "\\*stopped,bkptno=\"$decimal\",reason=\"breakpoint-hit\",disp=\"keep\".*func=\"__cxa_throw\".*$mi_gdb_prompt$" {
> +	    kfail "gdb/24541" "${testname}"
> +	}
>  	-re "\\*stopped,reason=\"breakpoint-hit\".*func=\"main\".*line=\"${main_lineno}\".*$mi_gdb_prompt$" {
>  	    pass "${testname}"
>  	}
> 


^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2019-06-16 21:45 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-05-09  0:05 [PATCH] gdb/mi: New commands to catch C++ exceptions Andrew Burgess
2019-05-09 21:50 ` Tom Tromey
2019-05-10  7:01 ` Eli Zaretskii
2019-05-11 23:46 ` [PATCHv2] " Andrew Burgess
2019-05-12  4:09   ` Eli Zaretskii
2019-06-15 22:34   ` Andrew Burgess
2019-06-16 13:14     ` Tom de Vries
2019-06-16 15:30       ` Andrew Burgess
2019-06-16 21:45         ` Tom de Vries

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox