1 | //===-- SBThreadPlan.cpp --------------------------------------------------===// |
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 | #include "lldb/API/SBThread.h" |
10 | #include "lldb/Utility/Instrumentation.h" |
11 | |
12 | #include "lldb/API/SBFileSpec.h" |
13 | #include "lldb/API/SBStream.h" |
14 | #include "lldb/API/SBStructuredData.h" |
15 | #include "lldb/API/SBSymbolContext.h" |
16 | #include "lldb/Breakpoint/BreakpointLocation.h" |
17 | #include "lldb/Core/Debugger.h" |
18 | #include "lldb/Core/StructuredDataImpl.h" |
19 | #include "lldb/Interpreter/CommandInterpreter.h" |
20 | #include "lldb/Symbol/CompileUnit.h" |
21 | #include "lldb/Symbol/SymbolContext.h" |
22 | #include "lldb/Target/Process.h" |
23 | #include "lldb/Target/Queue.h" |
24 | #include "lldb/Target/StopInfo.h" |
25 | #include "lldb/Target/SystemRuntime.h" |
26 | #include "lldb/Target/Target.h" |
27 | #include "lldb/Target/Thread.h" |
28 | #include "lldb/Target/ThreadPlan.h" |
29 | #include "lldb/Target/ThreadPlanPython.h" |
30 | #include "lldb/Target/ThreadPlanStepInRange.h" |
31 | #include "lldb/Target/ThreadPlanStepInstruction.h" |
32 | #include "lldb/Target/ThreadPlanStepOut.h" |
33 | #include "lldb/Target/ThreadPlanStepRange.h" |
34 | #include "lldb/Utility/State.h" |
35 | #include "lldb/Utility/Stream.h" |
36 | #include "lldb/Utility/StructuredData.h" |
37 | |
38 | #include "lldb/API/SBAddress.h" |
39 | #include "lldb/API/SBDebugger.h" |
40 | #include "lldb/API/SBEvent.h" |
41 | #include "lldb/API/SBFrame.h" |
42 | #include "lldb/API/SBProcess.h" |
43 | #include "lldb/API/SBThreadPlan.h" |
44 | #include "lldb/API/SBValue.h" |
45 | |
46 | #include <memory> |
47 | |
48 | using namespace lldb; |
49 | using namespace lldb_private; |
50 | |
51 | // Constructors |
52 | SBThreadPlan::SBThreadPlan() { LLDB_INSTRUMENT_VA(this); } |
53 | |
54 | SBThreadPlan::SBThreadPlan(const ThreadPlanSP &lldb_object_sp) |
55 | : m_opaque_wp(lldb_object_sp) { |
56 | LLDB_INSTRUMENT_VA(this, lldb_object_sp); |
57 | } |
58 | |
59 | SBThreadPlan::SBThreadPlan(const SBThreadPlan &rhs) |
60 | : m_opaque_wp(rhs.m_opaque_wp) { |
61 | LLDB_INSTRUMENT_VA(this, rhs); |
62 | } |
63 | |
64 | SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name) { |
65 | LLDB_INSTRUMENT_VA(this, sb_thread, class_name); |
66 | |
67 | Thread *thread = sb_thread.get(); |
68 | if (thread) |
69 | m_opaque_wp = std::make_shared<ThreadPlanPython>(args&: *thread, args&: class_name, |
70 | args: StructuredDataImpl()); |
71 | } |
72 | |
73 | SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name, |
74 | lldb::SBStructuredData &args_data) { |
75 | LLDB_INSTRUMENT_VA(this, sb_thread, class_name, args_data); |
76 | |
77 | Thread *thread = sb_thread.get(); |
78 | if (thread) |
79 | m_opaque_wp = std::make_shared<ThreadPlanPython>(args&: *thread, args&: class_name, |
80 | args&: *args_data.m_impl_up); |
81 | } |
82 | |
83 | // Assignment operator |
84 | |
85 | const lldb::SBThreadPlan &SBThreadPlan::operator=(const SBThreadPlan &rhs) { |
86 | LLDB_INSTRUMENT_VA(this, rhs); |
87 | |
88 | if (this != &rhs) |
89 | m_opaque_wp = rhs.m_opaque_wp; |
90 | return *this; |
91 | } |
92 | // Destructor |
93 | SBThreadPlan::~SBThreadPlan() = default; |
94 | |
95 | bool SBThreadPlan::IsValid() const { |
96 | LLDB_INSTRUMENT_VA(this); |
97 | return this->operator bool(); |
98 | } |
99 | SBThreadPlan::operator bool() const { |
100 | LLDB_INSTRUMENT_VA(this); |
101 | |
102 | return static_cast<bool>(GetSP()); |
103 | } |
104 | |
105 | void SBThreadPlan::Clear() { |
106 | LLDB_INSTRUMENT_VA(this); |
107 | |
108 | m_opaque_wp.reset(); |
109 | } |
110 | |
111 | lldb::StopReason SBThreadPlan::GetStopReason() { |
112 | LLDB_INSTRUMENT_VA(this); |
113 | |
114 | return eStopReasonNone; |
115 | } |
116 | |
117 | size_t SBThreadPlan::GetStopReasonDataCount() { |
118 | LLDB_INSTRUMENT_VA(this); |
119 | |
120 | return 0; |
121 | } |
122 | |
123 | uint64_t SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) { |
124 | LLDB_INSTRUMENT_VA(this, idx); |
125 | |
126 | return 0; |
127 | } |
128 | |
129 | SBThread SBThreadPlan::GetThread() const { |
130 | LLDB_INSTRUMENT_VA(this); |
131 | |
132 | ThreadPlanSP thread_plan_sp(GetSP()); |
133 | if (thread_plan_sp) { |
134 | return SBThread(thread_plan_sp->GetThread().shared_from_this()); |
135 | } else |
136 | return SBThread(); |
137 | } |
138 | |
139 | bool SBThreadPlan::GetDescription(lldb::SBStream &description) const { |
140 | LLDB_INSTRUMENT_VA(this, description); |
141 | |
142 | ThreadPlanSP thread_plan_sp(GetSP()); |
143 | if (thread_plan_sp) { |
144 | thread_plan_sp->GetDescription(s: description.get(), level: eDescriptionLevelFull); |
145 | } else { |
146 | description.Printf(format: "Empty SBThreadPlan" ); |
147 | } |
148 | return true; |
149 | } |
150 | |
151 | void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_wp) { |
152 | m_opaque_wp = lldb_object_wp; |
153 | } |
154 | |
155 | void SBThreadPlan::SetPlanComplete(bool success) { |
156 | LLDB_INSTRUMENT_VA(this, success); |
157 | |
158 | ThreadPlanSP thread_plan_sp(GetSP()); |
159 | if (thread_plan_sp) |
160 | thread_plan_sp->SetPlanComplete(success); |
161 | } |
162 | |
163 | bool SBThreadPlan::IsPlanComplete() { |
164 | LLDB_INSTRUMENT_VA(this); |
165 | |
166 | ThreadPlanSP thread_plan_sp(GetSP()); |
167 | if (thread_plan_sp) |
168 | return thread_plan_sp->IsPlanComplete(); |
169 | return true; |
170 | } |
171 | |
172 | bool SBThreadPlan::IsPlanStale() { |
173 | LLDB_INSTRUMENT_VA(this); |
174 | |
175 | ThreadPlanSP thread_plan_sp(GetSP()); |
176 | if (thread_plan_sp) |
177 | return thread_plan_sp->IsPlanStale(); |
178 | return true; |
179 | } |
180 | |
181 | bool SBThreadPlan::IsValid() { |
182 | LLDB_INSTRUMENT_VA(this); |
183 | |
184 | ThreadPlanSP thread_plan_sp(GetSP()); |
185 | if (thread_plan_sp) |
186 | return thread_plan_sp->ValidatePlan(error: nullptr); |
187 | return false; |
188 | } |
189 | |
190 | bool SBThreadPlan::GetStopOthers() { |
191 | LLDB_INSTRUMENT_VA(this); |
192 | |
193 | ThreadPlanSP thread_plan_sp(GetSP()); |
194 | if (thread_plan_sp) |
195 | return thread_plan_sp->StopOthers(); |
196 | return false; |
197 | } |
198 | |
199 | void SBThreadPlan::SetStopOthers(bool stop_others) { |
200 | LLDB_INSTRUMENT_VA(this, stop_others); |
201 | |
202 | ThreadPlanSP thread_plan_sp(GetSP()); |
203 | if (thread_plan_sp) |
204 | thread_plan_sp->SetStopOthers(stop_others); |
205 | } |
206 | |
207 | // This section allows an SBThreadPlan to push another of the common types of |
208 | // plans... |
209 | // |
210 | // FIXME, you should only be able to queue thread plans from inside the methods |
211 | // of a Scripted Thread Plan. Need a way to enforce that. |
212 | |
213 | SBThreadPlan |
214 | SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address, |
215 | lldb::addr_t size) { |
216 | LLDB_INSTRUMENT_VA(this, sb_start_address, size); |
217 | |
218 | SBError error; |
219 | return QueueThreadPlanForStepOverRange(start_address&: sb_start_address, range_size: size, error); |
220 | } |
221 | |
222 | SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange( |
223 | SBAddress &sb_start_address, lldb::addr_t size, SBError &error) { |
224 | LLDB_INSTRUMENT_VA(this, sb_start_address, size, error); |
225 | |
226 | ThreadPlanSP thread_plan_sp(GetSP()); |
227 | if (thread_plan_sp) { |
228 | Address *start_address = sb_start_address.get(); |
229 | if (!start_address) { |
230 | return SBThreadPlan(); |
231 | } |
232 | |
233 | AddressRange range(*start_address, size); |
234 | SymbolContext sc; |
235 | start_address->CalculateSymbolContext(sc: &sc); |
236 | Status plan_status; |
237 | |
238 | SBThreadPlan plan = SBThreadPlan( |
239 | thread_plan_sp->GetThread().QueueThreadPlanForStepOverRange( |
240 | abort_other_plans: false, range, addr_context: sc, stop_other_threads: eAllThreads, status&: plan_status)); |
241 | |
242 | if (plan_status.Fail()) |
243 | error.SetErrorString(plan_status.AsCString()); |
244 | else |
245 | plan.GetSP()->SetPrivate(true); |
246 | |
247 | return plan; |
248 | } |
249 | return SBThreadPlan(); |
250 | } |
251 | |
252 | SBThreadPlan |
253 | SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, |
254 | lldb::addr_t size) { |
255 | LLDB_INSTRUMENT_VA(this, sb_start_address, size); |
256 | |
257 | SBError error; |
258 | return QueueThreadPlanForStepInRange(start_address&: sb_start_address, range_size: size, error); |
259 | } |
260 | |
261 | SBThreadPlan |
262 | SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address, |
263 | lldb::addr_t size, SBError &error) { |
264 | LLDB_INSTRUMENT_VA(this, sb_start_address, size, error); |
265 | |
266 | ThreadPlanSP thread_plan_sp(GetSP()); |
267 | if (thread_plan_sp) { |
268 | Address *start_address = sb_start_address.get(); |
269 | if (!start_address) { |
270 | return SBThreadPlan(); |
271 | } |
272 | |
273 | AddressRange range(*start_address, size); |
274 | SymbolContext sc; |
275 | start_address->CalculateSymbolContext(sc: &sc); |
276 | |
277 | Status plan_status; |
278 | SBThreadPlan plan = |
279 | SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepInRange( |
280 | abort_other_plans: false, range, addr_context: sc, step_in_target: nullptr, stop_other_threads: eAllThreads, status&: plan_status)); |
281 | |
282 | if (plan_status.Fail()) |
283 | error.SetErrorString(plan_status.AsCString()); |
284 | else |
285 | plan.GetSP()->SetPrivate(true); |
286 | |
287 | return plan; |
288 | } |
289 | return SBThreadPlan(); |
290 | } |
291 | |
292 | SBThreadPlan |
293 | SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, |
294 | bool first_insn) { |
295 | LLDB_INSTRUMENT_VA(this, frame_idx_to_step_to, first_insn); |
296 | |
297 | SBError error; |
298 | return QueueThreadPlanForStepOut(frame_idx_to_step_to, first_insn, error); |
299 | } |
300 | |
301 | SBThreadPlan |
302 | SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to, |
303 | bool first_insn, SBError &error) { |
304 | LLDB_INSTRUMENT_VA(this, frame_idx_to_step_to, first_insn, error); |
305 | |
306 | ThreadPlanSP thread_plan_sp(GetSP()); |
307 | if (thread_plan_sp) { |
308 | SymbolContext sc; |
309 | sc = thread_plan_sp->GetThread().GetStackFrameAtIndex(idx: 0)->GetSymbolContext( |
310 | resolve_scope: lldb::eSymbolContextEverything); |
311 | |
312 | Status plan_status; |
313 | SBThreadPlan plan = |
314 | SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepOut( |
315 | abort_other_plans: false, addr_context: &sc, first_insn, stop_other_threads: false, report_stop_vote: eVoteYes, report_run_vote: eVoteNoOpinion, |
316 | frame_idx: frame_idx_to_step_to, status&: plan_status)); |
317 | |
318 | if (plan_status.Fail()) |
319 | error.SetErrorString(plan_status.AsCString()); |
320 | else |
321 | plan.GetSP()->SetPrivate(true); |
322 | |
323 | return plan; |
324 | } |
325 | return SBThreadPlan(); |
326 | } |
327 | |
328 | SBThreadPlan |
329 | SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) { |
330 | LLDB_INSTRUMENT_VA(this, sb_address); |
331 | |
332 | SBError error; |
333 | return QueueThreadPlanForRunToAddress(address: sb_address, error); |
334 | } |
335 | |
336 | SBThreadPlan SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address, |
337 | SBError &error) { |
338 | LLDB_INSTRUMENT_VA(this, sb_address, error); |
339 | |
340 | ThreadPlanSP thread_plan_sp(GetSP()); |
341 | if (thread_plan_sp) { |
342 | Address *address = sb_address.get(); |
343 | if (!address) |
344 | return SBThreadPlan(); |
345 | |
346 | Status plan_status; |
347 | SBThreadPlan plan = |
348 | SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForRunToAddress( |
349 | abort_other_plans: false, target_addr&: *address, stop_other_threads: false, status&: plan_status)); |
350 | |
351 | if (plan_status.Fail()) |
352 | error.SetErrorString(plan_status.AsCString()); |
353 | else |
354 | plan.GetSP()->SetPrivate(true); |
355 | |
356 | return plan; |
357 | } |
358 | return SBThreadPlan(); |
359 | } |
360 | |
361 | SBThreadPlan |
362 | SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name) { |
363 | LLDB_INSTRUMENT_VA(this, script_class_name); |
364 | |
365 | SBError error; |
366 | return QueueThreadPlanForStepScripted(script_class_name, error); |
367 | } |
368 | |
369 | SBThreadPlan |
370 | SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name, |
371 | SBError &error) { |
372 | LLDB_INSTRUMENT_VA(this, script_class_name, error); |
373 | |
374 | ThreadPlanSP thread_plan_sp(GetSP()); |
375 | if (thread_plan_sp) { |
376 | Status plan_status; |
377 | StructuredData::ObjectSP empty_args; |
378 | SBThreadPlan plan = |
379 | SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepScripted( |
380 | abort_other_plans: false, class_name: script_class_name, extra_args_sp: empty_args, stop_other_threads: false, status&: plan_status)); |
381 | |
382 | if (plan_status.Fail()) |
383 | error.SetErrorString(plan_status.AsCString()); |
384 | else |
385 | plan.GetSP()->SetPrivate(true); |
386 | |
387 | return plan; |
388 | } |
389 | return SBThreadPlan(); |
390 | } |
391 | |
392 | SBThreadPlan |
393 | SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name, |
394 | lldb::SBStructuredData &args_data, |
395 | SBError &error) { |
396 | LLDB_INSTRUMENT_VA(this, script_class_name, args_data, error); |
397 | |
398 | ThreadPlanSP thread_plan_sp(GetSP()); |
399 | if (thread_plan_sp) { |
400 | Status plan_status; |
401 | StructuredData::ObjectSP args_obj = args_data.m_impl_up->GetObjectSP(); |
402 | SBThreadPlan plan = |
403 | SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepScripted( |
404 | abort_other_plans: false, class_name: script_class_name, extra_args_sp: args_obj, stop_other_threads: false, status&: plan_status)); |
405 | |
406 | if (plan_status.Fail()) |
407 | error.SetErrorString(plan_status.AsCString()); |
408 | else |
409 | plan.GetSP()->SetPrivate(true); |
410 | |
411 | return plan; |
412 | } else { |
413 | return SBThreadPlan(); |
414 | } |
415 | } |
416 | |