github.com/searKing/golang/go@v1.2.117/os/signal/cgo/include/boost/stacktrace/stacktrace.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_STACKTRACE_HPP 8 #define BOOST_STACKTRACE_STACKTRACE_HPP 9 10 #include <boost/config.hpp> 11 #ifdef BOOST_HAS_PRAGMA_ONCE 12 # pragma once 13 #endif 14 15 #include <boost/core/no_exceptions_support.hpp> 16 #include <boost/container_hash/hash_fwd.hpp> 17 18 #include <iosfwd> 19 #include <string> 20 #include <vector> 21 22 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS 23 # include <type_traits> 24 #endif 25 26 #include <boost/stacktrace/stacktrace_fwd.hpp> 27 #include <boost/stacktrace/safe_dump_to.hpp> 28 #include <boost/stacktrace/detail/frame_decl.hpp> 29 #include <boost/stacktrace/frame.hpp> 30 31 #ifdef BOOST_INTEL 32 # pragma warning(push) 33 # pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline" 34 #endif 35 36 namespace boost { namespace stacktrace { 37 38 /// Class that on construction copies minimal information about call stack into its internals and provides access to that information. 39 /// @tparam Allocator Allocator to use during stack capture. 40 template <class Allocator> 41 class basic_stacktrace { 42 std::vector<boost::stacktrace::frame, Allocator> impl_; 43 typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t; 44 45 /// @cond 46 void fill(native_frame_ptr_t* begin, std::size_t size) { 47 if (!size) { 48 return; 49 } 50 51 impl_.reserve(static_cast<std::size_t>(size)); 52 for (std::size_t i = 0; i < size; ++i) { 53 if (!begin[i]) { 54 return; 55 } 56 impl_.push_back( 57 frame(begin[i]) 58 ); 59 } 60 } 61 62 static std::size_t frames_count_from_buffer_size(std::size_t buffer_size) noexcept { 63 const std::size_t ret = (buffer_size > sizeof(native_frame_ptr_t) ? buffer_size / sizeof(native_frame_ptr_t) : 0); 64 return (ret > 1024 ? 1024 : ret); // Dealing with suspiciously big sizes 65 } 66 67 BOOST_NOINLINE void init(std::size_t frames_to_skip, std::size_t max_depth) { 68 BOOST_CONSTEXPR_OR_CONST std::size_t buffer_size = 128; 69 if (!max_depth) { 70 return; 71 } 72 73 BOOST_TRY { 74 { // Fast path without additional allocations 75 native_frame_ptr_t buffer[buffer_size]; 76 const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, buffer_size < max_depth ? buffer_size : max_depth, frames_to_skip + 1); 77 if (buffer_size > frames_count || frames_count == max_depth) { 78 fill(buffer, frames_count); 79 return; 80 } 81 } 82 83 // Failed to fit in `buffer_size`. Allocating memory: 84 #ifdef BOOST_NO_CXX11_ALLOCATOR 85 typedef typename Allocator::template rebind<native_frame_ptr_t>::other allocator_void_t; 86 #else 87 typedef typename std::allocator_traits<Allocator>::template rebind_alloc<native_frame_ptr_t> allocator_void_t; 88 #endif 89 std::vector<native_frame_ptr_t, allocator_void_t> buf(buffer_size * 2, 0, impl_.get_allocator()); 90 do { 91 const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(&buf[0], buf.size() < max_depth ? buf.size() : max_depth, frames_to_skip + 1); 92 if (buf.size() > frames_count || frames_count == max_depth) { 93 fill(&buf[0], frames_count); 94 return; 95 } 96 97 buf.resize(buf.size() * 2); 98 } while (buf.size() < buf.max_size()); // close to `true`, but suppresses `C4127: conditional expression is constant`. 99 } BOOST_CATCH (...) { 100 // ignore exception 101 } 102 BOOST_CATCH_END 103 } 104 /// @endcond 105 106 public: 107 typedef typename std::vector<boost::stacktrace::frame, Allocator>::value_type value_type; 108 typedef typename std::vector<boost::stacktrace::frame, Allocator>::allocator_type allocator_type; 109 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer pointer; 110 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_pointer const_pointer; 111 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference reference; 112 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reference const_reference; 113 typedef typename std::vector<boost::stacktrace::frame, Allocator>::size_type size_type; 114 typedef typename std::vector<boost::stacktrace::frame, Allocator>::difference_type difference_type; 115 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator iterator; 116 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_iterator const_iterator; 117 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator reverse_iterator; 118 typedef typename std::vector<boost::stacktrace::frame, Allocator>::const_reverse_iterator const_reverse_iterator; 119 120 /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations. 121 /// 122 /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined. 123 /// 124 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. 125 BOOST_FORCEINLINE basic_stacktrace() noexcept 126 : impl_() 127 { 128 init(0 , static_cast<std::size_t>(-1)); 129 } 130 131 /// @brief Stores the current function call sequence inside *this without any decoding or any other heavy platform specific operations. 132 /// 133 /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined. 134 /// 135 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. 136 /// 137 /// @param a Allocator that would be passed to underlying storage. 138 BOOST_FORCEINLINE explicit basic_stacktrace(const allocator_type& a) noexcept 139 : impl_(a) 140 { 141 init(0 , static_cast<std::size_t>(-1)); 142 } 143 144 /// @brief Stores [skip, skip + max_depth) of the current function call sequence inside *this without any decoding or any other heavy platform specific operations. 145 /// 146 /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined. 147 /// 148 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. 149 /// 150 /// @param skip How many top calls to skip and do not store in *this. 151 /// 152 /// @param max_depth Max call sequence depth to collect. 153 /// 154 /// @param a Allocator that would be passed to underlying storage. 155 /// 156 /// @throws Nothing. Note that default construction of allocator may throw, however it is 157 /// performed outside the constructor and exception in `allocator_type()` would not result in calling `std::terminate`. 158 BOOST_FORCEINLINE basic_stacktrace(std::size_t skip, std::size_t max_depth, const allocator_type& a = allocator_type()) noexcept 159 : impl_(a) 160 { 161 init(skip , max_depth); 162 } 163 164 /// @b Complexity: O(st.size()) 165 /// 166 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. 167 basic_stacktrace(const basic_stacktrace& st) 168 : impl_(st.impl_) 169 {} 170 171 /// @b Complexity: O(st.size()) 172 /// 173 /// @b Async-Handler-Safety: Safe if Allocator construction, copying, Allocator::allocate and Allocator::deallocate are async signal safe. 174 basic_stacktrace& operator=(const basic_stacktrace& st) { 175 impl_ = st.impl_; 176 return *this; 177 } 178 179 #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED 180 /// @b Complexity: O(1) 181 /// 182 /// @b Async-Handler-Safety: Safe if Allocator::deallocate is async signal safe. 183 ~basic_stacktrace() noexcept = default; 184 #endif 185 186 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) 187 /// @b Complexity: O(1) 188 /// 189 /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe. 190 basic_stacktrace(basic_stacktrace&& st) noexcept 191 : impl_(std::move(st.impl_)) 192 {} 193 194 /// @b Complexity: O(st.size()) 195 /// 196 /// @b Async-Handler-Safety: Safe if Allocator construction and copying are async signal safe. 197 basic_stacktrace& operator=(basic_stacktrace&& st) 198 #ifndef BOOST_NO_CXX11_HDR_TYPE_TRAITS 199 noexcept(( std::is_nothrow_move_assignable< std::vector<boost::stacktrace::frame, Allocator> >::value )) 200 #else 201 noexcept 202 #endif 203 { 204 impl_ = std::move(st.impl_); 205 return *this; 206 } 207 #endif 208 209 /// @returns Number of function names stored inside the class. 210 /// 211 /// @b Complexity: O(1) 212 /// 213 /// @b Async-Handler-Safety: Safe. 214 size_type size() const noexcept { 215 return impl_.size(); 216 } 217 218 /// @param frame_no Zero based index of frame to return. 0 219 /// is the function index where stacktrace was constructed and 220 /// index close to this->size() contains function `main()`. 221 /// @returns frame that references the actual frame info, stored inside *this. 222 /// 223 /// @b Complexity: O(1). 224 /// 225 /// @b Async-Handler-Safety: Safe. 226 const_reference operator[](std::size_t frame_no) const noexcept { 227 return impl_[frame_no]; 228 } 229 230 /// @b Complexity: O(1) 231 /// 232 /// @b Async-Handler-Safety: Safe. 233 const_iterator begin() const noexcept { return impl_.begin(); } 234 /// @b Complexity: O(1) 235 /// 236 /// @b Async-Handler-Safety: Safe. 237 const_iterator cbegin() const noexcept { return impl_.begin(); } 238 /// @b Complexity: O(1) 239 /// 240 /// @b Async-Handler-Safety: Safe. 241 const_iterator end() const noexcept { return impl_.end(); } 242 /// @b Complexity: O(1) 243 /// 244 /// @b Async-Handler-Safety: Safe. 245 const_iterator cend() const noexcept { return impl_.end(); } 246 247 /// @b Complexity: O(1) 248 /// 249 /// @b Async-Handler-Safety: Safe. 250 const_reverse_iterator rbegin() const noexcept { return impl_.rbegin(); } 251 /// @b Complexity: O(1) 252 /// 253 /// @b Async-Handler-Safety: Safe. 254 const_reverse_iterator crbegin() const noexcept { return impl_.rbegin(); } 255 /// @b Complexity: O(1) 256 /// 257 /// @b Async-Handler-Safety: Safe. 258 const_reverse_iterator rend() const noexcept { return impl_.rend(); } 259 /// @b Complexity: O(1) 260 /// 261 /// @b Async-Handler-Safety: Safe. 262 const_reverse_iterator crend() const noexcept { return impl_.rend(); } 263 264 265 /// @brief Allows to check that stack trace capturing was successful. 266 /// @returns `true` if `this->size() != 0` 267 /// 268 /// @b Complexity: O(1) 269 /// 270 /// @b Async-Handler-Safety: Safe. 271 constexpr explicit operator bool () const noexcept { return !empty(); } 272 273 /// @brief Allows to check that stack trace failed. 274 /// @returns `true` if `this->size() == 0` 275 /// 276 /// @b Complexity: O(1) 277 /// 278 /// @b Async-Handler-Safety: Safe. 279 bool empty() const noexcept { return !size(); } 280 281 const std::vector<boost::stacktrace::frame, Allocator>& as_vector() const noexcept { 282 return impl_; 283 } 284 285 /// Constructs stacktrace from basic_istreamable that references the dumped stacktrace. Terminating zero frame is discarded. 286 /// 287 /// @b Complexity: O(N) 288 template <class Char, class Trait> 289 static basic_stacktrace from_dump(std::basic_istream<Char, Trait>& in, const allocator_type& a = allocator_type()) { 290 typedef typename std::basic_istream<Char, Trait>::pos_type pos_type; 291 basic_stacktrace ret(0, 0, a); 292 293 // reserving space 294 const pos_type pos = in.tellg(); 295 in.seekg(0, in.end); 296 const std::size_t frames_count = frames_count_from_buffer_size(static_cast<std::size_t>(in.tellg())); 297 in.seekg(pos); 298 299 if (!frames_count) { 300 return ret; 301 } 302 303 native_frame_ptr_t ptr = 0; 304 ret.impl_.reserve(frames_count); 305 while (in.read(reinterpret_cast<Char*>(&ptr), sizeof(ptr))) { 306 if (!ptr) { 307 break; 308 } 309 310 ret.impl_.push_back(frame(ptr)); 311 } 312 313 return ret; 314 } 315 316 /// Constructs stacktrace from raw memory dump. Terminating zero frame is discarded. 317 /// 318 /// @param begin Beginning of the memory where the stacktrace was saved using the boost::stacktrace::safe_dump_to 319 /// 320 /// @param buffer_size_in_bytes Size of the memory. Usually the same value that was passed to the boost::stacktrace::safe_dump_to 321 /// 322 /// @b Complexity: O(size) in worst case 323 static basic_stacktrace from_dump(const void* begin, std::size_t buffer_size_in_bytes, const allocator_type& a = allocator_type()) { 324 basic_stacktrace ret(0, 0, a); 325 const native_frame_ptr_t* first = static_cast<const native_frame_ptr_t*>(begin); 326 const std::size_t frames_count = frames_count_from_buffer_size(buffer_size_in_bytes); 327 if (!frames_count) { 328 return ret; 329 } 330 331 const native_frame_ptr_t* const last = first + frames_count; 332 ret.impl_.reserve(frames_count); 333 for (; first != last; ++first) { 334 if (!*first) { 335 break; 336 } 337 338 ret.impl_.push_back(frame(*first)); 339 } 340 341 return ret; 342 } 343 }; 344 345 /// @brief Compares stacktraces for less, order is platform dependent. 346 /// 347 /// @b Complexity: Amortized O(1); worst case O(size()) 348 /// 349 /// @b Async-Handler-Safety: Safe. 350 template <class Allocator1, class Allocator2> 351 bool operator< (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept { 352 return lhs.size() < rhs.size() || (lhs.size() == rhs.size() && lhs.as_vector() < rhs.as_vector()); 353 } 354 355 /// @brief Compares stacktraces for equality. 356 /// 357 /// @b Complexity: Amortized O(1); worst case O(size()) 358 /// 359 /// @b Async-Handler-Safety: Safe. 360 template <class Allocator1, class Allocator2> 361 bool operator==(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept { 362 return lhs.as_vector() == rhs.as_vector(); 363 } 364 365 366 /// Comparison operators that provide platform dependant ordering and have amortized O(1) complexity; O(size()) worst case complexity; are Async-Handler-Safe. 367 template <class Allocator1, class Allocator2> 368 bool operator> (const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept { 369 return rhs < lhs; 370 } 371 372 template <class Allocator1, class Allocator2> 373 bool operator<=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept { 374 return !(lhs > rhs); 375 } 376 377 template <class Allocator1, class Allocator2> 378 bool operator>=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept { 379 return !(lhs < rhs); 380 } 381 382 template <class Allocator1, class Allocator2> 383 bool operator!=(const basic_stacktrace<Allocator1>& lhs, const basic_stacktrace<Allocator2>& rhs) noexcept { 384 return !(lhs == rhs); 385 } 386 387 /// Fast hashing support, O(st.size()) complexity; Async-Handler-Safe. 388 template <class Allocator> 389 std::size_t hash_value(const basic_stacktrace<Allocator>& st) noexcept { 390 return boost::hash_range(st.as_vector().begin(), st.as_vector().end()); 391 } 392 393 /// Returns std::string with the stacktrace in a human readable format; unsafe to use in async handlers. 394 template <class Allocator> 395 std::string to_string(const basic_stacktrace<Allocator>& bt) { 396 if (!bt) { 397 return std::string(); 398 } 399 400 return boost::stacktrace::detail::to_string(&bt.as_vector()[0], bt.size()); 401 } 402 403 /// Outputs stacktrace in a human readable format to the output stream `os`; unsafe to use in async handlers. 404 template <class CharT, class TraitsT, class Allocator> 405 std::basic_ostream<CharT, TraitsT>& operator<<(std::basic_ostream<CharT, TraitsT>& os, const basic_stacktrace<Allocator>& bt) { 406 return os << boost::stacktrace::to_string(bt); 407 } 408 409 /// This is the typedef to use unless you'd like to provide a specific allocator to boost::stacktrace::basic_stacktrace. 410 typedef basic_stacktrace<> stacktrace; 411 412 }} // namespace boost::stacktrace 413 414 #ifdef BOOST_INTEL 415 # pragma warning(pop) 416 #endif 417 418 #endif // BOOST_STACKTRACE_STACKTRACE_HPP