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 <vector> |
15 | |
16 | #include "lldb/Target/StackFrame.h" |
17 | |
18 | namespace lldb_private { |
19 | |
20 | class ScriptedThread; |
21 | |
22 | class StackFrameList { |
23 | public: |
24 | // Constructors and Destructors |
25 | StackFrameList(Thread &thread, const lldb::StackFrameListSP &prev_frames_sp, |
26 | bool show_inline_frames); |
27 | |
28 | ~StackFrameList(); |
29 | |
30 | /// Get the number of visible frames. Frames may be created if \p can_create |
31 | /// is true. Synthetic (inline) frames expanded from the concrete frame #0 |
32 | /// (aka invisible frames) are not included in this count. |
33 | uint32_t GetNumFrames(bool can_create = true); |
34 | |
35 | /// Get the frame at index \p idx. Invisible frames cannot be indexed. |
36 | lldb::StackFrameSP GetFrameAtIndex(uint32_t idx); |
37 | |
38 | /// Get the first concrete frame with index greater than or equal to \p idx. |
39 | /// Unlike \ref GetFrameAtIndex, this cannot return a synthetic frame. |
40 | lldb::StackFrameSP GetFrameWithConcreteFrameIndex(uint32_t unwind_idx); |
41 | |
42 | /// Retrieve the stack frame with the given ID \p stack_id. |
43 | lldb::StackFrameSP GetFrameWithStackID(const StackID &stack_id); |
44 | |
45 | /// Mark a stack frame as the currently selected frame and return its index. |
46 | uint32_t SetSelectedFrame(lldb_private::StackFrame *frame); |
47 | |
48 | /// Get the currently selected frame index. |
49 | /// We should only call SelectMostRelevantFrame if (a) the user hasn't already |
50 | /// selected a frame, and (b) if this really is a user facing |
51 | /// "GetSelectedFrame". SMRF runs the frame recognizers which can do |
52 | /// arbitrary work that ends up being dangerous to do internally. Also, |
53 | /// for most internal uses we don't actually want the frame changed by the |
54 | /// SMRF logic. So unless this is in a command or SB API, you should |
55 | /// pass false here. |
56 | uint32_t |
57 | GetSelectedFrameIndex(SelectMostRelevant select_most_relevant_frame); |
58 | |
59 | /// Mark a stack frame as the currently selected frame using the frame index |
60 | /// \p idx. Like \ref GetFrameAtIndex, invisible frames cannot be selected. |
61 | bool SetSelectedFrameByIndex(uint32_t idx); |
62 | |
63 | /// If the current inline depth (i.e the number of invisible frames) is valid, |
64 | /// subtract it from \p idx. Otherwise simply return \p idx. |
65 | uint32_t GetVisibleStackFrameIndex(uint32_t idx) { |
66 | if (m_current_inlined_depth < UINT32_MAX) |
67 | return idx - m_current_inlined_depth; |
68 | else |
69 | return idx; |
70 | } |
71 | |
72 | /// Calculate and set the current inline depth. This may be used to update |
73 | /// the StackFrameList's set of inline frames when execution stops, e.g when |
74 | /// a breakpoint is hit. |
75 | void CalculateCurrentInlinedDepth(); |
76 | |
77 | /// If the currently selected frame comes from the currently selected thread, |
78 | /// point the default file and line of the thread's target to the location |
79 | /// specified by the frame. |
80 | void SetDefaultFileAndLineToSelectedFrame(); |
81 | |
82 | /// Clear the cache of frames. |
83 | void Clear(); |
84 | |
85 | void Dump(Stream *s); |
86 | |
87 | /// If \p stack_frame_ptr is contained in this StackFrameList, return its |
88 | /// wrapping shared pointer. |
89 | lldb::StackFrameSP |
90 | GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr); |
91 | |
92 | size_t GetStatus(Stream &strm, uint32_t first_frame, uint32_t num_frames, |
93 | bool show_frame_info, uint32_t num_frames_with_source, |
94 | bool show_unique = false, |
95 | const char *frame_marker = nullptr); |
96 | |
97 | protected: |
98 | friend class Thread; |
99 | friend class ScriptedThread; |
100 | |
101 | bool SetFrameAtIndex(uint32_t idx, lldb::StackFrameSP &frame_sp); |
102 | |
103 | /// Realizes frames up to (and including) end_idx (which can be greater than |
104 | /// the actual number of frames.) |
105 | /// Returns true if the function was interrupted, false otherwise. |
106 | bool GetFramesUpTo(uint32_t end_idx, |
107 | InterruptionControl allow_interrupt = AllowInterruption); |
108 | |
109 | void GetOnlyConcreteFramesUpTo(uint32_t end_idx, Unwind &unwinder); |
110 | |
111 | void SynthesizeTailCallFrames(StackFrame &next_frame); |
112 | |
113 | bool GetAllFramesFetched() { return m_concrete_frames_fetched == UINT32_MAX; } |
114 | |
115 | void SetAllFramesFetched() { m_concrete_frames_fetched = UINT32_MAX; } |
116 | |
117 | bool DecrementCurrentInlinedDepth(); |
118 | |
119 | void ResetCurrentInlinedDepth(); |
120 | |
121 | uint32_t GetCurrentInlinedDepth(); |
122 | |
123 | void SetCurrentInlinedDepth(uint32_t new_depth); |
124 | |
125 | void SelectMostRelevantFrame(); |
126 | |
127 | typedef std::vector<lldb::StackFrameSP> collection; |
128 | typedef collection::iterator iterator; |
129 | typedef collection::const_iterator const_iterator; |
130 | |
131 | /// The thread this frame list describes. |
132 | Thread &m_thread; |
133 | |
134 | /// The old stack frame list. |
135 | // TODO: The old stack frame list is used to fill in missing frame info |
136 | // heuristically when it's otherwise unavailable (say, because the unwinder |
137 | // fails). We should have stronger checks to make sure that this is a valid |
138 | // source of information. |
139 | lldb::StackFrameListSP m_prev_frames_sp; |
140 | |
141 | /// A mutex for this frame list. |
142 | // TODO: This mutex may not always be held when required. In particular, uses |
143 | // of the StackFrameList APIs in lldb_private::Thread look suspect. Consider |
144 | // passing around a lock_guard reference to enforce proper locking. |
145 | mutable std::recursive_mutex m_mutex; |
146 | |
147 | /// A cache of frames. This may need to be updated when the program counter |
148 | /// changes. |
149 | collection m_frames; |
150 | |
151 | /// The currently selected frame. An optional is used to record whether anyone |
152 | /// has set the selected frame on this stack yet. We only let recognizers |
153 | /// change the frame if this is the first time GetSelectedFrame is called. |
154 | std::optional<uint32_t> m_selected_frame_idx; |
155 | |
156 | /// The number of concrete frames fetched while filling the frame list. This |
157 | /// is only used when synthetic frames are enabled. |
158 | uint32_t m_concrete_frames_fetched; |
159 | |
160 | /// The number of synthetic function activations (invisible frames) expanded |
161 | /// from the concrete frame #0 activation. |
162 | // TODO: Use an optional instead of UINT32_MAX to denote invalid values. |
163 | uint32_t m_current_inlined_depth; |
164 | |
165 | /// The program counter value at the currently selected synthetic activation. |
166 | /// This is only valid if m_current_inlined_depth is valid. |
167 | // TODO: Use an optional instead of UINT32_MAX to denote invalid values. |
168 | lldb::addr_t m_current_inlined_pc; |
169 | |
170 | /// Whether or not to show synthetic (inline) frames. Immutable. |
171 | const bool m_show_inlined_frames; |
172 | |
173 | private: |
174 | StackFrameList(const StackFrameList &) = delete; |
175 | const StackFrameList &operator=(const StackFrameList &) = delete; |
176 | }; |
177 | |
178 | } // namespace lldb_private |
179 | |
180 | #endif // LLDB_TARGET_STACKFRAMELIST_H |
181 | |