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
48using namespace lldb;
49using namespace lldb_private;
50
51// Constructors
52SBThreadPlan::SBThreadPlan() { LLDB_INSTRUMENT_VA(this); }
53
54SBThreadPlan::SBThreadPlan(const ThreadPlanSP &lldb_object_sp)
55 : m_opaque_wp(lldb_object_sp) {
56 LLDB_INSTRUMENT_VA(this, lldb_object_sp);
57}
58
59SBThreadPlan::SBThreadPlan(const SBThreadPlan &rhs)
60 : m_opaque_wp(rhs.m_opaque_wp) {
61 LLDB_INSTRUMENT_VA(this, rhs);
62}
63
64SBThreadPlan::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
73SBThreadPlan::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
85const 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
93SBThreadPlan::~SBThreadPlan() = default;
94
95bool SBThreadPlan::IsValid() const {
96 LLDB_INSTRUMENT_VA(this);
97 return this->operator bool();
98}
99SBThreadPlan::operator bool() const {
100 LLDB_INSTRUMENT_VA(this);
101
102 return static_cast<bool>(GetSP());
103}
104
105void SBThreadPlan::Clear() {
106 LLDB_INSTRUMENT_VA(this);
107
108 m_opaque_wp.reset();
109}
110
111lldb::StopReason SBThreadPlan::GetStopReason() {
112 LLDB_INSTRUMENT_VA(this);
113
114 return eStopReasonNone;
115}
116
117size_t SBThreadPlan::GetStopReasonDataCount() {
118 LLDB_INSTRUMENT_VA(this);
119
120 return 0;
121}
122
123uint64_t SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) {
124 LLDB_INSTRUMENT_VA(this, idx);
125
126 return 0;
127}
128
129SBThread 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
139bool 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
151void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_wp) {
152 m_opaque_wp = lldb_object_wp;
153}
154
155void 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
163bool 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
172bool 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
181bool 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
190bool 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
199void 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
213SBThreadPlan
214SBThreadPlan::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
222SBThreadPlan 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
252SBThreadPlan
253SBThreadPlan::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
261SBThreadPlan
262SBThreadPlan::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
292SBThreadPlan
293SBThreadPlan::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
301SBThreadPlan
302SBThreadPlan::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
328SBThreadPlan
329SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) {
330 LLDB_INSTRUMENT_VA(this, sb_address);
331
332 SBError error;
333 return QueueThreadPlanForRunToAddress(address: sb_address, error);
334}
335
336SBThreadPlan 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
361SBThreadPlan
362SBThreadPlan::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
369SBThreadPlan
370SBThreadPlan::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
392SBThreadPlan
393SBThreadPlan::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

source code of lldb/source/API/SBThreadPlan.cpp