improve Ada exception catchpoint MI notification
authorJoel Brobecker <brobecker@gnat.com>
Fri, 1 Apr 2011 16:59:58 +0000 (16:59 +0000)
committerJoel Brobecker <brobecker@gnat.com>
Fri, 1 Apr 2011 16:59:58 +0000 (16:59 +0000)
This rewrites the code generating the Ada exception catchpoint hit
notification for both the GDB/MI case as well as the non-MI case,
by using the relevant ui_out_* functions to generate the output.
the MI notifications for Ada exception catchpoints now include
the stop reason, and the breakpoint "disp", much like other breakpoint
events do.  It also introduces a new field "exception-name" for
exception catchpoints (excluding "failed assertion catchpoints,
where we just want to know that it was a failed assertion).

gdb/ChangeLog:

        * breakpoint.h (bpdisp_text): Add declaration.
        * breakpoint.c (bpdisp_text): Make non-static.
        * ada-lang.c: #include "mi/mi-common.h".
        (print_it_exception): Rewrite to improve GDB/MI output.

gdb/doc/ChangeLog:

        * gdb.texinfo (GDB/MI Ada Exception Information): Document
        the "exception-name" field in the *stopped async record.

gdb/testsuite/ChangeLog:

        * gdb.ada/mi_catch_ex: New testcase.

gdb/ChangeLog
gdb/ada-lang.c
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.ada/mi_catch_ex.exp [new file with mode: 0644]
gdb/testsuite/gdb.ada/mi_catch_ex/foo.adb [new file with mode: 0644]

index 8d582ae..bc94029 100644 (file)
@@ -1,3 +1,10 @@
+2011-04-01  Joel Brobecker  <brobecker@adacore.com>
+
+       * breakpoint.h (bpdisp_text): Add declaration.
+       * breakpoint.c (bpdisp_text): Make non-static.
+       * ada-lang.c: #include "mi/mi-common.h".
+       (print_it_exception): Rewrite to improve GDB/MI output.
+
 2011-04-01  Pedro Alves  <pedro@codesourcery.com>
 
        * arm-tdep.h (struct address_space): Add forward declaration.
index 2063f3d..6b0f510 100644 (file)
@@ -60,6 +60,7 @@
 
 #include "psymtab.h"
 #include "value.h"
+#include "mi/mi-common.h"
 
 /* Define whether or not the C operator '/' truncates towards zero for
    differently signed operands (truncation direction is undefined in C).
@@ -10745,40 +10746,63 @@ ada_exception_name_addr (enum exception_catchpoint_kind ex,
 static enum print_stop_action
 print_it_exception (enum exception_catchpoint_kind ex, struct breakpoint *b)
 {
-  const CORE_ADDR addr = ada_exception_name_addr (ex, b);
-  char exception_name[256];
+  annotate_catchpoint (b->number);
 
-  if (addr != 0)
+  if (ui_out_is_mi_like_p (uiout))
     {
-      read_memory (addr, exception_name, sizeof (exception_name) - 1);
-      exception_name [sizeof (exception_name) - 1] = '\0';
+      ui_out_field_string (uiout, "reason",
+                          async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
     }
 
-  ada_find_printable_frame (get_current_frame ());
+  ui_out_text (uiout, "\nCatchpoint ");
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
 
-  annotate_catchpoint (b->number);
   switch (ex)
     {
       case ex_catch_exception:
-        if (addr != 0)
-          printf_filtered (_("\nCatchpoint %d, %s at "),
-                           b->number, exception_name);
-        else
-          printf_filtered (_("\nCatchpoint %d, exception at "), b->number);
-        break;
       case ex_catch_exception_unhandled:
-        if (addr != 0)
-          printf_filtered (_("\nCatchpoint %d, unhandled %s at "),
-                           b->number, exception_name);
-        else
-          printf_filtered (_("\nCatchpoint %d, unhandled exception at "),
-                           b->number);
-        break;
+       {
+         const CORE_ADDR addr = ada_exception_name_addr (ex, b);
+         char exception_name[256];
+
+         if (addr != 0)
+           {
+             read_memory (addr, exception_name, sizeof (exception_name) - 1);
+             exception_name [sizeof (exception_name) - 1] = '\0';
+           }
+         else
+           {
+             /* For some reason, we were unable to read the exception
+                name.  This could happen if the Runtime was compiled
+                without debugging info, for instance.  In that case,
+                just replace the exception name by the generic string
+                "exception" - it will read as "an exception" in the
+                notification we are about to print.  */
+             sprintf (exception_name, "exception");
+           }
+         /* In the case of unhandled exception breakpoints, we print
+            the exception name as "unhandled EXCEPTION_NAME", to make
+            it clearer to the user which kind of catchpoint just got
+            hit.  We used ui_out_text to make sure that this extra
+            info does not pollute the exception name in the MI case.  */
+         if (ex == ex_catch_exception_unhandled)
+           ui_out_text (uiout, "unhandled ");
+         ui_out_field_string (uiout, "exception-name", exception_name);
+       }
+       break;
       case ex_catch_assert:
-        printf_filtered (_("\nCatchpoint %d, failed assertion at "),
-                         b->number);
-        break;
+       /* In this case, the name of the exception is not really
+          important.  Just print "failed assertion" to make it clearer
+          that his program just hit an assertion-failure catchpoint.
+          We used ui_out_text because this info does not belong in
+          the MI output.  */
+       ui_out_text (uiout, "failed assertion");
+       break;
     }
+  ui_out_text (uiout, " at ");
+  ada_find_printable_frame (get_current_frame ());
 
   return PRINT_SRC_AND_LOC;
 }
index 3b1367b..2a25c8d 100644 (file)
@@ -251,7 +251,7 @@ breakpoint_commands (struct breakpoint *b)
 
 static int breakpoint_proceeded;
 
-static const char *
+const char *
 bpdisp_text (enum bpdisp disp)
 {
   /* NOTE: the following values are a part of MI protocol and
index 18a7ce7..7a9c2d4 100644 (file)
@@ -961,6 +961,10 @@ extern void breakpoint_auto_delete (bpstat);
    is hit.  */
 extern struct command_line *breakpoint_commands (struct breakpoint *b);
 
+/* Return a string image of DISP.  The string is static, and thus should
+   NOT be deallocated after use.  */
+const char *bpdisp_text (enum bpdisp disp);
+
 extern void break_command (char *, int);
 
 extern void hbreak_command_wrapper (char *, int);
index 424f5c2..1e464a0 100644 (file)
@@ -1,3 +1,8 @@
+2011-04-01  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdb.texinfo (GDB/MI Ada Exception Information): Document
+       the "exception-name" field in the *stopped async record.
+
 2011-03-31  Thiago Jung Bauermann  <bauerman@br.ibm.com>
            Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
 
index e72a305..bccef40 100644 (file)
@@ -24947,6 +24947,7 @@ follow development on @email{gdb@@sourceware.org} and
 * GDB/MI Async Records::
 * GDB/MI Frame Information::
 * GDB/MI Thread Information::
+* GDB/MI Ada Exception Information
 @end menu
 
 @node GDB/MI Result Records
@@ -25212,6 +25213,13 @@ The value of this field is an integer number of the processor core the
 thread was last seen on.  This field is optional.
 @end table
 
+@node GDB/MI Ada Exception Information
+@subsection @sc{gdb/mi} Ada Exception Information
+
+Whenever a @code{*stopped} record is emitted because the program
+stopped after hitting an exception catchpoint (@pxref{Set Catchpoints}),
+@value{GDBN} provides the name of the exception that was raised via
+the @code{exception-name} field.
 
 @c %%%%%%%%%%%%%%%%%%%%%%%%%%%% SECTION %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
 @node GDB/MI Simple Examples
index 9db1d99..fc02e25 100644 (file)
@@ -1,3 +1,7 @@
+2011-04-01  Joel Brobecker  <brobecker@adacore.com>
+
+       * gdb.ada/mi_catch_ex: New testcase.
+
 2011-04-01  Pedro Alves  <pedro@codesourcery.com>
 
        * gdb.cp/cpexprs.exp (Overloaded methods): No longer try the
diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex.exp b/gdb/testsuite/gdb.ada/mi_catch_ex.exp
new file mode 100644 (file)
index 0000000..dadc574
--- /dev/null
@@ -0,0 +1,137 @@
+# Copyright 2011 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/>.
+
+load_lib "ada.exp"
+
+set testdir "mi_catch_ex"
+set testfile "${testdir}/foo"
+set srcfile ${srcdir}/${subdir}/${testfile}.adb
+set binfile ${objdir}/${subdir}/${testfile}
+
+file mkdir ${objdir}/${subdir}/${testdir}
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable [list debug additional_flags=-gnata ]] != "" } {
+  return -1
+}
+
+# Some global variables used to simplify the maintenance of some of
+# the regular expressions below.
+set any_nb "\[0-9\]+"
+set eol "\[\r\n\]+"
+
+# Before going any further, verify that we can insert exception
+# catchpoints...  That way, we won't have to do this while doing
+# the actual GDB/MI testing.
+
+clean_restart ${testfile}
+
+if ![runto_main] then {
+   fail "Cannot run to main, testcase aborted"
+   return 0
+}
+
+set msg "insert catchpoint on all Ada exceptions"
+gdb_test_multiple "catch exception" $msg {
+    -re "Catchpoint $any_nb: all Ada exceptions$eol$gdb_prompt $" {
+       pass $msg
+    }
+    -re "Cannot break on __gnat_raise_nodefer_with_msg in this configuration\.\[\r\n\]+$gdb_prompt $" {
+       # If the runtime was not built with enough debug information,
+       # or if it was stripped, we can not test exception
+       # catchpoints.
+       unsupported $msg
+       return -1
+    }
+}
+
+# Now, we can start the GDB/MI testing itself...
+
+load_lib mi-support.exp
+set MIFLAGS "-i=mi"
+
+gdb_exit
+if [mi_gdb_start] {
+    continue
+}
+
+mi_delete_breakpoints
+mi_gdb_reinitialize_dir $srcdir/$subdir
+mi_gdb_load ${binfile}
+
+####################################
+# 1. Try catching all exceptions.  #
+####################################
+
+if ![mi_run_to_main] then {
+   fail "Cannot run to main, testcase aborted"
+   return 0
+}
+
+mi_gdb_test "catch exception"
+
+mi_execute_to "exec-continue" \
+              "breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb\",exception-name=\"CONSTRAINT_ERROR" \
+              "foo" "" ".*" ".*" \
+              ".*" \
+              "continue to exception catchpoint hit"
+
+mi_execute_to "exec-continue" \
+              "breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb\",exception-name=\"PROGRAM_ERROR" \
+              "foo" "" ".*" ".*" \
+              ".*" \
+              "continue to exception catchpoint hit"
+
+################################################
+# 2. Try catching only some of the exceptions. #
+################################################
+
+# Here is the scenario:
+#  - Restart the debugger from scratch, runto_main
+#  - We'll catch only "Program_Error"
+#    We'll catch assertions
+#    We'll catch unhandled exceptions
+#  - continue, we should see the first Program_Error exception
+#  - continue, we should see the failed assertion
+#  - continue, we should see the unhandled Constrait_Error exception
+#  - continue, the program exits.
+
+if ![mi_run_to_main] then {
+   fail "Cannot run to main, testcase aborted"
+   return 0
+}
+
+mi_gdb_test "catch exception Program_Error"
+
+mi_gdb_test "catch assert"
+
+mi_gdb_test "catch exception unhandled"
+
+mi_execute_to "exec-continue" \
+              "breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb\",exception-name=\"PROGRAM_ERROR" \
+              "foo" "" ".*" ".*" \
+              ".*" \
+              "continue to exception catchpoint hit"
+
+mi_execute_to "exec-continue" \
+              "breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb" \
+              "foo" "" ".*" ".*" \
+              ".*" \
+              "continue to exception catchpoint hit"
+
+mi_execute_to "exec-continue" \
+              "breakpoint-hit\",disp=\"keep\",bkptno=\"$any_nb\",exception-name=\"CONSTRAINT_ERROR" \
+              "foo" "" ".*" ".*" \
+              ".*" \
+              "continue to exception catchpoint hit"
+
diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex/foo.adb b/gdb/testsuite/gdb.ada/mi_catch_ex/foo.adb
new file mode 100644 (file)
index 0000000..a2eceac
--- /dev/null
@@ -0,0 +1,43 @@
+--  Copyright 2007, 2008, 2009, 2010, 2011 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/>.
+
+procedure Foo is
+begin
+
+   begin
+      raise Constraint_Error;  -- SPOT1
+   exception
+      when others =>
+         null;
+   end;
+
+   begin
+      raise Program_Error;  -- SPOT2
+   exception
+      when others =>
+         null;
+   end;
+
+   begin
+      pragma Assert (False);  -- SPOT3
+      null;
+   exception
+      when others =>
+         null;
+   end;
+
+   raise Constraint_Error;  -- SPOT4
+
+end Foo;