Printing stack trace
Printing stack trace
Basically I don’t like JAVA as it’s principles doesn’t coincide with what ever I have learnt. But I adore the programming ease it provides to developers i.e., interface provided.
Most of the times I will be working on Linux and gcc. So I thought how to do it on Linux. While searching I stumbled across a libc function back trace. Voilla!!! I thought I got what I was searching for.
void *traces[MAX_STACK_DEPTH] ;backtrace(traces, MAX_STACK_DEPTH) ;
backtrace gives u the traces once u specify MAX_STACK_DEPTH. These traces are nothing but pointers in ur code segment.
OK fine. libc developers thought about that and provided one more function backtrace_symbols. It accepts those traces and returns function name and offset within the function.
function_names = (char **)backtrace_symbols(traces, trace_size) ;
Now let us reiterate what we have discussed. Basically I want to find stack trace of the function I am in. Following code snippet illustrates that.
void fn(int ) ;
void fn(double , char ) ;
void show_stack_frame(int, double ) ;
char *pszProgramName ;
int main(int argc, char *argv[])
{
pszProgramName = argv[0] ;
fn(5) ;
return 0 ;
}
void fn(int x)
{
fn(6.78, 'a') ;
}
void fn(double y, char c)
{
show_stack_frame(5, 8.9) ;
}
void show_stack_frame(int x,double y)
{
void *traces[10] ;
char **function_names ;
int i ;
int trace_size = backtrace(traces, 10) ;
function_names = (char **)backtrace_symbols(traces, trace_size) ;
for(i = 0 ; i < style="">printf("%d: %s\n", i, function_names[i]) ;
}
Compile this program using –rdynamic flag. This is needed to get appropriate function names.
$ g++ -g -rdynamic main.cc –o main
Once u run this program u get following ouput.
0: ./main(_Z16show_stack_frameid+0x20) [0x8048938]
1: ./main(_Z3fn1dc+0x2c) [0x8048912]
2: ./main(_Z3fn1i+0x1a) [0x80488e0]
3: ./main(main+0x24) [0x80488bc]
4: /lib/tls/libc.so.6(__libc_start_main+0xe4) [0x42015574]
5: ./main(_ZNSt8ios_base4InitD1Ev+0x31) [0x8048809] <>
Looks good. But still function names and prefixed and appended with ugly characters. What’s that? I have never given such names to my function in my life.
This is called mangling. One of the biggest grieves for novices when they come to C++.
C++ allows u to overload functions. But when it comes to linker only thing it knows is the function name and its relocatable address. So how would compiler notify linker that there exists two fn functions accepting different set of parameters.
Simple generate a function name based on parameters it accepts and use it for internal purposes. That’s exactly is being done as shown in output.
If there exists a function fn with signature:
void fn(int ) ;then mangled name will be:
_Z3fni.
(1) Function name: fn
(2) Parameter it accepts: i stands for int.
GCC site will give u all the data types and equivalent mangled names.
Now what do u expect me to do? Get a list of all the mangled equivalents and translate into equivalent ones? No. don’t worry. There is an utility program available to do for exactly that purpose. c++filt which takes a mangled name and gives equivalent demangled one.
fn1(int)
Gr8. Now what do u expect? Invoke c++filt on each of these mangled name and get the demangled name. Also I need source file and line no. info. Where do I get them from?
addr2line is a bin utility program which accepts an executable and address and gives demangled function name, source file and line no. info.
$ addr2line -e main -fC 0x8048938
show_stack_frame(int, double)
/home/prasad/StackTrace/main.cc:40
Gr8. Now u want me to replace c++filt with addr2line to get this extra info. No. Don’t worry. We will discuss how to get the required stack info. programmatically in next section.
Till that happy hacking into bin util programs. Have fun!!.

1 Comments:
I think this is a very good feature, but arn't you copying "java". I'm damm sure u must be a big fan of java...U should change ur name to Cool-Java-Coder.
On a serous note, is this stack tracing portable to other platforms??
Post a Comment
Subscribe to Post Comments [Atom]
<< Home