libunwind: walking and resuming call chains, in the same process or another one
libunwind official github repo (in need of new / additional maintainer, mail/open issue if interested)
At a glance
- What is it?
- libunwind is a portable C API for determining the current call chain of ELF program threads and for resuming execution at any point in it, with local and remote operation. It suits a tool that needs a backtrace from a live or crashed process, and it is MIT licensed with a maintainer position advertised in its own description.
- Who is it for?
- libunwind fits a systems programmer who needs a call chain from a running process or a coredump, and who cannot assume a C++ runtime's own unwinder is present, because the API is a plain C interface with no dependency on a particular toolchain. Skip it if you are on Windows, since the supported systems table lists Linux, FreeBSD, QNX and Solaris, and skip it if you only need a backtrace inside a C++ program with a working exception handler.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 8 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 23, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the API actually does
libunwind is a portable and efficient C API for determining the current call chain of ELF program threads of execution and for resuming execution at any point in that call chain. The API supports both local, same process, and remote, other process, operation.
That is two capabilities in one, and the second is the unusual one. Walking a call chain is what a backtrace does, and plenty of libraries do that. Resuming execution at any point in that call chain is the reverse operation, and it is what makes the library a tool for debugging, for injection, and for analysis rather than just for error messages.
The local and remote split is a design decision with a lot of weight behind it. A local unwinder walks the stack of the calling thread directly, which is fast and simple. A remote unwinder takes a process id and a thread id and reconstructs the stack of a thread in another process, which requires reading that process's memory and interpreting its unwind information. Same API, very different implementation underneath.
The applications listed in the documentation are worth reading because they map onto the two halves.
Program introspection covers error messages showing a backtrace of the call chain leading to a problem, and performance monitoring and analysis.
Debugging covers the debugging and analysis of the call chain of a remote program, and the post-mortem analysis of a coredump.
Language runtime exception handling is where the optionality does a lot of work. libunwind optionally provides an alternative implementation of the Itanium exception handling ABI used by many popular toolchains. So it can replace the unwinder that a C++ compiler normally links in, which matters when you are building a runtime, a profiler, or a language implementation and the default unwinder is not the one you want.
And the fourth use is the one that surprises people: alternative `setjmp()`/`longjmp()`. libunwind optionally provides an alternative implementation of the `setjmp()`/`longjmp()` functionality of the C standard library.
The library is C, MIT licensed, and the last push was on 2026-10-15.
The supported systems table, and what the exceptions say
The architecture and operating system table is long, and the interesting entries are the ones that are not a clean tick.
On Linux the support is broad: x86-64, x86, ARM, AArch64, Alpha, PPC32, PPC64, PPC64LE, s390x, SPARC64, SuperH, IA-64, MIPS and RISC-V are all marked as working, and LoongArch is 64-bit only. The presence of Alpha, IA-64, SuperH and SPARC64 says something about the age and reach of the project, since those are architectures you will not find in current hardware but which appear in older systems, firmware and embedded contexts where a portable unwinder is still wanted.
The two qualified entries are the interesting ones. PA-RISC on Linux works well, but the C library is missing unwind-info, which means the library itself is fine but the frames below your code may not be walkable, because the information needed to unwind through the C library is not there. And HP-UX on IA-64 mostly works, but is known to have serious limitations.
That distinction between the library being sound and the platform being complete is worth keeping in mind. A missing unwind-info in the C library is not a bug in libunwind, it is a gap in the toolchain around it, and it produces a backtrace that stops partway up the stack rather than an error.
On FreeBSD there is x86-64, x86, AArch64, PPC32, PPC64 and RISC-V. QNX is supported on Aarch64 and x86-64, and Solaris on x86-64.
Continuous integration runs for Linux with GNU tools, for FreeBSD and for Windows, and the three badges at the top of the documentation are for those three workflows. The Windows CI is the interesting one, because Windows is not in the supported systems table at all, so that job is presumably testing that the code compiles there rather than that the unwinder works, which is consistent with the library being ELF specific in the first place.
Meson is the build, Autotools is on the way out
The build instructions are short, and the migration is the notable part.
This library uses Meson as its build system, and it can be built and installed with:
$ meson setup build --prefix=PREFIX
$ meson compile -C build
$ meson install -C buildThe `PREFIX` is the installation prefix, and by default a prefix of `/usr/local` is used, such that `libunwind.a` is installed in `/usr/local/lib` and `unwind.h` is installed in `/usr/local/include`.
Those two filenames are worth noticing. The public header is `unwind.h`, and the static library is `libunwind.a`. The `.a` in the name is a hint about the default build, and a project that is often linked into language runtimes and embedded in binaries is likely to be built static so that the unwinder is available in a program that has no shared library dependency.
The Autotools build still exists, but it is deprecated and planned for removal in a future release, and new usage should build with Meson instead:
$ autoreconf -i
$ ./configure --prefix=PREFIX
$ make
$ make installThe `autoreconf -i` step is noted as needed only for building from git, and it depends on libtool. So the Autotools path is being kept working for existing packagers while the project moves to Meson, which is a common pattern and one that creates a slow migration burden for distribution maintainers.
The repository carries both build systems at the top level, with `meson.build`, `meson_options.txt`, a `Makefile.am` and a `configure.ac`, plus a `CMakeLists.txt`. Having three build systems in one tree is unusual, and the `subprojects/` directory is the Meson mechanism for wrapping a dependency, and `cross/` is for cross compilation configuration.
The top level also has a `SECURITY.md` for reporting vulnerabilities, which is a meaningful file in a library like this, since a bug in an unwinder is a potential memory safety issue in every program that uses it.
Regression tests and the benchmark that tells you the cost
Two test commands, and the second one is the more interesting for anyone deciding whether to adopt the library.
After building the library, you can run a set of regression tests with:
$ meson test -C buildWith Autotools, use `make check` instead.
Then there is the performance side. The distribution includes a few simple performance tests which give some idea of the basic cost of various libunwind operations, run with:
$ meson test -C build --benchmarkWith Autotools, run `make perf` from the `tests` directory instead.
The phrase some idea of the basic cost is a careful hedge, and it should be read carefully. These are simple benchmarks bundled with the distribution, not a performance suite, and their purpose is to give a rough sense of what unwinding costs rather than to produce numbers you can quote in a design document.
That still matters, because unwinding is not free and the cost profile drives the design decisions of anything built on it. A backtrace at a crash is a rare event and can be expensive. A backtrace sampled on a timer in a profiler is a frequent event and has to be cheap, and the per-frame cost of the unwinder is part of the profiler's own overhead. A language runtime that unwinds on every exception is in the same category.
So the benchmark exists to answer a question that a user of the library has to answer for themselves: what does it cost on my platform, on my architecture, with my build flags. The library is portable across fifteen or so Linux architectures, and the cost of an unwind step is not identical between them, since the amount of information the compiler has to emit for each frame differs by architecture and by optimisation level.
The `tests/` directory at the top of the repository holds both the regression suite and the benchmarks, and the `doc/` directory holds the documentation.
Where libunwind stops being the right tool
There are four cases where a different answer is better, and one of them is a matter of project governance rather than technology.
The first is Windows and macOS, in the sense of the Apple platforms. The supported systems table lists Linux, FreeBSD, QNX and Solaris, and the library is described as working on ELF programs, so a PE or Mach-O program is out of scope. On those platforms the platform's own unwinder is what you use.
The second is a C++ program with a working exception handler. If your toolchain already links an unwinder and your backtrace can come from the runtime, replacing it with libunwind buys little. libunwind earns its place when you need the remote operation, or when you are building a runtime and need to control the unwinder, or when you need to unwind a process where the default unwinder is not present.
The third is the platform gap. A missing unwind-info in the C library, as on PA-RISC, and the known limitations on HP-UX, are cases where the answer is that the stack cannot be fully walked on that platform. For a debugging tool, a partial backtrace is a real limitation, and it is better to know about it before you deploy on that hardware.
The fourth is a project governance matter, and it is the one a user of this library should weigh. The repository description says it is the official libunwind github repo and says it is in need of a new or additional maintainer, with an invitation to mail or open an issue if interested. A foundational library with a single maintainer is a supply chain risk, and libunwind is the kind of thing that ends up in every program that links a language runtime. The project is not archived, the last push was on 2026-10-15, and the recent releases are 1.8.3 from 2025-09-04, 1.8.2 from 2025-05-22 and 1.8.1 from 2024-02-22.
The alternative approach for most of these cases is the platform unwinder, or a platform specific backtrace library, or the language runtime's own facilities. The difference in approach is that libunwind is a single C API that behaves the same across a very wide set of Unix-like systems, which is exactly what you want if you are writing a profiler or a runtime that has to work on a fleet of mixed machines, and exactly what you do not need if you are on one platform with a working toolchain.
Editorial conclusion
libunwind fits a systems programmer who needs a call chain from a running process or a coredump, and who cannot assume a C++ runtime's own unwinder is present, because the API is a plain C interface with no dependency on a particular toolchain. Skip it if you are on Windows, since the supported systems table lists Linux, FreeBSD, QNX and Solaris, and skip it if you only need a backtrace inside a C++ program with a working exception handler. Before you build, use Meson rather than the Autotools path, since the Autotools build is deprecated and planned for removal, and note the maintainer situation, because the repository description says it is in need of a new or additional maintainer.
Frequently asked questions
What is libunwind?
It is a portable and efficient C API for determining the current call chain of ELF program threads of execution and for resuming execution at any point in that call chain, supporting both local same process and remote other process operation.
How do I build and install libunwind?
With Meson, by running `meson setup build --prefix=PREFIX`, `meson compile -C build` and `meson install -C build`. The default prefix is /usr/local, so libunwind.a goes to /usr/local/lib and unwind.h to /usr/local/include. The Autotools build still works but is deprecated and planned for removal.
Which operating systems and architectures does libunwind support?
Linux on x86-64, x86, ARM, AArch64, Alpha, PPC32, PPC64, PPC64LE, s390x, SPARC64, SuperH, IA-64, MIPS, RISC-V and 64-bit LoongArch, plus FreeBSD on x86-64, x86, AArch64, PPC32, PPC64 and RISC-V, QNX on Aarch64 and x86-64, and Solaris on x86-64. PA-RISC on Linux works well but the C library is missing unwind-info, and HP-UX on IA-64 mostly works with known serious limitations.
How do I run the libunwind regression tests?
Run `meson test -C build` after building, or `make check` with the Autotools build. The bundled performance tests are run with `meson test -C build --benchmark`, or `make perf` from the tests directory with Autotools.
Can libunwind replace the C++ exception handling unwinder?
Yes, optionally. The library can provide an alternative implementation of the Itanium exception handling ABI used by many popular toolchains, and it can also provide an alternative implementation of the C standard library's setjmp and longjmp functionality.
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/libunwind-libunwind)Was this useful?