| 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 { | 
|  |