1 // Copyright 2019 The Chromium Authors. All rights reserved.
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       int platform_stack_alignment,
91       uintptr_t* stack_buffer_bottom);
92 };
93 
94 }  // namespace base
95 
96 #endif  // BASE_PROFILER_STACK_COPIER_H_
97