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?
Function call stack in C is a dynamic data structure where elements are stored at contiguous memory locations. Function call stack is maintained for every function call where it contains its own local variables and parameters of the callee function.
During a function call, a function may accept one or more inputs as arguments, process them and return the result to the calling program. For example, in function call sqrt (x), the sqrt function accepts the value of x as input and returns its square root.
Calling a FunctionWhen a program calls a function, the program control is transferred to the called function. A called function performs a defined task and when its return statement is executed or when its function-ending closing brace is reached, it returns the program control back to the main program.
The CALL statement transfers control from one object program to another within the run unit. The program containing the CALL statement is the calling program; the program identified in the CALL statement is the called subprogram.
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 use nm
to figure out the real function which contains this address.
You can't get the function parameters this way.
With the GNU C Library, you can use the backtrace
module. Here is an example for that:
#include <stdio.h>
#include <execinfo.h>
#include <stdlib.h>
void handler(char *caller) {
void *array[10];
size_t size;
printf("Stack Trace Start for %s\n",caller);
size = backtrace(array, 10);
backtrace_symbols_fd(array, size, 2);
printf("Stack Trace End\n");
}
void car() {
handler("car()");
printf("Continue Execution");
}
void baz() {car(); }
void bar() { baz(); }
void foo() { bar(); }
int main(int argc, char **argv) {
foo();
}
compile with -g -rdynamic
compiler option to load the symbols
gcc -g -rdynamic Test1.c -o Test
You will see an output similar to
Stack Trace Start for car()
./Test(handler+0x2d)[0x80486f1]
./Test(car+0x12)[0x804872e]
./Test(baz+0xb)[0x8048747]
./Test(bar+0xb)[0x8048754]
./Test(foo+0xb)[0x8048761]
./Test(main+0xb)[0x804876e]
/lib/i386-linux-gnu/libc.so.6(__libc_start_main+0xe7)[0x126e37]
./Test[0x8048631]
Stack Trace End
Continue Execution in car
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With