C++23 stacktrace, and leveraging existing LLVM code for symbols + debug info (original) (raw)
February 22, 2025, 10:51pm 1
Hi all! I decided I would try my hand at implementing C++23’s <stacktrace>
:
https://eel.is/c++draft/stacktrace
To actually implement stacktrace we need a few things: (1) walking the stack and grabbing caller addresses; (2) resolving those to symbols; and (3) resolving them to source file and line number.
For the first one we have libunwind
, so that’s straightfoward enough. (At least I think libcxx can use it, since it’s embedded in libcxxabi
? In my build tree, under build/libcxx/test-suite-install/include
, I see unwind.h
and libunwind.h
.)
But for the others, I’m not sure how to proceed. I can’t seem to find a library that’s #include
-able by libcxx code. Of course there are many places where executable and debug formats are parsed – lldb, lld, ob2yaml, dwarfdump, compiler-rt for -SAN error reporting – but they’re not feasible to include directly, or even copy-pasta under libcxx.
(For fun / educational purposes, I tried creating one supporting only 64-bit OS X, but even that one implementation got nontrivial enough to give me pause. And that’s not including ELF, PE, (both the 32 and 64-bit variants of all these), DWARF, PDB, and the intricacies of those platforms’ dynamic loaders.)
So to that end I’d like to ask the community what the most preferable way forward is. Taking a step back: ideally there would be a library for parsing object files and interpreting debug information. It would preferably be lean and fast, since this may be done at runtime for various reasons, e.g. error reporting and tracing hotspots for performance. Finally, since stacktrace
accepts a caller-provided allocator, there’s probably concern about how (and how much) memory can be allocated during the operation.
I’m very interested to hear what y’all think. Thanks!
For objects at least there’s LLVMObject…
Hi @h-vetinari – yup that part of the LLVM libs would be perfect (DebugInfo
as well!), but I think I’ll have trouble trying to use this from libcxx
unfortunately.
I guess libcxx
is a little tricky in terms of what it’s able to depend on. It includes only files from within libcxx
, and occasionally, <cxxabi.h>
(very few examples outside of those). No instances of #include "llvm/..."
Except for a handful on unit tests.
Bigcheese February 23, 2025, 3:57am 4
This definitely feels like something that libc++ should just call into the support libraries for, since a lot of systems already have these somewhere, but it’s going to be a per-OS API. For example on MacOS the needed info is often in a totally separate dSYM file, with special ways to find it.
Boost stacktrace, which std::stacktrace was based on, uses either libbacktrace or calls out to addr2line (or something special on Windows), but some platforms can do better.
For platforms without an API for this, I think we should consider refactoring the sanitizer symbolization code to be usable here. It may make sense to use the libbacktrace API to allow different implementations, and LLVM can have it’s own version that uses llvm/DebugInfo/Symbolize
. This also let’s us get it working quickly with the existing libbacktrace. I don’t think it makes sense to invent something totally new here, or add a bunch of platform specific code to libc++.
Thanks @Bigcheese ! More questions: by existing libbacktrace
, do you mean something that exists within llvm-project, or libbacktrace project (which is used in gcc)? If the latter, could/should I wholesale include this in third-party
or somewhere, or assume (for now) that at runtime the system has this installed?
Bigcheese February 23, 2025, 5:02pm 6
I mean just using it as an external dependency until LLVM has its own version.
I think it’s fine if initially std::stacktrace doesn’t symbolicate if you don’t configure libc++ to use libbacktrace.
I’d also wait for the libc++ maintainers and some debug info people to weigh in here before fully committing to a direction.
@ldionne @dblaikie @JDevlieghere
dblaikie February 23, 2025, 5:28pm 7
Check out how LLVM’s build depends on zlib and zstd, I think - those are external library dependencies we use optionally. I’d guess this would be similar.
Seems like a reasonable first pass to me, but I imagine it’ll be more of a question for the libc++ folks.
R-Goc March 4, 2025, 2:01pm 8
Are you sure you can use libunwind everywhere? It is not built for windows and not used there. AFAIK you’d probably want to call into a platform api (stackwalk64 on windows).
@philnik started an implementation of this a while ago, see ⚙ D123228 [libc++][WIP] Implement P0881R7 (std::stacktrace).
I am not sure if he has any plans to continue working on that topic. Either way, that earlier attempt might still be useful so you don’t have to start from scratch