• 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_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