xref: /aosp_15_r20/external/cronet/base/profiler/unwinder.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1*6777b538SAndroid Build Coastguard Worker // Copyright 2019 The Chromium Authors
2*6777b538SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*6777b538SAndroid Build Coastguard Worker // found in the LICENSE file.
4*6777b538SAndroid Build Coastguard Worker 
5*6777b538SAndroid Build Coastguard Worker #ifndef BASE_PROFILER_UNWINDER_H_
6*6777b538SAndroid Build Coastguard Worker #define BASE_PROFILER_UNWINDER_H_
7*6777b538SAndroid Build Coastguard Worker 
8*6777b538SAndroid Build Coastguard Worker #include <vector>
9*6777b538SAndroid Build Coastguard Worker 
10*6777b538SAndroid Build Coastguard Worker #include "base/base_export.h"
11*6777b538SAndroid Build Coastguard Worker #include "base/memory/raw_ptr.h"
12*6777b538SAndroid Build Coastguard Worker #include "base/profiler/frame.h"
13*6777b538SAndroid Build Coastguard Worker #include "base/profiler/module_cache.h"
14*6777b538SAndroid Build Coastguard Worker #include "base/profiler/register_context.h"
15*6777b538SAndroid Build Coastguard Worker 
16*6777b538SAndroid Build Coastguard Worker namespace base {
17*6777b538SAndroid Build Coastguard Worker 
18*6777b538SAndroid Build Coastguard Worker // The result of attempting to unwind stack frames.
19*6777b538SAndroid Build Coastguard Worker enum class UnwindResult {
20*6777b538SAndroid Build Coastguard Worker   // The end of the stack was reached successfully.
21*6777b538SAndroid Build Coastguard Worker   kCompleted,
22*6777b538SAndroid Build Coastguard Worker 
23*6777b538SAndroid Build Coastguard Worker   // The walk reached a frame that it doesn't know how to unwind, but might be
24*6777b538SAndroid Build Coastguard Worker   // unwindable by the other native/aux unwinder.
25*6777b538SAndroid Build Coastguard Worker   kUnrecognizedFrame,
26*6777b538SAndroid Build Coastguard Worker 
27*6777b538SAndroid Build Coastguard Worker   // The walk was aborted and is not resumable.
28*6777b538SAndroid Build Coastguard Worker   kAborted,
29*6777b538SAndroid Build Coastguard Worker };
30*6777b538SAndroid Build Coastguard Worker 
31*6777b538SAndroid Build Coastguard Worker // Unwinder provides an interface for stack frame unwinder implementations for
32*6777b538SAndroid Build Coastguard Worker // use with the StackSamplingProfiler. Initialize() must be invoked prior to the
33*6777b538SAndroid Build Coastguard Worker // invocation of any other function on the interface. The profiler is expected
34*6777b538SAndroid Build Coastguard Worker // to call CanUnwind() to determine if the Unwinder thinks it can unwind from
35*6777b538SAndroid Build Coastguard Worker // the frame represented by the context values, then TryUnwind() to attempt the
36*6777b538SAndroid Build Coastguard Worker // unwind.
37*6777b538SAndroid Build Coastguard Worker class BASE_EXPORT Unwinder {
38*6777b538SAndroid Build Coastguard Worker  public:
39*6777b538SAndroid Build Coastguard Worker   virtual ~Unwinder() = default;
40*6777b538SAndroid Build Coastguard Worker 
41*6777b538SAndroid Build Coastguard Worker   // Initializes this unwinder to use |module_cache| in subsequent methods
42*6777b538SAndroid Build Coastguard Worker   // UpdateModules() and TryUnwinder(). This unwinder may add any modules it
43*6777b538SAndroid Build Coastguard Worker   // recognizes or register a module factory to the ModuleCache. |module_cache|
44*6777b538SAndroid Build Coastguard Worker   // must outlive this Unwinder.
45*6777b538SAndroid Build Coastguard Worker   void Initialize(ModuleCache* module_cache);
46*6777b538SAndroid Build Coastguard Worker 
47*6777b538SAndroid Build Coastguard Worker   // Invoked at the time the stack is captured. IMPORTANT NOTE: this function is
48*6777b538SAndroid Build Coastguard Worker   // invoked while the target thread is suspended. To avoid deadlock it must not
49*6777b538SAndroid Build Coastguard Worker   // invoke any non-reentrant code that is also invoked by the target thread. In
50*6777b538SAndroid Build Coastguard Worker   // particular, it may not perform any heap allocation or deallocation,
51*6777b538SAndroid Build Coastguard Worker   // including indirectly via use of DCHECK/CHECK or other logging statements.
OnStackCapture()52*6777b538SAndroid Build Coastguard Worker   virtual void OnStackCapture() {}
53*6777b538SAndroid Build Coastguard Worker 
54*6777b538SAndroid Build Coastguard Worker   // Allows the unwinder to update ModuleCache with any modules it's responsible
55*6777b538SAndroid Build Coastguard Worker   // for. Invoked for each sample between OnStackCapture() and the initial
56*6777b538SAndroid Build Coastguard Worker   // invocations of CanUnwindFrom()/TryUnwind().
UpdateModules()57*6777b538SAndroid Build Coastguard Worker   virtual void UpdateModules() {}
58*6777b538SAndroid Build Coastguard Worker 
59*6777b538SAndroid Build Coastguard Worker   // Returns true if the unwinder recognizes the code referenced by
60*6777b538SAndroid Build Coastguard Worker   // |current_frame| as code from which it should be able to unwind. When
61*6777b538SAndroid Build Coastguard Worker   // multiple unwinders are in use, each should return true for a disjoint set
62*6777b538SAndroid Build Coastguard Worker   // of frames. Note that if the unwinder returns true it may still legitmately
63*6777b538SAndroid Build Coastguard Worker   // fail to unwind; e.g. in the case of a native unwind for a function that
64*6777b538SAndroid Build Coastguard Worker   // doesn't have unwind information.
65*6777b538SAndroid Build Coastguard Worker   virtual bool CanUnwindFrom(const Frame& current_frame) const = 0;
66*6777b538SAndroid Build Coastguard Worker 
67*6777b538SAndroid Build Coastguard Worker   // Attempts to unwind the frame represented by the context values.
68*6777b538SAndroid Build Coastguard Worker   // Walks the native frames on the stack pointed to by the stack pointer in
69*6777b538SAndroid Build Coastguard Worker   // |thread_context|, appending the frames to |stack|. When invoked
70*6777b538SAndroid Build Coastguard Worker   // stack->back() contains the frame corresponding to the state in
71*6777b538SAndroid Build Coastguard Worker   // |thread_context|.
72*6777b538SAndroid Build Coastguard Worker   // Precondition: RegisterContextStackPointer(thread_context) is less than
73*6777b538SAndroid Build Coastguard Worker   // |stack_top|.
74*6777b538SAndroid Build Coastguard Worker   // Postcondition: If the implementation returns UNRECOGNIZED_FRAME, indicating
75*6777b538SAndroid Build Coastguard Worker   // that it successfully unwound, RegisterContextStackPointer(thread_context)
76*6777b538SAndroid Build Coastguard Worker   // is greater than the previous value and less than |stack_top|.
77*6777b538SAndroid Build Coastguard Worker   virtual UnwindResult TryUnwind(RegisterContext* thread_context,
78*6777b538SAndroid Build Coastguard Worker                                  uintptr_t stack_top,
79*6777b538SAndroid Build Coastguard Worker                                  std::vector<Frame>* stack) = 0;
80*6777b538SAndroid Build Coastguard Worker 
81*6777b538SAndroid Build Coastguard Worker   Unwinder(const Unwinder&) = delete;
82*6777b538SAndroid Build Coastguard Worker   Unwinder& operator=(const Unwinder&) = delete;
83*6777b538SAndroid Build Coastguard Worker 
84*6777b538SAndroid Build Coastguard Worker  protected:
85*6777b538SAndroid Build Coastguard Worker   Unwinder() = default;
86*6777b538SAndroid Build Coastguard Worker 
87*6777b538SAndroid Build Coastguard Worker   // Invoked to allow the unwinder to add any modules it recognizes or register
88*6777b538SAndroid Build Coastguard Worker   // a module factory to the ModuleCache.
InitializeModules()89*6777b538SAndroid Build Coastguard Worker   virtual void InitializeModules() {}
90*6777b538SAndroid Build Coastguard Worker 
module_cache()91*6777b538SAndroid Build Coastguard Worker   ModuleCache* module_cache() const { return module_cache_; }
92*6777b538SAndroid Build Coastguard Worker 
93*6777b538SAndroid Build Coastguard Worker  private:
94*6777b538SAndroid Build Coastguard Worker   raw_ptr<ModuleCache> module_cache_ = nullptr;
95*6777b538SAndroid Build Coastguard Worker };
96*6777b538SAndroid Build Coastguard Worker 
97*6777b538SAndroid Build Coastguard Worker }  // namespace base
98*6777b538SAndroid Build Coastguard Worker 
99*6777b538SAndroid Build Coastguard Worker #endif  // BASE_PROFILER_UNWINDER_H_
100