This patch to the diagnostic code uses the new backtrace library to
print a backtrace on an ICE.  For example, here is the output of a test
case I took from a C++ PR:

/home/iant/foo2.cc:6:6: internal compiler error: in cp_lexer_new_from_tokens, 
at cp/parser.c:638
0xec549f internal_error(char const*, ...)
        ../../trunk/gcc/diagnostic.c:1057
0xec3f53 fancy_abort(char const*, int, char const*)
        ../../trunk/gcc/diagnostic.c:1111
0x5ff78e cp_lexer_new_from_tokens
        ../../trunk/gcc/cp/parser.c:638
0x5ff78e cp_parser_push_lexer_for_tokens
        ../../trunk/gcc/cp/parser.c:3290
0x60ff40 cp_parser_late_parsing_for_member
        ../../trunk/gcc/cp/parser.c:21713
0x60ff40 cp_parser_class_specifier_1
        ../../trunk/gcc/cp/parser.c:18207
0x60ff40 cp_parser_class_specifier
        ../../trunk/gcc/cp/parser.c:18231
0x60ff40 cp_parser_type_specifier
        ../../trunk/gcc/cp/parser.c:13390
0x61c83d cp_parser_decl_specifier_seq
        ../../trunk/gcc/cp/parser.c:10731
0x628317 cp_parser_single_declaration
        ../../trunk/gcc/cp/parser.c:21313
0x6289c0 cp_parser_template_declaration_after_export
        ../../trunk/gcc/cp/parser.c:21198
0x62de39 cp_parser_declaration
        ../../trunk/gcc/cp/parser.c:10183
0x62c487 cp_parser_declaration_seq_opt
        ../../trunk/gcc/cp/parser.c:10105
0x62c762 cp_parser_translation_unit
        ../../trunk/gcc/cp/parser.c:3757
0x62c762 c_parse_file()
        ../../trunk/gcc/cp/parser.c:27557
0x72e4e4 c_common_parse_file()
        ../../trunk/gcc/c-family/c-opts.c:1138
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.


Bootstrapped on x86_64-unknown-linux-gnu.  I didn't bother to run the
testsuite, since the code only changes when an ICE occurs anyhow.

OK for mainline?

Ian

gcc/:

2012-09-17  Ian Lance Taylor  <i...@google.com>

        * diagnostic.c: Include "demangle.h" and "backtrace.h".
        (bt_stop): New static array.
        (bt_callback, bt_err_callback): New static functions.
        (diagnostic_action_after_output): Call backtrace_full for DK_ICE.
        * Makefile.in (BACKTRACE): New variable.
        (BACKTRACEINC, LIBBACKTRACE): New variables.
        (BACKTRACE_H): New variable.
        (LIBDEPS, LIBS): Add $(LIBBACKTRACE).
        (INCLUDES): Add $(BACKTRACEINC).
        (diagnostic.o): Depend upon $(DEMANGLE_H) and $(BACKTRACE_H).

./:

2012-09-17  Ian Lance Taylor  <i...@google.com>

        * Makefile.def: Make all-gcc depend on all-libbacktrace.
        * Makefile.in: Rebuild.


Index: gcc/diagnostic.c
===================================================================
--- gcc/diagnostic.c	(revision 191393)
+++ gcc/diagnostic.c	(working copy)
@@ -27,8 +27,10 @@ along with GCC; see the file COPYING3.  
 #include "system.h"
 #include "coretypes.h"
 #include "version.h"
+#include "demangle.h"
 #include "input.h"
 #include "intl.h"
+#include "backtrace.h"
 #include "diagnostic.h"
 
 #define pedantic_warning_kind(DC)			\
@@ -296,6 +298,93 @@ diagnostic_show_locus (diagnostic_contex
   pp_set_prefix (context->printer, saved_prefix);
 }
 
+/* Functions at which to stop the backtrace print.  It's not
+   particularly helpful to print the callers of these functions.  */
+
+static const char * const bt_stop[] =
+{
+  "main",
+  "toplev_main",
+  "execute_one_pass",
+  "compile_file",
+};
+
+/* A callback function passed to the backtrace_full function.  */
+
+static int
+bt_callback (void *data, uintptr_t pc, const char *filename, int lineno,
+	     const char *function)
+{
+  int *pcount = (int *) data;
+
+  /* If we don't have any useful information, don't print
+     anything.  */
+  if (filename == NULL && function == NULL)
+    return 0;
+
+  /* Print up to 20 functions.  We could make this a --param, but
+     since this is only for debugging just use a constant for now.  */
+  if (*pcount >= 20)
+    {
+      /* Returning a non-zero value stops the backtrace.  */
+      return 1;
+    }
+  ++*pcount;
+
+  char *alc = NULL;
+  if (function != NULL)
+    {
+      char *str = cplus_demangle_v3 (function,
+				     (DMGL_VERBOSE | DMGL_ANSI
+				      | DMGL_GNU_V3 | DMGL_PARAMS));
+      if (str != NULL)
+	{
+	  alc = str;
+	  function = str;
+	}
+
+      for (size_t i = 0; i < ARRAY_SIZE (bt_stop); ++i)
+	{
+	  size_t len = strlen (bt_stop[i]);
+	  if (strncmp (function, bt_stop[i], len) == 0
+	      && (function[len] == '\0' || function[len] == '('))
+	    {
+	      if (alc != NULL)
+		free (alc);
+	      /* Returning a non-zero value stops the backtrace.  */
+	      return 1;
+	    }
+	}
+    }
+
+  fprintf (stderr, "0x%lx %s\n\t%s:%d\n",
+	   pc,
+	   function == NULL ? "???" : function,
+	   filename == NULL ? "???" : filename,
+	   lineno);
+
+  if (alc != NULL)
+    free (alc);
+
+  return 0;
+}
+
+/* A callback function passed to the backtrace_full function.  This is
+   called if backtrace_full has an error.  */
+
+static void
+bt_err_callback (void *data ATTRIBUTE_UNUSED, const char *msg, int errnum)
+{
+  if (errnum < 0)
+    {
+      /* This means that no debug info was available.  Just quietly
+	 skip printing backtrace info.  */
+      return;
+    }
+  fprintf (stderr, "%s%s%s\n", msg, errnum == 0 ? "" : ": ",
+	   errnum == 0 ? "" : xstrerror (errnum));
+}
+
 /* Take any action which is expected to happen after the diagnostic
    is written out.  This function does not always return.  */
 static void
@@ -334,6 +423,17 @@ diagnostic_action_after_output (diagnost
       break;
 
     case DK_ICE:
+      {
+	struct backtrace_state *state =
+	  backtrace_create_state (NULL, 0, bt_err_callback, NULL);
+	if (state != NULL)
+	  {
+	    int count = 0;
+	    backtrace_full (state, 2, bt_callback, bt_err_callback,
+			    (void *) &count);
+	  }
+      }
+
       if (context->abort_on_error)
 	real_abort ();
 
Index: gcc/Makefile.in
===================================================================
--- gcc/Makefile.in	(revision 191393)
+++ gcc/Makefile.in	(working copy)
@@ -346,6 +346,11 @@ DECNUMFMT = $(srcdir)/../libdecnumber/$(
 DECNUMINC = -I$(DECNUM) -I$(DECNUMFMT) -I../libdecnumber
 LIBDECNUMBER = ../libdecnumber/libdecnumber.a
 
+# The backtrace library.
+BACKTRACE = $(srcdir)/../libbacktrace
+BACKTRACEINC = -I$(BACKTRACE)
+LIBBACKTRACE = ../libbacktrace/.libs/libbacktrace.a
+
 # Target to use when installing include directory.  Either
 # install-headers-tar, install-headers-cpio or install-headers-cp.
 INSTALL_HEADERS_DIR = @build_install_headers_dir@
@@ -905,6 +910,7 @@ OPTS_H = $(INPUT_H) $(VEC_H) opts.h
 DECNUM_H = $(DECNUM)/decContext.h $(DECNUM)/decDPD.h $(DECNUM)/decNumber.h \
 	$(DECNUMFMT)/decimal32.h $(DECNUMFMT)/decimal64.h \
 	$(DECNUMFMT)/decimal128.h $(DECNUMFMT)/decimal128Local.h
+BACKTRACE_H = $(BACKTRACE)/backtrace.h
 MKDEPS_H = $(srcdir)/../libcpp/include/mkdeps.h
 SYMTAB_H = $(srcdir)/../libcpp/include/symtab.h $(OBSTACK_H)
 CPP_ID_DATA_H = $(CPPLIB_H) $(srcdir)/../libcpp/include/cpp-id-data.h
@@ -987,7 +993,7 @@ BUILD_LIBIBERTY = $(build_libobjdir)/lib
 
 # Dependencies on the intl and portability libraries.
 LIBDEPS= libcommon.a $(CPPLIB) $(LIBIBERTY) $(LIBINTL_DEP) $(LIBICONV_DEP) \
-	$(LIBDECNUMBER)
+	$(LIBDECNUMBER) $(LIBBACKTRACE)
 
 # Likewise, for use in the tools that must run on this machine
 # even if we are cross-building GCC.
@@ -995,8 +1001,8 @@ BUILD_LIBDEPS= $(BUILD_LIBIBERTY)
 
 # How to link with both our special library facilities
 # and the system's installed libraries.
-LIBS = @LIBS@ libcommon.a $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBIBERTY) \
-	$(LIBDECNUMBER) $(HOST_LIBS)
+LIBS = @LIBS@ libcommon.a $(CPPLIB) $(LIBINTL) $(LIBICONV) $(LIBBACKTRACE) \
+	$(LIBIBERTY) $(LIBDECNUMBER) $(HOST_LIBS)
 BACKENDLIBS = $(CLOOGLIBS) $(GMPLIBS) $(PLUGINLIBS) $(HOST_LIBS) \
 	$(ZLIB)
 # Any system libraries needed just for GNAT.
@@ -1028,7 +1034,7 @@ BUILD_ERRORS = build/errors.o
 # libintl.h will be found in ../intl if we are using the included libintl.
 INCLUDES = -I. -I$(@D) -I$(srcdir) -I$(srcdir)/$(@D) \
 	   -I$(srcdir)/../include @INCINTL@ \
-	   $(CPPINC) $(GMPINC) $(DECNUMINC) \
+	   $(CPPINC) $(GMPINC) $(DECNUMINC) $(BACKTRACEINC) \
 	   $(CLOOGINC) $(ISLINC)
 
 .c.o:
@@ -2613,7 +2619,8 @@ fold-const.o : fold-const.c $(CONFIG_H) 
    $(GGC_H) $(TM_P_H) langhooks.h $(MD5_H) intl.h $(TARGET_H) \
    $(GIMPLE_H) realmpfr.h $(TREE_FLOW_H)
 diagnostic.o : diagnostic.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \
-   version.h $(INPUT_H) intl.h $(DIAGNOSTIC_H) diagnostic.def
+   version.h $(DEMANGLE_H) $(INPUT_H) intl.h $(BACKTRACE_H) $(DIAGNOSTIC_H) \
+   diagnostic.def
 opts.o : opts.c $(OPTS_H) $(OPTIONS_H) $(DIAGNOSTIC_CORE_H) $(CONFIG_H) $(SYSTEM_H) \
    coretypes.h $(TM_H) \
    $(DIAGNOSTIC_H) insn-attr-common.h intl.h $(COMMON_TARGET_H) \
Index: Makefile.def
===================================================================
--- Makefile.def	(revision 191397)
+++ Makefile.def	(working copy)
@@ -305,6 +305,7 @@ dependencies = { module=all-gcc; on=all-
 dependencies = { module=all-gcc; on=all-build-libiberty; };
 dependencies = { module=all-gcc; on=all-build-fixincludes; };
 dependencies = { module=all-gcc; on=all-zlib; };
+dependencies = { module=all-gcc; on=all-libbacktrace; hard=true; };
 dependencies = { module=all-gcc; on=all-libcpp; hard=true; };
 dependencies = { module=all-gcc; on=all-libdecnumber; hard=true; };
 dependencies = { module=all-gcc; on=all-libiberty; };

Reply via email to