github.com/searKing/golang/go@v1.2.117/runtime/cgosymbolizer/include/boost/stacktrace/detail/libbacktrace_impls.hpp (about)

     1  // Copyright Antony Polukhin, 2016-2020.
     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  
     7  #ifndef BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
     8  #define BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP
     9  
    10  #include <boost/config.hpp>
    11  #ifdef BOOST_HAS_PRAGMA_ONCE
    12  #   pragma once
    13  #endif
    14  
    15  #include <boost/stacktrace/detail/to_hex_array.hpp>
    16  #include <boost/stacktrace/detail/to_dec_array.hpp>
    17  #include <boost/stacktrace/detail/location_from_symbol.hpp>
    18  #include <boost/core/demangle.hpp>
    19  
    20  #ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
    21  #   include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
    22  #else
    23  #   include <backtrace.h>
    24  #endif
    25  
    26  namespace boost { namespace stacktrace { namespace detail {
    27  
    28  
    29  struct pc_data {
    30      std::string* function;
    31      std::string* filename;
    32      std::size_t line;
    33  };
    34  
    35  inline void libbacktrace_syminfo_callback(void *data, uintptr_t /*pc*/, const char *symname, uintptr_t /*symval*/, uintptr_t /*symsize*/) {
    36      pc_data& d = *static_cast<pc_data*>(data);
    37      if (d.function && symname) {
    38          *d.function = symname;
    39      }
    40  }
    41  
    42  // Old versions of libbacktrace have different signature for the callback
    43  inline void libbacktrace_syminfo_callback(void *data, uintptr_t pc, const char *symname, uintptr_t symval) {
    44      boost::stacktrace::detail::libbacktrace_syminfo_callback(data, pc, symname, symval, 0);
    45  }
    46  
    47  inline int libbacktrace_full_callback(void *data, uintptr_t /*pc*/, const char *filename, int lineno, const char *function) {
    48      pc_data& d = *static_cast<pc_data*>(data);
    49      if (d.filename && filename) {
    50          *d.filename = filename;
    51      }
    52      if (d.function && function) {
    53          *d.function = function;
    54      }
    55      d.line = lineno;
    56      return 0;
    57  }
    58  
    59  inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
    60      // Do nothing, just return.
    61  }
    62  
    63  // Not async-signal-safe, so this method is not called from async-safe functions.
    64  //
    65  // This function is not async signal safe because:
    66  // * Dynamic initialization of a block-scope variable with static storage duration could lock a mutex
    67  // * No guarantees on `backtrace_create_state` function.
    68  //
    69  // Currently `backtrace_create_state` can not detect file name on Windows https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82543
    70  // That's why we provide a `prog_location` here.
    71  BOOST_SYMBOL_VISIBLE inline ::backtrace_state* construct_state(const program_location& prog_location) BOOST_NOEXCEPT {
    72      // [dcl.inline]: A static local variable in an inline function with external linkage always refers to the same object.
    73  
    74      // TODO: The most obvious solution:
    75      //
    76      //static ::backtrace_state* state = ::backtrace_create_state(
    77      //    prog_location.name(),
    78      //    1, // allow safe concurrent usage of the same state
    79      //    boost::stacktrace::detail::libbacktrace_error_callback,
    80      //    0 // pointer to data that will be passed to callback
    81      //);
    82      //
    83      //
    84      // Unfortunately, that solution segfaults when `construct_state()` function is in .so file
    85      // and multiple threads concurrently work with state.
    86  
    87  
    88  #ifndef BOOST_HAS_THREADS
    89      static
    90  #else
    91  
    92      // Result of `construct_state()` invocation is not stored by the callers, so `thread_local`
    93      // gives a single `state` per thread and that state is not shared between threads in any way.
    94  
    95  #   ifndef BOOST_NO_CXX11_THREAD_LOCAL
    96      thread_local
    97  #   elif defined(__GNUC__)
    98      static __thread
    99  #   else
   100      /* just a local variable */
   101  #   endif
   102  
   103  #endif
   104        ::backtrace_state* state = ::backtrace_create_state(
   105          prog_location.name(),
   106          0,
   107          boost::stacktrace::detail::libbacktrace_error_callback,
   108          0
   109      );
   110      return state;
   111  }
   112  
   113  struct to_string_using_backtrace {
   114      std::string res;
   115      boost::stacktrace::detail::program_location prog_location;
   116      ::backtrace_state* state;
   117      std::string filename;
   118      std::size_t line;
   119  
   120      void prepare_function_name(const void* addr) {
   121          boost::stacktrace::detail::pc_data data = {&res, &filename, 0};
   122          if (state) {
   123              ::backtrace_pcinfo(
   124                  state,
   125                  reinterpret_cast<uintptr_t>(addr),
   126                  boost::stacktrace::detail::libbacktrace_full_callback,
   127                  boost::stacktrace::detail::libbacktrace_error_callback,
   128                  &data
   129              ) 
   130              ||
   131              ::backtrace_syminfo(
   132                  state,
   133                  reinterpret_cast<uintptr_t>(addr),
   134                  boost::stacktrace::detail::libbacktrace_syminfo_callback,
   135                  boost::stacktrace::detail::libbacktrace_error_callback,
   136                  &data
   137              );
   138          }
   139          line = data.line;
   140      }
   141  
   142      bool prepare_source_location(const void* /*addr*/) {
   143          if (filename.empty() || !line) {
   144              return false;
   145          }
   146  
   147          res += " at ";
   148          res += filename;
   149          res += ':';
   150          res += boost::stacktrace::detail::to_dec_array(line).data();
   151          return true;
   152      }
   153  
   154      to_string_using_backtrace() BOOST_NOEXCEPT {
   155          state = boost::stacktrace::detail::construct_state(prog_location);
   156      }
   157  };
   158  
   159  template <class Base> class to_string_impl_base;
   160  typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
   161  
   162  inline std::string name_impl(const void* addr) {
   163      std::string res;
   164  
   165      boost::stacktrace::detail::program_location prog_location;
   166      ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
   167  
   168      boost::stacktrace::detail::pc_data data = {&res, 0, 0};
   169      if (state) {
   170          ::backtrace_pcinfo(
   171              state,
   172              reinterpret_cast<uintptr_t>(addr),
   173              boost::stacktrace::detail::libbacktrace_full_callback,
   174              boost::stacktrace::detail::libbacktrace_error_callback,
   175              &data
   176          )
   177          ||
   178          ::backtrace_syminfo(
   179              state,
   180              reinterpret_cast<uintptr_t>(addr),
   181              boost::stacktrace::detail::libbacktrace_syminfo_callback,
   182              boost::stacktrace::detail::libbacktrace_error_callback,
   183              &data
   184          );
   185      }
   186      if (!res.empty()) {
   187          res = boost::core::demangle(res.c_str());
   188      }
   189  
   190      return res;
   191  }
   192  
   193  } // namespace detail
   194  
   195  std::string frame::source_file() const {
   196      std::string res;
   197  
   198      if (!addr_) {
   199          return res;
   200      }
   201  
   202      boost::stacktrace::detail::program_location prog_location;
   203      ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
   204  
   205      boost::stacktrace::detail::pc_data data = {0, &res, 0};
   206      if (state) {
   207          ::backtrace_pcinfo(
   208              state,
   209              reinterpret_cast<uintptr_t>(addr_),
   210              boost::stacktrace::detail::libbacktrace_full_callback,
   211              boost::stacktrace::detail::libbacktrace_error_callback,
   212              &data
   213          );
   214      }
   215  
   216      return res;
   217  }
   218  
   219  std::size_t frame::source_line() const {
   220      if (!addr_) {
   221          return 0;
   222      }
   223  
   224      boost::stacktrace::detail::program_location prog_location;
   225      ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
   226  
   227      boost::stacktrace::detail::pc_data data = {0, 0, 0};
   228      if (state) {
   229          ::backtrace_pcinfo(
   230              state,
   231              reinterpret_cast<uintptr_t>(addr_),
   232              boost::stacktrace::detail::libbacktrace_full_callback,
   233              boost::stacktrace::detail::libbacktrace_error_callback,
   234              &data
   235          );
   236      }
   237  
   238      return data.line;
   239  }
   240  
   241  
   242  }} // namespace boost::stacktrace
   243  
   244  #endif // BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP