How can I print stack trace for caught exceptions in C++ & code injection in C++

Viewed 27162

I want to have stack trace not for my exceptions only but also for any descendants of std::exception

As I understand, stack trace is completely lost when exception is caught because of stack unwinding (unrolling).

So the only way I see to grab it is injection of code saving context info (stack trace) at the place of std::exception constructor call. Am I right?

If it is the case, please tell me how code injection can be done (if it can) in C++. Your method may be not completely safe because I need it for Debug version of my app only. May be I need to use assembler?

I'm interested only in solution for GCC. It can use c++0x features

5 Answers

Check out backward at backward-cpp it does a good job and is well maintained

Example code

In trace.hxx

#define BACKWARD_HAS_DW 1 // or #define BACKWARD_HAS_BFD 1 check docs
#include <backward.hpp>

class recoverable_err final: std::runtime_error
  {
    backward::StackTrace stacktrace_;

  public:
    explicit recoverable_err(std::string msg) noexcept;

    auto
    print_stacktrace(std::ostream &stream)const noexcept -> void;

    [[nodiscard]] auto
    what() const noexcept -> const char * final;
  };

In trace.cxx

  #include "trace.hxx"
  
  recoverable_err::recoverable_err(std::string msg) noexcept
      : std::runtime_error{ msg }
      , stacktrace_{ backward::StackTrace() }
  {
    stacktrace_.load_here();
  }

  auto
  recoverable_err::print_stacktrace(std::ostream &stream)const  noexcept -> void
  {
    using namespace backward;
    Printer p;
    p.object = true;
    p.color_mode = ColorMode::always;
    p.address = true;
    p.print(stacktrace_, stream);
  }

  auto
  recoverable_err::what() const noexcept -> const char *
  {
    return std::runtime_error::what();
  }

Usage in main

auto
main() -> int
{
  try
    {
      throw recoverable_err("Recover from nasty error");
    }
  catch (recoverable_err const &ex)
    {
      std::cerr << ex.what();
      ex.print_stacktrace(std::cerr);
    }
  catch (std::exception const &ex)
    {
      std::cerr << "Using default class\n";
      std::cerr << ex.what();
    }
}
Related