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