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 { |