backward-cpp ライブラリ#

backward-cpp は簡単に読みやすいスタックトレースを出力するライブラリ。

以下に使用してみた例を示す。

Note

このリポジトリ にソースコードとビルド用の CMakeLists.txt などを置いた。

スタックトレースを取得する例#

#include <backward.hpp>

void test1() {
    backward::StackTrace st;
    st.load_here();
    backward::Printer p;
    p.object = true;
    p.color_mode = backward::ColorMode::automatic;
    p.address = true;
    p.print(st, stderr);
}

class Test {
public:
    void test2(const std::string &) { test1(); }
};

int main() {
    Test().test2("abc");
    return 0;
}

これを実行すると次のようになった。

$ ./bin/test_backtrace
Stack trace (most recent call last):
#7    Object "", at 0xffffffffffffffff, in
#6    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_backtrace", at 0x4048fd, in _start
#5    Object "/lib/x86_64-linux-gnu/libc.so.6", at 0x7f820fff30b2, in __libc_start_main
#4    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_backtrace", at 0x404adf, in main
      Source "/home/kenta/test/test-backward-cpp/src/test_backtrace.cpp", line 19, in int main() [0x404adf]
         16: };
         17:
         18: int main() {
      >  19:     Test().test2("abc");
         20:     return 0;
         21: }
#3    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_backtrace", at 0x404e54, in Test::test2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
      Source "/home/kenta/test/test-backward-cpp/src/test_backtrace.cpp", line 15, in Test::test2(const string &) [0x404e54]
         13: class Test {
         14: public:
      >  15:     void test2(const std::string &) { test1(); }
         16: };
         17:
         18: int main() {
#2    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_backtrace", at 0x4049f2, in test1()
      Source "/home/kenta/test/test-backward-cpp/src/test_backtrace.cpp", line 5, in test1() [0x4049f2]
          3: void test1() {
          4:     backward::StackTrace st;
      >   5:     st.load_here();
          6:     backward::Printer p;
          7:     p.object = true;
          8:     p.color_mode = backward::ColorMode::automatic;
#1    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_backtrace", at 0x404be1, in backward::StackTraceImpl<backward::system_tag::linux_tag>::load_here(unsigned long, void*, void*)
      Source "/home/kenta/.conan/data/backward-cpp/1.6/_/_/package/759153e8b6a68049c52431bd581c49bae41f8bda/include/backward.hpp", line 869, in size_t backward::StackTraceImpl<backward::system_tag::linux_tag>::load_here(size_t depth, void *context, void *error_addr) [0x404be1]
        866:       return 0;
        867:     }
        868:     _stacktrace.resize(depth);
      > 869:     size_t trace_cnt = details::unwind(callback(*this), depth);
        870:     _stacktrace.resize(trace_cnt);
        871:     skip_n_firsts(0);
        872:     return size();
#0    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_backtrace", at 0x405110, in unsigned long backward::details::unwind<backward::StackTraceImpl<backward::system_tag::linux_tag>::callback>(backward::StackTraceImpl<backward::system_tag::linux_tag>::callback, unsigned long)
      Source "/home/kenta/.conan/data/backward-cpp/1.6/_/_/package/759153e8b6a68049c52431bd581c49bae41f8bda/include/backward.hpp", line 851, in size_t backward::details::unwind<backward::StackTraceImpl<backward::system_tag::linux_tag>::callback>(callback f, size_t depth) [0x405110]
        849: template <typename F> size_t unwind(F f, size_t depth) {
        850:   Unwinder<F> unwinder;
      > 851:   return unwinder(f, depth);
        852: }
        853:
        854: } // namespace details

例外にスタックトレースを含める例#

#include <sstream>

#include <backward.hpp>

[[noreturn]] void throw_with_backtrace(const std::string& message) {
    std::ostringstream stream;
    stream << message << "\n\n";

    backward::StackTrace st;
    st.load_here();
    backward::Printer p;
    p.object = true;
    p.color_mode = backward::ColorMode::never;
    p.address = true;
    p.print(st, stream);

    throw std::runtime_error(stream.str());
}

void test1() { throw_with_backtrace("Test exception"); }

class Test {
public:
    void test2(const std::string&) { test1(); }
};

int main() {
    Test().test2("abc");
    return 0;
}

これを実行すると次のようになった。

$ ./bin/test_exception
terminate called after throwing an instance of 'std::runtime_error'
  what():  Test exception

Stack trace (most recent call last):
#8    Object "", at 0xffffffffffffffff, in
#7    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_exception", at 0x40381d, in _start
#6    Object "/lib/x86_64-linux-gnu/libc.so.6", at 0x7f7b48a790b2, in __libc_start_main
#5    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_exception", at 0x403bbf, in main
      Source "/home/kenta/test/test-backward-cpp/src/test_exception.cpp", line 28, in int main() [0x403bbf]
         25: };
         26:
         27: int main() {
      >  28:     Test().test2("abc");
         29:     return 0;
         30: }
#4    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_exception", at 0x403e74, in Test::test2(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
      Source "/home/kenta/test/test-backward-cpp/src/test_exception.cpp", line 24, in Test::test2(const string &) [0x403e74]
         22: class Test {
         23: public:
      >  24:     void test2(const std::string&) { test1(); }
         25: };
         26:
         27: int main() {
#3    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_exception", at 0x403b34, in test1()
      Source "/home/kenta/test/test-backward-cpp/src/test_exception.cpp", line 20, in test1() [0x403b34]
         17:     throw std::runtime_error(stream.str());
         18: }
         19:
      >  20: void test1() { throw_with_backtrace("Test exception"); }
         21:
         22: class Test {
         23: public:
#2    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_exception", at 0x40395f, in throw_with_backtrace(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)
      Source "/home/kenta/test/test-backward-cpp/src/test_exception.cpp", line 10, in throw_with_backtrace(const string &message) [0x40395f]
          7:     stream << message << "\n\n";
          8:
          9:     backward::StackTrace st;
      >  10:     st.load_here();
         11:     backward::Printer p;
         12:     p.object = true;
         13:     p.color_mode = backward::ColorMode::never;
#1    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_exception", at 0x403cc1, in backward::StackTraceImpl<backward::system_tag::linux_tag>::load_here(unsigned long, void*, void*)
      Source "/home/kenta/.conan/data/backward-cpp/1.6/_/_/package/759153e8b6a68049c52431bd581c49bae41f8bda/include/backward.hpp", line 869, in size_t backward::StackTraceImpl<backward::system_tag::linux_tag>::load_here(size_t depth, void *context, void *error_addr) [0x403cc1]
        866:       return 0;
        867:     }
        868:     _stacktrace.resize(depth);
      > 869:     size_t trace_cnt = details::unwind(callback(*this), depth);
        870:     _stacktrace.resize(trace_cnt);
        871:     skip_n_firsts(0);
        872:     return size();
#0    Object "/home/kenta/test/test-backward-cpp/build/Debug/bin/test_exception", at 0x404130, in unsigned long backward::details::unwind<backward::StackTraceImpl<backward::system_tag::linux_tag>::callback>(backward::StackTraceImpl<backward::system_tag::linux_tag>::callback, unsigned long)
      Source "/home/kenta/.conan/data/backward-cpp/1.6/_/_/package/759153e8b6a68049c52431bd581c49bae41f8bda/include/backward.hpp", line 851, in size_t backward::details::unwind<backward::StackTraceImpl<backward::system_tag::linux_tag>::callback>(callback f, size_t depth) [0x404130]
        849: template <typename F> size_t unwind(F f, size_t depth) {
        850:   Unwinder<F> unwinder;
      > 851:   return unwinder(f, depth);
        852: }
        853:
        854: } // namespace details

Aborted

例外を投げる部分でスタックトレースを含める必要があるため、既存のライブラリなどが投げる例外には使用できないが、自分でライブラリを作る際には役に立つのではないか。