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() { } } }