Right now, on FreeBSD/macOS stack traces contain only the hex addresses which makes reading them hard.
dladdr(3) seems like a reasonably good way to look up symbols. A quick test on FreeBSD mostly works - symbols in shared libraries are found just fine, but any symbol in the main executable isn't. For example:
[800a12000] CRIT libjeffpc.so`print_stacktrace+0x3d [0x80025809d] [800a12000] CRIT libjeffpc.so`jeffpc_assfail+0x91 [0x800258221] [800a12000] CRIT libjeffpc.so`jeffpc_assfail3+0x1b [0x80025825b] [800a12000] CRIT test_xstrerror`0x2026ae [0x2026ae] [800a12000] CRIT libjeffpc.so`xstrerror+0x1c [0x80025859c]
Note the lack of a symbol on the second to last line. Building the executable with the
-E
linker option works around this issue (by putting symbols in the dynamic symbol table):[800a12000] CRIT libjeffpc.so`print_stacktrace+0x30 [0x800258090] [800a12000] CRIT libjeffpc.so`jeffpc_assfail+0x91 [0x800258241] [800a12000] CRIT libjeffpc.so`jeffpc_assfail3+0x1b [0x80025827b] [800a12000] CRIT test_xstrerror`main+0x40e [0x2027ae] [800a12000] CRIT libjeffpc.so`xstrerror+0x1c [0x8002585dc]
Using
-E
is not a real solution since we shouldn't be dictating how executables are linked.As a data point, libunwind seems to use dladdr(3) with a fallback to opening the executable ELF file and doing the symbol lookup there. libjeffpc could use libunwind with a little bit of awkward code to separate out the stack walking from symbol lookup.
- stack walking could be kept as is, or replaced with a cursor walk
- symbol name could...
- use the recently (2 months ago) added
unw_get_proc_name_by_ip
, or- the long-time present
unw_get_proc_name
if we can figure out how to construct a cursor
unw_get_proc_name_by_ip
has been around for a while. FreeBSD 14.0 has it. Debian 12 doesn't (it has 1.6.2-3, but also libunwind-{13,14,15,16} which may be somehow related to llvm).
If there is no
addrtosymstr
and no libunwind/unw_get_proc_name_by_ip
, we could fall back to dladdr(3). It's not perfect, but it'd be better than just a bunch of hex addresses.
I have a promising prototype that uses a combination of
dladdr
andunw_get_proc_by_ip
. dladdr(3) provides the module name. It also provides the symbol name ifunw_get_proc_by_ip
fails or libunwind is not present.There is a bit more conditional compilation I need to implement to handle the scenario of libunwind being present but
unw_get_proc_by_ip
not existing in it (as is the case in Debian 12).