| Index: base/debug/stack_trace.h
|
| diff --git a/base/debug/stack_trace.h b/base/debug/stack_trace.h
|
| index 23e7b5164b63472409a92e992c5c1095dfa48d26..d4918d60654b808719ebcfdda6be74d43174f75d 100644
|
| --- a/base/debug/stack_trace.h
|
| +++ b/base/debug/stack_trace.h
|
| @@ -11,6 +11,7 @@
|
| #include <string>
|
|
|
| #include "base/base_export.h"
|
| +#include "base/macros.h"
|
| #include "build/build_config.h"
|
|
|
| #if defined(OS_POSIX)
|
| @@ -113,6 +114,57 @@ class BASE_EXPORT StackTrace {
|
| BASE_EXPORT size_t TraceStackFramePointers(const void** out_trace,
|
| size_t max_depth,
|
| size_t skip_initial);
|
| +
|
| +// Links stack frame |fp| to |parent_fp|, so that during stack unwinding
|
| +// TraceStackFramePointers() visits |parent_fp| after visiting |fp|.
|
| +// Both frame pointers must come from __builtin_frame_address().
|
| +// Destructor restores original linkage of |fp| to avoid corrupting caller's
|
| +// frame register on return.
|
| +//
|
| +// This class can be used to repair broken stack frame chain in cases
|
| +// when execution flow goes into code built without frame pointers:
|
| +//
|
| +// void DoWork() {
|
| +// Call_SomeLibrary();
|
| +// }
|
| +// static __thread void* g_saved_fp;
|
| +// void Call_SomeLibrary() {
|
| +// g_saved_fp = __builtin_frame_address(0);
|
| +// some_library_call(...); // indirectly calls SomeLibrary_Callback()
|
| +// }
|
| +// void SomeLibrary_Callback() {
|
| +// ScopedStackFrameLinker linker(__builtin_frame_address(0), g_saved_fp);
|
| +// ...
|
| +// TraceStackFramePointers(...);
|
| +// }
|
| +//
|
| +// This produces the following trace:
|
| +//
|
| +// #0 SomeLibrary_Callback()
|
| +// #1 <address of the code inside SomeLibrary that called #0>
|
| +// #2 DoWork()
|
| +// ...rest of the trace...
|
| +//
|
| +// SomeLibrary doesn't use frame pointers, so when SomeLibrary_Callback()
|
| +// is called, stack frame register contains bogus value that becomes callback'
|
| +// parent frame address. Without ScopedStackFrameLinker unwinding would've
|
| +// stopped at that bogus frame address yielding just two first frames (#0, #1).
|
| +// ScopedStackFrameLinker overwrites callback's parent frame address with
|
| +// Call_SomeLibrary's frame, so unwinder produces full trace without even
|
| +// noticing that stack frame chain was broken.
|
| +class BASE_EXPORT ScopedStackFrameLinker {
|
| + public:
|
| + ScopedStackFrameLinker(void* fp, void* parent_fp);
|
| + ~ScopedStackFrameLinker();
|
| +
|
| + private:
|
| + void* fp_;
|
| + void* parent_fp_;
|
| + void* original_parent_fp_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(ScopedStackFrameLinker);
|
| +};
|
| +
|
| #endif // HAVE_TRACE_STACK_FRAME_POINTERS
|
|
|
| namespace internal {
|
|
|