1 // Copyright 2019 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_PROFILER_STACK_COPIER_H_ 6 #define BASE_PROFILER_STACK_COPIER_H_ 7 8 #include <stdint.h> 9 10 #include "base/base_export.h" 11 #include "base/profiler/register_context.h" 12 #include "base/time/time.h" 13 14 namespace base { 15 16 class StackBuffer; 17 18 // StackCopier causes a thread to be suspended, copies its stack, and resumes 19 // the thread's execution. It's intended to provide an abstraction over stack 20 // copying techniques where the thread suspension is performed directly by the 21 // profiler thread (Windows and Mac platforms) vs. where the thread suspension 22 // is performed by the OS through signals (Android). 23 class BASE_EXPORT StackCopier { 24 public: 25 // Interface that may be implemented by the caller of CopyStack() to receive a 26 // callback when the stack is copied, while the target thread is suspended. 27 class BASE_EXPORT Delegate { 28 public: ~Delegate()29 virtual ~Delegate() {} 30 31 // Invoked at the time the stack is copied. 32 // IMPORTANT NOTE: to avoid deadlock implementations of this interface must 33 // not invoke any non-reentrant code that is also invoked by the target 34 // thread. In particular, it may not perform any heap allocation or 35 // deallocation, including indirectly via use of DCHECK/CHECK or other 36 // logging statements. 37 virtual void OnStackCopy() = 0; 38 }; 39 40 virtual ~StackCopier(); 41 42 // Copies the thread's register context into |thread_context|, the stack into 43 // |stack_buffer|, and the top of stack address into |stack_top|. Records 44 // |timestamp| at the time the stack was copied. delegate->OnStackCopy() will 45 // be invoked while the thread is suspended. Returns true if successful. 46 virtual bool CopyStack(StackBuffer* stack_buffer, 47 uintptr_t* stack_top, 48 TimeTicks* timestamp, 49 RegisterContext* thread_context, 50 Delegate* delegate) = 0; 51 52 protected: 53 // If the value at |pointer| points to the original stack, rewrite it to point 54 // to the corresponding location in the copied stack. 55 // 56 // NO HEAP ALLOCATIONS. 57 static uintptr_t RewritePointerIfInOriginalStack( 58 const uint8_t* original_stack_bottom, 59 const uintptr_t* original_stack_top, 60 const uint8_t* stack_copy_bottom, 61 uintptr_t pointer); 62 63 // Copies the stack to a buffer while rewriting possible pointers to locations 64 // within the stack to point to the corresponding locations in the copy. This 65 // is necessary to handle stack frames with dynamic stack allocation, where a 66 // pointer to the beginning of the dynamic allocation area is stored on the 67 // stack and/or in a non-volatile register. 68 // 69 // Eager rewriting of anything that looks like a pointer to the stack, as done 70 // in this function, does not adversely affect the stack unwinding. The only 71 // other values on the stack the unwinding depends on are return addresses, 72 // which should not point within the stack memory. The rewriting is guaranteed 73 // to catch all pointers because the stacks are guaranteed by the ABI to be 74 // sizeof(uintptr_t*) aligned. 75 // 76 // |original_stack_bottom| and |original_stack_top| are different pointer 77 // types due on their differing guaranteed alignments -- the bottom may only 78 // be 1-byte aligned while the top is aligned to double the pointer width. 79 // 80 // Returns a pointer to the bottom address in the copied stack. This value 81 // matches the alignment of |original_stack_bottom| to ensure that the stack 82 // contents have the same alignment as in the original stack. As a result the 83 // value will be different than |stack_buffer_bottom| if 84 // |original_stack_bottom| is not aligned to double the pointer width. 85 // 86 // NO HEAP ALLOCATIONS. 87 static const uint8_t* CopyStackContentsAndRewritePointers( 88 const uint8_t* original_stack_bottom, 89 const uintptr_t* original_stack_top, 90 size_t platform_stack_alignment, 91 uintptr_t* stack_buffer_bottom); 92 }; 93 94 } // namespace base 95 96 #endif // BASE_PROFILER_STACK_COPIER_H_ 97