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; };