xref: /freebsd/contrib/llvm-project/lldb/include/lldb/Target/StackFrameList.h (revision e64bea71c21eb42e97aa615188ba91f6cce0d36d)
1 //===-- StackFrameList.h ----------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLDB_TARGET_STACKFRAMELIST_H
10 #define LLDB_TARGET_STACKFRAMELIST_H
11 
12 #include <memory>
13 #include <mutex>
14 #include <shared_mutex>
15 #include <vector>
16 
17 #include "lldb/Target/StackFrame.h"
18 
19 namespace lldb_private {
20 
21 class ScriptedThread;
22 
23 class StackFrameList {
24 public:
25   // Constructors and Destructors
26   StackFrameList(Thread &thread, const lldb::StackFrameListSP &prev_frames_sp,
27                  bool show_inline_frames);
28 
29   ~StackFrameList();
30 
31   /// Get the number of visible frames. Frames may be created if \p can_create
32   /// is true. Synthetic (inline) frames expanded from the concrete frame #0
33   /// (aka invisible frames) are not included in this count.
34   uint32_t GetNumFrames(bool can_create = true);
35 
36   /// Get the frame at index \p idx. Invisible frames cannot be indexed.
37   lldb::StackFrameSP GetFrameAtIndex(uint32_t idx);
38 
39   /// Get the first concrete frame with index greater than or equal to \p idx.
40   /// Unlike \ref GetFrameAtIndex, this cannot return a synthetic frame.
41   lldb::StackFrameSP GetFrameWithConcreteFrameIndex(uint32_t unwind_idx);
42 
43   /// Retrieve the stack frame with the given ID \p stack_id.
44   lldb::StackFrameSP GetFrameWithStackID(const StackID &stack_id);
45 
46   /// Mark a stack frame as the currently selected frame and return its index.
47   uint32_t SetSelectedFrame(lldb_private::StackFrame *frame);
48 
49   /// Resets the selected frame index of this object.
50   void ClearSelectedFrameIndex();
51 
52   /// Get the currently selected frame index.
53   /// We should only call SelectMostRelevantFrame if (a) the user hasn't already
54   /// selected a frame, and (b) if this really is a user facing
55   /// "GetSelectedFrame".  SMRF runs the frame recognizers which can do
56   /// arbitrary work that ends up being dangerous to do internally.  Also,
57   /// for most internal uses we don't actually want the frame changed by the
58   /// SMRF logic.  So unless this is in a command or SB API, you should
59   /// pass false here.
60   uint32_t
61   GetSelectedFrameIndex(SelectMostRelevant select_most_relevant_frame);
62 
63   /// Mark a stack frame as the currently selected frame using the frame index
64   /// \p idx. Like \ref GetFrameAtIndex, invisible frames cannot be selected.
65   bool SetSelectedFrameByIndex(uint32_t idx);
66 
67   /// If the current inline depth (i.e the number of invisible frames) is valid,
68   /// subtract it from \p idx. Otherwise simply return \p idx.
GetVisibleStackFrameIndex(uint32_t idx)69   uint32_t GetVisibleStackFrameIndex(uint32_t idx) {
70     if (m_current_inlined_depth < UINT32_MAX)
71       return idx - m_current_inlined_depth;
72     else
73       return idx;
74   }
75 
76   /// Calculate and set the current inline depth. This may be used to update
77   /// the StackFrameList's set of inline frames when execution stops, e.g when
78   /// a breakpoint is hit.
79   void CalculateCurrentInlinedDepth();
80 
81   /// If the currently selected frame comes from the currently selected thread,
82   /// point the default file and line of the thread's target to the location
83   /// specified by the frame.
84   void SetDefaultFileAndLineToSelectedFrame();
85 
86   /// Clear the cache of frames.
87   void Clear();
88 
89   void Dump(Stream *s);
90 
91   /// If \p stack_frame_ptr is contained in this StackFrameList, return its
92   /// wrapping shared pointer.
93   lldb::StackFrameSP
94   GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr);
95 
96   size_t GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames,
97                    bool show_frame_info, uint32_t num_frames_with_source,
98                    bool show_unique = false, bool show_hidden = false,
99                    const char *frame_marker = nullptr);
100 
101   /// Returns whether we have currently fetched all the frames of a stack.
102   bool WereAllFramesFetched() const;
103 
104 protected:
105   friend class Thread;
106   friend class ScriptedThread;
107 
108   /// Use this API to build a stack frame list (used for scripted threads, for
109   /// instance.)  This API is not meant for StackFrameLists that have unwinders
110   /// and partake in lazy stack filling (using GetFramesUpTo).  Rather if you
111   /// are building StackFrameLists with this API, you should build the entire
112   /// list before making it available for use.
113   bool SetFrameAtIndex(uint32_t idx, lldb::StackFrameSP &frame_sp);
114 
115   /// Ensures that frames up to (and including) `end_idx` are realized in the
116   /// StackFrameList.  `end_idx` can be larger than the actual number of frames,
117   /// in which case all the frames will be fetched.  Acquires the writer end of
118   /// the list mutex.
119   /// Returns true if the function was interrupted, false otherwise.
120   /// Callers should first check (under the shared mutex) whether we need to
121   /// fetch frames or not.
122   bool GetFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
123 
124   // This should be called with either the reader or writer end of the list
125   // mutex held:
GetAllFramesFetched()126   bool GetAllFramesFetched() const {
127     return m_concrete_frames_fetched == UINT32_MAX;
128   }
129 
130   // This should be called with the writer end of the list mutex held.
SetAllFramesFetched()131   void SetAllFramesFetched() { m_concrete_frames_fetched = UINT32_MAX; }
132 
133   bool DecrementCurrentInlinedDepth();
134 
135   void ResetCurrentInlinedDepth();
136 
137   uint32_t GetCurrentInlinedDepth();
138 
139   void SetCurrentInlinedDepth(uint32_t new_depth);
140 
141   /// Calls into the stack frame recognizers and stop info to set the most
142   /// relevant frame.  This can call out to arbitrary user code so it can't
143   /// hold the StackFrameList mutex.
144   void SelectMostRelevantFrame();
145 
146   typedef std::vector<lldb::StackFrameSP> collection;
147   typedef collection::iterator iterator;
148   typedef collection::const_iterator const_iterator;
149 
150   /// The thread this frame list describes.
151   Thread &m_thread;
152 
153   /// The old stack frame list.
154   // TODO: The old stack frame list is used to fill in missing frame info
155   // heuristically when it's otherwise unavailable (say, because the unwinder
156   // fails). We should have stronger checks to make sure that this is a valid
157   // source of information.
158   lldb::StackFrameListSP m_prev_frames_sp;
159 
160   /// A mutex for this frame list.  The only public API that requires the
161   /// unique lock is Clear.  All other clients take the shared lock, though
162   /// if we need more frames we may swap shared for unique to fulfill that
163   /// requirement.
164   mutable std::shared_mutex m_list_mutex;
165 
166   // Setting the inlined depth should be protected against other attempts to
167   // change it, but since it doesn't mutate the list itself, we can limit the
168   // critical regions it produces by having a separate mutex.
169   mutable std::mutex m_inlined_depth_mutex;
170 
171   /// A cache of frames. This may need to be updated when the program counter
172   /// changes.
173   collection m_frames;
174 
175   /// The currently selected frame. An optional is used to record whether anyone
176   /// has set the selected frame on this stack yet. We only let recognizers
177   /// change the frame if this is the first time GetSelectedFrame is called.
178   ///
179   /// Thread-safety:
180   /// This member is not protected by a mutex.
181   /// LLDB really only should have an opinion about the selected frame index
182   /// when a process stops, before control gets handed back to the user.
183   /// After that, it's up to them to change it whenever they feel like it.
184   /// If two parts of lldb decided they wanted to be in control of the selected
185   /// frame index on stop the right way to fix it would need to be some explicit
186   /// negotiation for who gets to control this.
187   std::optional<uint32_t> m_selected_frame_idx;
188 
189   /// The number of concrete frames fetched while filling the frame list. This
190   /// is only used when synthetic frames are enabled.
191   uint32_t m_concrete_frames_fetched;
192 
193   /// The number of synthetic function activations (invisible frames) expanded
194   /// from the concrete frame #0 activation.
195   // TODO: Use an optional instead of UINT32_MAX to denote invalid values.
196   uint32_t m_current_inlined_depth;
197 
198   /// The program counter value at the currently selected synthetic activation.
199   /// This is only valid if m_current_inlined_depth is valid.
200   // TODO: Use an optional instead of UINT32_MAX to denote invalid values.
201   lldb::addr_t m_current_inlined_pc;
202 
203   /// Whether or not to show synthetic (inline) frames. Immutable.
204   const bool m_show_inlined_frames;
205 
206 private:
207   uint32_t SetSelectedFrameNoLock(lldb_private::StackFrame *frame);
208   lldb::StackFrameSP
209   GetFrameAtIndexNoLock(uint32_t idx,
210                         std::shared_lock<std::shared_mutex> &guard);
211 
212   /// These two Fetch frames APIs and SynthesizeTailCallFrames are called in
213   /// GetFramesUpTo, they are the ones that actually add frames.  They must be
214   /// called with the writer end of the list mutex held.
215 
216   /// Returns true if fetching frames was interrupted, false otherwise.
217   bool FetchFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
218   /// Not currently interruptible so returns void.
219   void FetchOnlyConcreteFramesUpTo(uint32_t end_idx);
220   void SynthesizeTailCallFrames(StackFrame &next_frame);
221 
222   StackFrameList(const StackFrameList &) = delete;
223   const StackFrameList &operator=(const StackFrameList &) = delete;
224 };
225 
226 } // namespace lldb_private
227 
228 #endif // LLDB_TARGET_STACKFRAMELIST_H
229