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