~jeffpc/libjeffpc#1: 
Stack trace symbol lookup on FreeBSD/macOS

Right now, on FreeBSD/macOS stack traces contain only the hex addresses which makes reading them hard.

Status
REPORTED
Submitter
~jeffpc
Assigned to
No-one
Submitted
2 years ago
Updated
4 months ago
Labels
bug platform-specific

~jeffpc 2 years ago*

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

~jeffpc 4 months ago

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).

~jeffpc 4 months ago

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.

~jeffpc 4 months ago

I have a promising prototype that uses a combination of dladdr and unw_get_proc_by_ip. dladdr(3) provides the module name. It also provides the symbol name if unw_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).

Register here or Log in to comment, or comment via email.