| Avi Drissman | e4622aa | 2022-09-08 20:36:06 | [diff] [blame] | 1 | // Copyright 2012 The Chromium Authors |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef BASE_DEBUG_STACK_TRACE_H_ |
| 6 | #define BASE_DEBUG_STACK_TRACE_H_ |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 7 | |
| avi | ebe805c | 2015-12-24 08:20:28 | [diff] [blame] | 8 | #include <stddef.h> |
| 9 | |
| Lei Zhang | 4493f55 | 2025-06-14 06:11:31 | [diff] [blame] | 10 | #include <array> |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 11 | #include <iosfwd> |
| [email protected] | d4114ba | 2011-10-12 16:13:40 | [diff] [blame] | 12 | #include <string> |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 13 | |
| [email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 14 | #include "base/base_export.h" |
| Daniel Cheng | a0e290d | 2023-10-16 18:47:24 | [diff] [blame] | 15 | #include "base/containers/span.h" |
| Scott Violet | 4416579 | 2018-02-22 02:08:08 | [diff] [blame] | 16 | #include "base/debug/debugging_buildflags.h" |
| Keishi Hattori | f28f4f8 | 2022-06-21 11:32:15 | [diff] [blame] | 17 | #include "base/memory/raw_ptr.h" |
| Greg Thompson | c82cbc9 | 2024-04-10 07:36:06 | [diff] [blame] | 18 | #include "base/strings/cstring_view.h" |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 19 | #include "build/build_config.h" |
| 20 | |
| Xiaohan Wang | 131aa4d | 2022-01-15 19:39:41 | [diff] [blame] | 21 | #if BUILDFLAG(IS_POSIX) |
| Andreas Haas | 54c0c02 | 2019-06-14 17:33:53 | [diff] [blame] | 22 | #include <signal.h> |
| [email protected] | 47c4556 | 2012-11-17 14:33:25 | [diff] [blame] | 23 | #include <unistd.h> |
| 24 | #endif |
| 25 | |
| Xiaohan Wang | 131aa4d | 2022-01-15 19:39:41 | [diff] [blame] | 26 | #if BUILDFLAG(IS_WIN) |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 27 | struct _EXCEPTION_POINTERS; |
| wittman | 7808da7 | 2015-02-03 17:46:51 | [diff] [blame] | 28 | struct _CONTEXT; |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 29 | #endif |
| 30 | |
| Jan Keitel | 4161bcb | 2024-08-01 12:44:24 | [diff] [blame] | 31 | namespace base::debug { |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 32 | |
| [email protected] | 11b93faa | 2012-11-01 21:58:30 | [diff] [blame] | 33 | // Enables stack dump to console output on exception and signals. |
| 34 | // When enabled, the process will quit immediately. This is meant to be used in |
| 35 | // unit_tests only! This is not thread-safe: only call from main thread. |
| jam | 79dc59a | 2015-08-17 03:38:16 | [diff] [blame] | 36 | // In sandboxed processes, this has to be called before the sandbox is turned |
| 37 | // on. |
| [email protected] | ad9a012 | 2014-03-22 00:34:52 | [diff] [blame] | 38 | // Calling this function on Linux opens /proc/self/maps and caches its |
| jam | 79dc59a | 2015-08-17 03:38:16 | [diff] [blame] | 39 | // contents. In non-official builds, this function also opens the object files |
| 40 | // that are loaded in memory and caches their file descriptors (this cannot be |
| [email protected] | ad9a012 | 2014-03-22 00:34:52 | [diff] [blame] | 41 | // done in official builds because it has security implications). |
| jam | 79dc59a | 2015-08-17 03:38:16 | [diff] [blame] | 42 | BASE_EXPORT bool EnableInProcessStackDumping(); |
| [email protected] | ad9a012 | 2014-03-22 00:34:52 | [diff] [blame] | 43 | |
| Alex Gough | d007d62 | 2025-09-11 17:55:49 | [diff] [blame] | 44 | #if BUILDFLAG(IS_WIN) |
| 45 | // Returns `true` if EnableInProcessStackDumping() was called and succeeded. |
| 46 | // Only supported on Windows. |
| 47 | BASE_EXPORT bool InProcessStackDumpingEnabled(); |
| Alex Gough | 0bbe87d | 2025-09-12 21:12:11 | [diff] [blame] | 48 | |
| 49 | // Allows tests to exercise code that runs when symbolization is not available. |
| 50 | BASE_EXPORT bool DisableInProcessStackDumpingForTesting(); |
| Alex Gough | d007d62 | 2025-09-11 17:55:49 | [diff] [blame] | 51 | #endif // BUILDFLAG(IS_WIN) |
| 52 | |
| Nico Weber | 6f2d26d | 2025-06-27 07:32:08 | [diff] [blame] | 53 | #if BUILDFLAG(IS_POSIX) |
| Andreas Haas | ef19d59 | 2019-04-30 18:16:51 | [diff] [blame] | 54 | // Sets a first-chance callback for the stack dump signal handler. This callback |
| 55 | // is called at the beginning of the signal handler to handle special kinds of |
| 56 | // signals, like out-of-bounds memory accesses in WebAssembly (WebAssembly Trap |
| 57 | // Handler). |
| 58 | // {SetStackDumpFirstChanceCallback} returns {true} if the callback |
| 59 | // has been set correctly. It returns {false} if the stack dump signal handler |
| 60 | // has not been registered with the OS, e.g. because of ASAN. |
| 61 | BASE_EXPORT bool SetStackDumpFirstChanceCallback(bool (*handler)(int, |
| Andreas Haas | 54c0c02 | 2019-06-14 17:33:53 | [diff] [blame] | 62 | siginfo_t*, |
| Eric Holk | dc499db | 2017-07-17 17:57:35 | [diff] [blame] | 63 | void*)); |
| 64 | #endif |
| 65 | |
| erikchen | d6b2b82 | 2017-02-22 21:10:31 | [diff] [blame] | 66 | // Returns end of the stack, or 0 if we couldn't get it. |
| erikchen | f7c8a0d | 2017-04-06 21:15:27 | [diff] [blame] | 67 | #if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) |
| erikchen | d6b2b82 | 2017-02-22 21:10:31 | [diff] [blame] | 68 | BASE_EXPORT uintptr_t GetStackEnd(); |
| 69 | #endif |
| 70 | |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 71 | // A stacktrace can be helpful in debugging. For example, you can include a |
| 72 | // stacktrace member in a object (probably around #ifndef NDEBUG) so that you |
| 73 | // can later see where the given object was created from. |
| [email protected] | 0bea725 | 2011-08-05 15:34:00 | [diff] [blame] | 74 | class BASE_EXPORT StackTrace { |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 75 | public: |
| Daniel Cheng | 42dd844 | 2024-03-05 22:14:11 | [diff] [blame] | 76 | // LINT.IfChange(max_stack_frames) |
| Daniel Cheng | 1e96ff3 | 2023-06-26 20:01:01 | [diff] [blame] | 77 | #if BUILDFLAG(IS_ANDROID) |
| Alison Gale | d94ce4f | 2024-04-22 15:20:39 | [diff] [blame] | 78 | // TODO(crbug.com/41437515): Testing indicates that Android has issues |
| Daniel Cheng | 1e96ff3 | 2023-06-26 20:01:01 | [diff] [blame] | 79 | // with a larger value here, so leave Android at 62. |
| 80 | static constexpr size_t kMaxTraces = 62; |
| 81 | #else |
| 82 | // For other platforms, use 250. This seems reasonable without |
| 83 | // being huge. |
| 84 | static constexpr size_t kMaxTraces = 250; |
| 85 | #endif |
| Daniel Cheng | 42dd844 | 2024-03-05 22:14:11 | [diff] [blame] | 86 | // LINT.ThenChange(dwarf_line_no.cc:max_stack_frames) |
| Daniel Cheng | 1e96ff3 | 2023-06-26 20:01:01 | [diff] [blame] | 87 | |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 88 | // Creates a stacktrace from the current location. |
| 89 | StackTrace(); |
| 90 | |
| wez | 73f8d7e | 2017-01-29 06:18:13 | [diff] [blame] | 91 | // Creates a stacktrace from the current location, of up to |count| entries. |
| 92 | // |count| will be limited to at most |kMaxTraces|. |
| 93 | explicit StackTrace(size_t count); |
| 94 | |
| danakj | e75c6c81 | 2024-07-26 20:37:47 | [diff] [blame] | 95 | // Creates a stacktrace from an existing array of instruction pointers (such |
| 96 | // as returned by Addresses()). Only the first `kMaxTraces` of the span will |
| 97 | // be used. |
| 98 | explicit StackTrace(span<const void* const> trace); |
| [email protected] | f01ae981 | 2011-08-30 19:33:04 | [diff] [blame] | 99 | |
| Xiaohan Wang | 131aa4d | 2022-01-15 19:39:41 | [diff] [blame] | 100 | #if BUILDFLAG(IS_WIN) |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 101 | // Creates a stacktrace for an exception. |
| 102 | // Note: this function will throw an import not found (StackWalk64) exception |
| 103 | // on system without dbghelp 5.1. |
| jam | 79dc59a | 2015-08-17 03:38:16 | [diff] [blame] | 104 | StackTrace(_EXCEPTION_POINTERS* exception_pointers); |
| rnk | 0565cdd6 | 2015-10-06 16:48:30 | [diff] [blame] | 105 | StackTrace(const _CONTEXT* context); |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 106 | #endif |
| 107 | |
| Gabriel Charette | ae1bb01 | 2021-05-06 19:31:21 | [diff] [blame] | 108 | // Returns true if this current test environment is expected to have |
| 109 | // symbolized frames when printing a stack trace. |
| 110 | static bool WillSymbolizeToStreamForTesting(); |
| 111 | |
| Xiyuan Xia | e9dc9d4 | 2025-09-25 16:14:13 | [diff] [blame] | 112 | // Initialize features. |
| 113 | static void InitializeFeatures(); |
| 114 | |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 115 | // Copying and assignment are allowed with the default functions. |
| 116 | |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 117 | // Gets an array of instruction pointer values. |*count| will be set to the |
| Bruce Dawson | 19e29bb | 2020-01-06 21:20:14 | [diff] [blame] | 118 | // number of elements in the returned array. Addresses()[0] will contain an |
| 119 | // address from the leaf function, and Addresses()[count-1] will contain an |
| 120 | // address from the root function (i.e.; the thread's entry point). |
| Daniel Cheng | a0e290d | 2023-10-16 18:47:24 | [diff] [blame] | 121 | span<const void* const> addresses() const { |
| Jan Keitel | 4161bcb | 2024-08-01 12:44:24 | [diff] [blame] | 122 | return span(trace_).first(count_); |
| Daniel Cheng | a0e290d | 2023-10-16 18:47:24 | [diff] [blame] | 123 | } |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 124 | |
| [email protected] | 5ddbf1c | 2013-08-29 01:59:38 | [diff] [blame] | 125 | // Prints the stack trace to stderr. |
| 126 | void Print() const; |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 127 | |
| Mason Freed | b9ef2b6 | 2018-09-10 17:17:27 | [diff] [blame] | 128 | // Prints the stack trace to stderr, prepending the given string before |
| 129 | // each output line. |
| Greg Thompson | 8b1b295b | 2024-04-10 07:44:14 | [diff] [blame] | 130 | void PrintWithPrefix(cstring_view prefix_string) const; |
| Mason Freed | b9ef2b6 | 2018-09-10 17:17:27 | [diff] [blame] | 131 | |
| Gabriel Charette | ae1bb01 | 2021-05-06 19:31:21 | [diff] [blame] | 132 | #if !defined(__UCLIBC__) && !defined(_AIX) |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 133 | // Resolves backtrace to symbols and write to stream. |
| [email protected] | 501dfc4 | 2011-04-14 16:34:00 | [diff] [blame] | 134 | void OutputToStream(std::ostream* os) const; |
| Mason Freed | b9ef2b6 | 2018-09-10 17:17:27 | [diff] [blame] | 135 | // Resolves backtrace to symbols and write to stream, with the provided |
| 136 | // prefix string prepended to each line. |
| 137 | void OutputToStreamWithPrefix(std::ostream* os, |
| Greg Thompson | 8b1b295b | 2024-04-10 07:44:14 | [diff] [blame] | 138 | cstring_view prefix_string) const; |
| [email protected] | 816e5045 | 2014-04-09 22:29:38 | [diff] [blame] | 139 | #endif |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 140 | |
| [email protected] | d4114ba | 2011-10-12 16:13:40 | [diff] [blame] | 141 | // Resolves backtrace to symbols and returns as string. |
| 142 | std::string ToString() const; |
| 143 | |
| Mason Freed | b9ef2b6 | 2018-09-10 17:17:27 | [diff] [blame] | 144 | // Resolves backtrace to symbols and returns as string, prepending the |
| 145 | // provided prefix string to each line. |
| Greg Thompson | 8b1b295b | 2024-04-10 07:44:14 | [diff] [blame] | 146 | std::string ToStringWithPrefix(cstring_view prefix_string) const; |
| Mason Freed | b9ef2b6 | 2018-09-10 17:17:27 | [diff] [blame] | 147 | |
| Greg Thompson | c82cbc9 | 2024-04-10 07:36:06 | [diff] [blame] | 148 | // Sets a message to be emitted in place of symbolized stack traces. When |
| 149 | // such a message is provided, collection and symbolization of stack traces |
| 150 | // is suppressed. Suppression is cancelled if `message` is empty. |
| 151 | static void SuppressStackTracesWithMessageForTesting(std::string message); |
| 152 | |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 153 | private: |
| Greg Thompson | c82cbc9 | 2024-04-10 07:36:06 | [diff] [blame] | 154 | // Prints `message` with an optional prefix. |
| Greg Thompson | 8b1b295b | 2024-04-10 07:44:14 | [diff] [blame] | 155 | static void PrintMessageWithPrefix(cstring_view prefix_string, |
| Greg Thompson | c82cbc9 | 2024-04-10 07:36:06 | [diff] [blame] | 156 | cstring_view message); |
| 157 | |
| Greg Thompson | 8b1b295b | 2024-04-10 07:44:14 | [diff] [blame] | 158 | void PrintWithPrefixImpl(cstring_view prefix_string) const; |
| Greg Thompson | c82cbc9 | 2024-04-10 07:36:06 | [diff] [blame] | 159 | #if !defined(__UCLIBC__) && !defined(_AIX) |
| 160 | void OutputToStreamWithPrefixImpl(std::ostream* os, |
| Greg Thompson | 8b1b295b | 2024-04-10 07:44:14 | [diff] [blame] | 161 | cstring_view prefix_string) const; |
| Greg Thompson | c82cbc9 | 2024-04-10 07:36:06 | [diff] [blame] | 162 | #endif |
| 163 | |
| Greg Thompson | 75724f9 | 2024-03-21 08:31:27 | [diff] [blame] | 164 | // Returns true if generation of symbolized stack traces is to be suppressed. |
| 165 | static bool ShouldSuppressOutput(); |
| 166 | |
| Xiaohan Wang | 131aa4d | 2022-01-15 19:39:41 | [diff] [blame] | 167 | #if BUILDFLAG(IS_WIN) |
| rnk | 0565cdd6 | 2015-10-06 16:48:30 | [diff] [blame] | 168 | void InitTrace(const _CONTEXT* context_record); |
| wittman | 7808da7 | 2015-02-03 17:46:51 | [diff] [blame] | 169 | #endif |
| 170 | |
| Jan Keitel | 4161bcb | 2024-08-01 12:44:24 | [diff] [blame] | 171 | std::array<const void*, kMaxTraces> trace_; |
| [email protected] | e645c7a | 2012-07-25 21:43:44 | [diff] [blame] | 172 | |
| Greg Thompson | 75724f9 | 2024-03-21 08:31:27 | [diff] [blame] | 173 | // The number of valid frames in |trace_|, or 0 if collection was suppressed. |
| 174 | size_t count_ = 0; |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 175 | }; |
| 176 | |
| Gabriel Charette | c41da451 | 2019-02-22 02:07:10 | [diff] [blame] | 177 | // Forwards to StackTrace::OutputToStream(). |
| 178 | BASE_EXPORT std::ostream& operator<<(std::ostream& os, const StackTrace& s); |
| 179 | |
| Vlad Tsyrklevich | 2788d5996 | 2019-01-23 03:32:45 | [diff] [blame] | 180 | // Record a stack trace with up to |count| frames into |trace|. Returns the |
| 181 | // number of frames read. |
| danakj | e75c6c81 | 2024-07-26 20:37:47 | [diff] [blame] | 182 | BASE_EXPORT size_t CollectStackTrace(span<const void*> trace); |
| Vlad Tsyrklevich | 2788d5996 | 2019-01-23 03:32:45 | [diff] [blame] | 183 | |
| Greg Thompson | 75724f9 | 2024-03-21 08:31:27 | [diff] [blame] | 184 | // A helper for tests that must either override the default suppression of |
| 185 | // symbolized stack traces in death tests, or the default generation of them in |
| 186 | // normal tests. |
| 187 | class BASE_EXPORT OverrideStackTraceOutputForTesting { |
| Greg Thompson | a6e88c1 | 2024-03-13 16:37:13 | [diff] [blame] | 188 | public: |
| Greg Thompson | 75724f9 | 2024-03-21 08:31:27 | [diff] [blame] | 189 | enum class Mode { |
| 190 | kUnset, |
| 191 | kForceOutput, |
| 192 | kSuppressOutput, |
| 193 | }; |
| 194 | explicit OverrideStackTraceOutputForTesting(Mode mode); |
| 195 | OverrideStackTraceOutputForTesting( |
| 196 | const OverrideStackTraceOutputForTesting&) = delete; |
| 197 | OverrideStackTraceOutputForTesting& operator=( |
| 198 | const OverrideStackTraceOutputForTesting&) = delete; |
| 199 | ~OverrideStackTraceOutputForTesting(); |
| Greg Thompson | a6e88c1 | 2024-03-13 16:37:13 | [diff] [blame] | 200 | }; |
| 201 | |
| erikchen | f7c8a0d | 2017-04-06 21:15:27 | [diff] [blame] | 202 | #if BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) |
| ssid | c1d5a3d | 2020-09-11 05:20:30 | [diff] [blame] | 203 | |
| 204 | // For stack scanning to be efficient it's very important for the thread to |
| 205 | // be started by Chrome. In that case we naturally terminate unwinding once |
| 206 | // we reach the origin of the stack (i.e. GetStackEnd()). If the thread is |
| 207 | // not started by Chrome (e.g. Android's main thread), then we end up always |
| 208 | // scanning area at the origin of the stack, wasting time and not finding any |
| 209 | // frames (since Android libraries don't have frame pointers). Scanning is not |
| 210 | // enabled on other posix platforms due to legacy reasons. |
| Xiaohan Wang | 131aa4d | 2022-01-15 19:39:41 | [diff] [blame] | 211 | #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) |
| ssid | c1d5a3d | 2020-09-11 05:20:30 | [diff] [blame] | 212 | constexpr bool kEnableScanningByDefault = true; |
| 213 | #else |
| 214 | constexpr bool kEnableScanningByDefault = false; |
| 215 | #endif |
| 216 | |
| dskiba | 79080da0 | 2016-04-23 00:10:27 | [diff] [blame] | 217 | // Traces the stack by using frame pointers. This function is faster but less |
| 218 | // reliable than StackTrace. It should work for debug and profiling builds, |
| 219 | // but not for release builds (although there are some exceptions). |
| 220 | // |
| 221 | // Writes at most |max_depth| frames (instruction pointers) into |out_trace| |
| 222 | // after skipping |skip_initial| frames. Note that the function itself is not |
| 223 | // added to the trace so |skip_initial| should be 0 in most cases. |
| ssid | c1d5a3d | 2020-09-11 05:20:30 | [diff] [blame] | 224 | // Returns number of frames written. |enable_scanning| enables scanning on |
| 225 | // platforms that do not enable scanning by default. |
| 226 | BASE_EXPORT size_t |
| danakj | e75c6c81 | 2024-07-26 20:37:47 | [diff] [blame] | 227 | TraceStackFramePointers(span<const void*> out_trace, |
| ssid | c1d5a3d | 2020-09-11 05:20:30 | [diff] [blame] | 228 | size_t skip_initial, |
| 229 | bool enable_scanning = kEnableScanningByDefault); |
| 230 | |
| dskiba | a8c951e | 2016-10-25 23:39:11 | [diff] [blame] | 231 | // Links stack frame |fp| to |parent_fp|, so that during stack unwinding |
| 232 | // TraceStackFramePointers() visits |parent_fp| after visiting |fp|. |
| 233 | // Both frame pointers must come from __builtin_frame_address(). |
| 234 | // Destructor restores original linkage of |fp| to avoid corrupting caller's |
| 235 | // frame register on return. |
| 236 | // |
| 237 | // This class can be used to repair broken stack frame chain in cases |
| 238 | // when execution flow goes into code built without frame pointers: |
| 239 | // |
| 240 | // void DoWork() { |
| 241 | // Call_SomeLibrary(); |
| 242 | // } |
| 243 | // static __thread void* g_saved_fp; |
| 244 | // void Call_SomeLibrary() { |
| 245 | // g_saved_fp = __builtin_frame_address(0); |
| 246 | // some_library_call(...); // indirectly calls SomeLibrary_Callback() |
| 247 | // } |
| 248 | // void SomeLibrary_Callback() { |
| 249 | // ScopedStackFrameLinker linker(__builtin_frame_address(0), g_saved_fp); |
| 250 | // ... |
| 251 | // TraceStackFramePointers(...); |
| 252 | // } |
| 253 | // |
| 254 | // This produces the following trace: |
| 255 | // |
| 256 | // #0 SomeLibrary_Callback() |
| 257 | // #1 <address of the code inside SomeLibrary that called #0> |
| 258 | // #2 DoWork() |
| 259 | // ...rest of the trace... |
| 260 | // |
| 261 | // SomeLibrary doesn't use frame pointers, so when SomeLibrary_Callback() |
| 262 | // is called, stack frame register contains bogus value that becomes callback' |
| 263 | // parent frame address. Without ScopedStackFrameLinker unwinding would've |
| 264 | // stopped at that bogus frame address yielding just two first frames (#0, #1). |
| 265 | // ScopedStackFrameLinker overwrites callback's parent frame address with |
| 266 | // Call_SomeLibrary's frame, so unwinder produces full trace without even |
| 267 | // noticing that stack frame chain was broken. |
| 268 | class BASE_EXPORT ScopedStackFrameLinker { |
| 269 | public: |
| 270 | ScopedStackFrameLinker(void* fp, void* parent_fp); |
| Peter Boström | 7319bbd | 2021-09-15 22:59:38 | [diff] [blame] | 271 | |
| 272 | ScopedStackFrameLinker(const ScopedStackFrameLinker&) = delete; |
| 273 | ScopedStackFrameLinker& operator=(const ScopedStackFrameLinker&) = delete; |
| 274 | |
| dskiba | a8c951e | 2016-10-25 23:39:11 | [diff] [blame] | 275 | ~ScopedStackFrameLinker(); |
| 276 | |
| 277 | private: |
| Keishi Hattori | f28f4f8 | 2022-06-21 11:32:15 | [diff] [blame] | 278 | raw_ptr<void> fp_; |
| 279 | raw_ptr<void> parent_fp_; |
| 280 | raw_ptr<void> original_parent_fp_; |
| dskiba | a8c951e | 2016-10-25 23:39:11 | [diff] [blame] | 281 | }; |
| 282 | |
| erikchen | f7c8a0d | 2017-04-06 21:15:27 | [diff] [blame] | 283 | #endif // BUILDFLAG(CAN_UNWIND_WITH_FRAME_POINTERS) |
| dskiba | 79080da0 | 2016-04-23 00:10:27 | [diff] [blame] | 284 | |
| [email protected] | 1e218b7 | 2012-11-14 19:32:23 | [diff] [blame] | 285 | namespace internal { |
| 286 | |
| Xiaohan Wang | 131aa4d | 2022-01-15 19:39:41 | [diff] [blame] | 287 | #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) |
| [email protected] | 1e218b7 | 2012-11-14 19:32:23 | [diff] [blame] | 288 | // POSIX doesn't define any async-signal safe function for converting |
| 289 | // an integer to ASCII. We'll have to define our own version. |
| 290 | // itoa_r() converts a (signed) integer to ASCII. It returns "buf", if the |
| 291 | // conversion was successful or NULL otherwise. It never writes more than "sz" |
| 292 | // bytes. Output will be truncated as needed, and a NUL character is always |
| 293 | // appended. |
| danakj | d53babfe | 2024-10-09 14:04:16 | [diff] [blame] | 294 | BASE_EXPORT void itoa_r(intptr_t i, |
| 295 | int base, |
| 296 | size_t padding, |
| 297 | base::span<char> buf); |
| Xiaohan Wang | 131aa4d | 2022-01-15 19:39:41 | [diff] [blame] | 298 | #endif // BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) |
| [email protected] | 1e218b7 | 2012-11-14 19:32:23 | [diff] [blame] | 299 | |
| 300 | } // namespace internal |
| 301 | |
| Jan Keitel | 4161bcb | 2024-08-01 12:44:24 | [diff] [blame] | 302 | } // namespace base::debug |
| [email protected] | 5858035 | 2010-10-26 04:07:50 | [diff] [blame] | 303 | |
| 304 | #endif // BASE_DEBUG_STACK_TRACE_H_ |