]>
Commit | Line | Data |
---|---|---|
1e59de90 | 1 | // Copyright Antony Polukhin, 2016-2022. |
b32b8144 FG |
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 | ||
11fdf7f2 TL |
15 | #if defined(BOOST_WINDOWS) |
16 | #include <boost/winapi/config.hpp> | |
17 | #endif | |
18 | ||
b32b8144 FG |
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 | ||
50 | 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> | |
64 | 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 | /// | |
92f5a8d4 | 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) |
b32b8144 FG |
88 | /// |
89 | /// @param memory Preallocated buffer to store current function call sequence into. | |
90 | /// | |
91 | /// @param size Size of the preallocated buffer. | |
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 | /// | |
92f5a8d4 | 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) |
b32b8144 FG |
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. | |
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 | ||
11fdf7f2 | 114 | /// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe. |
b32b8144 FG |
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. | |
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 | ||
11fdf7f2 | 127 | /// @brief Opens a file and rewrites its content with current function call sequence if such operations are async signal safe. |
b32b8144 FG |
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. | |
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 | ||
11fdf7f2 | 146 | /// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe. |
b32b8144 FG |
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 | ||
11fdf7f2 | 157 | /// @brief Writes into the provided file descriptor the current function call sequence if such operation is async signal safe. |
b32b8144 FG |
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 | ||
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 | ||
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 | |
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 | ||
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 |