1

I would like too see the stacktrace after the exception is thrown of course using debugger. Normally, when the exception is never caught, the debugger stops the program after receiving SIGABRT and I can see the whole stack trace and recognize the reason for the exception.

However how to diagnose the cause of the exception after catching it?

#include <iostream>
#include <stdexcept>

void foo() {
    throw std::runtime_error("An error message");
}

int main() {
    try {
        foo();
    } catch (const std::exception &e) {
        std::cerr << e.what(); // add breakpoint here
    }        
    return 0;
}

Adding a breakpoint in the catch section naturally stops the program after catching exception however the stack trace doesn't contain foo() call therefore the cause of the exception cannot be diagnosed.

Please note that the example is really minimal and simple. With complex and nested calls the information that exception occurred somewhere in the try section is virtually useless. And I cannot simply avoid catching exception because if I don't catch it then it is caught by the framework I'm using and the stacktrace is lost.

GPMueller
  • 2,881
  • 2
  • 27
  • 36
Rames
  • 918
  • 11
  • 27
  • 3
    This is specific to a debugger. For GDB type `catch throw` for Visual Studio it is enabled by default. Otherwise, read the documentation shipped with your debugger. – Ivan Aksamentov - Drop Dec 04 '16 at 19:30
  • @Drop I'm interested mostly in GDB. Not as straightforward as putting the breakpoint in IDE but basically works. It stops on every `throw` so not 100% what I wanted but it is quite close and I can accept this as an answer unless someone has a better solution. – Rames Dec 04 '16 at 19:44
  • There is also `catch catch` and other catchpoints ([src](ftp://ftp.gnu.org/old-gnu/Manuals/gdb/html_node/gdb_30.html)). Looks like it's what you need. Although part with backtrace is not included. – Ivan Aksamentov - Drop Dec 04 '16 at 19:53

4 Answers4

0

However how too diagnose the cause of the exception after catching it?

You cannot. The stack has already been unwound at the point of the catch. If you want to diagnose reasons for a throw you'll need to include them in the exception at the point of the throw (this could include a full stack trace if you were so inclined, but that would be system-dependent).

Other things you might want to consider:

a) add more precondition checks at the call sites of API calls (where you can't modify the code in the call)

b) add precondition checks (asserts or throws) in functions and methods that you control. You can remove them in a release build if performance is an issue.

c) include the full reason for the throw in the message of thrown exceptions.

Richard Hodges
  • 68,278
  • 7
  • 90
  • 142
0

I have never used it myself, but might worth taking a look at it:

https://www.codeproject.com/articles/11132/walking-the-callstack

Especially at the paragraph

Displaying the callstack of an exception

With this StackWalker you can also display the callstack inside an exception handler. You only need to write a filter-function which does the stack-walking.

GeorgeT
  • 484
  • 3
  • 5
  • That's windows and MSVC specific answer. I will not accept it since I cannot check it on Linux, but may be useful for others reading this topic. – Rames Dec 04 '16 at 20:52
0

If you are working with your own exceptions, then my libexcept library may be useful to you. This library offers a few class. The base class is capable of collecting a stack trace at the time it gets instantiated. 99% of the time, this gives you all the information you need to debug the issue. When you just know where the exception occurred, but not how it was called, it can be much more difficult to kow how to fix the problem. (Yeah! Because the same function may be called in 20 different ways so just knowing exactly which exception occurred is often not enough.)

In a project where you throw exceptions only when something really bad happens, this can even be kept in your release version. Then you can log the stack traces in your client's logs and make it hundred of times easier to debug remote/end client crashes.

I have a binary (pre-compiled version) for Ubuntu 16.04 on Launchpad (install the PPA in your apt lists and then install libexcept_1.0.5.0~xenial_amd64.deb or whatever version is current.)

To use, derive from one of the two classes offered:

class my_exception : public libexcept::logic_exception_t
{
   ...
};

And in your catch() you can print the stack trace using the get_stack_trace() to get a vector of strings. In our case, we actually send that to our logs.

try
{
    ...
    throw my_exception("what happened?!");
    ...
}
catch(my_exception const & e)
{
    stack_trace_t const & stack(e.get_stack_trace());
    for(auto s : stack)
    {
        SNAP_LOG_ERROR(*s);
    }
}

Obviously, you probably will want to have a function if you are to log the stack trace in many places.

For exceptions that you do not generate, though, you just can't really do much. However, you can re-throw with your own exception if you want to write a wrapper so as to at least narrow the location where the exceptions are coming from.

Say you are using a 3rd party library and expect library to throw once in a while...

try
{
    library::func();   // may throw
}
catch(library::exception const & e)
{
    throw my_exception(e.what());   // converted exception
}

Now you at least have a stack trace from this low level catch.

Alexis Wilke
  • 19,179
  • 10
  • 84
  • 156
0

This question is rather old, but I want to add that one can do such a trace in standard C++11:

Use std::nested_exception and std::throw_with_nested

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! It should work fine to add a breakpoint in the corresponding catch-statement where you generated the 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"

or my "trace" library, which is similar to what was given in this answer, but cross-platform.

GPMueller
  • 2,881
  • 2
  • 27
  • 36