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.
::dladdr1has the information I needed.Given I have
addr_ptrwhich is either the address in a shared library or in the shared exe, I can get the base address to subtract fromaddr_ptrby calling into::dladdr1and using the returned::link_mapdata structure.The
::link_maphas a field calledl_addrwhich is 0 for the exe and non-zero for linked libraries.So given an
addr_ptrthat has the parsed address:final_ptrhas the correct value now to pass toaddr2line