libbacktrace_impls.hpp 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. // Copyright Antony Polukhin, 2016-2018.
  2. //
  3. // Distributed under the Boost Software License, Version 1.0. (See
  4. // accompanying file LICENSE_1_0.txt or copy at
  5. // http://www.boost.org/LICENSE_1_0.txt)
  6. #ifndef BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
  7. #define BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
  8. #include <boost/config.hpp>
  9. #ifdef BOOST_HAS_PRAGMA_ONCE
  10. # pragma once
  11. #endif
  12. #include <boost/stacktrace/detail/to_hex_array.hpp>
  13. #include <boost/stacktrace/detail/to_dec_array.hpp>
  14. #include <boost/stacktrace/detail/location_from_symbol.hpp>
  15. #include <boost/core/demangle.hpp>
  16. #include <backtrace.h>
  17. namespace boost { namespace stacktrace { namespace detail {
  18. struct pc_data {
  19. std::string* function;
  20. std::string* filename;
  21. std::size_t line;
  22. };
  23. inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
  24. pc_data& d = *static_cast<pc_data*>(data);
  25. if (d.filename && filename) {
  26. *d.filename = filename;
  27. }
  28. if (d.function && function) {
  29. *d.function = function;
  30. }
  31. d.line = lineno;
  32. return 0;
  33. }
  34. inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
  35. // Do nothing, just return.
  36. }
  37. inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
  38. // Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
  39. // That's why we provide a `prog_location` here.
  40. return ::backtrace_create_state(
  41. prog_location.name(), 0 /*thread-safe*/, boost::stacktrace::detail::libbacktrace_error_callback, 0
  42. );
  43. // TODO: this does not seem to work well when this function is in .so:
  44. // Not async-signal-safe, so this method is not called from async-safe functions.
  45. //
  46. // This function is not async signal safe because:
  47. // * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
  48. // * No guarantees on `backtrace_create_state` function.
  49. // [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
  50. /*
  51. static ::backtrace_state* state = ::backtrace_create_state(
  52. 0, 1 , boost::stacktrace::detail::libbacktrace_error_callback, 0
  53. );
  54. return state;
  55. */
  56. }
  57. struct to_string_using_backtrace {
  58. std::string res;
  59. boost::stacktrace::detail::program_location prog_location;
  60. ::backtrace_state* state;
  61. std::string filename;
  62. std::size_t line;
  63. void prepare_function_name(const void* addr) {
  64. boost::stacktrace::detail::pc_data data = {&res, &filename, 0};
  65. if (state) {
  66. ::backtrace_pcinfo(
  67. state,
  68. reinterpret_cast<uintptr_t>(addr),
  69. boost::stacktrace::detail::libbacktrace_full_callback,
  70. boost::stacktrace::detail::libbacktrace_error_callback,
  71. &data
  72. );
  73. }
  74. line = data.line;
  75. }
  76. bool prepare_source_location(const void* /*addr*/) {
  77. if (filename.empty() || !line) {
  78. return false;
  79. }
  80. res += " at ";
  81. res += filename;
  82. res += ':';
  83. res += boost::stacktrace::detail::to_dec_array(line).data();
  84. return true;
  85. }
  86. to_string_using_backtrace() BOOST_NOEXCEPT {
  87. state = boost::stacktrace::detail::construct_state(prog_location);
  88. }
  89. };
  90. template <class Base> class to_string_impl_base;
  91. typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
  92. inline std::string name_impl(const void* addr) {
  93. std::string res;
  94. boost::stacktrace::detail::program_location prog_location;
  95. ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
  96. boost::stacktrace::detail::pc_data data = {&res, 0, 0};
  97. if (state) {
  98. ::backtrace_pcinfo(
  99. state,
  100. reinterpret_cast<uintptr_t>(addr),
  101. boost::stacktrace::detail::libbacktrace_full_callback,
  102. boost::stacktrace::detail::libbacktrace_error_callback,
  103. &data
  104. );
  105. }
  106. if (!res.empty()) {
  107. res = boost::core::demangle(res.c_str());
  108. }
  109. return res;
  110. }
  111. } // namespace detail
  112. std::string frame::source_file() const {
  113. std::string res;
  114. boost::stacktrace::detail::program_location prog_location;
  115. ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
  116. boost::stacktrace::detail::pc_data data = {0, &res, 0};
  117. if (state) {
  118. ::backtrace_pcinfo(
  119. state,
  120. reinterpret_cast<uintptr_t>(addr_),
  121. boost::stacktrace::detail::libbacktrace_full_callback,
  122. boost::stacktrace::detail::libbacktrace_error_callback,
  123. &data
  124. );
  125. }
  126. return res;
  127. }
  128. std::size_t frame::source_line() const {
  129. boost::stacktrace::detail::program_location prog_location;
  130. ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
  131. boost::stacktrace::detail::pc_data data = {0, 0, 0};
  132. if (state) {
  133. ::backtrace_pcinfo(
  134. state,
  135. reinterpret_cast<uintptr_t>(addr_),
  136. boost::stacktrace::detail::libbacktrace_full_callback,
  137. boost::stacktrace::detail::libbacktrace_error_callback,
  138. &data
  139. );
  140. }
  141. return data.line;
  142. }
  143. }} // namespace boost::stacktrace
  144. #endif // BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP