xref: /llvm-project/lldb/include/lldb/Target/StackFrameList.h (revision 186fac33d08b34be494caa58fe63972f69c6d6ab)
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   /// Get the currently selected frame index.
50   /// We should only call SelectMostRelevantFrame if (a) the user hasn't already
51   /// selected a frame, and (b) if this really is a user facing
52   /// "GetSelectedFrame".  SMRF runs the frame recognizers which can do
53   /// arbitrary work that ends up being dangerous to do internally.  Also,
54   /// for most internal uses we don't actually want the frame changed by the
55   /// SMRF logic.  So unless this is in a command or SB API, you should
56   /// pass false here.
57   uint32_t
58   GetSelectedFrameIndex(SelectMostRelevant select_most_relevant_frame);
59 
60   /// Mark a stack frame as the currently selected frame using the frame index
61   /// \p idx. Like \ref GetFrameAtIndex, invisible frames cannot be selected.
62   bool SetSelectedFrameByIndex(uint32_t idx);
63 
64   /// If the current inline depth (i.e the number of invisible frames) is valid,
65   /// subtract it from \p idx. Otherwise simply return \p idx.
66   uint32_t GetVisibleStackFrameIndex(uint32_t idx) {
67     if (m_current_inlined_depth < UINT32_MAX)
68       return idx - m_current_inlined_depth;
69     else
70       return idx;
71   }
72 
73   /// Calculate and set the current inline depth. This may be used to update
74   /// the StackFrameList's set of inline frames when execution stops, e.g when
75   /// a breakpoint is hit.
76   void CalculateCurrentInlinedDepth();
77 
78   /// If the currently selected frame comes from the currently selected thread,
79   /// point the default file and line of the thread's target to the location
80   /// specified by the frame.
81   void SetDefaultFileAndLineToSelectedFrame();
82 
83   /// Clear the cache of frames.
84   void Clear();
85 
86   void Dump(Stream *s);
87 
88   /// If \p stack_frame_ptr is contained in this StackFrameList, return its
89   /// wrapping shared pointer.
90   lldb::StackFrameSP
91   GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr);
92 
93   size_t GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames,
94                    bool show_frame_info, uint32_t num_frames_with_source,
95                    bool show_unique = false, bool show_hidden = false,
96                    const char *frame_marker = nullptr);
97 
98   /// Returns whether we have currently fetched all the frames of a stack.
99   bool WereAllFramesFetched() const;
100 
101 protected:
102   friend class Thread;
103   friend class ScriptedThread;
104 
105   /// Use this API to build a stack frame list (used for scripted threads, for
106   /// instance.)  This API is not meant for StackFrameLists that have unwinders
107   /// and partake in lazy stack filling (using GetFramesUpTo).  Rather if you
108   /// are building StackFrameLists with this API, you should build the entire
109   /// list before making it available for use.
110   bool SetFrameAtIndex(uint32_t idx, lldb::StackFrameSP &frame_sp);
111 
112   /// Ensures that frames up to (and including) `end_idx` are realized in the
113   /// StackFrameList.  `end_idx` can be larger than the actual number of frames,
114   /// in which case all the frames will be fetched.  Acquires the writer end of
115   /// the list mutex.
116   /// Returns true if the function was interrupted, false otherwise.
117   /// Callers should first check (under the shared mutex) whether we need to
118   /// fetch frames or not.
119   bool GetFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
120 
121   // This should be called with either the reader or writer end of the list
122   // mutex held:
123   bool GetAllFramesFetched() const {
124     return m_concrete_frames_fetched == UINT32_MAX;
125   }
126 
127   // This should be called with the writer end of the list mutex held.
128   void SetAllFramesFetched() { m_concrete_frames_fetched = UINT32_MAX; }
129 
130   bool DecrementCurrentInlinedDepth();
131 
132   void ResetCurrentInlinedDepth();
133 
134   uint32_t GetCurrentInlinedDepth();
135 
136   void SetCurrentInlinedDepth(uint32_t new_depth);
137 
138   /// Calls into the stack frame recognizers and stop info to set the most
139   /// relevant frame.  This can call out to arbitrary user code so it can't
140   /// hold the StackFrameList mutex.
141   void SelectMostRelevantFrame();
142 
143   typedef std::vector<lldb::StackFrameSP> collection;
144   typedef collection::iterator iterator;
145   typedef collection::const_iterator const_iterator;
146 
147   /// The thread this frame list describes.
148   Thread &m_thread;
149 
150   /// The old stack frame list.
151   // TODO: The old stack frame list is used to fill in missing frame info
152   // heuristically when it's otherwise unavailable (say, because the unwinder
153   // fails). We should have stronger checks to make sure that this is a valid
154   // source of information.
155   lldb::StackFrameListSP m_prev_frames_sp;
156 
157   /// A mutex for this frame list.  The only public API that requires the
158   /// unique lock is Clear.  All other clients take the shared lock, though
159   /// if we need more frames we may swap shared for unique to fulfill that
160   /// requirement.
161   mutable std::shared_mutex m_list_mutex;
162 
163   // Setting the inlined depth should be protected against other attempts to
164   // change it, but since it doesn't mutate the list itself, we can limit the
165   // critical regions it produces by having a separate mutex.
166   mutable std::mutex m_inlined_depth_mutex;
167 
168   /// A cache of frames. This may need to be updated when the program counter
169   /// changes.
170   collection m_frames;
171 
172   /// The currently selected frame. An optional is used to record whether anyone
173   /// has set the selected frame on this stack yet. We only let recognizers
174   /// change the frame if this is the first time GetSelectedFrame is called.
175   std::optional<uint32_t> m_selected_frame_idx;
176 
177   /// The number of concrete frames fetched while filling the frame list. This
178   /// is only used when synthetic frames are enabled.
179   uint32_t m_concrete_frames_fetched;
180 
181   /// The number of synthetic function activations (invisible frames) expanded
182   /// from the concrete frame #0 activation.
183   // TODO: Use an optional instead of UINT32_MAX to denote invalid values.
184   uint32_t m_current_inlined_depth;
185 
186   /// The program counter value at the currently selected synthetic activation.
187   /// This is only valid if m_current_inlined_depth is valid.
188   // TODO: Use an optional instead of UINT32_MAX to denote invalid values.
189   lldb::addr_t m_current_inlined_pc;
190 
191   /// Whether or not to show synthetic (inline) frames. Immutable.
192   const bool m_show_inlined_frames;
193 
194 private:
195   uint32_t SetSelectedFrameNoLock(lldb_private::StackFrame *frame);
196   lldb::StackFrameSP
197   GetFrameAtIndexNoLock(uint32_t idx,
198                         std::shared_lock<std::shared_mutex> &guard);
199 
200   /// These two Fetch frames APIs and SynthesizeTailCallFrames are called in
201   /// GetFramesUpTo, they are the ones that actually add frames.  They must be
202   /// called with the writer end of the list mutex held.
203 
204   /// Returns true if fetching frames was interrupted, false otherwise.
205   bool FetchFramesUpTo(uint32_t end_idx, InterruptionControl allow_interrupt);
206   /// Not currently interruptible so returns void.
207   void FetchOnlyConcreteFramesUpTo(uint32_t end_idx);
208   void SynthesizeTailCallFrames(StackFrame &next_frame);
209 
210   StackFrameList(const StackFrameList &) = delete;
211   const StackFrameList &operator=(const StackFrameList &) = delete;
212 };
213 
214 } // namespace lldb_private
215 
216 #endif // LLDB_TARGET_STACKFRAMELIST_H
217