OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "base/debug/stack_trace.h" | 5 #include "base/debug/stack_trace.h" |
6 | 6 |
7 #include <string.h> | 7 #include <string.h> |
8 | 8 |
9 #include <algorithm> | 9 #include <algorithm> |
10 #include <limits> | |
11 #include <sstream> | 10 #include <sstream> |
12 | 11 |
13 #include "base/macros.h" | 12 #include "base/macros.h" |
14 | 13 |
15 #if HAVE_TRACE_STACK_FRAME_POINTERS | 14 #if HAVE_TRACE_STACK_FRAME_POINTERS |
16 | 15 |
17 #if defined(OS_LINUX) || defined(OS_ANDROID) | 16 #if defined(OS_LINUX) || defined(OS_ANDROID) |
18 #include <pthread.h> | 17 #include <pthread.h> |
19 #include "base/process/process_handle.h" | 18 #include "base/process/process_handle.h" |
20 #include "base/threading/platform_thread.h" | 19 #include "base/threading/platform_thread.h" |
21 #endif | 20 #endif |
22 | 21 |
23 #if defined(OS_LINUX) && defined(__GLIBC__) | 22 #if defined(OS_LINUX) && defined(__GLIBC__) |
24 extern "C" void* __libc_stack_end; | 23 extern "C" void* __libc_stack_end; |
25 #endif | 24 #endif |
26 | 25 |
27 #endif // HAVE_TRACE_STACK_FRAME_POINTERS | 26 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
28 | 27 |
29 namespace base { | 28 namespace base { |
30 namespace debug { | 29 namespace debug { |
31 | 30 |
32 StackTrace::StackTrace(const void* const* trace, size_t count) { | 31 namespace { |
33 count = std::min(count, arraysize(trace_)); | |
34 if (count) | |
35 memcpy(trace_, trace, count * sizeof(trace_[0])); | |
36 count_ = count; | |
37 } | |
38 | |
39 StackTrace::~StackTrace() { | |
40 } | |
41 | |
42 const void *const *StackTrace::Addresses(size_t* count) const { | |
43 *count = count_; | |
44 if (count_) | |
45 return trace_; | |
46 return NULL; | |
47 } | |
48 | |
49 std::string StackTrace::ToString() const { | |
50 std::stringstream stream; | |
51 #if !defined(__UCLIBC__) | |
52 OutputToStream(&stream); | |
53 #endif | |
54 return stream.str(); | |
55 } | |
56 | 32 |
57 #if HAVE_TRACE_STACK_FRAME_POINTERS | 33 #if HAVE_TRACE_STACK_FRAME_POINTERS |
58 | 34 |
59 static uintptr_t GetStackEnd() { | 35 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) |
| 36 // GCC and LLVM generate slightly different frames on ARM, see |
| 37 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates |
| 38 // x86-compatible frame, while GCC needs adjustment. |
| 39 constexpr size_t kStackFrameAdjustment = sizeof(uintptr_t); |
| 40 #else |
| 41 constexpr size_t kStackFrameAdjustment = 0; |
| 42 #endif |
| 43 |
| 44 // Returns end of the stack, or 0 if we couldn't get it. |
| 45 uintptr_t GetStackEnd() { |
60 #if defined(OS_ANDROID) | 46 #if defined(OS_ANDROID) |
61 // Bionic reads proc/maps on every call to pthread_getattr_np() when called | 47 // Bionic reads proc/maps on every call to pthread_getattr_np() when called |
62 // from the main thread. So we need to cache end of stack in that case to get | 48 // from the main thread. So we need to cache end of stack in that case to get |
63 // acceptable performance. | 49 // acceptable performance. |
64 // For all other threads pthread_getattr_np() is fast enough as it just reads | 50 // For all other threads pthread_getattr_np() is fast enough as it just reads |
65 // values from its pthread_t argument. | 51 // values from its pthread_t argument. |
66 static uintptr_t main_stack_end = 0; | 52 static uintptr_t main_stack_end = 0; |
67 | 53 |
68 bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId(); | 54 bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId(); |
69 if (is_main_thread && main_stack_end) { | 55 if (is_main_thread && main_stack_end) { |
(...skipping 10 matching lines...) Expand all Loading... |
80 reinterpret_cast<void**>(&stack_begin), | 66 reinterpret_cast<void**>(&stack_begin), |
81 &stack_size); | 67 &stack_size); |
82 pthread_attr_destroy(&attributes); | 68 pthread_attr_destroy(&attributes); |
83 } | 69 } |
84 DCHECK(!error); | 70 DCHECK(!error); |
85 | 71 |
86 uintptr_t stack_end = stack_begin + stack_size; | 72 uintptr_t stack_end = stack_begin + stack_size; |
87 if (is_main_thread) { | 73 if (is_main_thread) { |
88 main_stack_end = stack_end; | 74 main_stack_end = stack_end; |
89 } | 75 } |
90 return stack_end; | 76 return stack_end; // 0 in case of error |
91 | 77 |
92 #elif defined(OS_LINUX) && defined(__GLIBC__) | 78 #elif defined(OS_LINUX) && defined(__GLIBC__) |
93 | 79 |
94 if (GetCurrentProcId() == PlatformThread::CurrentId()) { | 80 if (GetCurrentProcId() == PlatformThread::CurrentId()) { |
95 // For the main thread we have a shortcut. | 81 // For the main thread we have a shortcut. |
96 return reinterpret_cast<uintptr_t>(__libc_stack_end); | 82 return reinterpret_cast<uintptr_t>(__libc_stack_end); |
97 } | 83 } |
98 | 84 |
99 // No easy way to get stack end for non-main threads, see crbug.com/617730. | 85 // No easy way to get end of the stack for non-main threads, |
100 | 86 // see crbug.com/617730. |
101 #else | |
102 | |
103 // TODO(dskiba): support Windows, macOS | |
104 | 87 |
105 #endif | 88 #endif |
106 | 89 |
107 // Couldn't get end of stack address. | 90 // Don't know how to get end of the stack. |
108 return std::numeric_limits<uintptr_t>::max(); | 91 return 0; |
109 } | 92 } |
110 | 93 |
| 94 uintptr_t GetNextStackFrame(uintptr_t fp) { |
| 95 return reinterpret_cast<const uintptr_t*>(fp)[0] - kStackFrameAdjustment; |
| 96 } |
| 97 |
| 98 uintptr_t GetStackFramePC(uintptr_t fp) { |
| 99 return reinterpret_cast<const uintptr_t*>(fp)[1]; |
| 100 } |
| 101 |
| 102 bool IsStackFrameValid(uintptr_t fp, uintptr_t prev_fp, uintptr_t stack_end) { |
| 103 // With the stack growing downwards, older stack frame must be |
| 104 // at a greater address that the current one. |
| 105 if (fp <= prev_fp) return false; |
| 106 |
| 107 // Assume huge stack frames are bogus. |
| 108 if (fp - prev_fp > 100000) return false; |
| 109 |
| 110 // Check alignment. |
| 111 if (fp & (sizeof(uintptr_t) - 1)) return false; |
| 112 |
| 113 if (stack_end) { |
| 114 // Both fp[0] and fp[1] must be within the stack. |
| 115 if (fp > stack_end - 2 * sizeof(uintptr_t)) return false; |
| 116 |
| 117 // Additional check to filter out false positives. |
| 118 if (GetStackFramePC(fp) < 32768) return false; |
| 119 } |
| 120 |
| 121 return true; |
| 122 }; |
| 123 |
| 124 // ScanStackForNextFrame() scans the stack for a valid frame to allow unwinding |
| 125 // past system libraries. Only supported on Linux where system libraries are |
| 126 // usually in the middle of the trace: |
| 127 // |
| 128 // TraceStackFramePointers |
| 129 // <more frames from Chrome> |
| 130 // base::WorkSourceDispatch <-- unwinding stops (next frame is invalid), |
| 131 // g_main_context_dispatch ScanStackForNextFrame() is called |
| 132 // <more frames from glib> |
| 133 // g_main_context_iteration |
| 134 // base::MessagePumpGlib::Run <-- ScanStackForNextFrame() finds valid frame, |
| 135 // base::RunLoop::Run unwinding resumes |
| 136 // <more frames from Chrome> |
| 137 // __libc_start_main |
| 138 // |
| 139 // For stack scanning to be efficient it's very important for the thread to |
| 140 // be started by Chrome. In that case we naturally terminate unwinding once |
| 141 // we reach the origin of the stack (i.e. GetStackEnd()). If the thread is |
| 142 // not started by Chrome (e.g. Android's main thread), then we end up always |
| 143 // scanning area at the origin of the stack, wasting time and not finding any |
| 144 // frames (since Android libraries don't have frame pointers). |
| 145 // |
| 146 // ScanStackForNextFrame() returns 0 if it couldn't find a valid frame |
| 147 // (or if stack scanning is not supported on the current platform). |
| 148 uintptr_t ScanStackForNextFrame(uintptr_t fp, uintptr_t stack_end) { |
| 149 #if defined(OS_LINUX) |
| 150 // Enough to resume almost all prematurely terminated traces. |
| 151 constexpr size_t kMaxStackScanArea = 8192; |
| 152 |
| 153 if (!stack_end) { |
| 154 // Too dangerous to scan without knowing where the stack ends. |
| 155 return 0; |
| 156 } |
| 157 |
| 158 fp += sizeof(uintptr_t); // current frame is known to be invalid |
| 159 uintptr_t last_fp_to_scan = std::min(fp + kMaxStackScanArea, stack_end) - |
| 160 sizeof(uintptr_t); |
| 161 for (;fp <= last_fp_to_scan; fp += sizeof(uintptr_t)) { |
| 162 uintptr_t next_fp = GetNextStackFrame(fp); |
| 163 if (IsStackFrameValid(next_fp, fp, stack_end)) { |
| 164 // Check two frames deep. Since stack frame is just a pointer to |
| 165 // a higher address on the stack, it's relatively easy to find |
| 166 // something that looks like one. However two linked frames are |
| 167 // far less likely to be bogus. |
| 168 uintptr_t next2_fp = GetNextStackFrame(next_fp); |
| 169 if (IsStackFrameValid(next2_fp, next_fp, stack_end)) { |
| 170 return fp; |
| 171 } |
| 172 } |
| 173 } |
| 174 #endif // defined(OS_LINUX) |
| 175 |
| 176 return 0; |
| 177 } |
| 178 |
| 179 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
| 180 |
| 181 } // namespace |
| 182 |
| 183 StackTrace::StackTrace(const void* const* trace, size_t count) { |
| 184 count = std::min(count, arraysize(trace_)); |
| 185 if (count) |
| 186 memcpy(trace_, trace, count * sizeof(trace_[0])); |
| 187 count_ = count; |
| 188 } |
| 189 |
| 190 StackTrace::~StackTrace() { |
| 191 } |
| 192 |
| 193 const void *const *StackTrace::Addresses(size_t* count) const { |
| 194 *count = count_; |
| 195 if (count_) |
| 196 return trace_; |
| 197 return NULL; |
| 198 } |
| 199 |
| 200 std::string StackTrace::ToString() const { |
| 201 std::stringstream stream; |
| 202 #if !defined(__UCLIBC__) |
| 203 OutputToStream(&stream); |
| 204 #endif |
| 205 return stream.str(); |
| 206 } |
| 207 |
| 208 #if HAVE_TRACE_STACK_FRAME_POINTERS |
| 209 |
111 size_t TraceStackFramePointers(const void** out_trace, | 210 size_t TraceStackFramePointers(const void** out_trace, |
112 size_t max_depth, | 211 size_t max_depth, |
113 size_t skip_initial) { | 212 size_t skip_initial) { |
114 // Usage of __builtin_frame_address() enables frame pointers in this | 213 // Usage of __builtin_frame_address() enables frame pointers in this |
115 // function even if they are not enabled globally. So 'sp' will always | 214 // function even if they are not enabled globally. So 'fp' will always |
116 // be valid. | 215 // be valid. |
117 uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); | 216 uintptr_t fp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)) - |
| 217 kStackFrameAdjustment; |
118 | 218 |
119 uintptr_t stack_end = GetStackEnd(); | 219 uintptr_t stack_end = GetStackEnd(); |
120 | 220 |
121 size_t depth = 0; | 221 size_t depth = 0; |
122 while (depth < max_depth) { | 222 while (depth < max_depth) { |
123 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) | |
124 // GCC and LLVM generate slightly different frames on ARM, see | |
125 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates | |
126 // x86-compatible frame, while GCC needs adjustment. | |
127 sp -= sizeof(uintptr_t); | |
128 #endif | |
129 | |
130 // Both sp[0] and s[1] must be valid. | |
131 if (sp + 2 * sizeof(uintptr_t) > stack_end) { | |
132 break; | |
133 } | |
134 | |
135 if (skip_initial != 0) { | 223 if (skip_initial != 0) { |
136 skip_initial--; | 224 skip_initial--; |
137 } else { | 225 } else { |
138 out_trace[depth++] = reinterpret_cast<const void**>(sp)[1]; | 226 out_trace[depth++] = reinterpret_cast<const void*>(GetStackFramePC(fp)); |
139 } | 227 } |
140 | 228 |
141 // Find out next frame pointer | 229 uintptr_t next_fp = GetNextStackFrame(fp); |
142 // (heuristics are from TCMalloc's stacktrace functions) | 230 if (IsStackFrameValid(next_fp, fp, stack_end)) { |
143 { | 231 fp = next_fp; |
144 uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0]; | 232 continue; |
| 233 } |
145 | 234 |
146 // With the stack growing downwards, older stack frame must be | 235 next_fp = ScanStackForNextFrame(fp, stack_end); |
147 // at a greater address that the current one. | 236 if (next_fp) { |
148 if (next_sp <= sp) break; | 237 fp = next_fp; |
| 238 continue; |
| 239 } |
149 | 240 |
150 // Assume stack frames larger than 100,000 bytes are bogus. | 241 // Failed to find next frame. |
151 if (next_sp - sp > 100000) break; | 242 break; |
152 | |
153 // Check alignment. | |
154 if (sp & (sizeof(void*) - 1)) break; | |
155 | |
156 sp = next_sp; | |
157 } | |
158 } | 243 } |
159 | 244 |
160 return depth; | 245 return depth; |
161 } | 246 } |
162 | 247 |
163 #endif // HAVE_TRACE_STACK_FRAME_POINTERS | 248 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
164 | 249 |
165 } // namespace debug | 250 } // namespace debug |
166 } // namespace base | 251 } // namespace base |
OLD | NEW |