-
Notifications
You must be signed in to change notification settings - Fork 0
Home
Here you can find all information about the CallstackLibrary as well as the documentation of the source code.
This library can translate backtraces obtained by the function backtrace
into a human-readable format.
It will use the debug symbols of the application, in case they are not available, the information obtained
by the dynamic linker is used.
Additional C++ functionality and optimizations can be enabled while compiling the library.
There is also a wrapper class for simplified usage of this library in C++ code.
Additionally, there is an exception class capable of printing its construction stacktrace.
- Using the function
callstack_new()
a callstack can be generated. - The getter function
callstack_toArray()
provides simple access to the translated callstack. - The callstack structure can also be placed anywhere and filled using the functions
callstack_emplace()
andcallstack_emplaceWithBacktrace()
.
Tip
Example:
#include <stdio.h> // For printf(...)
#include <callstack.h>
int main(void) {
struct callstack* callstack = callstack_new();
struct callstack_frame* frames = callstack_toArray(callstack);
printf("The current callstack:\n");
for (size_t i = 0; i < callstack_getFrameCount(callstack); ++i) {
printf("In: (%s) %s (%s:%ld)\n", callstack_frame_getShortestName(&frames[i]),
frames[i].function == NULL ? "???" : frames[i].function,
callstack_frame_getShortestSourceFileOr(&frames[i], "???"),
frames[i].sourceLine);
}
callstack_delete(callstack);
}
With the C++ wrapper class the lifecycle management of callstack objects is simplified.
To use it, you need to do nothing - it is automatically included if you compile your code with a C++ compiler.
The move semantic is also supported by the wrapper if compiled using a compiler supporting C++11.
In order to get demangled C++ function names, the library needs to be compiled with the C++ exclusive functions enabled, see below.
Tip
Example:
#include <iostream>
#include <callstack.h>
int main() {
lcs::callstack callstack;
callstack_frame* frames = callstack_toArray(callstack);
std::cout << "The current callstack:" << std::endl;
for (size_t i = 0; i < callstack_getFrameCount(callstack); ++i) {
std::cout << "In: (" << callstack_frame_getShortestName(&frames[i])
<< ") " << (frames[i].function == NULL ? "???" : frames[i].function)
<< " (" << callstack_frame_getShortestSourceFileOr(&frames[i], "???")
<< ":" << frames[i].sourceLine
<< ")" << std::endl;
}
}
With the callstack exception an exception capable of creating and printing its construction stacktrace is available.
It can be thrown directly:
// main.cpp
#include <iostream>
#include <callstack_exception.hpp>
void bar() {
throw lcs::exception("Callstack exception with a message");
}
void foo() { bar(); }
int main() {
try {
foo();
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
Compiled and linked on macOS using c++ -g main.cpp -I<path/to/library>/include -L<path/to/library> -lcallstack
and after
enabling C++ functions of the library creates the following output:
lcs::exception: "Callstack exception with a message", stacktrace:
At: (a.out) lcs::callstack::callstack(bool) (include/callstack.hpp:81)
in: (a.out) lcs::callstack::callstack(bool) (include/callstack.hpp:79)
in: (a.out) lcs::exception::exception(char const*, bool) (include/callstack_exception.hpp:126)
in: (a.out) lcs::exception::exception(char const*, bool) (include/callstack_exception.hpp:127)
in: (a.out) bar() (main.cpp:8)
in: (a.out) foo() (main.cpp:11)
in: (a.out) main (main.cpp:15)
in: (/usr/lib/dyld) start + 1903
The callstack exception can easily serve as base class for other exceptions:
// main.cpp
#include <iostream>
#include <callstack_exception.hpp>
class CustomStacktraceException: public lcs::exception {};
void foo() {
throw CustomStacktraceException();
}
void bar() { foo(); }
int main() {
try {
bar();
} catch (std::exception& e) {
std::cerr << e.what() << std::endl;
}
}
Compiled and linked on Debian using g++ -g main.cpp -I<path/to/library>/include -L<path/to/library> -lcallstack
and after
enabling C++ functions of the library creates the following output:
CustomStacktraceException, stacktrace:
At: (a.out) lcs::callstack::callstack(bool) (include/callstack.hpp:81)
in: (a.out) lcs::exception::exception(bool) (include/callstack_exception.hpp:116)
in: (a.out) CustomStacktraceException::CustomStacktraceException() (main.cpp:7)
in: (a.out) foo() (main.cpp:10)
in: (a.out) bar() (main.cpp:13)
in: (a.out) main (main.cpp:17)
in: (/usr/lib/x86_64-linux-gnu/libc.so.6) << Unknown >>
in: (/usr/lib/x86_64-linux-gnu/libc.so.6) __libc_start_main + 133
in: (a.out) _start + 33
The C++ name demangler and a few other optional functions are disabled by default. To enable them while compiling the
library, pass CXX_FUNCTIONS=true
to make
:
make CXX_FUNCTIONS=true
The C++ optimizations can be enabled by passing CXX_OPTIMIZED=true
the same way:
make CXX_OPTIMIZED=true
The two flags can be combined:
make CXX_FUNCTIONS=true CXX_OPTIMIZED=true
When linking statically against the CallstackLibrary with C++ functions and / or optimizations enabled the application additionally needs to be linked against the C++ standard library of your compiler (this is usually already the case when linking C++ code).
Copyright (C) 2022, 2024 mhahnFr.
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. A copy of the license is included in the section entitled "GNU Free Documentation License".