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