GCC stack backtraces

Ian Lance Taylor iant@google.com
Wed Aug 29 07:24:00 GMT 2012


I've spent the last couple of days working on a stack backtrace library.

It uses the GCC unwind interface to collect a stack trace, and parses
DWARF debug info to get file/line/function information.  (Of course it's
silly to write yet another DWARF reader, but I didn't find an existing
reader that seemed wholly suitable.)  The code currently only works for
ELF/DWARF, but it's designed to support other object file and debug
formats should anybody care to write them.  Since its use in GCC would
be purely for GCC developers, it's not essential that it be fully
portable.


I picked a random PR that causes an ICE.  Here is the final output of
g++ -c foo.cc:

foo.cc:6:6: internal compiler error: in cp_lexer_new_from_tokens, at cp/parser.c:638
0xed6e77 diagnostic_report_diagnostic(diagnostic_context*, diagnostic_info*)
	../../trunk/gcc/diagnostic.c:700
0xed7c2f internal_error(char const*, ...)
	../../trunk/gcc/diagnostic.c:1003
0xed6703 fancy_abort(char const*, int, char const*)
	../../trunk/gcc/diagnostic.c:1057
0x5bc3ee cp_lexer_new_from_tokens
	../../trunk/gcc/cp/parser.c:638
0x5bc3ee cp_parser_push_lexer_for_tokens
	../../trunk/gcc/cp/parser.c:3293
0x5c5510 cp_parser_late_parsing_for_member
	../../trunk/gcc/cp/parser.c:21741
0x5c5510 cp_parser_class_specifier_1
	../../trunk/gcc/cp/parser.c:18210
0x5c5510 cp_parser_class_specifier
	../../trunk/gcc/cp/parser.c:18234
0x5c5510 cp_parser_type_specifier
	../../trunk/gcc/cp/parser.c:13393
0x5dd56d cp_parser_decl_specifier_seq
	../../trunk/gcc/cp/parser.c:10734
0x5e00d7 cp_parser_single_declaration
	../../trunk/gcc/cp/parser.c:21344
0x5e1211 cp_parser_template_declaration_after_export
	../../trunk/gcc/cp/parser.c:21231
0x5ea9f9 cp_parser_declaration
	../../trunk/gcc/cp/parser.c:10186
0x5e9507 cp_parser_declaration_seq_opt
	../../trunk/gcc/cp/parser.c:10108
0x5eae92 cp_parser_translation_unit
	../../trunk/gcc/cp/parser.c:3760
0x5eae92 c_parse_file()
	../../trunk/gcc/cp/parser.c:27585
0x6ed0c4 c_common_parse_file()
	../../trunk/gcc/c-family/c-opts.c:1137
0xa2017b compile_file
	../../trunk/gcc/toplev.c:546
0xa21d89 do_compile
	../../trunk/gcc/toplev.c:1863
0xa21d89 toplev_main(int, char**)
	../../trunk/gcc/toplev.c:1939
0x7fb0a50d8c4c ???
	???:0
0x4c6db8 ???
	???:0
Please submit a full bug report,
with preprocessed source if appropriate.
See <http://gcc.gnu.org/bugs.html> for instructions.


So, big deal.  You can get a stack backtrace from gdb anyhow.

For a more interesting use I hacked ggc-common.c to collect detailed
statistics when used with -fmem-report.  This gives us data similar to,
and better than, that you get when you configure GCC with
--enable-gather-detailed-mem-stats.  However, with this approach you do
not need to recompile GCC.  Running this modified GCC with -fmem-report
-O2 -g combine.ii took 36 seconds.  The full report is too large to
attach here, but here are the last few entries of the ggc-common.c.
Note that I spent exactly 0 seconds making the report pretty.

0xbf1151 ../../trunk/gcc/tree.c:7607 build_function_type(tree_node*, tree_node*)
0x50f1c0 ../../trunk/gcc/cp/decl.c:9346 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq const*, decl_context, int, tree_node**)
0x514a75 ../../trunk/gcc/cp/decl.c:4366 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, tree_node*, tree_node*, tree_node**)
0x5dbeca ../../trunk/gcc/cp/parser.c:15720 cp_parser_init_declarator
0x5de4ba ../../trunk/gcc/cp/parser.c:10445 cp_parser_simple_declaration
0x5e6337 ../../trunk/gcc/cp/parser.c:10326 cp_parser_block_declaration
0x5ea8fb ../../trunk/gcc/cp/parser.c:10222 cp_parser_declaration
0x5e9507 ../../trunk/gcc/cp/parser.c:10108 cp_parser_declaration_seq_opt
0x5eae92 ../../trunk/gcc/cp/parser.c:3760 cp_parser_translation_unit
0x5eae92 ../../trunk/gcc/cp/parser.c:27585 c_parse_file()
0x6ed0c4 ../../trunk/gcc/c-family/c-opts.c:1137 c_common_parse_file()
0xa2017b ../../trunk/gcc/toplev.c:546 compile_file
0xa21d89 ../../trunk/gcc/toplev.c:1863 do_compile
0xa21d89 ../../trunk/gcc/toplev.c:1939 toplev_main(int, char**)
0x7f4044f36c4c ???:0 ???
0x4c6db8 ???:0 ???
    611352: 1.0%          0: 0.0%     181776: 0.6%          0: 0.0%       4721
0xbf342f ../../trunk/gcc/tree.c:1224 build_int_cst_wide(tree_node*, unsigned long, long)
0xbf37a5 ../../trunk/gcc/tree.c:1065 double_int_to_tree(tree_node*, double_int)
0xbf37ea ../../trunk/gcc/tree.c:1042 build_int_cst(tree_node*, long)
0xa19fee ../../trunk/gcc/stor-layout.c:2545 set_min_and_max_values_for_integral_type(tree_node*, int, bool)
0x502788 ../../trunk/gcc/cp/decl.c:12345 finish_enum_value_list(tree_node*)
0x5d53d4 ../../trunk/gcc/cp/parser.c:14609 cp_parser_enum_specifier
0x5c4c1d ../../trunk/gcc/cp/parser.c:13365 cp_parser_type_specifier
0x5dd56d ../../trunk/gcc/cp/parser.c:10734 cp_parser_decl_specifier_seq
0x5de309 ../../trunk/gcc/cp/parser.c:10377 cp_parser_simple_declaration
0x5e6337 ../../trunk/gcc/cp/parser.c:10326 cp_parser_block_declaration
0x5ea8fb ../../trunk/gcc/cp/parser.c:10222 cp_parser_declaration
0x5e9507 ../../trunk/gcc/cp/parser.c:10108 cp_parser_declaration_seq_opt
0x5eae92 ../../trunk/gcc/cp/parser.c:3760 cp_parser_translation_unit
0x5eae92 ../../trunk/gcc/cp/parser.c:27585 c_parse_file()
0x6ed0c4 ../../trunk/gcc/c-family/c-opts.c:1137 c_common_parse_file()
0xa2017b ../../trunk/gcc/toplev.c:546 compile_file
0xa21d89 ../../trunk/gcc/toplev.c:1863 do_compile
0xa21d89 ../../trunk/gcc/toplev.c:1939 toplev_main(int, char**)
0x7f4044f36c4c ???:0 ???
0x4c6db8 ???:0 ???
         0: 0.0%          0: 0.0%     837344: 2.8%     276192:16.2%        137
0xc147e7 ../../trunk/gcc/var-tracking.c:8568 emit_note_insn_var_location
0xf18f08 ../../trunk/libiberty/hashtab.c:784 htab_traverse
0xc22ea7 ../../trunk/gcc/var-tracking.c:8756 emit_notes_for_changes
0xc23054 ../../trunk/gcc/var-tracking.c:8870 emit_notes_for_differences
0xc23054 ../../trunk/gcc/var-tracking.c:9245 vt_emit_notes
0xc23b49 ../../trunk/gcc/var-tracking.c:10048 variable_tracking_main_1
0xc23b49 ../../trunk/gcc/var-tracking.c:10062 variable_tracking_main()
0x97de5e ../../trunk/gcc/passes.c:2157 execute_one_pass(opt_pass*)
0x97e214 ../../trunk/gcc/passes.c:2212 execute_pass_list(opt_pass*)
0x97e226 ../../trunk/gcc/passes.c:2213 execute_pass_list(opt_pass*)
0x97e226 ../../trunk/gcc/passes.c:2213 execute_pass_list(opt_pass*)
0x7782d7 ../../trunk/gcc/cgraphunit.c:1609 expand_function
0x77a179 ../../trunk/gcc/cgraphunit.c:1714 expand_all_functions
0x77a179 ../../trunk/gcc/cgraphunit.c:2012 compile()
0x77a774 ../../trunk/gcc/cgraphunit.c:2089 finalize_compilation_unit()
0x5aa0ba ../../trunk/gcc/cp/decl2.c:4024 cp_write_global_declarations()
0xa201c4 ../../trunk/gcc/toplev.c:560 compile_file
0xa21d89 ../../trunk/gcc/toplev.c:1863 do_compile
0xa21d89 ../../trunk/gcc/toplev.c:1939 toplev_main(int, char**)
0x7f4044f36c4c ???:0 ???
0x4c6db8 ???:0 ???
    872704: 1.5%          0: 0.0%          0: 0.0%          0: 0.0%      13636
0xbf03e8 ../../trunk/gcc/tree.c:4093 build_decl_stat(unsigned int, tree_code, tree_node*, tree_node*)
0x5bb085 ../../trunk/gcc/cp/lex.c:532 build_lang_decl_loc(unsigned int, tree_code, tree_node*, tree_node*)
0x516729 ../../trunk/gcc/cp/decl.c:7175 grokfndecl
0x5129fd ../../trunk/gcc/cp/decl.c:10394 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq const*, decl_context, int, tree_node**)
0x514a75 ../../trunk/gcc/cp/decl.c:4366 start_decl(cp_declarator const*, cp_decl_specifier_seq*, int, tree_node*, tree_node*, tree_node**)
0x5dbeca ../../trunk/gcc/cp/parser.c:15720 cp_parser_init_declarator
0x5de4ba ../../trunk/gcc/cp/parser.c:10445 cp_parser_simple_declaration
0x5e6337 ../../trunk/gcc/cp/parser.c:10326 cp_parser_block_declaration
0x5ea8fb ../../trunk/gcc/cp/parser.c:10222 cp_parser_declaration
0x5e9507 ../../trunk/gcc/cp/parser.c:10108 cp_parser_declaration_seq_opt
0x5eae92 ../../trunk/gcc/cp/parser.c:3760 cp_parser_translation_unit
0x5eae92 ../../trunk/gcc/cp/parser.c:27585 c_parse_file()
0x6ed0c4 ../../trunk/gcc/c-family/c-opts.c:1137 c_common_parse_file()
0xa2017b ../../trunk/gcc/toplev.c:546 compile_file
0xa21d89 ../../trunk/gcc/toplev.c:1863 do_compile
0xa21d89 ../../trunk/gcc/toplev.c:1939 toplev_main(int, char**)
0x7f4044f36c4c ???:0 ???
0x4c6db8 ???:0 ???
         0: 0.0%        864: 0.0%    1348128: 4.5%     149888: 8.8%       4684
0xb86a21 ../../trunk/gcc/tree-ssanames.c:140 make_ssa_name_fn(function*, tree_node*, gimple_statement_d*)
0xa7a3c1 ../../trunk/gcc/tree-flow-inline.h:1144 make_ssa_name
0xa7a3c1 ../../trunk/gcc/tree-into-ssa.c:1396 rewrite_stmt
0xa7a3c1 ../../trunk/gcc/tree-into-ssa.c:1471 rewrite_enter_block
0xe275fa ../../trunk/gcc/domwalk.c:188 walk_dominator_tree(dom_walk_data*, basic_block_def*)
0xa7bc70 ../../trunk/gcc/tree-into-ssa.c:2265 rewrite_blocks
0xa7bf97 ../../trunk/gcc/tree-into-ssa.c:2432 rewrite_into_ssa
0x97de5e ../../trunk/gcc/passes.c:2157 execute_one_pass(opt_pass*)
0x97e214 ../../trunk/gcc/passes.c:2212 execute_pass_list(opt_pass*)
0x97d37c ../../trunk/gcc/passes.c:1702 do_per_function_toporder(void (*)(void*), void*)
0x97e6ab ../../trunk/gcc/passes.c:2526 execute_ipa_pass_list(opt_pass*)
0x779fe1 ../../trunk/gcc/cgraphunit.c:1838 ipa_passes
0x779fe1 ../../trunk/gcc/cgraphunit.c:1961 compile()
0x77a774 ../../trunk/gcc/cgraphunit.c:2089 finalize_compilation_unit()
0x5aa0ba ../../trunk/gcc/cp/decl2.c:4024 cp_write_global_declarations()
0xa201c4 ../../trunk/gcc/toplev.c:560 compile_file
0xa21d89 ../../trunk/gcc/toplev.c:1863 do_compile
0xa21d89 ../../trunk/gcc/toplev.c:1939 toplev_main(int, char**)
0x7f4044f36c4c ???:0 ???
0x4c6db8 ???:0 ???
   1005760: 1.7%          0: 0.0%     359680: 1.2%          0: 0.0%      17068
0xa1ca7d ../../trunk/gcc/stringpool.c:75 alloc_node
0xef2dc7 ../../trunk/libcpp/symtab.c:158 ht_lookup_with_hash(ht*, unsigned char const*, unsigned long, unsigned int, ht_lookup_option)
0xee88de ../../trunk/libcpp/lex.c:1232 lex_identifier
0xeeadcf ../../trunk/libcpp/lex.c:2205 _cpp_lex_direct
0xeeb96b ../../trunk/libcpp/lex.c:1974 _cpp_lex_token
0xeefce7 ../../trunk/libcpp/macro.c:2357 cpp_get_token_1
0x6e6622 ../../trunk/gcc/c-family/c-lex.c:299 c_lex_with_flags(tree_node**, unsigned int*, unsigned char*, int)
0x5bf66f ../../trunk/gcc/cp/parser.c:719 cp_lexer_get_preprocessor_token
0x5ead40 ../../trunk/gcc/cp/parser.c:598 cp_lexer_new_main
0x5ead40 ../../trunk/gcc/cp/parser.c:3216 cp_parser_new
0x5ead40 ../../trunk/gcc/cp/parser.c:27582 c_parse_file()
0x6ed0c4 ../../trunk/gcc/c-family/c-opts.c:1137 c_common_parse_file()
0xa2017b ../../trunk/gcc/toplev.c:546 compile_file
0xa21d89 ../../trunk/gcc/toplev.c:1863 do_compile
0xa21d89 ../../trunk/gcc/toplev.c:1939 toplev_main(int, char**)
0x7f4044f36c4c ???:0 ???
0x4c6db8 ???:0 ???
     16016: 0.0%          0: 0.0%    1564728: 5.2%          0: 0.0%      17963
0xbf03e8 ../../trunk/gcc/tree.c:4093 build_decl_stat(unsigned int, tree_code, tree_node*, tree_node*)
0x59de96 ../../trunk/gcc/cp/decl2.c:181 cp_build_parm_decl(tree_node*, tree_node*)
0x5133de ../../trunk/gcc/cp/decl.c:10054 grokdeclarator(cp_declarator const*, cp_decl_specifier_seq const*, decl_context, int, tree_node**)
0x5defbc ../../trunk/gcc/cp/parser.c:17116 cp_parser_parameter_declaration_list
0x5df444 ../../trunk/gcc/cp/parser.c:17030 cp_parser_parameter_declaration_clause
0x5d6aee ../../trunk/gcc/cp/parser.c:16090 cp_parser_direct_declarator
0x5d6aee ../../trunk/gcc/cp/parser.c:15961 cp_parser_declarator
0x5dbb67 ../../trunk/gcc/cp/parser.c:15537 cp_parser_init_declarator
0x5de4ba ../../trunk/gcc/cp/parser.c:10445 cp_parser_simple_declaration
0x5e6337 ../../trunk/gcc/cp/parser.c:10326 cp_parser_block_declaration
0x5ea8fb ../../trunk/gcc/cp/parser.c:10222 cp_parser_declaration
0x5e9507 ../../trunk/gcc/cp/parser.c:10108 cp_parser_declaration_seq_opt
0x5eae92 ../../trunk/gcc/cp/parser.c:3760 cp_parser_translation_unit
0x5eae92 ../../trunk/gcc/cp/parser.c:27585 c_parse_file()
0x6ed0c4 ../../trunk/gcc/c-family/c-opts.c:1137 c_common_parse_file()
0xa2017b ../../trunk/gcc/toplev.c:546 compile_file
0xa21d89 ../../trunk/gcc/toplev.c:1863 do_compile
0xa21d89 ../../trunk/gcc/toplev.c:1939 toplev_main(int, char**)
0x7f4044f36c4c ???:0 ???
0x4c6db8 ???:0 ???
     32640: 0.1%          0: 0.0%    1555328: 5.2%          0: 0.0%      12406
Total                                              59553548         38936868         29879567          1701879          1921781
    Garbage            Freed             Leak         Overhead            Times



As you can see, this gives us the opportunity for some fairly detailed
analysis of where we are allocating memory, without requiring the
compiler to be recompiled, and without taking an inordinate amount of
time.


I expect to use this code not just for GCC proper, but also for libgo
(currently libgo uses Go code to parse DWARF, but that is not very
satisfactory as that code is only available if it has been imported into
the program).  So I put it under a BSD license, although that is open
for discussion.  Also in case it finds more uses elsewhere I wrote it in
reasonably portable C rather than C++.


I've attached two patches.  The first is the patch for the libbacktrace
library, plus the changes to the top level configure.ac and
Makefile.def.  The second is the changes to GCC proper that I used to
generate the above dumps.  The second patch is just quick and dirty work
to see if the library could work well.


Does this seem like something we could usefully add to GCC?  Does
anybody see any big problems with it?

The library is not quite ready to commit, but it's quite close.  It just
needs a bit more testing in uncommon build environments, i.e., anything
other than x86_64 GNU/Linux, to make sure that it at least builds and
does not crash even when it can't get a backtrace.

Ian


-------------- next part --------------
A non-text attachment was scrubbed...
Name: foo.patch
Type: text/x-diff
Size: 128174 bytes
Desc: libbacktrace
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20120829/eb347e57/attachment.bin>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: foo1.patch
Type: text/x-diff
Size: 8576 bytes
Desc: gcc patches
URL: <https://gcc.gnu.org/pipermail/gcc/attachments/20120829/eb347e57/attachment-0001.bin>


More information about the Gcc mailing list