1 1.1 mrg // <stacktrace> -*- C++ -*- 2 1.1 mrg 3 1.1 mrg // Copyright The GNU Toolchain Authors. 4 1.1 mrg // 5 1.1 mrg // This file is part of the GNU ISO C++ Library. This library is free 6 1.1 mrg // software; you can redistribute it and/or modify it under the 7 1.1 mrg // terms of the GNU General Public License as published by the 8 1.1 mrg // Free Software Foundation; either version 3. 9 1.1 mrg 10 1.1 mrg // This library is distributed in the hope that it will be useful, 11 1.1 mrg // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 1.1 mrg // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 1.1 mrg // GNU General Public License for more details. 14 1.1 mrg 15 1.1 mrg // Under Section 7 of GPL version 3, you are granted additional 16 1.1 mrg // permissions described in the GCC Runtime Library Exception, version 17 1.1 mrg // 3.1, as published by the Free Software Foundation. 18 1.1 mrg 19 1.1 mrg // You should have received a copy of the GNU General Public License and 20 1.1 mrg // a copy of the GCC Runtime Library Exception along with this program; 21 1.1 mrg // see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 22 1.1 mrg // <http://www.gnu.org/licenses/>. 23 1.1 mrg 24 1.1 mrg #ifndef _GLIBCXX_STACKTRACE 25 1.1 mrg #define _GLIBCXX_STACKTRACE 1 26 1.1 mrg 27 1.1 mrg #pragma GCC system_header 28 1.1 mrg 29 1.1 mrg #include <bits/c++config.h> 30 1.1 mrg 31 1.1 mrg #if __cplusplus > 202002L && _GLIBCXX_HAVE_STACKTRACE 32 1.1 mrg #include <compare> 33 1.1 mrg #include <new> 34 1.1 mrg #include <string> 35 1.1 mrg #include <sstream> 36 1.1 mrg #include <bits/stl_algobase.h> 37 1.1 mrg #include <bits/stl_algo.h> 38 1.1 mrg #include <bits/stl_iterator.h> 39 1.1 mrg #include <bits/stl_uninitialized.h> 40 1.1 mrg #include <ext/numeric_traits.h> 41 1.1 mrg 42 1.1 mrg struct __glibcxx_backtrace_state; 43 1.1 mrg struct __glibcxx_backtrace_simple_data; 44 1.1 mrg 45 1.1 mrg extern "C" 46 1.1 mrg { 47 1.1 mrg __glibcxx_backtrace_state* 48 1.1 mrg __glibcxx_backtrace_create_state(const char*, int, 49 1.1 mrg void(*)(void*, const char*, int), 50 1.1 mrg void*); 51 1.1 mrg 52 1.1 mrg int 53 1.1 mrg __glibcxx_backtrace_simple(__glibcxx_backtrace_state*, int, 54 1.1 mrg int (*) (void*, uintptr_t), 55 1.1 mrg void(*)(void*, const char*, int), 56 1.1 mrg void*); 57 1.1 mrg int 58 1.1 mrg __glibcxx_backtrace_pcinfo(__glibcxx_backtrace_state*, uintptr_t, 59 1.1 mrg int (*)(void*, uintptr_t, 60 1.1 mrg const char*, int, const char*), 61 1.1 mrg void(*)(void*, const char*, int), 62 1.1 mrg void*); 63 1.1 mrg 64 1.1 mrg int 65 1.1 mrg __glibcxx_backtrace_syminfo(__glibcxx_backtrace_state*, uintptr_t addr, 66 1.1 mrg void (*) (void*, uintptr_t, const char*, 67 1.1 mrg uintptr_t, uintptr_t), 68 1.1 mrg void(*)(void*, const char*, int), 69 1.1 mrg void*); 70 1.1 mrg } 71 1.1 mrg 72 1.1 mrg namespace __cxxabiv1 73 1.1 mrg { 74 1.1 mrg extern "C" char* 75 1.1 mrg __cxa_demangle(const char* __mangled_name, char* __output_buffer, 76 1.1 mrg size_t* __length, int* __status); 77 1.1 mrg } 78 1.1 mrg 79 1.1 mrg namespace std _GLIBCXX_VISIBILITY(default) 80 1.1 mrg { 81 1.1 mrg _GLIBCXX_BEGIN_NAMESPACE_VERSION 82 1.1 mrg 83 1.1 mrg #define __cpp_lib_stacktrace 202011L 84 1.1 mrg 85 1.1 mrg // [stacktrace.entry], class stacktrace_entry 86 1.1 mrg class stacktrace_entry 87 1.1 mrg { 88 1.1 mrg using uint_least32_t = __UINT_LEAST32_TYPE__; 89 1.1 mrg using uintptr_t = __UINTPTR_TYPE__; 90 1.1 mrg 91 1.1 mrg public: 92 1.1 mrg using native_handle_type = uintptr_t; 93 1.1 mrg 94 1.1 mrg // [stacktrace.entry.ctor], constructors 95 1.1 mrg 96 1.1 mrg constexpr 97 1.1 mrg stacktrace_entry() noexcept = default; 98 1.1 mrg 99 1.1 mrg constexpr 100 1.1 mrg stacktrace_entry(const stacktrace_entry& __other) noexcept = default; 101 1.1 mrg 102 1.1 mrg constexpr stacktrace_entry& 103 1.1 mrg operator=(const stacktrace_entry& __other) noexcept = default; 104 1.1 mrg 105 1.1 mrg ~stacktrace_entry() = default; 106 1.1 mrg 107 1.1 mrg // [stacktrace.entry.obs], observers 108 1.1 mrg 109 1.1 mrg constexpr native_handle_type 110 1.1 mrg native_handle() const noexcept { return _M_pc; } 111 1.1 mrg 112 1.1 mrg constexpr explicit operator bool() const noexcept { return _M_pc != -1; } 113 1.1 mrg 114 1.1 mrg // [stacktrace.entry.query], query 115 1.1 mrg string 116 1.1 mrg description() const 117 1.1 mrg { 118 1.1 mrg string __s; 119 1.1 mrg _M_get_info(&__s, nullptr, nullptr); 120 1.1 mrg return __s; 121 1.1 mrg } 122 1.1 mrg 123 1.1 mrg string 124 1.1 mrg source_file() const 125 1.1 mrg { 126 1.1 mrg string __s; 127 1.1 mrg _M_get_info(nullptr, &__s, nullptr); 128 1.1 mrg return __s; 129 1.1 mrg } 130 1.1 mrg 131 1.1 mrg uint_least32_t 132 1.1 mrg source_line() const 133 1.1 mrg { 134 1.1 mrg int __line = 0; 135 1.1 mrg _M_get_info(nullptr, nullptr, &__line); 136 1.1 mrg return __line; 137 1.1 mrg } 138 1.1 mrg 139 1.1 mrg // [stacktrace.entry.cmp], comparison 140 1.1 mrg friend constexpr bool 141 1.1 mrg operator==(const stacktrace_entry& __x, 142 1.1 mrg const stacktrace_entry& __y) noexcept 143 1.1 mrg { return __x._M_pc == __y._M_pc; } 144 1.1 mrg 145 1.1 mrg friend constexpr strong_ordering 146 1.1 mrg operator<=>(const stacktrace_entry& __x, 147 1.1 mrg const stacktrace_entry& __y) noexcept 148 1.1 mrg { return __x._M_pc <=> __y._M_pc; } 149 1.1 mrg 150 1.1 mrg private: 151 1.1 mrg native_handle_type _M_pc = -1; 152 1.1 mrg 153 1.1 mrg template<typename _Allocator> friend class basic_stacktrace; 154 1.1 mrg 155 1.1 mrg static __glibcxx_backtrace_state* 156 1.1 mrg _S_init() 157 1.1 mrg { 158 1.1 mrg static __glibcxx_backtrace_state* __state 159 1.1 mrg = __glibcxx_backtrace_create_state(nullptr, 1, nullptr, nullptr); 160 1.1 mrg return __state; 161 1.1 mrg } 162 1.1 mrg 163 1.1 mrg friend ostream& 164 1.1 mrg operator<<(ostream&, const stacktrace_entry&); 165 1.1 mrg 166 1.1 mrg bool 167 1.1 mrg _M_get_info(string* __desc, string* __file, int* __line) const 168 1.1 mrg { 169 1.1 mrg if (!*this) 170 1.1 mrg return false; 171 1.1 mrg 172 1.1 mrg struct _Data 173 1.1 mrg { 174 1.1 mrg string* _M_desc; 175 1.1 mrg string* _M_file; 176 1.1 mrg int* _M_line; 177 1.1 mrg } __data = { __desc, __file, __line }; 178 1.1 mrg 179 1.1 mrg auto __cb = [](void* __data, uintptr_t, const char* __filename, 180 1.1 mrg int __lineno, const char* __function) -> int { 181 1.1 mrg auto& __d = *static_cast<_Data*>(__data); 182 1.1 mrg if (__function && __d._M_desc) 183 1.1 mrg *__d._M_desc = _S_demangle(__function); 184 1.1 mrg if (__filename && __d._M_file) 185 1.1 mrg *__d._M_file = __filename; 186 1.1 mrg if (__d._M_line) 187 1.1 mrg *__d._M_line = __lineno; 188 1.1 mrg return __function != nullptr; 189 1.1 mrg }; 190 1.1 mrg const auto __state = _S_init(); 191 1.1 mrg if (::__glibcxx_backtrace_pcinfo(__state, _M_pc, +__cb, nullptr, &__data)) 192 1.1 mrg return true; 193 1.1 mrg if (__desc && __desc->empty()) 194 1.1 mrg { 195 1.1 mrg auto __cb2 = [](void* __data, uintptr_t, const char* __symname, 196 1.1 mrg uintptr_t, uintptr_t) { 197 1.1 mrg if (__symname) 198 1.1 mrg *static_cast<_Data*>(__data)->_M_desc = _S_demangle(__symname); 199 1.1 mrg }; 200 1.1 mrg if (::__glibcxx_backtrace_syminfo(__state, _M_pc, +__cb2, nullptr, 201 1.1 mrg &__data)) 202 1.1 mrg return true; 203 1.1 mrg } 204 1.1 mrg return false; 205 1.1 mrg } 206 1.1 mrg 207 1.1 mrg static string 208 1.1 mrg _S_demangle(const char* __name) 209 1.1 mrg { 210 1.1 mrg string __s; 211 1.1 mrg int __status; 212 1.1 mrg char* __str = __cxxabiv1::__cxa_demangle(__name, nullptr, nullptr, 213 1.1 mrg &__status); 214 1.1 mrg if (__status == 0) 215 1.1 mrg __s = __str; 216 1.1 mrg else 217 1.1 mrg __s = __name; 218 1.1 mrg __builtin_free(__str); 219 1.1 mrg return __s; 220 1.1 mrg } 221 1.1 mrg }; 222 1.1 mrg 223 1.1 mrg // [stacktrace.basic], class template basic_stacktrace 224 1.1 mrg template<typename _Allocator> 225 1.1 mrg class basic_stacktrace 226 1.1 mrg { 227 1.1 mrg using _AllocTraits = allocator_traits<_Allocator>; 228 1.1 mrg 229 1.1 mrg public: 230 1.1 mrg using value_type = stacktrace_entry; 231 1.1 mrg using const_reference = const value_type&; 232 1.1 mrg using reference = value_type&; 233 1.1 mrg using const_iterator 234 1.1 mrg = __gnu_cxx::__normal_iterator<value_type*, basic_stacktrace>; 235 1.1 mrg using iterator = const_iterator; 236 1.1 mrg using reverse_iterator = std::reverse_iterator<iterator>; 237 1.1 mrg using const_reverse_iterator = std::reverse_iterator<const_iterator>; 238 1.1 mrg using difference_type = ptrdiff_t; 239 1.1 mrg using size_type = unsigned short; 240 1.1 mrg using allocator_type = _Allocator; 241 1.1 mrg 242 1.1 mrg // [stacktrace.basic.ctor], creation and assignment 243 1.1 mrg 244 1.1 mrg [[__gnu__::__noinline__]] 245 1.1 mrg static basic_stacktrace 246 1.1 mrg current(const allocator_type& __alloc = allocator_type()) noexcept 247 1.1 mrg { 248 1.1 mrg basic_stacktrace __ret(__alloc); 249 1.1 mrg if (auto __cb = __ret._M_prepare()) [[likely]] 250 1.1 mrg { 251 1.1 mrg auto __state = stacktrace_entry::_S_init(); 252 1.1 mrg if (__glibcxx_backtrace_simple(__state, 1, __cb, nullptr, 253 1.1 mrg std::__addressof(__ret))) 254 1.1 mrg __ret._M_clear(); 255 1.1 mrg } 256 1.1 mrg return __ret; 257 1.1 mrg } 258 1.1 mrg 259 1.1 mrg [[__gnu__::__noinline__]] 260 1.1 mrg static basic_stacktrace 261 1.1 mrg current(size_type __skip, 262 1.1 mrg const allocator_type& __alloc = allocator_type()) noexcept 263 1.1 mrg { 264 1.1 mrg basic_stacktrace __ret(__alloc); 265 1.1 mrg if (__skip >= __INT_MAX__) [[unlikely]] 266 1.1 mrg return __ret; 267 1.1 mrg if (auto __cb = __ret._M_prepare()) [[likely]] 268 1.1 mrg { 269 1.1 mrg auto __state = stacktrace_entry::_S_init(); 270 1.1 mrg if (__glibcxx_backtrace_simple(__state, __skip + 1, __cb, nullptr, 271 1.1 mrg std::__addressof(__ret))) 272 1.1 mrg __ret._M_clear(); 273 1.1 mrg } 274 1.1 mrg 275 1.1 mrg return __ret; 276 1.1 mrg } 277 1.1 mrg 278 1.1 mrg [[__gnu__::__noinline__]] 279 1.1 mrg static basic_stacktrace 280 1.1 mrg current(size_type __skip, size_type __max_depth, 281 1.1 mrg const allocator_type& __alloc = allocator_type()) noexcept 282 1.1 mrg { 283 1.1 mrg __glibcxx_assert(__skip <= (size_type(-1) - __max_depth)); 284 1.1 mrg 285 1.1 mrg basic_stacktrace __ret(__alloc); 286 1.1 mrg if (__max_depth == 0) [[unlikely]] 287 1.1 mrg return __ret; 288 1.1 mrg if (__skip >= __INT_MAX__) [[unlikely]] 289 1.1 mrg return __ret; 290 1.1 mrg if (auto __cb = __ret._M_prepare(__max_depth)) [[likely]] 291 1.1 mrg { 292 1.1 mrg auto __state = stacktrace_entry::_S_init(); 293 1.1 mrg int __err = __glibcxx_backtrace_simple(__state, __skip + 1, __cb, 294 1.1 mrg nullptr, 295 1.1 mrg std::__addressof(__ret)); 296 1.1 mrg if (__err < 0) 297 1.1 mrg __ret._M_clear(); 298 1.1 mrg else if (__ret.size() > __max_depth) 299 1.1 mrg { 300 1.1 mrg __ret._M_impl._M_resize(__max_depth, __ret._M_alloc); 301 1.1 mrg 302 1.1 mrg if (__ret._M_impl._M_capacity / 2 >= __max_depth) 303 1.1 mrg { 304 1.1 mrg // shrink to fit 305 1.1 mrg _Impl __tmp = __ret._M_impl._M_clone(__ret._M_alloc); 306 1.1 mrg if (__tmp._M_capacity) 307 1.1 mrg { 308 1.1 mrg __ret._M_clear(); 309 1.1 mrg __ret._M_impl = __tmp; 310 1.1 mrg } 311 1.1 mrg } 312 1.1 mrg } 313 1.1 mrg } 314 1.1 mrg return __ret; 315 1.1 mrg } 316 1.1 mrg 317 1.1 mrg basic_stacktrace() 318 1.1 mrg noexcept(is_nothrow_default_constructible_v<allocator_type>) 319 1.1 mrg { } 320 1.1 mrg 321 1.1 mrg explicit 322 1.1 mrg basic_stacktrace(const allocator_type& __alloc) noexcept 323 1.1 mrg : _M_alloc(__alloc) 324 1.1 mrg { } 325 1.1 mrg 326 1.1 mrg basic_stacktrace(const basic_stacktrace& __other) noexcept 327 1.1 mrg : basic_stacktrace(__other, 328 1.1 mrg _AllocTraits::select_on_container_copy_construction(__other._M_alloc)) 329 1.1 mrg { } 330 1.1 mrg 331 1.1 mrg basic_stacktrace(basic_stacktrace&& __other) noexcept 332 1.1 mrg : _M_alloc(std::move(__other._M_alloc)), 333 1.1 mrg _M_impl(std::__exchange(__other._M_impl, {})) 334 1.1 mrg { } 335 1.1 mrg 336 1.1 mrg basic_stacktrace(const basic_stacktrace& __other, 337 1.1 mrg const allocator_type& __alloc) noexcept 338 1.1 mrg : _M_alloc(__alloc) 339 1.1 mrg { 340 1.1 mrg if (const auto __s = __other._M_impl._M_size) 341 1.1 mrg _M_impl = __other._M_impl._M_clone(_M_alloc); 342 1.1 mrg } 343 1.1 mrg 344 1.1 mrg basic_stacktrace(basic_stacktrace&& __other, 345 1.1 mrg const allocator_type& __alloc) noexcept 346 1.1 mrg : _M_alloc(__alloc) 347 1.1 mrg { 348 1.1 mrg if constexpr (_Allocator::is_always_equal::value) 349 1.1 mrg _M_impl = std::__exchange(__other._M_impl, {}); 350 1.1 mrg else if (_M_alloc == __other._M_alloc) 351 1.1 mrg _M_impl = std::__exchange(__other._M_impl, {}); 352 1.1 mrg else if (const auto __s = __other._M_impl._M_size) 353 1.1 mrg _M_impl = __other._M_impl._M_clone(_M_alloc); 354 1.1 mrg } 355 1.1 mrg 356 1.1 mrg basic_stacktrace& 357 1.1 mrg operator=(const basic_stacktrace& __other) noexcept 358 1.1 mrg { 359 1.1 mrg if (std::__addressof(__other) == this) 360 1.1 mrg return *this; 361 1.1 mrg 362 1.1 mrg constexpr bool __pocca 363 1.1 mrg = _AllocTraits::propagate_on_container_copy_assignment::value; 364 1.1 mrg constexpr bool __always_eq = _AllocTraits::is_always_equal::value; 365 1.1 mrg 366 1.1 mrg const auto __s = __other.size(); 367 1.1 mrg 368 1.1 mrg if constexpr (!__always_eq && __pocca) 369 1.1 mrg { 370 1.1 mrg if (_M_alloc != __other._M_alloc) 371 1.1 mrg { 372 1.1 mrg // Cannot keep the same storage, so deallocate it now. 373 1.1 mrg _M_clear(); 374 1.1 mrg } 375 1.1 mrg } 376 1.1 mrg 377 1.1 mrg if (_M_impl._M_capacity < __s) 378 1.1 mrg { 379 1.1 mrg // Need to allocate new storage. 380 1.1 mrg _M_clear(); 381 1.1 mrg 382 1.1 mrg if constexpr (__pocca) 383 1.1 mrg _M_alloc = __other._M_alloc; 384 1.1 mrg 385 1.1 mrg _M_impl = __other._M_impl._M_clone(_M_alloc); 386 1.1 mrg } 387 1.1 mrg else 388 1.1 mrg { 389 1.1 mrg // Current storage is large enough. 390 1.1 mrg _M_impl._M_resize(0, _M_alloc); 391 1.1 mrg _M_impl._M_assign(__other._M_impl, _M_alloc); 392 1.1 mrg 393 1.1 mrg if constexpr (__pocca) 394 1.1 mrg _M_alloc = __other._M_alloc; 395 1.1 mrg } 396 1.1 mrg 397 1.1 mrg return *this; 398 1.1 mrg } 399 1.1 mrg 400 1.1 mrg basic_stacktrace& 401 1.1 mrg operator=(basic_stacktrace&& __other) noexcept 402 1.1 mrg { 403 1.1 mrg if (std::__addressof(__other) == this) 404 1.1 mrg return *this; 405 1.1 mrg 406 1.1 mrg constexpr bool __pocma 407 1.1 mrg = _AllocTraits::propagate_on_container_move_assignment::value; 408 1.1 mrg 409 1.1 mrg if constexpr (_AllocTraits::is_always_equal::value) 410 1.1 mrg std::swap(_M_impl, __other._M_impl); 411 1.1 mrg else if (_M_alloc == __other._M_alloc) 412 1.1 mrg std::swap(_M_impl, __other._M_impl); 413 1.1 mrg else if constexpr (__pocma) 414 1.1 mrg { 415 1.1 mrg // Free current storage and take ownership of __other's storage. 416 1.1 mrg _M_clear(); 417 1.1 mrg _M_impl = std::__exchange(__other._M_impl, {}); 418 1.1 mrg } 419 1.1 mrg else // Allocators are unequal and don't propagate. 420 1.1 mrg { 421 1.1 mrg const size_type __s = __other.size(); 422 1.1 mrg 423 1.1 mrg if (_M_impl._M_capacity < __s) 424 1.1 mrg { 425 1.1 mrg // Need to allocate new storage. 426 1.1 mrg _M_clear(); 427 1.1 mrg _M_impl = __other._M_impl._M_clone(_M_alloc); 428 1.1 mrg } 429 1.1 mrg else 430 1.1 mrg { 431 1.1 mrg // Current storage is large enough. 432 1.1 mrg _M_impl._M_resize(0, _M_alloc); 433 1.1 mrg _M_impl._M_assign(__other._M_impl, _M_alloc); 434 1.1 mrg } 435 1.1 mrg } 436 1.1 mrg 437 1.1 mrg if constexpr (__pocma) 438 1.1 mrg _M_alloc = std::move(__other._M_alloc); 439 1.1 mrg 440 1.1 mrg return *this; 441 1.1 mrg } 442 1.1 mrg 443 1.1 mrg constexpr ~basic_stacktrace() 444 1.1 mrg { 445 1.1 mrg _M_clear(); 446 1.1 mrg } 447 1.1 mrg 448 1.1 mrg // [stacktrace.basic.obs], observers 449 1.1 mrg allocator_type get_allocator() const noexcept { return _M_alloc; } 450 1.1 mrg 451 1.1 mrg const_iterator 452 1.1 mrg begin() const noexcept 453 1.1 mrg { return const_iterator{_M_impl._M_frames}; } 454 1.1 mrg 455 1.1 mrg const_iterator 456 1.1 mrg end() const noexcept 457 1.1 mrg { return begin() + size(); } 458 1.1 mrg 459 1.1 mrg const_reverse_iterator 460 1.1 mrg rbegin() const noexcept 461 1.1 mrg { return std::make_reverse_iterator(end()); } 462 1.1 mrg 463 1.1 mrg const_reverse_iterator 464 1.1 mrg rend() const noexcept 465 1.1 mrg { return std::make_reverse_iterator(begin()); } 466 1.1 mrg 467 1.1 mrg const_iterator cbegin() const noexcept { return begin(); } 468 1.1 mrg const_iterator cend() const noexcept { return end(); } 469 1.1 mrg const_reverse_iterator crbegin() const noexcept { return rbegin(); }; 470 1.1 mrg const_reverse_iterator crend() const noexcept { return rend(); }; 471 1.1 mrg 472 1.1 mrg [[nodiscard]] bool empty() const noexcept { return size() == 0; } 473 1.1 mrg size_type size() const noexcept { return _M_impl._M_size; } 474 1.1 mrg 475 1.1 mrg size_type 476 1.1 mrg max_size() const noexcept 477 1.1 mrg { return _Impl::_S_max_size(_M_impl._M_alloc); } 478 1.1 mrg 479 1.1 mrg const_reference 480 1.1 mrg operator[](size_type __n) const noexcept 481 1.1 mrg { 482 1.1 mrg __glibcxx_assert(__n < size()); 483 1.1 mrg return begin()[__n]; 484 1.1 mrg } 485 1.1 mrg 486 1.1 mrg const_reference 487 1.1 mrg at(size_type __n) const 488 1.1 mrg { 489 1.1 mrg if (__n >= size()) 490 1.1 mrg __throw_out_of_range("basic_stacktrace::at: bad frame number"); 491 1.1 mrg return begin()[__n]; 492 1.1 mrg } 493 1.1 mrg 494 1.1 mrg // [stacktrace.basic.cmp], comparisons 495 1.1 mrg template<typename _Allocator2> 496 1.1 mrg friend bool 497 1.1 mrg operator==(const basic_stacktrace& __x, 498 1.1 mrg const basic_stacktrace<_Allocator2>& __y) noexcept 499 1.1 mrg { return std::equal(__x.begin(), __x.end(), __y.begin(), __y.end()); } 500 1.1 mrg 501 1.1 mrg template<typename _Allocator2> 502 1.1 mrg friend strong_ordering 503 1.1 mrg operator<=>(const basic_stacktrace& __x, 504 1.1 mrg const basic_stacktrace<_Allocator2>& __y) noexcept 505 1.1 mrg { 506 1.1 mrg if (auto __s = __x.size() <=> __y.size(); __s != 0) 507 1.1 mrg return __s; 508 1.1 mrg return std::lexicographical_compare_three_way(__x.begin(), __x.end(), 509 1.1 mrg __y.begin(), __y.end()); 510 1.1 mrg } 511 1.1 mrg 512 1.1 mrg // [stacktrace.basic.mod], modifiers 513 1.1 mrg void 514 1.1 mrg swap(basic_stacktrace& __other) noexcept 515 1.1 mrg { 516 1.1 mrg std::swap(_M_impl, __other._M_impl); 517 1.1 mrg if constexpr (_AllocTraits::propagate_on_container_swap::value) 518 1.1 mrg std::swap(_M_alloc, __other._M_alloc); 519 1.1 mrg else if constexpr (!_AllocTraits::is_always_equal::value) 520 1.1 mrg { 521 1.1 mrg __glibcxx_assert(_M_alloc == __other._M_alloc); 522 1.1 mrg } 523 1.1 mrg } 524 1.1 mrg 525 1.1 mrg private: 526 1.1 mrg bool 527 1.1 mrg _M_push_back(const value_type& __x) noexcept 528 1.1 mrg { 529 1.1 mrg return _M_impl._M_push_back(_M_alloc, __x); 530 1.1 mrg } 531 1.1 mrg 532 1.1 mrg void 533 1.1 mrg _M_clear() noexcept 534 1.1 mrg { 535 1.1 mrg _M_impl._M_resize(0, _M_alloc); 536 1.1 mrg _M_impl._M_deallocate(_M_alloc); 537 1.1 mrg } 538 1.1 mrg 539 1.1 mrg // Precondition: __max_depth != 0 540 1.1 mrg auto 541 1.1 mrg _M_prepare(size_type __max_depth = -1) noexcept 542 1.1 mrg -> int (*) (void*, uintptr_t) 543 1.1 mrg { 544 1.1 mrg auto __cb = +[](void* __data, uintptr_t __pc) { 545 1.1 mrg auto& __s = *static_cast<basic_stacktrace*>(__data); 546 1.1 mrg stacktrace_entry __f; 547 1.1 mrg __f._M_pc = __pc; 548 1.1 mrg if (__s._M_push_back(__f)) [[likely]] 549 1.1 mrg return 0; // continue tracing 550 1.1 mrg return -1; // stop tracing due to error 551 1.1 mrg }; 552 1.1 mrg 553 1.1 mrg if (__max_depth > 128) 554 1.1 mrg __max_depth = 64; // soft limit, _M_push_back will reallocate 555 1.1 mrg else 556 1.1 mrg __cb = [](void* __data, uintptr_t __pc) { 557 1.1 mrg auto& __s = *static_cast<basic_stacktrace*>(__data); 558 1.1 mrg stacktrace_entry __f; 559 1.1 mrg __f._M_pc = __pc; 560 1.1 mrg if (__s.size() == __s._M_impl._M_capacity) [[unlikely]] 561 1.1 mrg return 1; // stop tracing due to reaching max depth 562 1.1 mrg if (__s._M_push_back(__f)) [[likely]] 563 1.1 mrg return 0; // continue tracing 564 1.1 mrg return -1; // stop tracing due to error 565 1.1 mrg }; 566 1.1 mrg 567 1.1 mrg if (_M_impl._M_allocate(_M_alloc, __max_depth)) [[likely]] 568 1.1 mrg return __cb; 569 1.1 mrg return nullptr; 570 1.1 mrg } 571 1.1 mrg 572 1.1 mrg struct _Impl 573 1.1 mrg { 574 1.1 mrg using pointer = typename _AllocTraits::pointer; 575 1.1 mrg 576 1.1 mrg pointer _M_frames = nullptr; 577 1.1 mrg size_type _M_size = 0; 578 1.1 mrg size_type _M_capacity = 0; 579 1.1 mrg 580 1.1 mrg static size_type 581 1.1 mrg _S_max_size(const allocator_type& __alloc) noexcept 582 1.1 mrg { 583 1.1 mrg const size_t __size_max = __gnu_cxx::__int_traits<size_type>::__max; 584 1.1 mrg const size_t __alloc_max = _AllocTraits::max_size(__alloc); 585 1.1 mrg return std::min(__size_max, __alloc_max); 586 1.1 mrg } 587 1.1 mrg 588 1.1 mrg #if __has_builtin(__builtin_operator_new) >= 201802L 589 1.1 mrg # define _GLIBCXX_OPERATOR_NEW __builtin_operator_new 590 1.1 mrg # define _GLIBCXX_OPERATOR_DELETE __builtin_operator_delete 591 1.1 mrg #else 592 1.1 mrg # define _GLIBCXX_OPERATOR_NEW ::operator new 593 1.1 mrg # define _GLIBCXX_OPERATOR_DELETE ::operator delete 594 1.1 mrg #endif 595 1.1 mrg 596 1.1 mrg // Precondition: _M_frames == nullptr && __n != 0 597 1.1 mrg pointer 598 1.1 mrg _M_allocate(allocator_type& __alloc, size_type __n) noexcept 599 1.1 mrg { 600 1.1 mrg if (__n <= _S_max_size(__alloc)) [[likely]] 601 1.1 mrg { 602 1.1 mrg if constexpr (is_same_v<allocator_type, allocator<value_type>>) 603 1.1 mrg { 604 1.1 mrg // For std::allocator we use nothrow-new directly so we 605 1.1 mrg // don't need to handle bad_alloc exceptions. 606 1.1 mrg size_t __nb = __n * sizeof(value_type); 607 1.1 mrg void* const __p = _GLIBCXX_OPERATOR_NEW (__nb, nothrow_t{}); 608 1.1 mrg if (__p == nullptr) [[unlikely]] 609 1.1 mrg return nullptr; 610 1.1 mrg _M_frames = static_cast<pointer>(__p); 611 1.1 mrg } 612 1.1 mrg else 613 1.1 mrg { 614 1.1 mrg __try 615 1.1 mrg { 616 1.1 mrg _M_frames = __alloc.allocate(__n); 617 1.1 mrg } 618 1.1 mrg __catch (const std::bad_alloc&) 619 1.1 mrg { 620 1.1 mrg return nullptr; 621 1.1 mrg } 622 1.1 mrg } 623 1.1 mrg _M_capacity = __n; 624 1.1 mrg return _M_frames; 625 1.1 mrg } 626 1.1 mrg return nullptr; 627 1.1 mrg } 628 1.1 mrg 629 1.1 mrg void 630 1.1 mrg _M_deallocate(allocator_type& __alloc) noexcept 631 1.1 mrg { 632 1.1 mrg if (_M_capacity) 633 1.1 mrg { 634 1.1 mrg if constexpr (is_same_v<allocator_type, allocator<value_type>>) 635 1.1 mrg _GLIBCXX_OPERATOR_DELETE (static_cast<void*>(_M_frames), 636 1.1 mrg _M_capacity * sizeof(value_type)); 637 1.1 mrg else 638 1.1 mrg __alloc.deallocate(_M_frames, _M_capacity); 639 1.1 mrg _M_frames = nullptr; 640 1.1 mrg _M_capacity = 0; 641 1.1 mrg } 642 1.1 mrg } 643 1.1 mrg 644 1.1 mrg #undef _GLIBCXX_OPERATOR_DELETE 645 1.1 mrg #undef _GLIBCXX_OPERATOR_NEW 646 1.1 mrg 647 1.1 mrg // Precondition: __n <= _M_size 648 1.1 mrg void 649 1.1 mrg _M_resize(size_type __n, allocator_type& __alloc) noexcept 650 1.1 mrg { 651 1.1 mrg for (size_type __i = __n; __i < _M_size; ++__i) 652 1.1 mrg _AllocTraits::destroy(__alloc, &_M_frames[__i]); 653 1.1 mrg _M_size = __n; 654 1.1 mrg } 655 1.1 mrg 656 1.1 mrg bool 657 1.1 mrg _M_push_back(allocator_type& __alloc, 658 1.1 mrg const stacktrace_entry& __f) noexcept 659 1.1 mrg { 660 1.1 mrg if (_M_size == _M_capacity) [[unlikely]] 661 1.1 mrg { 662 1.1 mrg _Impl __tmp = _M_xclone(_M_capacity ? _M_capacity : 8, __alloc); 663 1.1 mrg if (!__tmp._M_capacity) [[unlikely]] 664 1.1 mrg return false; 665 1.1 mrg _M_resize(0, __alloc); 666 1.1 mrg _M_deallocate(__alloc); 667 1.1 mrg *this = __tmp; 668 1.1 mrg } 669 1.1 mrg stacktrace_entry* __addr = std::to_address(_M_frames + _M_size++); 670 1.1 mrg _AllocTraits::construct(__alloc, __addr, __f); 671 1.1 mrg return true; 672 1.1 mrg } 673 1.1 mrg 674 1.1 mrg // Precondition: _M_size != 0 675 1.1 mrg _Impl 676 1.1 mrg _M_clone(allocator_type& __alloc) const noexcept 677 1.1 mrg { 678 1.1 mrg return _M_xclone(_M_size, __alloc); 679 1.1 mrg } 680 1.1 mrg 681 1.1 mrg // Precondition: _M_size != 0 || __extra != 0 682 1.1 mrg _Impl 683 1.1 mrg _M_xclone(size_type __extra, allocator_type& __alloc) const noexcept 684 1.1 mrg { 685 1.1 mrg _Impl __i; 686 1.1 mrg if (__i._M_allocate(__alloc, _M_size + __extra)) [[likely]] 687 1.1 mrg __i._M_assign(*this, __alloc); 688 1.1 mrg return __i; 689 1.1 mrg } 690 1.1 mrg 691 1.1 mrg // Precondition: _M_capacity >= __other._M_size 692 1.1 mrg void 693 1.1 mrg _M_assign(const _Impl& __other, allocator_type& __alloc) noexcept 694 1.1 mrg { 695 1.1 mrg std::__uninitialized_copy_a(__other._M_frames, 696 1.1 mrg __other._M_frames + __other._M_size, 697 1.1 mrg _M_frames, __alloc); 698 1.1 mrg _M_size = __other._M_size; 699 1.1 mrg } 700 1.1 mrg }; 701 1.1 mrg 702 1.1 mrg [[no_unique_address]] allocator_type _M_alloc{}; 703 1.1 mrg 704 1.1 mrg _Impl _M_impl{}; 705 1.1 mrg }; 706 1.1 mrg 707 1.1 mrg // basic_stacktrace typedef names 708 1.1 mrg using stacktrace = basic_stacktrace<allocator<stacktrace_entry>>; 709 1.1 mrg 710 1.1 mrg // [stacktrace.basic.nonmem], non-member functions 711 1.1 mrg template<typename _Allocator> 712 1.1 mrg inline void 713 1.1 mrg swap(basic_stacktrace<_Allocator>& __a, basic_stacktrace<_Allocator>& __b) 714 1.1 mrg noexcept(noexcept(__a.swap(__b))) 715 1.1 mrg { __a.swap(__b); } 716 1.1 mrg 717 1.1 mrg inline ostream& 718 1.1 mrg operator<<(ostream& __os, const stacktrace_entry& __f) 719 1.1 mrg { 720 1.1 mrg string __desc, __file; 721 1.1 mrg int __line; 722 1.1 mrg if (__f._M_get_info(&__desc, &__file, &__line)) 723 1.1 mrg { 724 1.1 mrg __os.width(4); 725 1.1 mrg __os << __desc << " at " << __file << ':' << __line; 726 1.1 mrg } 727 1.1 mrg return __os; 728 1.1 mrg } 729 1.1 mrg 730 1.1 mrg template<typename _Allocator> 731 1.1 mrg inline ostream& 732 1.1 mrg operator<<(ostream& __os, const basic_stacktrace<_Allocator>& __st) 733 1.1 mrg { 734 1.1 mrg for (stacktrace::size_type __i = 0; __i < __st.size(); ++__i) 735 1.1 mrg { 736 1.1 mrg __os.width(4); 737 1.1 mrg __os << __i << "# " << __st[__i] << '\n'; 738 1.1 mrg } 739 1.1 mrg return __os; 740 1.1 mrg } 741 1.1 mrg 742 1.1 mrg inline string 743 1.1 mrg to_string(const stacktrace_entry& __f) 744 1.1 mrg { 745 1.1 mrg std::ostringstream __os; 746 1.1 mrg __os << __f; 747 1.1 mrg return std::move(__os).str(); 748 1.1 mrg } 749 1.1 mrg 750 1.1 mrg template<typename _Allocator> 751 1.1 mrg string 752 1.1 mrg to_string(const basic_stacktrace<_Allocator>& __st) 753 1.1 mrg { 754 1.1 mrg std::ostringstream __os; 755 1.1 mrg __os << __st; 756 1.1 mrg return std::move(__os).str(); 757 1.1 mrg } 758 1.1 mrg 759 1.1 mrg namespace pmr 760 1.1 mrg { 761 1.1 mrg template<typename _Tp> class polymorphic_allocator; 762 1.1 mrg using stacktrace 763 1.1 mrg = basic_stacktrace<polymorphic_allocator<stacktrace_entry>>; 764 1.1 mrg } 765 1.1 mrg 766 1.1 mrg // [stacktrace.basic.hash], hash support 767 1.1 mrg 768 1.1 mrg template<> 769 1.1 mrg struct hash<stacktrace_entry> 770 1.1 mrg { 771 1.1 mrg size_t 772 1.1 mrg operator()(const stacktrace_entry& __f) const noexcept 773 1.1 mrg { 774 1.1 mrg using __h = hash<stacktrace_entry::native_handle_type>; 775 1.1 mrg return __h()(__f.native_handle()); 776 1.1 mrg } 777 1.1 mrg }; 778 1.1 mrg 779 1.1 mrg template<typename _Allocator> 780 1.1 mrg struct hash<basic_stacktrace<_Allocator>> 781 1.1 mrg { 782 1.1 mrg size_t 783 1.1 mrg operator()(const basic_stacktrace<_Allocator>& __st) const noexcept 784 1.1 mrg { 785 1.1 mrg hash<stacktrace_entry> __h; 786 1.1 mrg size_t __val = _Hash_impl::hash(__st.size()); 787 1.1 mrg for (const auto& __f : __st) 788 1.1 mrg __val = _Hash_impl::__hash_combine(__h(__f), __val); 789 1.1 mrg return __val; 790 1.1 mrg } 791 1.1 mrg }; 792 1.1 mrg 793 1.1 mrg _GLIBCXX_END_NAMESPACE_VERSION 794 1.1 mrg } // namespace std 795 1.1 mrg #endif // C++23 796 1.1 mrg 797 1.1 mrg #endif /* _GLIBCXX_STACKTRACE */ 798