Index: base/debug/stack_trace.cc |
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc |
index 1c96a569d9795544231714f0d0b1f9b0da036355..70a960470569026e02d4b0e1ebd660a497a3876d 100644 |
--- a/base/debug/stack_trace.cc |
+++ b/base/debug/stack_trace.cc |
@@ -10,6 +10,7 @@ |
#include <sstream> |
#include "base/macros.h" |
+#include "base/third_party/symbolize/symbolize.h" |
namespace base { |
namespace debug { |
@@ -41,9 +42,61 @@ std::string StackTrace::ToString() const { |
#if HAVE_TRACE_STACK_FRAME_POINTERS |
+#if defined(OS_ANDROID) && !defined(COMPONENT_BUILD) |
+ |
+#define HAVE_CHROME_CODE_RANGE |
+ |
+bool FindChromeCodeRange(const void** out_start_address, |
+ const void** out_end_address) { |
+ struct FindArgs { |
+ const void** out_start_address; |
+ const void** out_end_address; |
+ }; |
+ |
+ auto find_callback = [](void* data, |
+ const google::MappedRegion& region) -> bool { |
+ const void* region_start_address = reinterpret_cast<const void*>( |
+ static_cast<uintptr_t>(region.start_address)); |
+ const void* region_end_address = reinterpret_cast<const void*>( |
+ static_cast<uintptr_t>(region.end_address)); |
+ |
+ const void* self_address = reinterpret_cast<const void*>( |
+ &FindChromeCodeRange); |
+ if (self_address >= region_start_address && |
+ self_address < region_end_address) { |
+ FindArgs* args = static_cast<FindArgs*>(data); |
+ *args->out_start_address = region_start_address; |
+ *args->out_end_address = region_end_address; |
+ return true; |
+ } |
+ |
+ return false; |
+ }; |
+ |
+ FindArgs args = { |
+ out_start_address, |
+ out_end_address |
+ }; |
+ return google::FindMappedRegion(&args, find_callback); |
+} |
+ |
+#endif // !defined(COMPONENT_BUILD) |
+ |
size_t TraceStackFramePointers(const void** out_trace, |
size_t max_depth, |
size_t skip_initial) { |
+#if defined(HAVE_CHROME_CODE_RANGE) |
+ static const void* chrome_code_start = 0; |
+ static const void* chrome_code_end = 0; |
+ if (!chrome_code_start || !chrome_code_end) { |
+ if (!FindChromeCodeRange(&chrome_code_start, &chrome_code_end)) { |
+ // Something went wrong; disable unwinding. |
+ chrome_code_start = reinterpret_cast<const void*>(UINTPTR_MAX); |
+ chrome_code_end = reinterpret_cast<const void*>(UINTPTR_MAX); |
+ } |
+ } |
+#endif |
+ |
// Usage of __builtin_frame_address() enables frame pointers in this |
// function even if they are not enabled globally. So 'sp' will always |
// be valid. |
@@ -61,7 +114,42 @@ size_t TraceStackFramePointers(const void** out_trace, |
if (skip_initial != 0) { |
skip_initial--; |
} else { |
- out_trace[depth++] = reinterpret_cast<const void**>(sp)[1]; |
+#if defined(HAVE_CHROME_CODE_RANGE) && \ |
+ defined(__clang__) && defined(__thumb__) |
+ |
+ // In thumb fp is r7 and lr is r14, so there can be 1-7 registers |
+ // in between. |
+ const void* pc; |
+ for (size_t i = 1; i <= 7; ++i) { |
+ pc = reinterpret_cast<const void**>(sp)[i]; |
+ if (pc >= chrome_code_start && pc < chrome_code_end) { |
+ // Looks like code, use it. |
+ break; |
+ } |
+ pc = nullptr; |
+ } |
+ if (!pc) { |
+ // Didn't find anything, stop unwinding. |
+ break; |
+ } |
+ out_trace[depth++] = pc; |
+ |
+#else |
+ |
+ // In arm mode we have proper stack frames, so lr always follows fp. |
+ const void* pc = reinterpret_cast<const void**>(sp)[1]; |
+ out_trace[depth++] = pc; |
+#if defined(HAVE_CHROME_CODE_RANGE) |
+ if (pc < chrome_code_start || pc >= chrome_code_end) { |
+ // Stop unwinding after first non-Chrome PC - it's either bogus, |
+ // or from a system library. But since system libraries on Android |
+ // and Linux are built without frame pointers, there is no point |
+ // diving into them. |
+ break; |
+ } |
+#endif |
+ |
+#endif // HAVE_CHROME_CODE_RANGE && __clang__ && __thumb__ |
} |
// Find out next frame pointer |