1 | //===-- StopInfo.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_STOPINFO_H |
10 | #define LLDB_TARGET_STOPINFO_H |
11 | |
12 | #include <string> |
13 | |
14 | #include "lldb/Target/Process.h" |
15 | #include "lldb/Utility/StructuredData.h" |
16 | #include "lldb/lldb-public.h" |
17 | |
18 | namespace lldb_private { |
19 | |
20 | class StopInfo : public std::enable_shared_from_this<StopInfo> { |
21 | friend class Process::ProcessEventData; |
22 | friend class ThreadPlanBase; |
23 | |
24 | public: |
25 | // Constructors and Destructors |
26 | StopInfo(Thread &thread, uint64_t value); |
27 | |
28 | virtual ~StopInfo() = default; |
29 | |
30 | bool IsValid() const; |
31 | |
32 | void SetThread(const lldb::ThreadSP &thread_sp) { m_thread_wp = thread_sp; } |
33 | |
34 | lldb::ThreadSP GetThread() const { return m_thread_wp.lock(); } |
35 | |
36 | // The value of the StopInfo depends on the StopReason. |
37 | // |
38 | // StopReason Meaning |
39 | // ------------------------------------------------ |
40 | // eStopReasonBreakpoint BreakpointSiteID |
41 | // eStopReasonSignal Signal number |
42 | // eStopReasonWatchpoint WatchpointLocationID |
43 | // eStopReasonPlanComplete No significance |
44 | |
45 | uint64_t GetValue() const { return m_value; } |
46 | |
47 | virtual lldb::StopReason GetStopReason() const = 0; |
48 | |
49 | // ShouldStopSynchronous will get called before any thread plans are |
50 | // consulted, and if it says we should resume the target, then we will just |
51 | // immediately resume. This should not run any code in or resume the target. |
52 | |
53 | virtual bool ShouldStopSynchronous(Event *event_ptr) { return true; } |
54 | |
55 | void OverrideShouldNotify(bool override_value) { |
56 | m_override_should_notify = override_value ? eLazyBoolYes : eLazyBoolNo; |
57 | } |
58 | |
59 | // If should stop returns false, check if we should notify of this event |
60 | virtual bool ShouldNotify(Event *event_ptr) { |
61 | if (m_override_should_notify == eLazyBoolCalculate) |
62 | return DoShouldNotify(event_ptr); |
63 | else |
64 | return m_override_should_notify == eLazyBoolYes; |
65 | } |
66 | |
67 | virtual void WillResume(lldb::StateType resume_state) { |
68 | // By default, don't do anything |
69 | } |
70 | |
71 | virtual const char *GetDescription() { return m_description.c_str(); } |
72 | |
73 | virtual void SetDescription(const char *desc_cstr) { |
74 | if (desc_cstr && desc_cstr[0]) |
75 | m_description.assign(s: desc_cstr); |
76 | else |
77 | m_description.clear(); |
78 | } |
79 | |
80 | virtual bool IsValidForOperatingSystemThread(Thread &thread) { return true; } |
81 | |
82 | /// A Continue operation can result in a false stop event |
83 | /// before any execution has happened. We need to detect this |
84 | /// and silently continue again one more time. |
85 | virtual bool WasContinueInterrupted(Thread &thread) { return false; } |
86 | |
87 | // Sometimes the thread plan logic will know that it wants a given stop to |
88 | // stop or not, regardless of what the ordinary logic for that StopInfo would |
89 | // dictate. The main example of this is the ThreadPlanCallFunction, which |
90 | // for instance knows - based on how that particular expression was executed |
91 | // - whether it wants all breakpoints to auto-continue or not. Use |
92 | // OverrideShouldStop on the StopInfo to implement this. |
93 | |
94 | void OverrideShouldStop(bool override_value) { |
95 | m_override_should_stop = override_value ? eLazyBoolYes : eLazyBoolNo; |
96 | } |
97 | |
98 | bool GetOverrideShouldStop() { |
99 | return m_override_should_stop != eLazyBoolCalculate; |
100 | } |
101 | |
102 | bool GetOverriddenShouldStopValue() { |
103 | return m_override_should_stop == eLazyBoolYes; |
104 | } |
105 | |
106 | StructuredData::ObjectSP GetExtendedInfo() { return m_extended_info; } |
107 | |
108 | static lldb::StopInfoSP |
109 | CreateStopReasonWithBreakpointSiteID(Thread &thread, |
110 | lldb::break_id_t break_id); |
111 | |
112 | // This creates a StopInfo for the thread where the should_stop is already |
113 | // set, and won't be recalculated. |
114 | static lldb::StopInfoSP CreateStopReasonWithBreakpointSiteID( |
115 | Thread &thread, lldb::break_id_t break_id, bool should_stop); |
116 | |
117 | static lldb::StopInfoSP |
118 | CreateStopReasonWithWatchpointID(Thread &thread, lldb::break_id_t watch_id, |
119 | bool silently_continue = false); |
120 | |
121 | static lldb::StopInfoSP |
122 | CreateStopReasonWithSignal(Thread &thread, int signo, |
123 | const char *description = nullptr, |
124 | std::optional<int> code = std::nullopt); |
125 | |
126 | static lldb::StopInfoSP CreateStopReasonToTrace(Thread &thread); |
127 | |
128 | static lldb::StopInfoSP |
129 | CreateStopReasonWithPlan(lldb::ThreadPlanSP &plan, |
130 | lldb::ValueObjectSP return_valobj_sp, |
131 | lldb::ExpressionVariableSP expression_variable_sp); |
132 | |
133 | static lldb::StopInfoSP |
134 | CreateStopReasonWithException(Thread &thread, const char *description); |
135 | |
136 | static lldb::StopInfoSP CreateStopReasonWithExec(Thread &thread); |
137 | |
138 | static lldb::StopInfoSP |
139 | CreateStopReasonProcessorTrace(Thread &thread, const char *description); |
140 | |
141 | static lldb::StopInfoSP CreateStopReasonFork(Thread &thread, |
142 | lldb::pid_t child_pid, |
143 | lldb::tid_t child_tid); |
144 | |
145 | static lldb::StopInfoSP CreateStopReasonVFork(Thread &thread, |
146 | lldb::pid_t child_pid, |
147 | lldb::tid_t child_tid); |
148 | |
149 | static lldb::StopInfoSP CreateStopReasonVForkDone(Thread &thread); |
150 | |
151 | static lldb::ValueObjectSP |
152 | GetReturnValueObject(lldb::StopInfoSP &stop_info_sp); |
153 | |
154 | static lldb::ExpressionVariableSP |
155 | GetExpressionVariable(lldb::StopInfoSP &stop_info_sp); |
156 | |
157 | static lldb::ValueObjectSP |
158 | GetCrashingDereference(lldb::StopInfoSP &stop_info_sp, |
159 | lldb::addr_t *crashing_address = nullptr); |
160 | |
161 | protected: |
162 | // Perform any action that is associated with this stop. This is done as the |
163 | // Event is removed from the event queue. ProcessEventData::DoOnRemoval does |
164 | // the job. |
165 | |
166 | virtual void PerformAction(Event *event_ptr) {} |
167 | |
168 | virtual bool DoShouldNotify(Event *event_ptr) { return false; } |
169 | |
170 | // Stop the thread by default. Subclasses can override this to allow the |
171 | // thread to continue if desired. The ShouldStop method should not do |
172 | // anything that might run code. If you need to run code when deciding |
173 | // whether to stop at this StopInfo, that must be done in the PerformAction. |
174 | // The PerformAction will always get called before the ShouldStop. This is |
175 | // done by the ProcessEventData::DoOnRemoval, though the ThreadPlanBase needs |
176 | // to consult this later on. |
177 | virtual bool ShouldStop(Event *event_ptr) { return true; } |
178 | |
179 | // Classes that inherit from StackID can see and modify these |
180 | lldb::ThreadWP m_thread_wp; // The thread corresponding to the stop reason. |
181 | uint32_t m_stop_id; // The process stop ID for which this stop info is valid |
182 | uint32_t m_resume_id; // This is the resume ID when we made this stop ID. |
183 | uint64_t m_value; // A generic value that can be used for things pertaining to |
184 | // this stop info |
185 | std::string m_description; // A textual description describing this stop. |
186 | LazyBool m_override_should_notify; |
187 | LazyBool m_override_should_stop; |
188 | |
189 | StructuredData::ObjectSP |
190 | m_extended_info; // The extended info for this stop info |
191 | |
192 | // This determines whether the target has run since this stop info. N.B. |
193 | // running to evaluate a user expression does not count. |
194 | bool HasTargetRunSinceMe(); |
195 | |
196 | // MakeStopInfoValid is necessary to allow saved stop infos to resurrect |
197 | // themselves as valid. It should only be used by |
198 | // Thread::RestoreThreadStateFromCheckpoint and to make sure the one-step |
199 | // needed for before-the-fact watchpoints does not prevent us from stopping |
200 | void MakeStopInfoValid(); |
201 | |
202 | private: |
203 | friend class Thread; |
204 | |
205 | StopInfo(const StopInfo &) = delete; |
206 | const StopInfo &operator=(const StopInfo &) = delete; |
207 | }; |
208 | |
209 | } // namespace lldb_private |
210 | |
211 | #endif // LLDB_TARGET_STOPINFO_H |
212 | |