]> git.proxmox.com Git - ceph.git/blame - ceph/src/boost/boost/stacktrace/detail/libbacktrace_impls.hpp
update ceph source to reef 18.1.2
[ceph.git] / ceph / src / boost / boost / stacktrace / detail / libbacktrace_impls.hpp
CommitLineData
1e59de90 1// Copyright Antony Polukhin, 2016-2022.
b32b8144
FG
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>
92f5a8d4 16#include <boost/stacktrace/detail/to_dec_array.hpp>
b32b8144
FG
17#include <boost/stacktrace/detail/location_from_symbol.hpp>
18#include <boost/core/demangle.hpp>
b32b8144 19
92f5a8d4
TL
20#ifdef BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
21# include BOOST_STACKTRACE_BACKTRACE_INCLUDE_FILE
22#else
23# include <backtrace.h>
24#endif
b32b8144
FG
25
26namespace boost { namespace stacktrace { namespace detail {
27
28
29struct pc_data {
30 std::string* function;
31 std::string* filename;
32 std::size_t line;
33};
34
92f5a8d4
TL
35inline 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
43inline 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
b32b8144
FG
47inline 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
59inline void libbacktrace_error_callback(void* /*data*/, const char* /*msg*/, int /*errnum*/) BOOST_NOEXCEPT {
60 // Do nothing, just return.
61}
62
92f5a8d4
TL
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.
71BOOST_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.
b32b8144 73
92f5a8d4 74 // TODO: The most obvious solution:
b32b8144 75 //
92f5a8d4
TL
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.
b32b8144 86
b32b8144 87
92f5a8d4
TL
88#ifndef BOOST_HAS_THREADS
89 static
90#else
b32b8144 91
92f5a8d4
TL
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
1e59de90 97# elif defined(__GNUC__) && !defined(__clang__)
92f5a8d4
TL
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 );
b32b8144 110 return state;
b32b8144
FG
111}
112
113struct 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
92f5a8d4
TL
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
b32b8144
FG
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 += ':';
92f5a8d4 150 res += boost::stacktrace::detail::to_dec_array(line).data();
b32b8144
FG
151 return true;
152 }
153
154 to_string_using_backtrace() BOOST_NOEXCEPT {
155 state = boost::stacktrace::detail::construct_state(prog_location);
156 }
157};
158
159template <class Base> class to_string_impl_base;
160typedef to_string_impl_base<to_string_using_backtrace> to_string_impl;
161
162inline 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
92f5a8d4
TL
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
b32b8144
FG
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
195std::string frame::source_file() const {
196 std::string res;
197
92f5a8d4
TL
198 if (!addr_) {
199 return res;
200 }
201
b32b8144
FG
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
219std::size_t frame::source_line() const {
92f5a8d4
TL
220 if (!addr_) {
221 return 0;
222 }
223
b32b8144
FG
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