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 <sstream> | 10 #include <sstream> |
11 | 11 |
12 #include "base/logging.h" | 12 #include "base/logging.h" |
13 #include "base/macros.h" | 13 #include "base/macros.h" |
14 | 14 |
15 #if HAVE_TRACE_STACK_FRAME_POINTERS | 15 #if HAVE_TRACE_STACK_FRAME_POINTERS |
16 | 16 |
17 #if defined(OS_LINUX) || defined(OS_ANDROID) | 17 #if defined(OS_LINUX) || defined(OS_ANDROID) |
18 #include <pthread.h> | 18 #include <pthread.h> |
19 #include "base/process/process_handle.h" | 19 #include "base/process/process_handle.h" |
20 #include "base/threading/platform_thread.h" | 20 #include "base/threading/platform_thread.h" |
21 #endif | 21 #endif |
22 | 22 |
| 23 #if defined(OS_MACOSX) |
| 24 #include <pthread.h> |
| 25 #endif |
| 26 |
23 #if defined(OS_LINUX) && defined(__GLIBC__) | 27 #if defined(OS_LINUX) && defined(__GLIBC__) |
24 extern "C" void* __libc_stack_end; | 28 extern "C" void* __libc_stack_end; |
25 #endif | 29 #endif |
26 | 30 |
27 #endif // HAVE_TRACE_STACK_FRAME_POINTERS | 31 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
28 | 32 |
29 namespace base { | 33 namespace base { |
30 namespace debug { | 34 namespace debug { |
31 | 35 |
32 namespace { | 36 namespace { |
33 | 37 |
34 #if HAVE_TRACE_STACK_FRAME_POINTERS | 38 #if HAVE_TRACE_STACK_FRAME_POINTERS |
35 | 39 |
36 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) | 40 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) |
37 // GCC and LLVM generate slightly different frames on ARM, see | 41 // GCC and LLVM generate slightly different frames on ARM, see |
38 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates | 42 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates |
39 // x86-compatible frame, while GCC needs adjustment. | 43 // x86-compatible frame, while GCC needs adjustment. |
40 constexpr size_t kStackFrameAdjustment = sizeof(uintptr_t); | 44 constexpr size_t kStackFrameAdjustment = sizeof(uintptr_t); |
41 #else | 45 #else |
42 constexpr size_t kStackFrameAdjustment = 0; | 46 constexpr size_t kStackFrameAdjustment = 0; |
43 #endif | 47 #endif |
44 | 48 |
45 // Returns end of the stack, or 0 if we couldn't get it. | |
46 uintptr_t GetStackEnd() { | |
47 #if defined(OS_ANDROID) | |
48 // Bionic reads proc/maps on every call to pthread_getattr_np() when called | |
49 // from the main thread. So we need to cache end of stack in that case to get | |
50 // acceptable performance. | |
51 // For all other threads pthread_getattr_np() is fast enough as it just reads | |
52 // values from its pthread_t argument. | |
53 static uintptr_t main_stack_end = 0; | |
54 | |
55 bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId(); | |
56 if (is_main_thread && main_stack_end) { | |
57 return main_stack_end; | |
58 } | |
59 | |
60 uintptr_t stack_begin = 0; | |
61 size_t stack_size = 0; | |
62 pthread_attr_t attributes; | |
63 int error = pthread_getattr_np(pthread_self(), &attributes); | |
64 if (!error) { | |
65 error = pthread_attr_getstack( | |
66 &attributes, | |
67 reinterpret_cast<void**>(&stack_begin), | |
68 &stack_size); | |
69 pthread_attr_destroy(&attributes); | |
70 } | |
71 DCHECK(!error); | |
72 | |
73 uintptr_t stack_end = stack_begin + stack_size; | |
74 if (is_main_thread) { | |
75 main_stack_end = stack_end; | |
76 } | |
77 return stack_end; // 0 in case of error | |
78 | |
79 #elif defined(OS_LINUX) && defined(__GLIBC__) | |
80 | |
81 if (GetCurrentProcId() == PlatformThread::CurrentId()) { | |
82 // For the main thread we have a shortcut. | |
83 return reinterpret_cast<uintptr_t>(__libc_stack_end); | |
84 } | |
85 | |
86 // No easy way to get end of the stack for non-main threads, | |
87 // see crbug.com/617730. | |
88 | |
89 #endif | |
90 | |
91 // Don't know how to get end of the stack. | |
92 return 0; | |
93 } | |
94 | |
95 uintptr_t GetNextStackFrame(uintptr_t fp) { | 49 uintptr_t GetNextStackFrame(uintptr_t fp) { |
96 return reinterpret_cast<const uintptr_t*>(fp)[0] - kStackFrameAdjustment; | 50 return reinterpret_cast<const uintptr_t*>(fp)[0] - kStackFrameAdjustment; |
97 } | 51 } |
98 | 52 |
99 uintptr_t GetStackFramePC(uintptr_t fp) { | 53 uintptr_t GetStackFramePC(uintptr_t fp) { |
100 return reinterpret_cast<const uintptr_t*>(fp)[1]; | 54 return reinterpret_cast<const uintptr_t*>(fp)[1]; |
101 } | 55 } |
102 | 56 |
103 bool IsStackFrameValid(uintptr_t fp, uintptr_t prev_fp, uintptr_t stack_end) { | 57 bool IsStackFrameValid(uintptr_t fp, uintptr_t prev_fp, uintptr_t stack_end) { |
104 // With the stack growing downwards, older stack frame must be | 58 // With the stack growing downwards, older stack frame must be |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
185 uintptr_t fp = reinterpret_cast<uintptr_t>(fpp) - kStackFrameAdjustment; | 139 uintptr_t fp = reinterpret_cast<uintptr_t>(fpp) - kStackFrameAdjustment; |
186 void* prev_parent_fp = reinterpret_cast<void**>(fp)[0]; | 140 void* prev_parent_fp = reinterpret_cast<void**>(fp)[0]; |
187 reinterpret_cast<void**>(fp)[0] = parent_fp; | 141 reinterpret_cast<void**>(fp)[0] = parent_fp; |
188 return prev_parent_fp; | 142 return prev_parent_fp; |
189 } | 143 } |
190 | 144 |
191 #endif // HAVE_TRACE_STACK_FRAME_POINTERS | 145 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
192 | 146 |
193 } // namespace | 147 } // namespace |
194 | 148 |
| 149 #if HAVE_TRACE_STACK_FRAME_POINTERS |
| 150 uintptr_t GetStackEnd() { |
| 151 #if defined(OS_ANDROID) |
| 152 // Bionic reads proc/maps on every call to pthread_getattr_np() when called |
| 153 // from the main thread. So we need to cache end of stack in that case to get |
| 154 // acceptable performance. |
| 155 // For all other threads pthread_getattr_np() is fast enough as it just reads |
| 156 // values from its pthread_t argument. |
| 157 static uintptr_t main_stack_end = 0; |
| 158 |
| 159 bool is_main_thread = GetCurrentProcId() == PlatformThread::CurrentId(); |
| 160 if (is_main_thread && main_stack_end) { |
| 161 return main_stack_end; |
| 162 } |
| 163 |
| 164 uintptr_t stack_begin = 0; |
| 165 size_t stack_size = 0; |
| 166 pthread_attr_t attributes; |
| 167 int error = pthread_getattr_np(pthread_self(), &attributes); |
| 168 if (!error) { |
| 169 error = pthread_attr_getstack( |
| 170 &attributes, reinterpret_cast<void**>(&stack_begin), &stack_size); |
| 171 pthread_attr_destroy(&attributes); |
| 172 } |
| 173 DCHECK(!error); |
| 174 |
| 175 uintptr_t stack_end = stack_begin + stack_size; |
| 176 if (is_main_thread) { |
| 177 main_stack_end = stack_end; |
| 178 } |
| 179 return stack_end; // 0 in case of error |
| 180 |
| 181 #elif defined(OS_LINUX) && defined(__GLIBC__) |
| 182 |
| 183 if (GetCurrentProcId() == PlatformThread::CurrentId()) { |
| 184 // For the main thread we have a shortcut. |
| 185 return reinterpret_cast<uintptr_t>(__libc_stack_end); |
| 186 } |
| 187 |
| 188 // No easy way to get end of the stack for non-main threads, |
| 189 // see crbug.com/617730. |
| 190 #elif defined(OS_MACOSX) |
| 191 return reinterpret_cast<uintptr_t>(pthread_get_stackaddr_np(pthread_self())); |
| 192 #endif |
| 193 |
| 194 // Don't know how to get end of the stack. |
| 195 return 0; |
| 196 } |
| 197 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
| 198 |
195 StackTrace::StackTrace() : StackTrace(arraysize(trace_)) {} | 199 StackTrace::StackTrace() : StackTrace(arraysize(trace_)) {} |
196 | 200 |
197 StackTrace::StackTrace(const void* const* trace, size_t count) { | 201 StackTrace::StackTrace(const void* const* trace, size_t count) { |
198 count = std::min(count, arraysize(trace_)); | 202 count = std::min(count, arraysize(trace_)); |
199 if (count) | 203 if (count) |
200 memcpy(trace_, trace, count * sizeof(trace_[0])); | 204 memcpy(trace_, trace, count * sizeof(trace_[0])); |
201 count_ = count; | 205 count_ = count; |
202 } | 206 } |
203 | 207 |
204 const void *const *StackTrace::Addresses(size_t* count) const { | 208 const void *const *StackTrace::Addresses(size_t* count) const { |
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
264 ScopedStackFrameLinker::~ScopedStackFrameLinker() { | 268 ScopedStackFrameLinker::~ScopedStackFrameLinker() { |
265 void* previous_parent_fp = LinkStackFrames(fp_, original_parent_fp_); | 269 void* previous_parent_fp = LinkStackFrames(fp_, original_parent_fp_); |
266 CHECK_EQ(parent_fp_, previous_parent_fp) | 270 CHECK_EQ(parent_fp_, previous_parent_fp) |
267 << "Stack frame's parent pointer has changed!"; | 271 << "Stack frame's parent pointer has changed!"; |
268 } | 272 } |
269 | 273 |
270 #endif // HAVE_TRACE_STACK_FRAME_POINTERS | 274 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
271 | 275 |
272 } // namespace debug | 276 } // namespace debug |
273 } // namespace base | 277 } // namespace base |
OLD | NEW |