Chromium Code Reviews| 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/macros.h" | 12 #include "base/macros.h" |
| 13 | 13 |
| 14 // TODO(dskiba): use blink::StackFrameDepth::getStackStart() instead | |
| 15 #if HAVE_TRACE_STACK_FRAME_POINTERS && \ | |
| 16 (defined(OS_ANDROID) || defined(OS_LINUX)) | |
| 17 #define HAVE_STACK_START | |
| 18 #include <pthread.h> | |
| 19 #if defined(__GLIBC__) | |
| 20 #include "base/process/process_handle.h" | |
| 21 #include "base/threading/platform_thread.h" | |
| 22 extern "C" void* __libc_stack_end; // NOLINT | |
| 23 #endif | |
| 24 #endif | |
| 25 | |
| 14 namespace base { | 26 namespace base { |
| 15 namespace debug { | 27 namespace debug { |
| 16 | 28 |
| 17 StackTrace::StackTrace(const void* const* trace, size_t count) { | 29 StackTrace::StackTrace(const void* const* trace, size_t count) { |
| 18 count = std::min(count, arraysize(trace_)); | 30 count = std::min(count, arraysize(trace_)); |
| 19 if (count) | 31 if (count) |
| 20 memcpy(trace_, trace, count * sizeof(trace_[0])); | 32 memcpy(trace_, trace, count * sizeof(trace_[0])); |
| 21 count_ = count; | 33 count_ = count; |
| 22 } | 34 } |
| 23 | 35 |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 34 std::string StackTrace::ToString() const { | 46 std::string StackTrace::ToString() const { |
| 35 std::stringstream stream; | 47 std::stringstream stream; |
| 36 #if !defined(__UCLIBC__) | 48 #if !defined(__UCLIBC__) |
| 37 OutputToStream(&stream); | 49 OutputToStream(&stream); |
| 38 #endif | 50 #endif |
| 39 return stream.str(); | 51 return stream.str(); |
| 40 } | 52 } |
| 41 | 53 |
| 42 #if HAVE_TRACE_STACK_FRAME_POINTERS | 54 #if HAVE_TRACE_STACK_FRAME_POINTERS |
| 43 | 55 |
| 56 #if defined(HAVE_STACK_START) | |
| 57 | |
| 58 static uintptr_t GetStackStart() { | |
| 59 #if defined(__GLIBC__) | |
| 60 if (GetCurrentProcId() == PlatformThread::CurrentId()) { | |
| 61 // Calling pthread_getattr_np() on the main thread sometimes fails, | |
| 62 // and also causes reentrancy deadlock in the renderer. | |
| 63 return reinterpret_cast<uintptr_t>(__libc_stack_end); | |
| 64 } | |
| 65 #endif | |
| 66 | |
| 67 uintptr_t stack_base = 0; | |
| 68 size_t stack_size = 0; | |
| 69 pthread_attr_t attributes; | |
| 70 int error = pthread_getattr_np(pthread_self(), &attributes); | |
| 71 if (!error) { | |
| 72 error = pthread_attr_getstack( | |
| 73 &attributes, | |
| 74 reinterpret_cast<void**>(&stack_base), | |
| 75 &stack_size); | |
| 76 pthread_attr_destroy(&attributes); | |
| 77 } | |
| 78 CHECK(!error); | |
|
mmenke
2016/05/27 17:39:43
include base/logging.h
| |
| 79 | |
| 80 return stack_base + stack_size; | |
| 81 } | |
| 82 | |
| 83 #endif // HAVE_STACK_START | |
| 84 | |
| 85 PerThreadStackInfo::PerThreadStackInfo(): start_address(0) {} | |
| 86 | |
| 44 size_t TraceStackFramePointers(const void** out_trace, | 87 size_t TraceStackFramePointers(const void** out_trace, |
| 45 size_t max_depth, | 88 size_t max_depth, |
| 46 size_t skip_initial) { | 89 size_t skip_initial, |
| 90 PerThreadStackInfo* stack_info) { | |
| 47 // Usage of __builtin_frame_address() enables frame pointers in this | 91 // Usage of __builtin_frame_address() enables frame pointers in this |
| 48 // function even if they are not enabled globally. So 'sp' will always | 92 // function even if they are not enabled globally. So 'sp' will always |
| 49 // be valid. | 93 // be valid. |
| 50 uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); | 94 uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); |
| 51 | 95 |
| 96 #if defined(HAVE_STACK_START) | |
| 97 if (stack_info && !stack_info->start_address) { | |
| 98 stack_info->start_address = GetStackStart(); | |
| 99 } | |
| 100 #endif | |
| 101 | |
| 52 size_t depth = 0; | 102 size_t depth = 0; |
| 53 while (depth < max_depth) { | 103 while (depth < max_depth) { |
| 54 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) | 104 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) |
| 55 // GCC and LLVM generate slightly different frames on ARM, see | 105 // GCC and LLVM generate slightly different frames on ARM, see |
| 56 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates | 106 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates |
| 57 // x86-compatible frame, while GCC needs adjustment. | 107 // x86-compatible frame, while GCC needs adjustment. |
| 58 sp -= sizeof(uintptr_t); | 108 sp -= sizeof(uintptr_t); |
| 59 #endif | 109 #endif |
| 60 | 110 |
| 111 #if defined(HAVE_STACK_START) | |
| 112 // Both sp[0] and s[1] must be valid. Note that since the stack | |
| 113 // is growing downwards, 'start_address' is the highest valid address. | |
| 114 if (stack_info && | |
| 115 sp + 2 * sizeof(uintptr_t) > stack_info->start_address) { | |
| 116 break; | |
| 117 } | |
| 118 #endif | |
| 119 | |
| 61 if (skip_initial != 0) { | 120 if (skip_initial != 0) { |
| 62 skip_initial--; | 121 skip_initial--; |
| 63 } else { | 122 } else { |
| 64 out_trace[depth++] = reinterpret_cast<const void**>(sp)[1]; | 123 out_trace[depth++] = reinterpret_cast<const void**>(sp)[1]; |
| 65 } | 124 } |
| 66 | 125 |
| 67 // Find out next frame pointer | 126 // Find out next frame pointer |
| 68 // (heuristics are from TCMalloc's stacktrace functions) | 127 // (heuristics are from TCMalloc's stacktrace functions) |
| 69 { | 128 { |
| 70 uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0]; | 129 uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0]; |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 83 } | 142 } |
| 84 } | 143 } |
| 85 | 144 |
| 86 return depth; | 145 return depth; |
| 87 } | 146 } |
| 88 | 147 |
| 89 #endif // HAVE_TRACE_STACK_FRAME_POINTERS | 148 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
| 90 | 149 |
| 91 } // namespace debug | 150 } // namespace debug |
| 92 } // namespace base | 151 } // namespace base |
| OLD | NEW |