Dukales

backtrace on terminate

Jul 24th, 2015
341
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 3.92 KB | None | 0 0
  1. // interface: demagle.hpp
  2. #pragma once
  3.  
  4. char const *
  5. get_demangled_name(char const * const symbol) noexcept;
  6.  
  7. //interface: backtrace.hpp
  8. #pragma once
  9. #include <ostream>
  10.  
  11. void
  12. backtrace(std::ostream & _out) noexcept;
  13.  
  14. // implementation: demangle.cpp
  15. #include "demangle.hpp"
  16.  
  17. #include <memory>
  18.  
  19. #include <cstdlib>
  20.  
  21. #include <cxxabi.h>
  22.  
  23. namespace
  24. {
  25.  
  26. #pragma clang diagnostic push
  27. #pragma clang diagnostic ignored "-Wglobal-constructors"
  28. #pragma clang diagnostic ignored "-Wexit-time-destructors"
  29. std::unique_ptr< char, decltype(std::free) & > demangled_name{nullptr, std::free};
  30. #pragma clang diagnostic pop
  31.  
  32. }
  33.  
  34. char const *
  35. get_demangled_name(char const * const symbol) noexcept
  36. {
  37.     if (!symbol) {
  38.         return "<null>";
  39.     }
  40.     int status = -4;
  41.     demangled_name.reset(abi::__cxa_demangle(symbol, demangled_name.release(), nullptr, &status));
  42.     return ((status == 0) ? demangled_name.get() : symbol);
  43. }
  44.  
  45. // implementation: backtrace.cpp
  46. #include "backtrace.hpp"
  47.  
  48. #include <iostream>
  49. #include <iomanip>
  50. #include <limits>
  51. #include <ostream>
  52.  
  53. #include <cstdint>
  54.  
  55. #define UNW_LOCAL_ONLY
  56. #include <libunwind.h>
  57.  
  58. namespace
  59. {
  60.  
  61. void
  62. print_reg(std::ostream & _out, unw_word_t reg) noexcept
  63. {
  64.     constexpr std::size_t address_width = std::numeric_limits< std::uintptr_t >::digits / 4;
  65.     _out << "0x" << std::setfill('0') << std::setw(address_width) << reg;
  66. }
  67.  
  68. char symbol[1024];
  69.  
  70. }
  71.  
  72. void
  73. backtrace(std::ostream & _out) noexcept
  74. {
  75.     unw_cursor_t cursor;
  76.     unw_context_t context;
  77.     unw_getcontext(&context);
  78.     unw_init_local(&cursor, &context);
  79.     _out << std::hex << std::uppercase;
  80.     while (0 < unw_step(&cursor)) {
  81.         unw_word_t ip = 0;
  82.         unw_get_reg(&cursor, UNW_REG_IP, &ip);
  83.         if (ip == 0) {
  84.             break;
  85.         }
  86.         unw_word_t sp = 0;
  87.         unw_get_reg(&cursor, UNW_REG_SP, &sp);
  88.         print_reg(_out, ip);
  89.         _out << ": (SP:";
  90.         print_reg(_out, sp);
  91.         _out << ") ";
  92.         unw_word_t offset = 0;
  93.         if (unw_get_proc_name(&cursor, symbol, sizeof(symbol), &offset) == 0) {
  94.             _out << "(" << get_demangled_name(symbol) << " + 0x" << offset << ")\n\n";
  95.         } else {
  96.             _out << "-- error: unable to obtain symbol name for this frame\n\n";
  97.         }
  98.     }
  99.     _out << std::flush;
  100. }
  101.  
  102. // implementation: backtrace_on_terminate.hpp
  103. #include "demangle.hpp"
  104. #include "backtrace.hpp"
  105.  
  106. #include <iostream>
  107. #include <type_traits>
  108. #include <exception>
  109. #include <memory>
  110. #include <typeinfo>
  111.  
  112. #include <cstdlib>
  113.  
  114. #include <cxxabi.h>
  115.  
  116. namespace
  117. {
  118.  
  119. [[noreturn]]
  120. void
  121. backtrace_on_terminate() noexcept;
  122.  
  123. static_assert(std::is_same< std::terminate_handler, decltype(&backtrace_on_terminate) >{});
  124.  
  125. #pragma clang diagnostic push
  126. #pragma clang diagnostic ignored "-Wglobal-constructors"
  127. #pragma clang diagnostic ignored "-Wexit-time-destructors"
  128. std::unique_ptr< std::remove_pointer_t< std::terminate_handler >, decltype(std::set_terminate) & > terminate_handler{std::set_terminate(backtrace_on_terminate), std::set_terminate};
  129. #pragma clang diagnostic pop
  130.  
  131. [[noreturn]]
  132. void
  133. backtrace_on_terminate() noexcept
  134. {
  135.     std::set_terminate(terminate_handler.release()); // to avoid infinite looping if any
  136.     backtrace(std::clog);
  137.     if (std::exception_ptr ep = std::current_exception()) {
  138.         try {
  139.             std::rethrow_exception(ep);
  140.         } catch (std::exception const & e) {
  141.             std::clog << "backtrace: unhandled exception derived from std::exception: " << e.what() << std::endl;
  142.         } catch (...) {
  143.             if (std::type_info * et = abi::__cxa_current_exception_type()) {
  144.                 std::clog << "backtrace: unhandled exception type: " << get_demangled_name(et->name()) << std::endl;
  145.             } else {
  146.                 std::clog << "backtrace: unhandled unknown exception" << std::endl;
  147.             }
  148.         }
  149.     }
  150.     std::_Exit(EXIT_FAILURE);
  151. }
  152.  
  153. }
Advertisement
Add Comment
Please, Sign In to add comment