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