Skip to content

Latest commit

 

History

History
90 lines (74 loc) · 4.08 KB

File metadata and controls

90 lines (74 loc) · 4.08 KB

Ditch Your Debugger

This article describes an alternative approach. There’s a tiny source library (just a single .c/.h pair) that implements some of these ideas, and an optional demo setup for it.

Study first, then type. The items below are best used to test beliefs, not create them.

Things You Need to Avoid the Debugger

  • Convenient checkpoints and value output. See the the CP(), TV() and TS() macros from the source library, or make editor macros for things like this:

    printf ("%s:%i:%s: checkpoint\n", __FILE__, __LINE__, __func__);

    If you don’t like having to tell printf() what type you’re printing when the compiler already knows, check out the the PT() and TP() macros from the optional format_free_print.h header in the source library download.

  • A way to get a backtrace. The (GNU-specific) backtrace() function and the addr2line program can do this. See the backtrace_with_line_numbers() function or BT_ASSERT() macro from the source library.

  • A way to look up the function and source location pointed to by a function pointer, so you can use instrumentation to find out what’s going to be called from a given point at run time. See what_func() from the source library which does this using the nm program and dladdr() function.

  • A strategy for dealing with memory errors. I use valgrind like this:

    valgrind --leak-check=yes --undef-value-errors=no ./my_exe my_exe_arg 2>&1 | tee /tmp/valgrind_log

    Valgrind looks sort of like a debugger, but you don’t have to operate inside it. There are other options, however.

  • A strategy for exploring your program’s call tree and sources statically. I use vim and cscope for C, and GNU global or exuberant ctags for other things. For whole-system exploration I like the HTML call graph and linked sources that global produces. The source library includes an example of how to integrate GNU cflow and global into your build system (in Makefile and cflow_and_global.mk files).

  • A decent build system, i.e. one that can rebuild your program fast. There are several things that may help with this:

    • The ccache program caches the results of compilation commands and reuses them when appropriate. It’s particularly helpful when your build system often rebuilds too much. It’s simple to use: just replacing gcc with ccache gcc in your compilation recipes is usually enough. See the Makefile in the source library for an example.

    • GNU binutils includes a new linker called gold. It can do incremental linking, which is much faster for large projects. See the Makefile in the source library for details.

    • The GNU automake and autoconf systems can add dependency tracking to your program automatically. They aren’t simple to use generally, but if you know you’re headed in that direction anyway it might be worth adopting them sooner rather than later.

This stuff can be extended arbitrarily. If you need to write some code to visualize your data you can do so in the most natural way using the language at hand, without any discontinuity between your basic instrumentation and those extensions.