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 // Unwinder provides an interface for stack frame unwinder implementations for 32 // use with the StackSamplingProfiler. Initialize() must be invoked prior to the 33 // invocation of any other function on the interface. The profiler is expected 34 // to call CanUnwind() to determine if the Unwinder thinks it can unwind from 35 // the frame represented by the context values, then TryUnwind() to attempt the 36 // unwind. 37 class BASE_EXPORT Unwinder { 38 public: 39 virtual ~Unwinder() = default; 40 41 // Initializes this unwinder to use |module_cache| in subsequent methods 42 // UpdateModules() and TryUnwinder(). This unwinder may add any modules it 43 // recognizes or register a module factory to the ModuleCache. |module_cache| 44 // must outlive this Unwinder. 45 void Initialize(ModuleCache* module_cache); 46 47 // Invoked at the time the stack is captured. IMPORTANT NOTE: this function is 48 // invoked while the target thread is suspended. To avoid deadlock it must not 49 // invoke any non-reentrant code that is also invoked by the target thread. In 50 // particular, it may not perform any heap allocation or deallocation, 51 // including indirectly via use of DCHECK/CHECK or other logging statements. OnStackCapture()52 virtual void OnStackCapture() {} 53 54 // Allows the unwinder to update ModuleCache with any modules it's responsible 55 // for. Invoked for each sample between OnStackCapture() and the initial 56 // invocations of CanUnwindFrom()/TryUnwind(). UpdateModules()57 virtual void UpdateModules() {} 58 59 // Returns true if the unwinder recognizes the code referenced by 60 // |current_frame| as code from which it should be able to unwind. When 61 // multiple unwinders are in use, each should return true for a disjoint set 62 // of frames. Note that if the unwinder returns true it may still legitmately 63 // fail to unwind; e.g. in the case of a native unwind for a function that 64 // doesn't have unwind information. 65 virtual bool CanUnwindFrom(const Frame& current_frame) const = 0; 66 67 // Attempts to unwind the frame represented by the context values. 68 // Walks the native frames on the stack pointed to by the stack pointer in 69 // |thread_context|, appending the frames to |stack|. When invoked 70 // stack->back() contains the frame corresponding to the state in 71 // |thread_context|. 72 // Precondition: RegisterContextStackPointer(thread_context) is less than 73 // |stack_top|. 74 // Postcondition: If the implementation returns UNRECOGNIZED_FRAME, indicating 75 // that it successfully unwound, RegisterContextStackPointer(thread_context) 76 // is greater than the previous value and less than |stack_top|. 77 virtual UnwindResult TryUnwind(RegisterContext* thread_context, 78 uintptr_t stack_top, 79 std::vector<Frame>* stack) = 0; 80 81 Unwinder(const Unwinder&) = delete; 82 Unwinder& operator=(const Unwinder&) = delete; 83 84 protected: 85 Unwinder() = default; 86 87 // Invoked to allow the unwinder to add any modules it recognizes or register 88 // a module factory to the ModuleCache. InitializeModules()89 virtual void InitializeModules() {} 90 module_cache()91 ModuleCache* module_cache() const { return module_cache_; } 92 93 private: 94 raw_ptr<ModuleCache> module_cache_ = nullptr; 95 }; 96 97 } // namespace base 98 99 #endif // BASE_PROFILER_UNWINDER_H_ 100