• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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