libbacktrace: symbolic backtraces from inside your own process
A C library that may be linked into a C/C++ program to produce symbolic backtraces
At a glance
- What is it?
- libbacktrace is a C library, written by Ian Lance Taylor, that a C or C++ program links in to print a symbolic backtrace at the point of failure. It reads DWARF and the object file format of the running binary, it is safe to call from a signal handler once you have warmed it up, and it is version 1.0 forever.
- Who is it for?
- Adopt libbacktrace if you need a backtrace with function names and file and line information from inside a crashing C or C++ program, especially in a signal handler, and if you control the build so the debug information is present. Do not adopt it if your binaries ship stripped, because the library reads the debugging information from the object files and cannot symbolise what is not there.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 50 days ago.
- What is it written in?
- Mainly C, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A backtracer that reads the binary it is running inside
libbacktrace is a C library that may be linked into a C or C++ program to produce symbolic backtraces. The word symbolic is the whole point. A raw backtrace is a list of return addresses, and on its own it is a list of numbers that a human cannot read and that a crash reporter has to symbolise later, out of process, using the debug information from a matching build. libbacktrace does the symbolisation on the spot, inside the process, by reading the object file and the DWARF debugging information that describe the running code, and turning return addresses into function names, source files and line numbers while the program is still alive to print them. The stated sample uses are to print a detailed backtrace when an error occurs, or to gather detailed profiling information. The author is Ian Lance Taylor, and the README is written for people who know what a signal handler is. The version policy is stated with a dry humour that is worth quoting, since the library is version 1.0 and it is likely that this will always be version 1.0.
The signal-safety rule and the warm-up call it requires
The most important paragraph in the README is the one about async-signal-safety, and it is a two-part contract that a user has to honour. In general the functions provided by this library are async-signal-safe, meaning that they may be safely called from a signal handler. But on systems that use dl_iterate_phdr, such as GNU/Linux, the first call to a libbacktrace function will call dl_iterate_phdr, which is not in general async-signal-safe. Therefore programs that call libbacktrace from a signal handler should ensure that they make an initial call from outside of a signal handler. The same reasoning applies to calling libbacktrace from within malloc, because dl_iterate_phdr can also call malloc, so the advice is to make an initial call to a libbacktrace function outside of malloc before trying to call libbacktrace functions within malloc. This is a small obligation with a real payoff. The alternative approach, where you install a handler that formats a backtrace at the moment of the crash, is exactly the case where you cannot afford to allocate, cannot afford to take a lock that might be held by the crashing thread, and cannot afford to run code that might deadlock. libbacktrace gives you a library that satisfies those constraints once warmed up, which is a rare and useful property. The cost is that the warm-up call has to happen somewhere safe in your startup path, and if you forget it, the failure appears at the worst possible moment.
Four object file formats, one set of DWARF rules
As of July 2024, libbacktrace supports ELF, PE/COFF, Mach-O, and XCOFF executables with DWARF debugging information, which the README translates into platforms: GNU/Linux, the BSDs, macOS, Windows, and AIX. The source layout reflects that, with one file per format in the tree, elf.c, macho.c, pecoff.c and xcoff.c, alongside the format-independent machinery in dwarf.c for the debugging information, read.c for the file reading, print.c for the output, fileline.c for the file and line mapping, mmap.c and mmapio.c for mapping the file into memory, posix.c for the platform bits, atomic.c, alloc.c and the various allocation-failure helpers, plus unknown.c and simple.c for the fallback and simplified paths. The library is written to make it straightforward to add support for other object file and debugging formats, which is the honest way to describe a design where the format handling is deliberately isolated from the DWARF parsing. The practical implication for an adopter is that the debug information has to be in the binary that is running. A stripped release build has nothing for the library to read, and the backtrace degrades to addresses, which is the situation where the library stops being worth linking in.
It depends on the C++ unwinder, and that is a constraint worth knowing
The README states that the library relies on the C++ unwind API defined by the Itanium C++ ABI, and that this API is provided by GCC and clang. That single dependency shapes the portability story. The library is not parsing a stack frame chain itself, it is asking the platform unwinder for the frame pointers, which is why it can produce a correct trace through frames that the compiler has optimised away or through a function that has no frame pointer, and why it works across a shared library boundary the way a naive frame-pointer walk does not. The cost is that the unwinder has to exist. On a system built with a different toolchain, or one where the unwinder is not available, there is an alternative path in the tree, which is what nounwind.c and the simple.c fallback are for, but the quality of the trace drops accordingly. For a Linux or macOS C or C++ project built with gcc or clang, which is the overwhelming majority of cases, this is a non-issue, and it is one of the reasons the library feels solid rather than clever. It is worth noting that the library also depends on the C++ ABI unwind being consistent with what the compiler emitted, so a mixed-toolchain binary is a case where the trace can be subtly wrong rather than obviously broken.
Autotools, and the build-id script that distributors need
The build is a conventional GNU autotools project, with configure.ac, Makefile.am, aclocal.m4, a generated configure, config.h.in, and the libtool machinery in ltmain.sh, which is how a library that produces a shared object gets built on the platforms where that needs help. The tree is laid out the way a C library from this school of development is laid out, with a file per concern and a set of self-contained test programs. Two files are worth singling out for anyone packaging the library. install-debuginfo-for-buildid.sh.in is a script that installs debug information for a build ID, which matters on Linux distributions where the debug information for a package is shipped separately from the binary and the two have to be matched by build ID rather than by path, and a backtrace printed in the field is only useful if it can be symbolised against the right debug data. The other is backtrace-supported.h.in, the template for the generated header. Building the library generates a file backtrace-supported.h, which a user of the library may use to determine whether backtraces will work, and the template holds the macros that it defines. That is a small and thoughtful piece of API design. It lets a program compile out its backtrace code when the platform cannot support it, rather than discovering the problem at runtime on the one machine that matters.
The test programs are the specification
The repository contains more test programs than you would expect for a library this small, and they are the clearest description of what the library actually does. There is btest.c for the basic path, edtest.c and edtest2.c for the ELF reader, mtest.c for the Mach-O reader, ttest.c for a specific case, stest.c for stripped binaries, mdtest.c, xztest.c and unittest.c, plus a shared harness in testlib.c and testlib.h and a test-driver script. There is also a compile script and a filetype.awk, which suggests the tests are parameterised over the object file types the library claims to handle, and strippedtest.c is the interesting one, because a stripped binary is the case where a backtracer silently degrades rather than failing loudly. The configuration directory, the config.guess and config.sub scripts and the missing helper are the standard autoconf machinery, and install-sh and move-if-change are the traditional shell helpers that come with it. There is one file in the tree that has nothing to do with any of this, Isaac.Newton-Opticks.txt, which is a text of a Newton poem and appears to be there for the pleasure of whoever finds it. The overall impression of the repository is of a library that has been refined over many years by someone who treats the tests as the contract.
Where libbacktrace is the wrong tool
The limits are specific. The first is the debug information requirement. libbacktrace reads the DWARF information in the executable and the shared objects it is using, so a production build that strips symbols, or that ships only a separate debug package matched by build ID on a different machine, will not get a symbolic trace from the library itself. In that environment you are back to collecting addresses and symbolising them offline, which is a perfectly good workflow but is not what this library does. The second is the unwinder dependency, which I mentioned above and which matters more than it looks on a platform where the toolchain is not gcc or clang. The third is scope. This is a backtracer, not a crash reporter, not a profiler and not a symbol server. The sample use of gathering detailed profiling information is a description of the data it can give you, not a profiler built on top of it. The fourth is the maintenance question, and the facts here are modest. The repository has no GitHub releases, the last push was on 2026-09-03, the version has been 1.0 since the beginning and is expected to stay 1.0, and the licence is described in the README as BSD with the exact text in the source files, while GitHub's own classification of the licence is one it cannot categorise. The last point is not a problem in itself, but it is the kind of detail a corporate legal review will ask about, and the answer is in the source files rather than in the metadata.
Editorial conclusion
Adopt libbacktrace if you need a backtrace with function names and file and line information from inside a crashing C or C++ program, especially in a signal handler, and if you control the build so the debug information is present. Do not adopt it if your binaries ship stripped, because the library reads the debugging information from the object files and cannot symbolise what is not there. Before you integrate it, make the first call outside both your signal handler and malloc on Linux, since the initial call can reach dl_iterate_phdr, and read the licence text in the source files, because GitHub classifies the licence as one it cannot categorise even though the README calls it BSD.
Frequently asked questions
What does libbacktrace do and who wrote it?
It is a C library that may be linked into a C or C++ program to produce symbolic backtraces, initially written by Ian Lance Taylor. The sample uses given are printing a detailed backtrace when an error occurs and gathering detailed profiling information.
Can libbacktrace be called from a signal handler?
The functions are generally async-signal-safe, but on systems using dl_iterate_phdr such as GNU/Linux the first call is not, because it calls dl_iterate_phdr. The documentation advises making an initial call from outside a signal handler, and similarly outside malloc, since dl_iterate_phdr can also call malloc.
Which platforms and file formats does libbacktrace support?
As of July 2024 it supports ELF, PE/COFF, Mach-O and XCOFF executables with DWARF debugging information, which covers GNU/Linux, the BSDs, macOS, Windows and AIX. It relies on the C++ unwind API defined by the Itanium C++ ABI, provided by GCC and clang.
How do I know whether backtraces will work in my build?
Building the library generates a file backtrace-supported.h that a user of the library may use to determine whether backtraces will work. The macros it defines are listed in the source file backtrace-supported.h.in.
What licence applies to libbacktrace?
The README states that the library is provided under a BSD license and that the source files hold the exact licence text, while GitHub classifies the licence as a custom one it cannot categorise. The repository publishes no GitHub releases and the last push was on 2026-09-03.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/ianlancetaylor-libbacktrace)Was this useful?