Index: base/debug/stack_trace.cc |
diff --git a/base/debug/stack_trace.cc b/base/debug/stack_trace.cc |
index 2250c8fb14cc43b76c9a1236f59722b8317a74a2..cedc7be29951e7f75088ab27abb97071ed89d4fe 100644 |
--- a/base/debug/stack_trace.cc |
+++ b/base/debug/stack_trace.cc |
@@ -39,5 +39,54 @@ std::string StackTrace::ToString() const { |
return stream.str(); |
} |
+#if HAVE_TRACE_STACK_FRAME_POINTERS |
+ |
+size_t TraceStackFramePointers(const void** out_trace, |
+ size_t max_depth, |
+ size_t skip_initial) { |
+ // 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)); |
+ |
+ size_t depth = 0; |
+ while (depth < max_depth) { |
+ if (skip_initial != 0) { |
+ skip_initial--; |
+ } else { |
+ out_trace[depth++] = reinterpret_cast<const void**>(sp)[1]; |
+ } |
+ |
+#if defined(__arm__) && defined(__GNUC__) && !defined(__clang__) |
+ // GCC and LLVM generate slightly different frames on ARM, see |
+ // https://llvm.org/bugs/show_bug.cgi?id=18505 - LLVM generates |
+ // x86-compatible frame, while GCC needs adjustment. |
+ sp -= sizeof(uintptr_t); |
+#endif |
+ |
+ // Find out next frame pointer |
+ // (heuristics are from TCMalloc's stacktrace functions) |
+ { |
+ uintptr_t next_sp = reinterpret_cast<const uintptr_t*>(sp)[0]; |
+ |
+ // With the stack growing downwards, older stack frame must be |
+ // at a greater address that the current one. |
+ if (next_sp <= sp) break; |
+ |
+ // Assume stack frames larger than 100,000 bytes are bogus. |
+ if (next_sp - sp > 100000) break; |
+ |
+ // Check alignment. |
+ if (sp & (sizeof(void*) - 1)) break; |
+ |
+ sp = next_sp; |
+ } |
+ } |
+ |
+ return depth; |
+} |
+ |
+#endif // HAVE_TRACE_STACK_FRAME_POINTERS |
+ |
} // namespace debug |
} // namespace base |