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