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