github.com/searKing/golang/go@v1.2.117/os/signal/cgo/include/boost/stacktrace/detail/libbacktrace_impls.hpp (about)

     1  // Copyright Antony Polukhin, 2016-2023.
     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*/) 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) 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. I failed to localize the root cause:
    86      // https://gcc.gnu.org/bugzilla//show_bug.cgi?id=87653
    87  
    88  #define BOOST_STACKTRACE_DETAIL_IS_MT 1
    89  
    90  #if !defined(BOOST_HAS_THREADS)
    91  #   define BOOST_STACKTRACE_DETAIL_STORAGE static
    92  #   undef BOOST_STACKTRACE_DETAIL_IS_MT
    93  #   define BOOST_STACKTRACE_DETAIL_IS_MT 0
    94  #elif defined(BOOST_STACKTRACE_BACKTRACE_FORCE_STATIC)
    95  #   define BOOST_STACKTRACE_DETAIL_STORAGE static
    96  #elif !defined(BOOST_NO_CXX11_THREAD_LOCAL)
    97  #   define BOOST_STACKTRACE_DETAIL_STORAGE thread_local
    98  #elif defined(__GNUC__) && !defined(__clang__)
    99  #   define BOOST_STACKTRACE_DETAIL_STORAGE static __thread
   100  #else
   101  #   define BOOST_STACKTRACE_DETAIL_STORAGE /* just a local variable */
   102  #endif
   103  
   104      BOOST_STACKTRACE_DETAIL_STORAGE ::backtrace_state* state = ::backtrace_create_state(
   105          prog_location.name(),
   106          BOOST_STACKTRACE_DETAIL_IS_MT,
   107          boost::stacktrace::detail::libbacktrace_error_callback,
   108          0
   109      );
   110  
   111  #undef BOOST_STACKTRACE_DETAIL_IS_MT
   112  #undef BOOST_STACKTRACE_DETAIL_STORAGE
   113  
   114      return state;
   115  }
   116  
   117  struct to_string_using_backtrace {
   118      std::string res;
   119      boost::stacktrace::detail::program_location prog_location;
   120      ::backtrace_state* state;
   121      std::string filename;
   122      std::size_t line;
   123  
   124      void prepare_function_name(const void* addr) {
   125          boost::stacktrace::detail::pc_data data = {&res, &filename, 0};
   126          if (state) {
   127              ::backtrace_pcinfo(
   128                  state,
   129                  reinterpret_cast<uintptr_t>(addr),
   130                  boost::stacktrace::detail::libbacktrace_full_callback,
   131                  boost::stacktrace::detail::libbacktrace_error_callback,
   132                  &data
   133              ) 
   134              ||
   135              ::backtrace_syminfo(
   136                  state,
   137                  reinterpret_cast<uintptr_t>(addr),
   138                  boost::stacktrace::detail::libbacktrace_syminfo_callback,
   139                  boost::stacktrace::detail::libbacktrace_error_callback,
   140                  &data
   141              );
   142          }
   143          line = data.line;
   144      }
   145  
   146      bool prepare_source_location(const void* /*addr*/) {
   147          if (filename.empty() || !line) {
   148              return false;
   149          }
   150  
   151          res += " at ";
   152          res += filename;
   153          res += ':';
   154          res += boost::stacktrace::detail::to_dec_array(line).data();
   155          return true;
   156      }
   157  
   158      to_string_using_backtrace() noexcept {
   159          state = boost::stacktrace::detail::construct_state(prog_location);
   160      }
   161  };
   162  
   163  template <class Base> class to_string_impl_base;
   164  typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
   165  
   166  inline std::string name_impl(const void* addr) {
   167      std::string res;
   168  
   169      boost::stacktrace::detail::program_location prog_location;
   170      ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
   171  
   172      boost::stacktrace::detail::pc_data data = {&res, 0, 0};
   173      if (state) {
   174          ::backtrace_pcinfo(
   175              state,
   176              reinterpret_cast<uintptr_t>(addr),
   177              boost::stacktrace::detail::libbacktrace_full_callback,
   178              boost::stacktrace::detail::libbacktrace_error_callback,
   179              &data
   180          )
   181          ||
   182          ::backtrace_syminfo(
   183              state,
   184              reinterpret_cast<uintptr_t>(addr),
   185              boost::stacktrace::detail::libbacktrace_syminfo_callback,
   186              boost::stacktrace::detail::libbacktrace_error_callback,
   187              &data
   188          );
   189      }
   190      if (!res.empty()) {
   191          res = boost::core::demangle(res.c_str());
   192      }
   193  
   194      return res;
   195  }
   196  
   197  } // namespace detail
   198  
   199  std::string frame::source_file() const {
   200      std::string res;
   201  
   202      if (!addr_) {
   203          return res;
   204      }
   205  
   206      boost::stacktrace::detail::program_location prog_location;
   207      ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
   208  
   209      boost::stacktrace::detail::pc_data data = {0, &res, 0};
   210      if (state) {
   211          ::backtrace_pcinfo(
   212              state,
   213              reinterpret_cast<uintptr_t>(addr_),
   214              boost::stacktrace::detail::libbacktrace_full_callback,
   215              boost::stacktrace::detail::libbacktrace_error_callback,
   216              &data
   217          );
   218      }
   219  
   220      return res;
   221  }
   222  
   223  std::size_t frame::source_line() const {
   224      if (!addr_) {
   225          return 0;
   226      }
   227  
   228      boost::stacktrace::detail::program_location prog_location;
   229      ::backtrace_state* state = boost::stacktrace::detail::construct_state(prog_location);
   230  
   231      boost::stacktrace::detail::pc_data data = {0, 0, 0};
   232      if (state) {
   233          ::backtrace_pcinfo(
   234              state,
   235              reinterpret_cast<uintptr_t>(addr_),
   236              boost::stacktrace::detail::libbacktrace_full_callback,
   237              boost::stacktrace::detail::libbacktrace_error_callback,
   238              &data
   239          );
   240      }
   241  
   242      return data.line;
   243  }
   244  
   245  
   246  }} // namespace boost::stacktrace
   247  
   248  #endif // BOOST_STACKTRACE_DETAIL_LIBBACKTRACE_IMPLS_HPP