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