Poor man’s function_graph trace for C programs
When studying Linux kernel sources, it’s often helpful to use ftrace’s
function_graph tracer, which traces function entry and exit points
and clearly shows how functions call each other.
Sometimes, it is useful to get such a trace from other code than the
Linux kernel. In case of C++ this is pretty easy, but for plain C, it
is trickier. I came up with the following to print nice traces. It
uses GCC cleanup variable attribute to register a function exit
callback.
#include <stdio.h>
int trace_indent = 2;
char trace_filler[] = {[0 ... 99] = ' '};
static void trace_end(const char **func)
{
trace_indent--;
fprintf(stderr, "%.*s}\n", 4*trace_indent, trace_filler);
}
#define TRACE(format, ...) \
const char *__tracer __attribute__ ((__cleanup__(trace_end))) = __func__; \
fprintf(stderr, "%.*s%s(" format ") {\n", 4*trace_indent, trace_filler, __func__, ##__VA_ARGS__); \
trace_indent++;It can be used this way:
void bar()
{
TRACE();
}
void foo(char *str)
{
TRACE("str=%s", str);
bar();
}
int main(int argc, char *argv[])
{
TRACE("argc=%d", argc);
foo("xxx");
return 0;
}When this program is run, it prints:
main(argc=1) {
foo(str=xxx) {
bar() {
}
}
}
Tags: