I'm using backtrace
and backtrace_symbols
to get a stacktrace when a custom exception is thrown in my program (for now, on Linux... Ubuntu specifically)
trace_size = backtrace(stack_traces, MAX_STACK_FRAMES);
messages = backtrace_symbols(stack_traces, trace_size);
From the stacktrace, I'm able to loop over each frame and extract an address that the program was at for this frame.
I get two types of addresses depending on where a function was defined:
- A library address:
/path/to/library.so(mangled_function_name+0x75) [0x7f02bcdfa849]
^^^^^^^^^^^^^^
- executable address:
/path/to/executable(mangled_function_name?+0x90) [0x403336]
^^^^^^^^
[0x7f02bcdfa849]
and [0x403336]
are where my concerns lie...
I want to pass these addresses to addr2line
.
However, for addresses belonging to shared libraries, this won't work. I learned that I first need to calculate the offset of the parsed address from the base address that the library was loaded at.
addr2line -e /path/to/library.so 0x7f02bcdfa849 # won't work
# or
addr2line -e /path/to/executable 0x403336 # works just fine
I know I can use ::dladdr
to find the base address and find the offset from that.
But, how can I tell, at runtime, whether I need to do this transformation? As in, how can I tell if an address belongs to a shared library at runtime?
I've tried simply checking if the .so
shows up in the frame of the stacktrace but that feels... wrong.
::dladdr1
has the information I needed.Given I have
addr_ptr
which is either the address in a shared library or in the shared exe, I can get the base address to subtract fromaddr_ptr
by calling into::dladdr1
and using the returned::link_map
data structure.The
::link_map
has a field calledl_addr
which is 0 for the exe and non-zero for linked libraries.So given an
addr_ptr
that has the parsed address:final_ptr
has the correct value now to pass toaddr2line