safe_dump_to.hpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // Copyright Antony Polukhin, 2016-2021.
  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. #ifndef BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
  7. #define BOOST_STACKTRACE_SAFE_DUMP_TO_HPP
  8. #include <boost/config.hpp>
  9. #ifdef BOOST_HAS_PRAGMA_ONCE
  10. # pragma once
  11. #endif
  12. #if defined(BOOST_WINDOWS)
  13. #include <boost/winapi/config.hpp>
  14. #endif
  15. #include <boost/stacktrace/detail/push_options.h>
  16. #ifdef BOOST_INTEL
  17. # pragma warning(push)
  18. # pragma warning(disable:2196) // warning #2196: routine is both "inline" and "noinline"
  19. #endif
  20. /// @file safe_dump_to.hpp This header contains low-level async-signal-safe functions for dumping call stacks. Dumps are binary serialized arrays of `void*`,
  21. /// so you could read them by using 'od -tx8 -An stacktrace_dump_failename' Linux command or using boost::stacktrace::stacktrace::from_dump functions.
  22. namespace boost { namespace stacktrace {
  23. /// @cond
  24. namespace detail {
  25. typedef const void* native_frame_ptr_t; // TODO: change to `typedef void(*native_frame_ptr_t)();`
  26. enum helper{ max_frames_dump = 128 };
  27. BOOST_STACKTRACE_FUNCTION std::size_t from_dump(const char* filename, native_frame_ptr_t* out_frames);
  28. BOOST_STACKTRACE_FUNCTION std::size_t dump(const char* file, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
  29. #if defined(BOOST_WINDOWS)
  30. BOOST_STACKTRACE_FUNCTION std::size_t dump(void* fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
  31. #else
  32. // POSIX
  33. BOOST_STACKTRACE_FUNCTION std::size_t dump(int fd, const native_frame_ptr_t* frames, std::size_t frames_count) BOOST_NOEXCEPT;
  34. #endif
  35. struct this_thread_frames { // struct is required to avoid warning about usage of inline+BOOST_NOINLINE
  36. BOOST_NOINLINE BOOST_STACKTRACE_FUNCTION static std::size_t collect(native_frame_ptr_t* out_frames, std::size_t max_frames_count, std::size_t skip) BOOST_NOEXCEPT;
  37. BOOST_NOINLINE static std::size_t safe_dump_to_impl(void* memory, std::size_t size, std::size_t skip) BOOST_NOEXCEPT {
  38. typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
  39. if (size < sizeof(native_frame_ptr_t)) {
  40. return 0;
  41. }
  42. native_frame_ptr_t* mem = static_cast<native_frame_ptr_t*>(memory);
  43. const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(mem, size / sizeof(native_frame_ptr_t) - 1, skip + 1);
  44. mem[frames_count] = 0;
  45. return frames_count + 1;
  46. }
  47. template <class T>
  48. BOOST_NOINLINE static std::size_t safe_dump_to_impl(T file, std::size_t skip, std::size_t max_depth) BOOST_NOEXCEPT {
  49. typedef boost::stacktrace::detail::native_frame_ptr_t native_frame_ptr_t;
  50. native_frame_ptr_t buffer[boost::stacktrace::detail::max_frames_dump + 1];
  51. if (max_depth > boost::stacktrace::detail::max_frames_dump) {
  52. max_depth = boost::stacktrace::detail::max_frames_dump;
  53. }
  54. const std::size_t frames_count = boost::stacktrace::detail::this_thread_frames::collect(buffer, max_depth, skip + 1);
  55. buffer[frames_count] = 0;
  56. return boost::stacktrace::detail::dump(file, buffer, frames_count + 1);
  57. }
  58. };
  59. } // namespace detail
  60. /// @endcond
  61. /// @brief Stores current function call sequence into the memory.
  62. ///
  63. /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
  64. ///
  65. /// @b Async-Handler-Safety: Safe.
  66. ///
  67. /// @returns Stored call sequence depth including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
  68. ///
  69. /// @param memory Preallocated buffer to store current function call sequence into.
  70. ///
  71. /// @param size Size of the preallocated buffer.
  72. BOOST_FORCEINLINE std::size_t safe_dump_to(void* memory, std::size_t size) BOOST_NOEXCEPT {
  73. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, 0);
  74. }
  75. /// @brief Stores current function call sequence into the memory.
  76. ///
  77. /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
  78. ///
  79. /// @b Async-Handler-Safety: Safe.
  80. ///
  81. /// @returns Stored call sequence depth including terminating zero frame. To get the actually consumed bytes multiply this value by the sizeof(boost::stacktrace::frame::native_frame_ptr_t)
  82. ///
  83. /// @param skip How many top calls to skip and do not store.
  84. ///
  85. /// @param memory Preallocated buffer to store current function call sequence into.
  86. ///
  87. /// @param size Size of the preallocated buffer.
  88. BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, void* memory, std::size_t size) BOOST_NOEXCEPT {
  89. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(memory, size, skip);
  90. }
  91. /// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
  92. ///
  93. /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
  94. ///
  95. /// @b Async-Handler-Safety: Safe.
  96. ///
  97. /// @returns Stored call sequence depth including terminating zero frame.
  98. ///
  99. /// @param file File to store current function call sequence.
  100. BOOST_FORCEINLINE std::size_t safe_dump_to(const char* file) BOOST_NOEXCEPT {
  101. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, 0, boost::stacktrace::detail::max_frames_dump);
  102. }
  103. /// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe.
  104. ///
  105. /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
  106. ///
  107. /// @b Async-Handler-Safety: Safe.
  108. ///
  109. /// @returns Stored call sequence depth including terminating zero frame.
  110. ///
  111. /// @param skip How many top calls to skip and do not store.
  112. ///
  113. /// @param max_depth Max call sequence depth to collect.
  114. ///
  115. /// @param file File to store current function call sequence.
  116. BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, const char* file) BOOST_NOEXCEPT {
  117. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(file, skip, max_depth);
  118. }
  119. #ifdef BOOST_STACKTRACE_DOXYGEN_INVOKED
  120. /// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
  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.
  125. ///
  126. /// @returns Stored call sequence depth including terminating zero frame.
  127. ///
  128. /// @param file File to store current function call sequence.
  129. BOOST_FORCEINLINE std::size_t safe_dump_to(platform_specific_descriptor fd) BOOST_NOEXCEPT;
  130. /// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe.
  131. ///
  132. /// @b Complexity: O(N) where N is call sequence length, O(1) if BOOST_STACKTRACE_USE_NOOP is defined.
  133. ///
  134. /// @b Async-Handler-Safety: Safe.
  135. ///
  136. /// @returns Stored call sequence depth including terminating zero frame.
  137. ///
  138. /// @param skip How many top calls to skip and do not store.
  139. ///
  140. /// @param max_depth Max call sequence depth to collect.
  141. ///
  142. /// @param file File to store current function call sequence.
  143. BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, platform_specific_descriptor fd) BOOST_NOEXCEPT;
  144. #elif defined(BOOST_WINDOWS)
  145. BOOST_FORCEINLINE std::size_t safe_dump_to(void* fd) BOOST_NOEXCEPT {
  146. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
  147. }
  148. BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, void* fd) BOOST_NOEXCEPT {
  149. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
  150. }
  151. #else
  152. // POSIX
  153. BOOST_FORCEINLINE std::size_t safe_dump_to(int fd) BOOST_NOEXCEPT {
  154. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, 0, boost::stacktrace::detail::max_frames_dump);
  155. }
  156. BOOST_FORCEINLINE std::size_t safe_dump_to(std::size_t skip, std::size_t max_depth, int fd) BOOST_NOEXCEPT {
  157. return boost::stacktrace::detail::this_thread_frames::safe_dump_to_impl(fd, skip, max_depth);
  158. }
  159. #endif
  160. }} // namespace boost::stacktrace
  161. #ifdef BOOST_INTEL
  162. # pragma warning(pop)
  163. #endif
  164. #include <boost/stacktrace/detail/pop_options.h>
  165. #if !defined(BOOST_STACKTRACE_LINK) || defined(BOOST_STACKTRACE_INTERNAL_BUILD_LIBS)
  166. # if defined(BOOST_STACKTRACE_USE_NOOP)
  167. # include <boost/stacktrace/detail/safe_dump_noop.ipp>
  168. # include <boost/stacktrace/detail/collect_noop.ipp>
  169. # else
  170. # if defined(BOOST_WINDOWS)
  171. # include <boost/stacktrace/detail/safe_dump_win.ipp>
  172. # else
  173. # include <boost/stacktrace/detail/safe_dump_posix.ipp>
  174. # endif
  175. # if defined(BOOST_WINDOWS) && !defined(BOOST_WINAPI_IS_MINGW) // MinGW does not provide RtlCaptureStackBackTrace. MinGW-w64 does.
  176. # include <boost/stacktrace/detail/collect_msvc.ipp>
  177. # else
  178. # include <boost/stacktrace/detail/collect_unwind.ipp>
  179. # endif
  180. # endif
  181. #endif
  182. #endif // BOOST_STACKTRACE_SAFE_DUMP_TO_HPP