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