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