An interposer to debug C++ exceptions
April 26, 2020
I've just released https://github.com/rkday/cpp-exception-interposer, which solves some problems I've had with tracking down the source of C++ exceptions (especially in environments where using gdb's catch throw
command is impractical).
The way it works is:
- it's an interposer, loaded with
LD_PRELOAD
, which means that the functions defined there take precedence over other libraries, including the C++ standard libary - it defines its own version of
__cxa_throw
, which is the function that gets called when an exception is thrown. The function signature is defined at https://libcxxabi.llvm.org/spec.html, and the process for throwing a C++ exception (including calling__cxa_throw
) defined at http://itanium-cxx-abi.github.io/cxx-abi/abi-eh.html#cxx-throw. - this version of
__cxa_throw
does two things:- uses
libbacktrace
to retrieve and print the function call stack. Note that we're early enough in exception processing that the stack hasn't been unwound, so the line of code which threw the exception is still available from the call stack. - uses
dlsym
andRTD_NEXT
to call the real__cxa_throw
, allowing exception processing to continue.
- uses
For an example, I'll quote from the README:
This program (compiled with g++ -g -std=c++17 -o exceptions exceptions.cpp
):
#include <stdexcept> #include <stdio.h> #include <optional> void foo() { std::optional<int> x; x.value(); } void bar() { try { foo(); } catch (std::exception& e) { printf("Exception caught and ignored\n"); } } int main() { bar(); }
normally provides this output:
$ ./exceptions Exception caught and ignored
but running it with the interposer provides much better diagnostics:
$ LD_PRELOAD=cpp-exception-interposer/cpp_exception_interposer.so ./exceptions *** C++ exception (St19bad_optional_access) thrown *** 0x7fa4646ee451 ??? ???:0 0x55958f3f12ea _ZSt27__throw_bad_optional_accessv /usr/include/c++/9.3.0/optional:99 0x55958f3f132c _ZNRSt8optionalIiE5valueEv /usr/include/c++/9.3.0/optional:931 0x55958f3f11e3 _Z3foov /home/rkd/src/exceptions.cpp:8 0x55958f3f1208 _Z3barv /home/rkd/src/exceptions.cpp:14 0x55958f3f125a main /home/rkd/src/exceptions.cpp:22 0x7fa4641ca022 ??? ???:0 0x55958f3f10ed ??? ???:0 0xffffffffffffffff ??? ???:0 *** Proceeding with C++ exception handling *** Exception caught and ignored