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


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

improve Ada exception catchpoint GDB/MI *stopped notification


Many thanks to Tom for the clarifications regarding the ui_out
handling.  I think I was able to come up with a version of the code
that minimizes the use of the is-mi-like routine.

Attached is the patch that I propose to commit, with documentation
of the new GDB/MI field.

Tested on x86_64-linux. I created a testcase for it, but had to put it
in gdb.ada, because the testing infrastructure expects the gnat_ada.gpr
file to be present in the parent directory where the inferior sources
are (ie gdb.ada) in order to build Ada programs.

-- 
Joel
commit dcc4c2b1fd72fb2a377b0891a6e4759af1fab3c5
Author: Joel Brobecker <brobecker@adacore.com>
Date:   Wed Mar 16 09:22:06 2011 -0700

    improve Ada exception catchpoint MI notification
    
    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.

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index ed51ab0..256f4eb 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -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).
@@ -10744,40 +10745,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;
 }
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index c55e5c0..6577b95 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -246,7 +246,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
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index bd09713..22479ac 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -917,6 +917,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);
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 0eeb38c..fe717d2 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -24807,6 +24807,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
@@ -25072,6 +25073,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
diff --git a/gdb/testsuite/gdb.ada/mi_catch_ex.exp b/gdb/testsuite/gdb.ada/mi_catch_ex.exp
new file mode 100644
index 0000000..dadc574
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/mi_catch_ex.exp
@@ -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
index 0000000..a2eceac
--- /dev/null
+++ b/gdb/testsuite/gdb.ada/mi_catch_ex/foo.adb
@@ -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;

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