Pages

Tuesday, January 18, 2011

Trace function calls with GCC

     With gcc it is possible to trace offline the execution of a program. GNU GCC has a feature that allows to gather a function call tree. When you compile your program with a special instrumentation flag, and link with a trace library that contains 4 specific functions, you can mark every entrance end exit from functions. From GCC manual:
-finstrument-functions
Generate instrumentation calls for entry and exit to functions. Just 
after function entry and just before function exit, the following 
profiling functions will be called with the address of the current 
function and its call site. (On some platforms, __builtin_return_address
 does not work beyond the current function, so the call site information 
may not be available to the profiling functions otherwise.)
          void __cyg_profile_func_enter (void *this_fn,
                                         void *call_site);
          void __cyg_profile_func_exit  (void *this_fn,
                                         void *call_site);
     
The first argument is the address of the start of the current function, 
which may be looked up exactly in the symbol table.
    If a function does not need to be instrumented, it can be excluded, using __attribute__ ((no_instrument_function)) in the function definition. (This helps to tell gcc to not instrument __cyg_* profiling functions.)
Profiling functions for enter and exit:
void __attribute__ ((no_instrument_function))
__cyg_profile_func_enter (void *func, void *caller);
void __attribute__ ((no_instrument_function))
__cyg_profile_func_exit (void *func, void *call_site);

    When an instrumented function is called,__cyg_profile_func_enter is also called, passing in the address of the function called as func and the address from which the function was called as caller. Conversely, when a function exits, the __cyg_profile_func_exit function is called, passing the function's address as func and the actual site from which the function exits as call_site.
    Within these profiling functions, you can record the address pairs for later analysis. To request that gcc instrument all functions, every file must be compiled with the options -finstrument-functions and-g to retain debugging symbols.
    So, now you can provide profiling functions to gcc that it will transparently insert into your application's function entry and exit points. But when the profiling functions are called, what do you do with the addresses that are provided? One option would be to just write the addresses to a file, together with the time function enters and exits.
    There are other 2 functions invoked: constructor when main is called, and destructor when the application exits. To create them, create 2 functions and apply constructor and destructor attributes to them:
void __attribute__ ((constructor))
trace_begin (void);
void __attribute__ ((destructor))
trace_end (void)
    In constructor and destructor you can open the trace files, and in __cyg_profile_func_* register info like function address, caller address, and time. 
To resolve the addresses to actual function names, the Addr2line tool (which is part of the standard GNU Binutils) is an utility that translates an instruction address and an executable image into a filename, function name, and source line number. The usage for this tool is as follows:
$ addr2line.exe -f -e prog 0x004011FF
f
/cygdrive/d/work/prog.c:35
    Here prog is the binary name, and 0x004011FF is the function address. The information returned gives the function name and location.
Here is an example on how to use this feature to link a small problem with the trace library and view a call tree.

No comments:

Post a Comment