The gcc design and maintainers are not oriented towards strong compile-time verification of (for example) gcc machine descriptions. Gcc machine descriptions are essentially macro-expanded into C code without much checking by a series of genfoo.c programs, leaving most machine description debugging to be done at runtime, with gdb being the tool of choice, preferably under emacs.
This is a somewhat unfortunate state of affairs, but for the moment it is what it is.
It took me quite awhile to figure out how to debug gcc effectively with this toolset; perhaps the following hints will save you some time.
The main issue when debugging gcc with gdb is that the gcc executable itself is just a small driver; the real work is mostly done in the cc1 executable, and consequently that is where the bugs breed and that is the executable you usually want to be connected to in gdb.
The two critical tools for accomplishing this are
Following are detailed instructions for doing the above in just twenty easy steps. They reflect my way of doing things — your way will probably differ, but they should get you started.
Assume that you have a stimulus program stimulus.c which is crashing gcc and that you are trying to debug the crash.
toprintf ("#line %d \"%s\"\n", loc->lineno, loc->filename);
in 766:read-rtl.c because the #lines do more harm than good in my experience. (they try to map the generated code back to the .md file, but the result just looks totally crazy when you're in gdb).printf ("/* #line %d \"%s\" */\n", loc->lineno, loc->filename);
or perhaps insteadrm TAGS find . | egrep '\.(texi|c|h|md)$' | xargs etags --append
where mymachine is the target architecture of interest.rm TAGS etags gcc/*.[ch] libiberty/*.[ch] gcc/config/mymachine/*.[ch]
Save the full cc1 path, (say) in emacs register 'c' via C-x r s c.
Save the rest of the line, say in emacs buffer 'xxx', and add run to the start, yielding something like
run -fpreprocessed stimulus.i -quiet -dumpbase stimulus.i -auxbase stimulus -O2 -fPIC -o ccNHpl1b.s
(The emacs gdb docs are here.)M-: (setq gdb-many-windows t) M-: (setq gdb-use-separate-io-buffer nil)
You can also set breakpoints in gcc sourcecode buffers just doing C-x <SPC>break _start break main break instantiate_virtual_regs break 'function.c':1705 break 'passes.c':init_optimization_passes break tree_rest_of_compilation break c_expand_body break recog_for_combine break rest_of_handle_combine
If line2 827-828 in your 'passes.c' file contain
then one way to set up pass narration is to in the gdb buffer doif (pass->execute) pass->execute();
This will set a breakpoint on line 828 and print out the name of the pass when stopping at it.break 'passes.c':828 commands p/s pass->name end
If you only want to stop at a given pass, say "ivopts", you might instead do
(For more information on this sort of stuff check out the gdb manual.)break 'passes.c':828 commands p/s pass->name end condition strcmp(pass->name,"ivopts")==0 end
so if you like to save keystrokes you might define gdb shortcutscall debug_rtx(insn) call debug_rtx_list(insn) call debug_tree(tree)
so that you can then type justdefine rx call debug_rtx($arg0) end define rxl call debug_rtx_list($arg0) end define tx call debug_tree($arg0) end
at the gdb prompt. You might want to save these definitions in a file so that you can read them with a gdb source command. (For more about gdb functions see the User-defined Commands section of the gdb manual.)rx(insn) rxl(insn) tx(tree)
so that gdb's current working directory is the directory containing your stimulus.c program.cd /path/to/stim
These commands tell gdb where to look for gcc source code. You'll probably want to specify three directories, as above, one each for the original gcc mainline code, the platform-specific gcc code, and the code generated from your mymachine.md machine description file.dir /path/to/gcc dir /path/to/gcc/config/mymachine dir /path/to/generated/code
run -fpreprocessed stimulus.i -quiet -dumpbase stimulus.i -auxbase stimulus -O2 -fPIC -o ccNHpl1b.s
And you're off single-stepping through the code using the gdb n(ext), s(tep), c(ontinue) commands etc. (The gnu manual section on them is here.) Wasn't that easy?
Two additional hints:
Finally, here is a complete list of debug_*() functions intended for interactive use from gdb. (You can of course also call other C functions interactively from gdb.) In general, you shouldn't try to memorize this list, just be aware that there a lot of such functions, and remember to look for them when you're in a particular part of the compiler where there is a datastructure you need to prettyprint interactively:
gcc/basic-block.h: void debug_bb (basic_block); gcc/basic-block.h: basic_block debug_bb_n (int); gcc/basic-block.h: void debug_regset (regset); gcc/bitmap.h: void debug_bitmap (bitmap); gcc/cp/cp-tree.h: void debug_class (tree); gcc/cp/cp-tree.h: void debug_thunks (tree); gcc/cp/cp-tree.h: void debug_binfo (tree); gcc/df.h: void debug_df_insn (rtx); gcc/df.h: void debug_df_regno (unsigned int); gcc/df.h: void debug_df_reg (rtx); gcc/df.h: void debug_df_defno (unsigned int); gcc/df.h: void debug_df_useno (unsigned int); gcc/df.h: void debug_df_ref (struct ref *); gcc/df.h: void debug_df_chain (struct df_link *); gcc/diagnostic.h: void debug_generic_expr (tree); gcc/diagnostic.h: void debug_generic_stmt (tree); gcc/diagnostic.h: void debug_c_tree (tree); gcc/dwarf2out.h: void debug_dwarf (void); gcc/dwarf2out.h: void debug_dwarf_die (struct die_struct *); gcc/flags.h: enum debug_info_level debug_info_level; gcc/reload.h: void debug_reload_to_stream (FILE *); gcc/reload.h: void debug_reload (void); gcc/rtl.h: void debug_rtx (rtx); gcc/rtl.h: void debug_rtx_list (rtx, int); gcc/rtl.h: void debug_rtx_range (rtx, rtx); gcc/rtl.h: rtx debug_rtx_find (rtx, int); gcc/sbitmap.h: void debug_sbitmap (sbitmap); gcc/tree-flow.h: void debug_tree_bb (basic_block); gcc/tree-flow.h: basic_block debug_tree_bb_n (int); gcc/tree-flow.h: void debug_tree_cfg (int); gcc/tree-flow.h: void debug_cfg_stats (void); gcc/tree-flow.h: void debug_loop_ir (void); gcc/tree-flow.h: void debug_dfa_stats (void); gcc/tree-flow.h: void debug_referenced_vars (void); gcc/tree-flow.h: void debug_variable (tree); gcc/tree-flow.h: void debug_subvars_for (tree); gcc/tree-flow.h: void debug_may_aliases_for (tree); gcc/tree-flow.h: void debug_alias_info (void); gcc/tree-flow.h: void debug_points_to_info (void); gcc/tree-flow.h: void debug_points_to_info_for (tree); gcc/tree-flow.h: void debug_dominator_optimization_stats (void); gcc/tree-flow.h: void debug_value_expressions (tree); gcc/tree.h: void debug_tree (tree); gcc/tree.h: bool debug_find_tree (tree, tree); gcc/tree-ssa-operands.h: void debug_immediate_uses (void); gcc/tree-ssa-operands.h: void debug_immediate_uses_for (tree var); gcc/tree-ssa-structalias.h: void debug_constraint (constraint_t); gcc/tree-ssa-structalias.h: void debug_constraints (void); gcc/tree-ssa-structalias.h: void debug_solution_for_var (unsigned int); gcc/tree-ssa-structalias.h: void debug_sa_points_to_info (void); gcc/debug.h: void debug_nothing_void (void); gcc/debug.h: void debug_nothing_charstar (const char *); gcc/debug.h: void debug_nothing_int_charstar (unsigned int, const char *); gcc/debug.h: void debug_nothing_int (unsigned int); gcc/debug.h: void debug_nothing_int_int (unsigned int, unsigned int); gcc/debug.h: void debug_nothing_tree (tree); gcc/debug.h: void debug_nothing_tree_int (tree, int); gcc/debug.h: void debug_nothing_tree_tree (tree, tree); gcc/debug.h: bool debug_true_tree (tree); gcc/debug.h: void debug_nothing_rtx (rtx); gcc/debug.h: void debug_flush_symbol_queue (void); gcc/debug.h: void debug_queue_symbol (tree); gcc/debug.h: void debug_free_queue (void); gcc/debug.h: int debug_nesting;
[ Back to Cynbe's Gcc Debugging Hints ]