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