Stack unwinding (stack trace) with GCC

Via blog.bigpixel.ro:
I always liked the nice stack trace you get in some languages like java, c#, etc, with a nice clean trace of where the issue happent. Can we have this in C/C++ with gcc? Of course we can.

Let’s use the following code in which we try to display our stack trace (assumes you are building it with -g to enable debug symbols):

On some platforms, gcc has a built-in function called __builtin_return_address. The info file says something like:

__builtin_return_address (LEVEL)’
This function returns the return address of the current function,
or of one of its callers. The LEVEL argument is number of frames
to scan up the call stack. A value of `0′ yields the return
address of the current function, a value of `1′ yields the return
address of the caller of the current function, and so forth.

The availability and useability of this buil-in depends on platform, compiler,etc.
Guarded with this knowledge , we can build our first (and crude) backtrace:

void show_backtrace()
{
// get current address
void* p = __builtin_return_address(0);
printf("0x%x\n", p);
// get callee address
p = __builtin_return_address(1);
printf("0x%x\n", p);
// we cannot get more addresses as we don't have any
// information about how many leves of calls we have
}

running this will display something like:

$ ./a.out
0x4007be
0x4007ce

As we expected, it display the last two functions called before calling our function to display the backtrace. We could get more in-detail backtrace if we know how many levels to ask, but unfortunatelly we don’t know from where this function will be called. In any case it will be called at least from main()which is called from libc initialization function, so getting back two levels of stack trace should be safe. It display the two return addresses, altough we don’t have enough information yet for displaying a nice file:line no pair, but hey,this is more than nothing. And anyway, we’ll fix that later.

Investigating a bit more in detail, seems like the standard library offers a function backtrace() and two other helper functions to allow backtrace. One backtrace using this function could look similar to:

It is more than we get from the previous attempt, as we get now the entire stack trace, and we don’t have to be carefull about how many levels we unwind.

Still, is far from a nice file:line style of stack trace provided by the other languages. Time to get serious about. A bit more search on internet reveals a nice library called unwind. (can be found here). From the homepage we get the following:

The primary goal of this project is to define a portable and efficient C programming interface (API) to determine the call-chain of a program. […]

Sounds good. Let’s have an another approach of stack trace using this time the unwind library:

Now this looks quite useable, we have the function names, we have the instruction pointer address.

At this moment, half of the problem is solved, we have the list of functions through wich went the call, we have the addresses from where the call was made. All we need now is a way to convert this into a nice file:line type of strack trace. And from here things get dirty.

One way would be to use the readelf helper application, to retrieve the debug informations from the executable file and transform it in something which can be used easily:

This starts to look interesting. Before the stack dump (maybe at application startup), we can execute the above command with popen and load the list of file:line:address values, then when while displaying the stack trace, we can lookup int this list to display a nice stack trace with function in file:line format. Still, there is lot of info to be loaded, specially if our application is quite large.

There is an easier approach. There is a little known utility called addr2line, who has exactly the functionality we are looking for: if you give him and executable file and a address, it will try to transform it into function:file:line trio.

addr2line translates addresses into file names and line numbers. Given
an address in an executable or an offset in a section of a relocatable
object, it uses the debugging information to figure out which file name
and line number are associated with it.

This will complete nicelly our stack unwinding. First, we need a way from getting the trio from addr2line. With the parameters as specifed bellow, the helper program will output first the name of function, or ?? if cannot resolve it and on the second line will display the file and line information in filename:lineno format (or ??:0 if cannot find the info). For this example we skip over the function name as we already have it from libunwind: