Without modifying the source code, how can i trace which functions are called and with what parameters, when some function(say func100 in the following example) is invoked. I would like the output to be as follows:
enter func100(p1001=xxx,p1002=xxx)
enter func110(p1101=xxx,p1102=xxx)
exit func110(p1101=xxx,p1102=xxx)
enter func120(p1201=xxx,p1202=xxx,p1203=xxx)
enter func121(p1211=xxx)
exit func121(p1211=xxx)
exit func120(p1201=xxx,p1202=xxx,p1203=xxx)
exit func100(p1001=xxx,p1002=xxx)
is this doable? or what's the solution with minimum modification of source code?
With the GNU C Library, you can use the
backtrace
module. Here is an example for that:compile with
-g -rdynamic
compiler option to load the symbolsYou will see an output similar to
You can write this handler function and call from anywhere in your program at any number of time. Remember to increase the
array
size as required.Sometimes I have to trace lots of function calls, even for external libraries I don't have any control, or I don't want to modify.
Sometime ago, I realized that you can combine gdb's regular expression breakpoints (regular ones are ok, too) and then just execute a set of commands to be run each time those breakpoints are triggered. See: http://www.ofb.net/gnu/gdb/gdb_35.html
For example, if you want to trace all the functions which start with "MPI_" prefix, you can do:
Silent command is used to hide gdb messages when a breakpoint is found. I usually print a couple of empty lines, so that it is easier to read.
Then, you just run the program: (gdb) run
Once your program starts running, gdb will print the N topmost backtrace levels.
If you want more detailed information, printing local variables of a given breakpoint is also possible, just insert more commands between
command
andend
.Bonus tip: add all of these to your
.gdbinit
file and pipe the execution into a file.I also encountered this problem of having good function call traces. Therefore, I wrote a Python GDB script (https://gist.github.com/stettberger/e6f2fe61206471e22e9e6f1926668093) that sets a breakpoint on every interesting function (defined by the environment variable TRACE_FUNCTION). GDB then invokes the python function, which decodes the frame and all its arguments. If it encounters a pointer it tries to dereference it and so print a function call trace to TRACE_FILE (default: /tmp/log) with arguments. For the following program
I get a detailed trace, where every line is a python tuple that can be read with
eval()
:The gist contains more information on the log file format.
If you use
gcc
, you can use the-finstrument-functions
compilation flag. It adds code that calls two functions,__cyg_profile_func_enter
and__cyg_profile_func_exit
, whenever a function enters/exits.You'll need to implement these functions, to do what you want. Make sure to compile them either without the flag, or with
attribute((no_instrument_function))
, so they won't try to call themselves.The functions' second parameter would be a pointer to the call site (i.e. the return address within the calling function). You can just print it with
%p
, but it will be somewhat hard to use. You can usenm
to figure out the real function which contains this address.You can't get the function parameters this way.
If you were on linux, callgrind might help. It basically collects statistics of what you're looking for, so, it might provide a way to access its raw data.
You can look into log4cxx, a project hosted by the apache foundation. I know that log4j, the java variant allowed you to set the sensitivity, and you could track every single thing that was done in the program. Maybe that the c++ variant is the same, but there are several alternatives-there's an aspect oriented c++ compiler, and you can define an aspect across all functions, and have it catch and print the variables. Another alternative is to use a debugger.
To summarize: debugger, log4cxx or AOP