SourceXR

C/C++ Cross-Reference Tool

Display an Exception Call Stack when Caught

It is very annoying and frustrating when a program is catching exceptions very deeply in the call stack because we lose all the information where the exception was thrown.

We implemented a small helper class based on the backtrace() function from the GNU C library that can be used to record the call stack when the exception is thrown and displayed when caught (or whenever if caught and rethrown).

Getting the Callstack

#include <string>
#include <execinfo.h> // backtrace(), etc

class ExcStack
{
    static const int size = 64;
    int _btsize;
    void *_buffer[size];

public:
    virtual ~ExcStack() {}

    ExcStack () {
        // record the call stack when the exception
        // is built
        _btsize = backtrace (_buffer, size);
    }

    void print (int fd) {
        backtrace_symbols_fd (_buffer, _btsize, fd);
    }

};

This class can be inherited from and whenever needed the print() method can be used to print the call stack to a file descriptor. It will be in raw format. The Perl script available here can be used to get the files and lines.

Sample Program

A very simple proof of concept is written below:

#include <string>
#include <iostream>

#include "ExcStack.h" // ExcStack class declaration

// all exceptions should inherit the helper class
class MyException : public ExcStack
{
    std::string _msg;
public:
    MyException (const char *msg)
     : _msg (msg)
    {}

    const char *what () { return _msg.c_str (); }
};

// samples functions
// throw exception
void fun () {
    throw MyException ("fun()");
}

void fun1 () {
    fun ();
}

void fun2 () {
    fun1 ();
}

int main ()
{
    try {
        fun2();
    }
    catch (MyException &e) {
        std::cerr << "exception caught: " << e.what () << "\n";
        e.print (2); // stderr fd
    }
    return 0;
}

If we run the previous program along with the stack printer we would get the following output (make sure to compile with the -g flag to have debug symbols):

exception caught: fun()
./a.out[0x400fd8]
./a.out[0x40103b]
./a.out[0x400e1d]
./a.out[0x400e4e]
./a.out[0x400e59]
./a.out[0x400e69]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xfd)[0x7f825e6a6ead]
./a.out[0x400d19]

And run through the Perl script, the output would be like the following one:

ExcStack::ExcStack() at exccallstack.cpp:15
MyException::MyException(char const*) at exccallstack.cpp:32
fun() at exccallstack.cpp:38
fun1() at exccallstack.cpp:43
fun2() at exccallstack.cpp:47
main at exccallstack.cpp:59
??
??:0
_start at ??:0

Calls to exception constructors are shown first, followed by the instantiation point where the exception was thrown.

Comments !