Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(243)

Side by Side Diff: base/debug/stack_trace.cc

Issue 2707973004: mac: Implement GetStackEnd(). (Closed)
Patch Set: Fix compile error. Created 3 years, 10 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « base/debug/stack_trace.h ('k') | base/debug/stack_trace_unittest.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
OLDNEW
« no previous file with comments | « base/debug/stack_trace.h ('k') | base/debug/stack_trace_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698