[LLVMdev] Generating a backtrace

Talin viridia at gmail.com
Fri Feb 19 19:29:08 PST 2010

After working with LLVM for several years now, one problem that remains
unsolved is how to generate a stack backtrace for exceptions.

My basic approach is simple: I have two different exception personality
functions, a "lightweight" one that just does the bare minimum needed to
handle exception, and a "capturing" one that (ideally) records the call
frame information as it unwinds the stack. My motivation for doing it this
way is that it would be too expensive to always capture call frame
information on every exception, so instead my compiler only uses the heavier
personality function when the exception backtrace information is actually
going to be used.

Within the personality function, there's a call to _Unwind_Backtrace(),
which walks through the list of call frames and calls a callback for each
one. Within the callback, I can get the value of the return address for each
call frame using _Unwind_GetIP(). So far so good.

The problem is converting those addresses into meaningful symbols. For some
reason that I don't understand, dladdr() doesn't seem to work on
LLVM-generated functions, even though I know those functions have full DWARF
debugging information. If I insert a printf into my backtrace code, and
print out the addresses of each return address I see something like this:

Function _Unwind_RaiseException
Function __libc_start_main

The hex values are ones where dladdr() failed to provide a function name. As
you can see, the only functions it was able to deal with are the libc
startup function, and _Unwind_Raise_Exception itself. Yet I know these
functions have symbolic names, since I can step through them in gdb, set
breakpoints, and so on.

I've tried a number of other approaches: Calling dlopen(NULL) and then using
dlsym() to try and locate __data_start so that I can then attempt to
manually parse the DWARF debug frames to translate the return addresses into
function names. Unfortunately, I can't seem to locate __data_start at all.
I've also tried calling the libc backtrace() function, but it produced
similarly useless results.

The really icky part about all of this is that even if I do come up with a
solution for these problems, I will then have to re-solve the same problems
for each different platform that LLVM supports. I kinda wish that there was
some LLVM intrinsic or library function that would hide all these details
from me :)

-- Talin
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20100219/af7c4212/attachment.html>

More information about the llvm-dev mailing list