Linux - segmentation fault only sometimes - how to debug - c++

I have a Linux program, that from time to time ends with a segmentation fault. The program is running periodically every hour, but the segmentation fault occurs only sometimes.
I have a problem to debug this, because if I run the program again with the same input, no error is reported and all is OK.
Is there a way, how to "report" in which part of the code error occured or what caused the problem?

The usual way is to have the crashing program generate a corefile and analyze this after the crash. Make sure, that:
the maximum corefile-size is big enough (i.e. unlimited) by calling ulimit -c unlimited in the shell, which starts the process.
The cwd is writable by the segfaulting process.
Then you can analyze the file with
gdb <exe> <corefile>

Since your code not crashing every time, you can use backtrace as well. Using this you can see the function call stack at the time of crash. There are many examples available. In my projects I normally use the following code for backtracing.
/*
* call reg_usr2 function from main
* gcc -rdynamic myfile.c -o output
*/
#include <stdio.h>
#include <stdarg.h>
#include <signal.h>
#include <unistd.h>
#include <stdlib.h>
#include <execinfo.h>
#define FILE_NAME "/tmp/debug"
#define MODE 0xFFFF
void dbgprint(int flag, char* fmt, ...)
{
if(flag & MODE) {
char buf[100];
va_list vlist;
FILE *fp = fopen(FILE_NAME,"a");
va_start(vlist, fmt);
vsnprintf( buf, sizeof( buf), fmt, vlist);
va_end( vlist);
fprintf(fp,"[%x]->%s\n", flag, buf);
fclose(fp);
}
}
/** Here is the code to print backtrace **/
void print_stack_trace ()
{
void *array[20];
size_t size;
char **strings;
size_t i;
size = backtrace (array, 20);
strings = backtrace_symbols (array, size);
dbgprint(0xFFFF, "Obtained %zd stack frames.", size);
dbgprint(0xFFFF, "-------------------------");
dbgprint(0xFFFF, "---------Backtrace-------");
for (i = 0; i < size; i++)
dbgprint (0xFFFF, "%s", strings[i]);
dbgprint(0xFFFF, "-------------------------");
free (strings);
}
void sig_handler(int signo)
{
FILE *fp = fopen(FILE_NAME,"a");
if (signo == SIGUSR2){
dbgprint(0xFFFF, "received SIGUSR2");
dbgprint(0xFFFF, "----------------");
}
print_stack_trace();
exit(0);
}
void reg_usr2()
{
if (signal(SIGUSR2, sig_handler) == SIG_ERR)
printf("\ncan't catch SIGUSR2\n");
}
int main()
{
reg_usr2(); //should be first line of main after variables
//Code.....
return 0;
}

You can generate backtrace by catching SIGSEGV signal, and see where your application throw an invalid access.
see https://stackoverflow.com/a/77336/4490542
But there is more easier solution, try running your application with catchsegv
catchsegv './program args'
and better alternative, valgrind
valgrind --tool=none ./program args

Related

Get line number of exception C [duplicate]

I want to have a way to report the stack trace to the user if an exception is thrown. What is the best way to do this? Does it take huge amounts of extra code?
To answer questions:
I'd like it to be portable if possible. I want information to pop up, so the user can copy the stack trace and email it to me if an error comes up.
Andrew Grant's answer does not help getting a stack trace of the throwing function, at least not with GCC, because a throw statement does not save the current stack trace on its own, and the catch handler won't have access to the stack trace at that point any more.
The only way - using GCC - to solve this is to make sure to generate a stack trace at the point of the throw instruction, and save that with the exception object.
This method requires, of course, that every code that throws an exception uses that particular Exception class.
Update 11 July 2017: For some helpful code, take a look at cahit beyaz's answer, which points to http://stacktrace.sourceforge.net - I haven't used it yet but it looks promising.
It depends which platform.
On GCC it's pretty trivial, see this post for more details.
On MSVC then you can use the StackWalker library that handles all of the underlying API calls needed for Windows.
You'll have to figure out the best way to integrate this functionality into your app, but the amount of code you need to write should be minimal.
If you are using Boost 1.65 or higher, you can use boost::stacktrace:
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
I would like to add a standard library option (i.e. cross-platform) how to generate exception backtraces, which has become available with C++11:
Use std::nested_exception and std::throw_with_nested
This won't give you a stack unwind, but in my opinion the next best thing.
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Unix: backtrace
Mac: backtrace
Windows: CaptureBackTrace
If you are using C++ and don't want/can't use Boost, you can print backtrace with demangled names using the following code [link to the original site].
Note, this solution is specific to Linux. It uses GNU's libc functions backtrace()/backtrace_symbols() (from execinfo.h) to get the backtraces and then uses __cxa_demangle() (from cxxabi.h) for demangling the backtrace symbol names.
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s\n",
symbollist[i], funcname, begin_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s\n",
symbollist[i], begin_name, begin_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
free(funcname);
free(symbollist);
}
#endif // _STACKTRACE_H_
HTH!
AFAIK libunwind is quite portable and so far I haven't found anything easier to use.
I recommend http://stacktrace.sourceforge.net/ project. It support Windows, Mac OS and also Linux
Since the stack is already unwound when entering the catch block, the solution in my case was to not catch certain exceptions which then lead to a SIGABRT. In the signal handler for SIGABRT I then fork() and execl() either gdb (in debug builds) or Google breakpads stackwalk (in release builds). Also I try to only use signal handler safe functions.
GDB:
static const char BACKTRACE_START[] = "<2>--- backtrace of entire stack ---\n";
static const char BACKTRACE_STOP[] = "<2>--- backtrace finished ---\n";
static char *ltrim(char *s)
{
while (' ' == *s) {
s++;
}
return s;
}
void Backtracer::print()
{
int child_pid = ::fork();
if (child_pid == 0) {
// redirect stdout to stderr
::dup2(2, 1);
// create buffer for parent pid (2+16+1 spaces to allow up to a 64 bit hex parent pid)
char pid_buf[32];
const char* stem = " ";
const char* s = stem;
char* d = &pid_buf[0];
while (static_cast<bool>(*s))
{
*d++ = *s++;
}
*d-- = '\0';
char* hexppid = d;
// write parent pid to buffer and prefix with 0x
int ppid = getppid();
while (ppid != 0) {
*hexppid = ((ppid & 0xF) + '0');
if(*hexppid > '9') {
*hexppid += 'a' - '0' - 10;
}
--hexppid;
ppid >>= 4;
}
*hexppid-- = 'x';
*hexppid = '0';
// invoke GDB
char name_buf[512];
name_buf[::readlink("/proc/self/exe", &name_buf[0], 511)] = 0;
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_START[0], sizeof(BACKTRACE_START));
(void)r;
::execl("/usr/bin/gdb",
"/usr/bin/gdb", "--batch", "-n", "-ex", "thread apply all bt full", "-ex", "quit",
&name_buf[0], ltrim(&pid_buf[0]), nullptr);
::exit(1); // if GDB failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
// make it work for non root users
if (0 != getuid()) {
::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
}
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_STOP[0], sizeof(BACKTRACE_STOP));
(void)r;
}
}
minidump_stackwalk:
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
int child_pid = ::fork();
if (child_pid == 0) {
::dup2(open("/dev/null", O_WRONLY), 2); // ignore verbose output on stderr
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_START[0], sizeof(MINIDUMP_STACKWALK_START));
(void)r;
::execl("/usr/bin/minidump_stackwalk", "/usr/bin/minidump_stackwalk", descriptor.path(), "/usr/share/breakpad-syms", nullptr);
::exit(1); // if minidump_stackwalk failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_STOP[0], sizeof(MINIDUMP_STACKWALK_STOP));
(void)r;
}
::remove(descriptor.path()); // this is not signal safe anymore but should still work
return succeeded;
}
Edit: To make it work for breakpad I also had to add this:
std::set_terminate([]()
{
ssize_t r = ::write(STDERR_FILENO, EXCEPTION, sizeof(EXCEPTION));
(void)r;
google_breakpad::ExceptionHandler::WriteMinidump(std::string("/tmp"), dumpCallback, NULL);
exit(1); // avoid creating a second dump by not calling std::abort
});
Source: How to get a stack trace for C++ using gcc with line number information? and Is it possible to attach gdb to a crashed process (a.k.a "just-in-time" debugging)
on linux with g++ check out this lib
https://sourceforge.net/projects/libcsdbg
it does all the work for you
On Windows, check out BugTrap. Its not longer at the original link, but its still available on CodeProject.
I have a similar problem, and though I like portability, I only need gcc support. In gcc, execinfo.h and the backtrace calls are available. To demangle the function names, Mr. Bingmann has a nice piece of code. To dump a backtrace on an exception, I create an exception that prints the backtrace in the constructor. If I were expecting this to work with an exception thrown in a library, it might require rebuilding/linking so that the backtracing exception is used.
/******************************************
#Makefile with flags for printing backtrace with function names
# compile with symbols for backtrace
CXXFLAGS=-g
# add symbols to dynamic symbol table for backtrace
LDFLAGS=-rdynamic
turducken: turducken.cc
******************************************/
#include <cstdio>
#include <stdexcept>
#include <execinfo.h>
#include "stacktrace.h" /* https://panthema.net/2008/0901-stacktrace-demangled/ */
// simple exception that prints backtrace when constructed
class btoverflow_error: public std::overflow_error
{
public:
btoverflow_error( const std::string& arg ) :
std::overflow_error( arg )
{
print_stacktrace();
};
};
void chicken(void)
{
throw btoverflow_error( "too big" );
}
void duck(void)
{
chicken();
}
void turkey(void)
{
duck();
}
int main( int argc, char *argv[])
{
try
{
turkey();
}
catch( btoverflow_error e)
{
printf( "caught exception: %s\n", e.what() );
}
}
Compiling and running this with gcc 4.8.4 yields a backtrace with nicely unmangled C++ function names:
stack trace:
./turducken : btoverflow_error::btoverflow_error(std::string const&)+0x43
./turducken : chicken()+0x48
./turducken : duck()+0x9
./turducken : turkey()+0x9
./turducken : main()+0x15
/lib/x86_64-linux-gnu/libc.so.6 : __libc_start_main()+0xf5
./turducken() [0x401629]
Poppy can gather not only the stack trace, but also parameter values, local variables, etc. - everything leading to the crash.
The following code stops the execution right after an exception is thrown. You need to set a windows_exception_handler along with a termination handler. I tested this in MinGW 32bits.
void beforeCrash(void);
static const bool SET_TERMINATE = std::set_terminate(beforeCrash);
void beforeCrash() {
__asm("int3");
}
int main(int argc, char *argv[])
{
SetUnhandledExceptionFilter(windows_exception_handler);
...
}
Check the following code for the windows_exception_handler function:
http://www.codedisqus.com/0ziVPgVPUk/exception-handling-and-stacktrace-under-windows-mingwgcc.html
Cpp-tool ex_diag - easyweight, multiplatform, minimal resource using, simple and flexible at trace.
A working example for OSX (tested right now on Catalina 10.15). Not portable to linux/windows obviously. Probably it will be usefull to somebody.
In the "Mew-exception" string you can use backtrace and/or backtrace_symbols functions
#include <stdexcept>
#include <typeinfo>
#include <dlfcn.h>
extern "C" void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
static void (*__cxa_throw_orig)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
extern "C" void luna_cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
{
printf("Mew-exception you can catch your backtrace here!");
__cxa_throw_orig(thrown_object, tinfo, dest);
}
//__attribute__ ((used))
//__attribute__ ((section ("__DATA,__interpose")))
static struct replace_pair_t {
void *replacement, *replacee;
} replace_pair = { (void*)luna_cxa_throw, (void*)__cxa_throw };
extern "C" const struct mach_header __dso_handle;
extern "C" void dyld_dynamic_interpose(const struct mach_header*,
const replace_pair_t replacements[],
size_t count);
int fn()
{
int a = 10; ++a;
throw std::runtime_error("Mew!");
}
int main(int argc, const char * argv[]) {
__cxa_throw_orig = (void (*)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)))dlsym(RTLD_DEFAULT, "__cxa_throw");
dyld_dynamic_interpose(&__dso_handle, &replace_pair, 1);
fn();
return 0;
}

Backtrace inside Signal Handler

I'm trying to following the code from this post to have signal handlers print a backtrace on errors such as floating point and segmentation faults. I'm using seg fault signals as a starting point. Here is the code:
#include <cstdlib> //for exit()
#include <signal.h> //signal handling
#include <execinfo.h> //backtrace, backtrace_symbols and backtrace_fd
#include <iostream>
#include <string.h>
#include <stdio.h>
#define TRACE_MSG fprintf(stderr, "TRACE at: %s() [%s:%d]\n", \
__FUNCTION__, __FILE__, __LINE__)
void show_stackframe()
{
void *trace[1024];
char **messages = (char **) NULL;
int i, trace_size = 0;
TRACE_MSG;
trace_size = backtrace(trace, 1024); // segfault here???
// More code here to print backtrace, but not needed at the moment..
TRACE_MSG;
}
void sigSegvHandler( int signum, siginfo_t* info, void* arg )
{
TRACE_MSG;
show_stackframe();
return;
}
double func_b()
{
show_stackframe(); // Show that backtrace works without being
// called inside sighandler.
TRACE_MSG;
int int_a[5];
int_a[0] = 4;
int_a[11] = 10; // cause a segfault on purpose to see
// how the signal handling performs.
return 1.1;
}
int main()
{
// Examine and change the seg fault signal
struct sigaction segvAction; // File: /usr/include/bits/sigaction.h
// Initialize segvAction struct to all zeros for initialiation
memset( &segvAction, 0, sizeof( segvAction ) );
segvAction.sa_sigaction = sigSegvHandler;
segvAction.sa_flags = SA_SIGINFO; //Invoke signal catching function with 3 arguments instead of 1
// Set the action for the SIGSEGV signal
sigaction( SIGSEGV, &segvAction, NULL );
func_b(); // Produce a SIGSEGV error
}
I am compiling using:
g++ -rdynamic testprogram.cpp -o testprogram
I receive the following output from the program:
TRACE at: show_stackframe() [stackoverflow.cpp:15]
TRACE at: show_stackframe() [stackoverflow.cpp:17]
TRACE at: func_b() [stackoverflow.cpp:33]
TRACE at: sigSegvHandler() [stackoverflow.cpp:22]
TRACE at: show_stackframe() [stackoverflow.cpp:15]
Segmentation fault
My question is why does show_stackframe() cause a segmentation fault inside of sigaction but works fine when not inside of the sigaction handler? I obviously seem to be setting up the signal handler/action incorrect but I haven't been able to find it all day. GDB doesn't seem to be any help in this case.
As stated here, the backtrace function is AS-Unsafe, which means it is unsafe to call from an asynchronous signal handler. Doing so invokes undefined behavior.

C++ retreive function or scope [duplicate]

I want to have a way to report the stack trace to the user if an exception is thrown. What is the best way to do this? Does it take huge amounts of extra code?
To answer questions:
I'd like it to be portable if possible. I want information to pop up, so the user can copy the stack trace and email it to me if an error comes up.
Andrew Grant's answer does not help getting a stack trace of the throwing function, at least not with GCC, because a throw statement does not save the current stack trace on its own, and the catch handler won't have access to the stack trace at that point any more.
The only way - using GCC - to solve this is to make sure to generate a stack trace at the point of the throw instruction, and save that with the exception object.
This method requires, of course, that every code that throws an exception uses that particular Exception class.
Update 11 July 2017: For some helpful code, take a look at cahit beyaz's answer, which points to http://stacktrace.sourceforge.net - I haven't used it yet but it looks promising.
It depends which platform.
On GCC it's pretty trivial, see this post for more details.
On MSVC then you can use the StackWalker library that handles all of the underlying API calls needed for Windows.
You'll have to figure out the best way to integrate this functionality into your app, but the amount of code you need to write should be minimal.
If you are using Boost 1.65 or higher, you can use boost::stacktrace:
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
I would like to add a standard library option (i.e. cross-platform) how to generate exception backtraces, which has become available with C++11:
Use std::nested_exception and std::throw_with_nested
This won't give you a stack unwind, but in my opinion the next best thing.
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Unix: backtrace
Mac: backtrace
Windows: CaptureBackTrace
If you are using C++ and don't want/can't use Boost, you can print backtrace with demangled names using the following code [link to the original site].
Note, this solution is specific to Linux. It uses GNU's libc functions backtrace()/backtrace_symbols() (from execinfo.h) to get the backtraces and then uses __cxa_demangle() (from cxxabi.h) for demangling the backtrace symbol names.
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s\n",
symbollist[i], funcname, begin_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s\n",
symbollist[i], begin_name, begin_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
free(funcname);
free(symbollist);
}
#endif // _STACKTRACE_H_
HTH!
AFAIK libunwind is quite portable and so far I haven't found anything easier to use.
I recommend http://stacktrace.sourceforge.net/ project. It support Windows, Mac OS and also Linux
Since the stack is already unwound when entering the catch block, the solution in my case was to not catch certain exceptions which then lead to a SIGABRT. In the signal handler for SIGABRT I then fork() and execl() either gdb (in debug builds) or Google breakpads stackwalk (in release builds). Also I try to only use signal handler safe functions.
GDB:
static const char BACKTRACE_START[] = "<2>--- backtrace of entire stack ---\n";
static const char BACKTRACE_STOP[] = "<2>--- backtrace finished ---\n";
static char *ltrim(char *s)
{
while (' ' == *s) {
s++;
}
return s;
}
void Backtracer::print()
{
int child_pid = ::fork();
if (child_pid == 0) {
// redirect stdout to stderr
::dup2(2, 1);
// create buffer for parent pid (2+16+1 spaces to allow up to a 64 bit hex parent pid)
char pid_buf[32];
const char* stem = " ";
const char* s = stem;
char* d = &pid_buf[0];
while (static_cast<bool>(*s))
{
*d++ = *s++;
}
*d-- = '\0';
char* hexppid = d;
// write parent pid to buffer and prefix with 0x
int ppid = getppid();
while (ppid != 0) {
*hexppid = ((ppid & 0xF) + '0');
if(*hexppid > '9') {
*hexppid += 'a' - '0' - 10;
}
--hexppid;
ppid >>= 4;
}
*hexppid-- = 'x';
*hexppid = '0';
// invoke GDB
char name_buf[512];
name_buf[::readlink("/proc/self/exe", &name_buf[0], 511)] = 0;
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_START[0], sizeof(BACKTRACE_START));
(void)r;
::execl("/usr/bin/gdb",
"/usr/bin/gdb", "--batch", "-n", "-ex", "thread apply all bt full", "-ex", "quit",
&name_buf[0], ltrim(&pid_buf[0]), nullptr);
::exit(1); // if GDB failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
// make it work for non root users
if (0 != getuid()) {
::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
}
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_STOP[0], sizeof(BACKTRACE_STOP));
(void)r;
}
}
minidump_stackwalk:
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
int child_pid = ::fork();
if (child_pid == 0) {
::dup2(open("/dev/null", O_WRONLY), 2); // ignore verbose output on stderr
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_START[0], sizeof(MINIDUMP_STACKWALK_START));
(void)r;
::execl("/usr/bin/minidump_stackwalk", "/usr/bin/minidump_stackwalk", descriptor.path(), "/usr/share/breakpad-syms", nullptr);
::exit(1); // if minidump_stackwalk failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_STOP[0], sizeof(MINIDUMP_STACKWALK_STOP));
(void)r;
}
::remove(descriptor.path()); // this is not signal safe anymore but should still work
return succeeded;
}
Edit: To make it work for breakpad I also had to add this:
std::set_terminate([]()
{
ssize_t r = ::write(STDERR_FILENO, EXCEPTION, sizeof(EXCEPTION));
(void)r;
google_breakpad::ExceptionHandler::WriteMinidump(std::string("/tmp"), dumpCallback, NULL);
exit(1); // avoid creating a second dump by not calling std::abort
});
Source: How to get a stack trace for C++ using gcc with line number information? and Is it possible to attach gdb to a crashed process (a.k.a "just-in-time" debugging)
on linux with g++ check out this lib
https://sourceforge.net/projects/libcsdbg
it does all the work for you
On Windows, check out BugTrap. Its not longer at the original link, but its still available on CodeProject.
I have a similar problem, and though I like portability, I only need gcc support. In gcc, execinfo.h and the backtrace calls are available. To demangle the function names, Mr. Bingmann has a nice piece of code. To dump a backtrace on an exception, I create an exception that prints the backtrace in the constructor. If I were expecting this to work with an exception thrown in a library, it might require rebuilding/linking so that the backtracing exception is used.
/******************************************
#Makefile with flags for printing backtrace with function names
# compile with symbols for backtrace
CXXFLAGS=-g
# add symbols to dynamic symbol table for backtrace
LDFLAGS=-rdynamic
turducken: turducken.cc
******************************************/
#include <cstdio>
#include <stdexcept>
#include <execinfo.h>
#include "stacktrace.h" /* https://panthema.net/2008/0901-stacktrace-demangled/ */
// simple exception that prints backtrace when constructed
class btoverflow_error: public std::overflow_error
{
public:
btoverflow_error( const std::string& arg ) :
std::overflow_error( arg )
{
print_stacktrace();
};
};
void chicken(void)
{
throw btoverflow_error( "too big" );
}
void duck(void)
{
chicken();
}
void turkey(void)
{
duck();
}
int main( int argc, char *argv[])
{
try
{
turkey();
}
catch( btoverflow_error e)
{
printf( "caught exception: %s\n", e.what() );
}
}
Compiling and running this with gcc 4.8.4 yields a backtrace with nicely unmangled C++ function names:
stack trace:
./turducken : btoverflow_error::btoverflow_error(std::string const&)+0x43
./turducken : chicken()+0x48
./turducken : duck()+0x9
./turducken : turkey()+0x9
./turducken : main()+0x15
/lib/x86_64-linux-gnu/libc.so.6 : __libc_start_main()+0xf5
./turducken() [0x401629]
Poppy can gather not only the stack trace, but also parameter values, local variables, etc. - everything leading to the crash.
The following code stops the execution right after an exception is thrown. You need to set a windows_exception_handler along with a termination handler. I tested this in MinGW 32bits.
void beforeCrash(void);
static const bool SET_TERMINATE = std::set_terminate(beforeCrash);
void beforeCrash() {
__asm("int3");
}
int main(int argc, char *argv[])
{
SetUnhandledExceptionFilter(windows_exception_handler);
...
}
Check the following code for the windows_exception_handler function:
http://www.codedisqus.com/0ziVPgVPUk/exception-handling-and-stacktrace-under-windows-mingwgcc.html
Cpp-tool ex_diag - easyweight, multiplatform, minimal resource using, simple and flexible at trace.
A working example for OSX (tested right now on Catalina 10.15). Not portable to linux/windows obviously. Probably it will be usefull to somebody.
In the "Mew-exception" string you can use backtrace and/or backtrace_symbols functions
#include <stdexcept>
#include <typeinfo>
#include <dlfcn.h>
extern "C" void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
static void (*__cxa_throw_orig)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
extern "C" void luna_cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
{
printf("Mew-exception you can catch your backtrace here!");
__cxa_throw_orig(thrown_object, tinfo, dest);
}
//__attribute__ ((used))
//__attribute__ ((section ("__DATA,__interpose")))
static struct replace_pair_t {
void *replacement, *replacee;
} replace_pair = { (void*)luna_cxa_throw, (void*)__cxa_throw };
extern "C" const struct mach_header __dso_handle;
extern "C" void dyld_dynamic_interpose(const struct mach_header*,
const replace_pair_t replacements[],
size_t count);
int fn()
{
int a = 10; ++a;
throw std::runtime_error("Mew!");
}
int main(int argc, const char * argv[]) {
__cxa_throw_orig = (void (*)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)))dlsym(RTLD_DEFAULT, "__cxa_throw");
dyld_dynamic_interpose(&__dso_handle, &replace_pair, 1);
fn();
return 0;
}

How to implement an exception handler with stack trace in C++ [duplicate]

I want to have a way to report the stack trace to the user if an exception is thrown. What is the best way to do this? Does it take huge amounts of extra code?
To answer questions:
I'd like it to be portable if possible. I want information to pop up, so the user can copy the stack trace and email it to me if an error comes up.
Andrew Grant's answer does not help getting a stack trace of the throwing function, at least not with GCC, because a throw statement does not save the current stack trace on its own, and the catch handler won't have access to the stack trace at that point any more.
The only way - using GCC - to solve this is to make sure to generate a stack trace at the point of the throw instruction, and save that with the exception object.
This method requires, of course, that every code that throws an exception uses that particular Exception class.
Update 11 July 2017: For some helpful code, take a look at cahit beyaz's answer, which points to http://stacktrace.sourceforge.net - I haven't used it yet but it looks promising.
It depends which platform.
On GCC it's pretty trivial, see this post for more details.
On MSVC then you can use the StackWalker library that handles all of the underlying API calls needed for Windows.
You'll have to figure out the best way to integrate this functionality into your app, but the amount of code you need to write should be minimal.
If you are using Boost 1.65 or higher, you can use boost::stacktrace:
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
I would like to add a standard library option (i.e. cross-platform) how to generate exception backtraces, which has become available with C++11:
Use std::nested_exception and std::throw_with_nested
This won't give you a stack unwind, but in my opinion the next best thing.
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Unix: backtrace
Mac: backtrace
Windows: CaptureBackTrace
If you are using C++ and don't want/can't use Boost, you can print backtrace with demangled names using the following code [link to the original site].
Note, this solution is specific to Linux. It uses GNU's libc functions backtrace()/backtrace_symbols() (from execinfo.h) to get the backtraces and then uses __cxa_demangle() (from cxxabi.h) for demangling the backtrace symbol names.
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s\n",
symbollist[i], funcname, begin_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s\n",
symbollist[i], begin_name, begin_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
free(funcname);
free(symbollist);
}
#endif // _STACKTRACE_H_
HTH!
AFAIK libunwind is quite portable and so far I haven't found anything easier to use.
I recommend http://stacktrace.sourceforge.net/ project. It support Windows, Mac OS and also Linux
Since the stack is already unwound when entering the catch block, the solution in my case was to not catch certain exceptions which then lead to a SIGABRT. In the signal handler for SIGABRT I then fork() and execl() either gdb (in debug builds) or Google breakpads stackwalk (in release builds). Also I try to only use signal handler safe functions.
GDB:
static const char BACKTRACE_START[] = "<2>--- backtrace of entire stack ---\n";
static const char BACKTRACE_STOP[] = "<2>--- backtrace finished ---\n";
static char *ltrim(char *s)
{
while (' ' == *s) {
s++;
}
return s;
}
void Backtracer::print()
{
int child_pid = ::fork();
if (child_pid == 0) {
// redirect stdout to stderr
::dup2(2, 1);
// create buffer for parent pid (2+16+1 spaces to allow up to a 64 bit hex parent pid)
char pid_buf[32];
const char* stem = " ";
const char* s = stem;
char* d = &pid_buf[0];
while (static_cast<bool>(*s))
{
*d++ = *s++;
}
*d-- = '\0';
char* hexppid = d;
// write parent pid to buffer and prefix with 0x
int ppid = getppid();
while (ppid != 0) {
*hexppid = ((ppid & 0xF) + '0');
if(*hexppid > '9') {
*hexppid += 'a' - '0' - 10;
}
--hexppid;
ppid >>= 4;
}
*hexppid-- = 'x';
*hexppid = '0';
// invoke GDB
char name_buf[512];
name_buf[::readlink("/proc/self/exe", &name_buf[0], 511)] = 0;
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_START[0], sizeof(BACKTRACE_START));
(void)r;
::execl("/usr/bin/gdb",
"/usr/bin/gdb", "--batch", "-n", "-ex", "thread apply all bt full", "-ex", "quit",
&name_buf[0], ltrim(&pid_buf[0]), nullptr);
::exit(1); // if GDB failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
// make it work for non root users
if (0 != getuid()) {
::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
}
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_STOP[0], sizeof(BACKTRACE_STOP));
(void)r;
}
}
minidump_stackwalk:
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
int child_pid = ::fork();
if (child_pid == 0) {
::dup2(open("/dev/null", O_WRONLY), 2); // ignore verbose output on stderr
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_START[0], sizeof(MINIDUMP_STACKWALK_START));
(void)r;
::execl("/usr/bin/minidump_stackwalk", "/usr/bin/minidump_stackwalk", descriptor.path(), "/usr/share/breakpad-syms", nullptr);
::exit(1); // if minidump_stackwalk failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_STOP[0], sizeof(MINIDUMP_STACKWALK_STOP));
(void)r;
}
::remove(descriptor.path()); // this is not signal safe anymore but should still work
return succeeded;
}
Edit: To make it work for breakpad I also had to add this:
std::set_terminate([]()
{
ssize_t r = ::write(STDERR_FILENO, EXCEPTION, sizeof(EXCEPTION));
(void)r;
google_breakpad::ExceptionHandler::WriteMinidump(std::string("/tmp"), dumpCallback, NULL);
exit(1); // avoid creating a second dump by not calling std::abort
});
Source: How to get a stack trace for C++ using gcc with line number information? and Is it possible to attach gdb to a crashed process (a.k.a "just-in-time" debugging)
on linux with g++ check out this lib
https://sourceforge.net/projects/libcsdbg
it does all the work for you
On Windows, check out BugTrap. Its not longer at the original link, but its still available on CodeProject.
I have a similar problem, and though I like portability, I only need gcc support. In gcc, execinfo.h and the backtrace calls are available. To demangle the function names, Mr. Bingmann has a nice piece of code. To dump a backtrace on an exception, I create an exception that prints the backtrace in the constructor. If I were expecting this to work with an exception thrown in a library, it might require rebuilding/linking so that the backtracing exception is used.
/******************************************
#Makefile with flags for printing backtrace with function names
# compile with symbols for backtrace
CXXFLAGS=-g
# add symbols to dynamic symbol table for backtrace
LDFLAGS=-rdynamic
turducken: turducken.cc
******************************************/
#include <cstdio>
#include <stdexcept>
#include <execinfo.h>
#include "stacktrace.h" /* https://panthema.net/2008/0901-stacktrace-demangled/ */
// simple exception that prints backtrace when constructed
class btoverflow_error: public std::overflow_error
{
public:
btoverflow_error( const std::string& arg ) :
std::overflow_error( arg )
{
print_stacktrace();
};
};
void chicken(void)
{
throw btoverflow_error( "too big" );
}
void duck(void)
{
chicken();
}
void turkey(void)
{
duck();
}
int main( int argc, char *argv[])
{
try
{
turkey();
}
catch( btoverflow_error e)
{
printf( "caught exception: %s\n", e.what() );
}
}
Compiling and running this with gcc 4.8.4 yields a backtrace with nicely unmangled C++ function names:
stack trace:
./turducken : btoverflow_error::btoverflow_error(std::string const&)+0x43
./turducken : chicken()+0x48
./turducken : duck()+0x9
./turducken : turkey()+0x9
./turducken : main()+0x15
/lib/x86_64-linux-gnu/libc.so.6 : __libc_start_main()+0xf5
./turducken() [0x401629]
Poppy can gather not only the stack trace, but also parameter values, local variables, etc. - everything leading to the crash.
The following code stops the execution right after an exception is thrown. You need to set a windows_exception_handler along with a termination handler. I tested this in MinGW 32bits.
void beforeCrash(void);
static const bool SET_TERMINATE = std::set_terminate(beforeCrash);
void beforeCrash() {
__asm("int3");
}
int main(int argc, char *argv[])
{
SetUnhandledExceptionFilter(windows_exception_handler);
...
}
Check the following code for the windows_exception_handler function:
http://www.codedisqus.com/0ziVPgVPUk/exception-handling-and-stacktrace-under-windows-mingwgcc.html
Cpp-tool ex_diag - easyweight, multiplatform, minimal resource using, simple and flexible at trace.
A working example for OSX (tested right now on Catalina 10.15). Not portable to linux/windows obviously. Probably it will be usefull to somebody.
In the "Mew-exception" string you can use backtrace and/or backtrace_symbols functions
#include <stdexcept>
#include <typeinfo>
#include <dlfcn.h>
extern "C" void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
static void (*__cxa_throw_orig)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
extern "C" void luna_cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
{
printf("Mew-exception you can catch your backtrace here!");
__cxa_throw_orig(thrown_object, tinfo, dest);
}
//__attribute__ ((used))
//__attribute__ ((section ("__DATA,__interpose")))
static struct replace_pair_t {
void *replacement, *replacee;
} replace_pair = { (void*)luna_cxa_throw, (void*)__cxa_throw };
extern "C" const struct mach_header __dso_handle;
extern "C" void dyld_dynamic_interpose(const struct mach_header*,
const replace_pair_t replacements[],
size_t count);
int fn()
{
int a = 10; ++a;
throw std::runtime_error("Mew!");
}
int main(int argc, const char * argv[]) {
__cxa_throw_orig = (void (*)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)))dlsym(RTLD_DEFAULT, "__cxa_throw");
dyld_dynamic_interpose(&__dso_handle, &replace_pair, 1);
fn();
return 0;
}

C++ display stack trace on exception

I want to have a way to report the stack trace to the user if an exception is thrown. What is the best way to do this? Does it take huge amounts of extra code?
To answer questions:
I'd like it to be portable if possible. I want information to pop up, so the user can copy the stack trace and email it to me if an error comes up.
Andrew Grant's answer does not help getting a stack trace of the throwing function, at least not with GCC, because a throw statement does not save the current stack trace on its own, and the catch handler won't have access to the stack trace at that point any more.
The only way - using GCC - to solve this is to make sure to generate a stack trace at the point of the throw instruction, and save that with the exception object.
This method requires, of course, that every code that throws an exception uses that particular Exception class.
Update 11 July 2017: For some helpful code, take a look at cahit beyaz's answer, which points to http://stacktrace.sourceforge.net - I haven't used it yet but it looks promising.
It depends which platform.
On GCC it's pretty trivial, see this post for more details.
On MSVC then you can use the StackWalker library that handles all of the underlying API calls needed for Windows.
You'll have to figure out the best way to integrate this functionality into your app, but the amount of code you need to write should be minimal.
If you are using Boost 1.65 or higher, you can use boost::stacktrace:
#include <boost/stacktrace.hpp>
// ... somewhere inside the bar(int) function that is called recursively:
std::cout << boost::stacktrace::stacktrace();
I would like to add a standard library option (i.e. cross-platform) how to generate exception backtraces, which has become available with C++11:
Use std::nested_exception and std::throw_with_nested
This won't give you a stack unwind, but in my opinion the next best thing.
It is described on StackOverflow here and here, how you can get a backtrace on your exceptions inside your code without need for a debugger or cumbersome logging, by simply writing a proper exception handler which will rethrow nested exceptions.
Since you can do this with any derived exception class, you can add a lot of information to such a backtrace!
You may also take a look at my MWE on GitHub, where a backtrace would look something like this:
Library API: Exception caught in function 'api_function'
Backtrace:
~/Git/mwe-cpp-exception/src/detail/Library.cpp:17 : library_function failed
~/Git/mwe-cpp-exception/src/detail/Library.cpp:13 : could not open file "nonexistent.txt"
Unix: backtrace
Mac: backtrace
Windows: CaptureBackTrace
If you are using C++ and don't want/can't use Boost, you can print backtrace with demangled names using the following code [link to the original site].
Note, this solution is specific to Linux. It uses GNU's libc functions backtrace()/backtrace_symbols() (from execinfo.h) to get the backtraces and then uses __cxa_demangle() (from cxxabi.h) for demangling the backtrace symbol names.
// stacktrace.h (c) 2008, Timo Bingmann from http://idlebox.net/
// published under the WTFPL v2.0
#ifndef _STACKTRACE_H_
#define _STACKTRACE_H_
#include <stdio.h>
#include <stdlib.h>
#include <execinfo.h>
#include <cxxabi.h>
/** Print a demangled stack backtrace of the caller function to FILE* out. */
static inline void print_stacktrace(FILE *out = stderr, unsigned int max_frames = 63)
{
fprintf(out, "stack trace:\n");
// storage array for stack trace address data
void* addrlist[max_frames+1];
// retrieve current stack addresses
int addrlen = backtrace(addrlist, sizeof(addrlist) / sizeof(void*));
if (addrlen == 0) {
fprintf(out, " <empty, possibly corrupt>\n");
return;
}
// resolve addresses into strings containing "filename(function+address)",
// this array must be free()-ed
char** symbollist = backtrace_symbols(addrlist, addrlen);
// allocate string which will be filled with the demangled function name
size_t funcnamesize = 256;
char* funcname = (char*)malloc(funcnamesize);
// iterate over the returned symbol lines. skip the first, it is the
// address of this function.
for (int i = 1; i < addrlen; i++)
{
char *begin_name = 0, *begin_offset = 0, *end_offset = 0;
// find parentheses and +address offset surrounding the mangled name:
// ./module(function+0x15c) [0x8048a6d]
for (char *p = symbollist[i]; *p; ++p)
{
if (*p == '(')
begin_name = p;
else if (*p == '+')
begin_offset = p;
else if (*p == ')' && begin_offset) {
end_offset = p;
break;
}
}
if (begin_name && begin_offset && end_offset
&& begin_name < begin_offset)
{
*begin_name++ = '\0';
*begin_offset++ = '\0';
*end_offset = '\0';
// mangled name is now in [begin_name, begin_offset) and caller
// offset in [begin_offset, end_offset). now apply
// __cxa_demangle():
int status;
char* ret = abi::__cxa_demangle(begin_name,
funcname, &funcnamesize, &status);
if (status == 0) {
funcname = ret; // use possibly realloc()-ed string
fprintf(out, " %s : %s+%s\n",
symbollist[i], funcname, begin_offset);
}
else {
// demangling failed. Output function name as a C function with
// no arguments.
fprintf(out, " %s : %s()+%s\n",
symbollist[i], begin_name, begin_offset);
}
}
else
{
// couldn't parse the line? print the whole line.
fprintf(out, " %s\n", symbollist[i]);
}
}
free(funcname);
free(symbollist);
}
#endif // _STACKTRACE_H_
HTH!
AFAIK libunwind is quite portable and so far I haven't found anything easier to use.
I recommend http://stacktrace.sourceforge.net/ project. It support Windows, Mac OS and also Linux
Since the stack is already unwound when entering the catch block, the solution in my case was to not catch certain exceptions which then lead to a SIGABRT. In the signal handler for SIGABRT I then fork() and execl() either gdb (in debug builds) or Google breakpads stackwalk (in release builds). Also I try to only use signal handler safe functions.
GDB:
static const char BACKTRACE_START[] = "<2>--- backtrace of entire stack ---\n";
static const char BACKTRACE_STOP[] = "<2>--- backtrace finished ---\n";
static char *ltrim(char *s)
{
while (' ' == *s) {
s++;
}
return s;
}
void Backtracer::print()
{
int child_pid = ::fork();
if (child_pid == 0) {
// redirect stdout to stderr
::dup2(2, 1);
// create buffer for parent pid (2+16+1 spaces to allow up to a 64 bit hex parent pid)
char pid_buf[32];
const char* stem = " ";
const char* s = stem;
char* d = &pid_buf[0];
while (static_cast<bool>(*s))
{
*d++ = *s++;
}
*d-- = '\0';
char* hexppid = d;
// write parent pid to buffer and prefix with 0x
int ppid = getppid();
while (ppid != 0) {
*hexppid = ((ppid & 0xF) + '0');
if(*hexppid > '9') {
*hexppid += 'a' - '0' - 10;
}
--hexppid;
ppid >>= 4;
}
*hexppid-- = 'x';
*hexppid = '0';
// invoke GDB
char name_buf[512];
name_buf[::readlink("/proc/self/exe", &name_buf[0], 511)] = 0;
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_START[0], sizeof(BACKTRACE_START));
(void)r;
::execl("/usr/bin/gdb",
"/usr/bin/gdb", "--batch", "-n", "-ex", "thread apply all bt full", "-ex", "quit",
&name_buf[0], ltrim(&pid_buf[0]), nullptr);
::exit(1); // if GDB failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
// make it work for non root users
if (0 != getuid()) {
::prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0);
}
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDERR_FILENO, &BACKTRACE_STOP[0], sizeof(BACKTRACE_STOP));
(void)r;
}
}
minidump_stackwalk:
static bool dumpCallback(const google_breakpad::MinidumpDescriptor& descriptor, void* context, bool succeeded)
{
int child_pid = ::fork();
if (child_pid == 0) {
::dup2(open("/dev/null", O_WRONLY), 2); // ignore verbose output on stderr
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_START[0], sizeof(MINIDUMP_STACKWALK_START));
(void)r;
::execl("/usr/bin/minidump_stackwalk", "/usr/bin/minidump_stackwalk", descriptor.path(), "/usr/share/breakpad-syms", nullptr);
::exit(1); // if minidump_stackwalk failed to start
} else if (child_pid == -1) {
::exit(1); // if forking failed
} else {
::waitpid(child_pid, nullptr, 0);
ssize_t r = ::write(STDOUT_FILENO, &MINIDUMP_STACKWALK_STOP[0], sizeof(MINIDUMP_STACKWALK_STOP));
(void)r;
}
::remove(descriptor.path()); // this is not signal safe anymore but should still work
return succeeded;
}
Edit: To make it work for breakpad I also had to add this:
std::set_terminate([]()
{
ssize_t r = ::write(STDERR_FILENO, EXCEPTION, sizeof(EXCEPTION));
(void)r;
google_breakpad::ExceptionHandler::WriteMinidump(std::string("/tmp"), dumpCallback, NULL);
exit(1); // avoid creating a second dump by not calling std::abort
});
Source: How to get a stack trace for C++ using gcc with line number information? and Is it possible to attach gdb to a crashed process (a.k.a "just-in-time" debugging)
on linux with g++ check out this lib
https://sourceforge.net/projects/libcsdbg
it does all the work for you
On Windows, check out BugTrap. Its not longer at the original link, but its still available on CodeProject.
I have a similar problem, and though I like portability, I only need gcc support. In gcc, execinfo.h and the backtrace calls are available. To demangle the function names, Mr. Bingmann has a nice piece of code. To dump a backtrace on an exception, I create an exception that prints the backtrace in the constructor. If I were expecting this to work with an exception thrown in a library, it might require rebuilding/linking so that the backtracing exception is used.
/******************************************
#Makefile with flags for printing backtrace with function names
# compile with symbols for backtrace
CXXFLAGS=-g
# add symbols to dynamic symbol table for backtrace
LDFLAGS=-rdynamic
turducken: turducken.cc
******************************************/
#include <cstdio>
#include <stdexcept>
#include <execinfo.h>
#include "stacktrace.h" /* https://panthema.net/2008/0901-stacktrace-demangled/ */
// simple exception that prints backtrace when constructed
class btoverflow_error: public std::overflow_error
{
public:
btoverflow_error( const std::string& arg ) :
std::overflow_error( arg )
{
print_stacktrace();
};
};
void chicken(void)
{
throw btoverflow_error( "too big" );
}
void duck(void)
{
chicken();
}
void turkey(void)
{
duck();
}
int main( int argc, char *argv[])
{
try
{
turkey();
}
catch( btoverflow_error e)
{
printf( "caught exception: %s\n", e.what() );
}
}
Compiling and running this with gcc 4.8.4 yields a backtrace with nicely unmangled C++ function names:
stack trace:
./turducken : btoverflow_error::btoverflow_error(std::string const&)+0x43
./turducken : chicken()+0x48
./turducken : duck()+0x9
./turducken : turkey()+0x9
./turducken : main()+0x15
/lib/x86_64-linux-gnu/libc.so.6 : __libc_start_main()+0xf5
./turducken() [0x401629]
Poppy can gather not only the stack trace, but also parameter values, local variables, etc. - everything leading to the crash.
The following code stops the execution right after an exception is thrown. You need to set a windows_exception_handler along with a termination handler. I tested this in MinGW 32bits.
void beforeCrash(void);
static const bool SET_TERMINATE = std::set_terminate(beforeCrash);
void beforeCrash() {
__asm("int3");
}
int main(int argc, char *argv[])
{
SetUnhandledExceptionFilter(windows_exception_handler);
...
}
Check the following code for the windows_exception_handler function:
http://www.codedisqus.com/0ziVPgVPUk/exception-handling-and-stacktrace-under-windows-mingwgcc.html
Cpp-tool ex_diag - easyweight, multiplatform, minimal resource using, simple and flexible at trace.
A working example for OSX (tested right now on Catalina 10.15). Not portable to linux/windows obviously. Probably it will be usefull to somebody.
In the "Mew-exception" string you can use backtrace and/or backtrace_symbols functions
#include <stdexcept>
#include <typeinfo>
#include <dlfcn.h>
extern "C" void __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
static void (*__cxa_throw_orig)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *));
extern "C" void luna_cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *))
{
printf("Mew-exception you can catch your backtrace here!");
__cxa_throw_orig(thrown_object, tinfo, dest);
}
//__attribute__ ((used))
//__attribute__ ((section ("__DATA,__interpose")))
static struct replace_pair_t {
void *replacement, *replacee;
} replace_pair = { (void*)luna_cxa_throw, (void*)__cxa_throw };
extern "C" const struct mach_header __dso_handle;
extern "C" void dyld_dynamic_interpose(const struct mach_header*,
const replace_pair_t replacements[],
size_t count);
int fn()
{
int a = 10; ++a;
throw std::runtime_error("Mew!");
}
int main(int argc, const char * argv[]) {
__cxa_throw_orig = (void (*)(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)))dlsym(RTLD_DEFAULT, "__cxa_throw");
dyld_dynamic_interpose(&__dso_handle, &replace_pair, 1);
fn();
return 0;
}