Chromium Code Reviews| Index: base/debug/stack_trace.cc |
| diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc |
| index 1c96a569d9795544231714f0d0b1f9b0da036355..9ad2e9fd45b2552e979df72659f8b361bf1c5fcf 100644 |
| --- a/base/debug/stack_trace.cc |
| +++ b/base/debug/stack_trace.cc |
| @@ -11,6 +11,18 @@ |
| #include "base/macros.h" |
| +// TODO(dskiba): use blink::StackFrameDepth::getStackStart() instead |
| +#if HAVE_TRACE_STACK_FRAME_POINTERS && \ |
| + (defined(OS_ANDROID) || defined(OS_LINUX)) |
| +#define HAVE_STACK_START |
| +#include <pthread.h> |
| +#if defined(__GLIBC__) |
| +#include "base/process/process_handle.h" |
| +#include "base/threading/platform_thread.h" |
| +extern "C" void* __libc_stack_end; // NOLINT |
| +#endif |
| +#endif |
| + |
| namespace base { |
| namespace debug { |
| @@ -41,14 +53,52 @@ std::string StackTrace::ToString() const { |
| #if HAVE_TRACE_STACK_FRAME_POINTERS |
| +#if defined(HAVE_STACK_START) |
| + |
| +static uintptr_t GetStackStart() { |
| +#if defined(__GLIBC__) |
| + if (GetCurrentProcId() == PlatformThread::CurrentId()) { |
| + // Calling pthread_getattr_np() on the main thread sometimes fails, |
| + // and also causes reentrancy deadlock in the renderer. |
| + return reinterpret_cast<uintptr_t>(__libc_stack_end); |
| + } |
| +#endif |
| + |
| + uintptr_t stack_base = 0; |
| + size_t stack_size = 0; |
| + pthread_attr_t attributes; |
| + int error = pthread_getattr_np(pthread_self(), &attributes); |
| + if (!error) { |
| + error = pthread_attr_getstack( |
| + &attributes, |
| + reinterpret_cast<void**>(&stack_base), |
| + &stack_size); |
| + pthread_attr_destroy(&attributes); |
| + } |
| + CHECK(!error); |
|
mmenke
2016/05/27 17:39:43
include base/logging.h
|
| + |
| + return stack_base + stack_size; |
| +} |
| + |
| +#endif // HAVE_STACK_START |
| + |
| +PerThreadStackInfo::PerThreadStackInfo(): start_address(0) {} |
| + |
| size_t TraceStackFramePointers(const void** out_trace, |
| size_t max_depth, |
| - size_t skip_initial) { |
| + size_t skip_initial, |
| + PerThreadStackInfo* stack_info) { |
| // Usage of __builtin_frame_address() enables frame pointers in this |
| // function even if they are not enabled globally. So 'sp' will always |
| // be valid. |
| uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); |
| +#if defined(HAVE_STACK_START) |
| + if (stack_info && !stack_info->start_address) { |
| + stack_info->start_address = GetStackStart(); |
| + } |
| +#endif |
| + |
| size_t depth = 0; |
| while (depth < max_depth) { |
| #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) |
| @@ -58,6 +108,15 @@ size_t TraceStackFramePointers(const void** out_trace, |
| sp -= sizeof(uintptr_t); |
| #endif |
| +#if defined(HAVE_STACK_START) |
| + // Both sp[0] and s[1] must be valid. Note that since the stack |
| + // is growing downwards, 'start_address' is the highest valid address. |
| + if (stack_info && |
| + sp + 2 * sizeof(uintptr_t) > stack_info->start_address) { |
| + break; |
| + } |
| +#endif |
| + |
| if (skip_initial != 0) { |
| skip_initial--; |
| } else { |