safe_dump_to.hpp 9.0 KB

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