Wednesday, August 10, 2005

Runtime traces for C

While porting some software from Windows to Linux, I needed to see backtraces. If there is no global exception handler and an exception in C++ is not caught, it aborts the program. The reports I got went along the lines of some program output:

$ run_foo
Aborted.

Not very helpful!

So I wrote a small pair of trace macros based on the GNU C Library's backtrace facility. Although this facility is only available for UNIX and Linux platforms, my tracing macros still are helpful under Windows sans backtracing.

#ifndef TRACE_H_
#define TRACE_H_

#include <stdio.h>
#include <stdlib.h>

#define TRACE_BACKTRACE_FRAMES 10

#ifdef __GNUC__
# define __FUNCTION__ __PRETTY_FUNCTION__
#endif

/* Emacs-style output */
#ifdef EMACS
# define TRACE_PREFIX   fprintf (stderr, "%s:%d:%s", __FILE__, __LINE__, __FUNCTION__)
#else
# define TRACE_PREFIX   fprintf (stderr, "%s(%d):%s", __FILE__, __LINE__, __FUNCTION__)
#endif /* EMACS */

#ifdef linux
# include <execinfo.h>

# define TRACE_DUMP()   do {     void *array[TRACE_BACKTRACE_FRAMES];     int n = backtrace (array, sizeof (array) / sizeof (void *));     char **symbols = backtrace_symbols (array, n);     int i;      for (i = 0; i < n; ++i)       fprintf (stderr, " -[%d]%s\n", i, symbols[i]);      free (symbols);   } while (0)
#else
# define TRACE_DUMP()
#endif /* linux */

#define TRACE()   TRACE_PREFIX; fprintf (stderr, "\n");   TRACE_DUMP ()

#define TRACE_MSG(MSG)   TRACE_PREFIX; fprintf (stderr, ": %s\n", MSG);   TRACE_DUMP ()

#endif /* TRACE_H_ */

Use the EMACS define to switch between Emacs-style and regular line tracing.

UPDATE: I meant to provide sample output:

trace.c(9):bob: Some interesting debug message.
 -[0]./trace(bob+0x51) [0x804878d]
 -[1]./trace(main+0x21) [0x8048817]
 -[2]/lib/tls/libc.so.6(__libc_start_main+0xd0) [0x4021de80]
 -[3]./trace [0x80486a1]

One thing jumps out immediately: this is not Java. But one can tease out that main called bob and bob wrote a trace message. Notice this:

trace.c(9):bob: Some interesting debug message.
 -[0]./trace(main+0x51) [0x8048841]
 -[1]/lib/tls/libc.so.6(__libc_start_main+0xd0) [0x4021de80]
 -[2]./trace [0x80486a1]

That is the same output with -O3 passed to GCC. The compiler inlines away the trivial bob function. -O2 did not inline the function.

No comments: