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 #include "base/third_party/symbolize/symbolize.h" |
13 | 14 |
14 namespace base { | 15 namespace base { |
15 namespace debug { | 16 namespace debug { |
16 | 17 |
17 StackTrace::StackTrace(const void* const* trace, size_t count) { | 18 StackTrace::StackTrace(const void* const* trace, size_t count) { |
18 count = std::min(count, arraysize(trace_)); | 19 count = std::min(count, arraysize(trace_)); |
19 if (count) | 20 if (count) |
20 memcpy(trace_, trace, count * sizeof(trace_[0])); | 21 memcpy(trace_, trace, count * sizeof(trace_[0])); |
21 count_ = count; | 22 count_ = count; |
22 } | 23 } |
(...skipping 11 matching lines...) Expand all Loading... |
34 std::string StackTrace::ToString() const { | 35 std::string StackTrace::ToString() const { |
35 std::stringstream stream; | 36 std::stringstream stream; |
36 #if !defined(__UCLIBC__) | 37 #if !defined(__UCLIBC__) |
37 OutputToStream(&stream); | 38 OutputToStream(&stream); |
38 #endif | 39 #endif |
39 return stream.str(); | 40 return stream.str(); |
40 } | 41 } |
41 | 42 |
42 #if HAVE_TRACE_STACK_FRAME_POINTERS | 43 #if HAVE_TRACE_STACK_FRAME_POINTERS |
43 | 44 |
| 45 #if defined(OS_ANDROID) && !defined(COMPONENT_BUILD) |
| 46 |
| 47 #define HAVE_CHROME_CODE_RANGE |
| 48 |
| 49 bool FindChromeCodeRange(const void** out_start_address, |
| 50 const void** out_end_address) { |
| 51 struct FindArgs { |
| 52 const void** out_start_address; |
| 53 const void** out_end_address; |
| 54 }; |
| 55 |
| 56 auto find_callback = [](void* data, |
| 57 const google::MappedRegion& region) -> bool { |
| 58 const void* region_start_address = reinterpret_cast<const void*>( |
| 59 static_cast<uintptr_t>(region.start_address)); |
| 60 const void* region_end_address = reinterpret_cast<const void*>( |
| 61 static_cast<uintptr_t>(region.end_address)); |
| 62 |
| 63 const void* self_address = reinterpret_cast<const void*>( |
| 64 &FindChromeCodeRange); |
| 65 if (self_address >= region_start_address && |
| 66 self_address < region_end_address) { |
| 67 FindArgs* args = static_cast<FindArgs*>(data); |
| 68 *args->out_start_address = region_start_address; |
| 69 *args->out_end_address = region_end_address; |
| 70 return true; |
| 71 } |
| 72 |
| 73 return false; |
| 74 }; |
| 75 |
| 76 FindArgs args = { |
| 77 out_start_address, |
| 78 out_end_address |
| 79 }; |
| 80 return google::FindMappedRegion(&args, find_callback); |
| 81 } |
| 82 |
| 83 #endif // !defined(COMPONENT_BUILD) |
| 84 |
44 size_t TraceStackFramePointers(const void** out_trace, | 85 size_t TraceStackFramePointers(const void** out_trace, |
45 size_t max_depth, | 86 size_t max_depth, |
46 size_t skip_initial) { | 87 size_t skip_initial) { |
| 88 #if defined(HAVE_CHROME_CODE_RANGE) |
| 89 static const void* chrome_code_start = 0; |
| 90 static const void* chrome_code_end = 0; |
| 91 if (!chrome_code_start || !chrome_code_end) { |
| 92 if (!FindChromeCodeRange(&chrome_code_start, &chrome_code_end)) { |
| 93 // Something went wrong; disable unwinding. |
| 94 chrome_code_start = reinterpret_cast<const void*>(UINTPTR_MAX); |
| 95 chrome_code_end = reinterpret_cast<const void*>(UINTPTR_MAX); |
| 96 } |
| 97 } |
| 98 #endif |
| 99 |
47 // Usage of __builtin_frame_address() enables frame pointers in this | 100 // Usage of __builtin_frame_address() enables frame pointers in this |
48 // function even if they are not enabled globally. So 'sp' will always | 101 // function even if they are not enabled globally. So 'sp' will always |
49 // be valid. | 102 // be valid. |
50 uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); | 103 uintptr_t sp = reinterpret_cast<uintptr_t>(__builtin_frame_address(0)); |
51 | 104 |
52 size_t depth = 0; | 105 size_t depth = 0; |
53 while (depth < max_depth) { | 106 while (depth < max_depth) { |
54 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) | 107 #if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) |
55 // GCC and LLVM generate slightly different frames on ARM, see | 108 // GCC and LLVM generate slightly different frames on ARM, see |
56 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates | 109 // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates |
57 // x86-compatible frame, while GCC needs adjustment. | 110 // x86-compatible frame, while GCC needs adjustment. |
58 sp -= sizeof(uintptr_t); | 111 sp -= sizeof(uintptr_t); |
59 #endif | 112 #endif |
60 | 113 |
61 if (skip_initial != 0) { | 114 if (skip_initial != 0) { |
62 skip_initial--; | 115 skip_initial--; |
63 } else { | 116 } else { |
64 out_trace[depth++] = reinterpret_cast<const void**>(sp)[1]; | 117 #if defined(HAVE_CHROME_CODE_RANGE) && \ |
| 118 defined(__clang__) && defined(__thumb__) |
| 119 |
| 120 // In thumb fp is r7 and lr is r14, so there can be 1-7 registers |
| 121 // in between. |
| 122 const void* pc; |
| 123 for (size_t i = 1; i <= 7; ++i) { |
| 124 pc = reinterpret_cast<const void**>(sp)[i]; |
| 125 if (pc >= chrome_code_start && pc < chrome_code_end) { |
| 126 // Looks like code, use it. |
| 127 break; |
| 128 } |
| 129 pc = nullptr; |
| 130 } |
| 131 if (!pc) { |
| 132 // Didn't find anything, stop unwinding. |
| 133 break; |
| 134 } |
| 135 out_trace[depth++] = pc; |
| 136 |
| 137 #else |
| 138 |
| 139 // In arm mode we have proper stack frames, so lr always follows fp. |
| 140 const void* pc = reinterpret_cast<const void**>(sp)[1]; |
| 141 out_trace[depth++] = pc; |
| 142 #if defined(HAVE_CHROME_CODE_RANGE) |
| 143 if (pc < chrome_code_start || pc >= chrome_code_end) { |
| 144 // Stop unwinding after first non-Chrome PC - it's either bogus, |
| 145 // or from a system library. But since system libraries on Android |
| 146 // and Linux are built without frame pointers, there is no point |
| 147 // diving into them. |
| 148 break; |
| 149 } |
| 150 #endif |
| 151 |
| 152 #endif // HAVE_CHROME_CODE_RANGE && __clang__ && __thumb__ |
65 } | 153 } |
66 | 154 |
67 // Find out next frame pointer | 155 // Find out next frame pointer |
68 // (heuristics are from TCMalloc's stacktrace functions) | 156 // (heuristics are from TCMalloc's stacktrace functions) |
69 { | 157 { |
70 uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0]; | 158 uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0]; |
71 | 159 |
72 // With the stack growing downwards, older stack frame must be | 160 // With the stack growing downwards, older stack frame must be |
73 // at a greater address that the current one. | 161 // at a greater address that the current one. |
74 if (next_sp <= sp) break; | 162 if (next_sp <= sp) break; |
75 | 163 |
76 // Assume stack frames larger than 100,000 bytes are bogus. | 164 // Assume stack frames larger than 100,000 bytes are bogus. |
77 if (next_sp - sp > 100000) break; | 165 if (next_sp - sp > 100000) break; |
78 | 166 |
79 // Check alignment. | 167 // Check alignment. |
80 if (sp & (sizeof(void*) - 1)) break; | 168 if (sp & (sizeof(void*) - 1)) break; |
81 | 169 |
82 sp = next_sp; | 170 sp = next_sp; |
83 } | 171 } |
84 } | 172 } |
85 | 173 |
86 return depth; | 174 return depth; |
87 } | 175 } |
88 | 176 |
89 #endif // HAVE_TRACE_STACK_FRAME_POINTERS | 177 #endif // HAVE_TRACE_STACK_FRAME_POINTERS |
90 | 178 |
91 } // namespace debug | 179 } // namespace debug |
92 } // namespace base | 180 } // namespace base |
OLD | NEW |