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