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
SBThreadPlan()52 SBThreadPlan::SBThreadPlan() { LLDB_INSTRUMENT_VA(this); }
53
SBThreadPlan(const ThreadPlanSP & lldb_object_sp)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
SBThreadPlan(const SBThreadPlan & rhs)59 SBThreadPlan::SBThreadPlan(const SBThreadPlan &rhs)
60 : m_opaque_wp(rhs.m_opaque_wp) {
61 LLDB_INSTRUMENT_VA(this, rhs);
62 }
63
SBThreadPlan(lldb::SBThread & sb_thread,const char * class_name)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>(*thread, class_name,
70 StructuredDataImpl());
71 }
72
SBThreadPlan(lldb::SBThread & sb_thread,const char * class_name,lldb::SBStructuredData & args_data)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>(*thread, class_name,
80 *args_data.m_impl_up);
81 }
82
83 // Assignment operator
84
operator =(const SBThreadPlan & rhs)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
IsValid() const95 bool SBThreadPlan::IsValid() const {
96 LLDB_INSTRUMENT_VA(this);
97 return this->operator bool();
98 }
operator bool() const99 SBThreadPlan::operator bool() const {
100 LLDB_INSTRUMENT_VA(this);
101
102 return static_cast<bool>(GetSP());
103 }
104
Clear()105 void SBThreadPlan::Clear() {
106 LLDB_INSTRUMENT_VA(this);
107
108 m_opaque_wp.reset();
109 }
110
GetStopReason()111 lldb::StopReason SBThreadPlan::GetStopReason() {
112 LLDB_INSTRUMENT_VA(this);
113
114 return eStopReasonNone;
115 }
116
GetStopReasonDataCount()117 size_t SBThreadPlan::GetStopReasonDataCount() {
118 LLDB_INSTRUMENT_VA(this);
119
120 return 0;
121 }
122
GetStopReasonDataAtIndex(uint32_t idx)123 uint64_t SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) {
124 LLDB_INSTRUMENT_VA(this, idx);
125
126 return 0;
127 }
128
GetThread() const129 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
GetDescription(lldb::SBStream & description) const139 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(description.get(), eDescriptionLevelFull);
145 } else {
146 description.Printf("Empty SBThreadPlan");
147 }
148 return true;
149 }
150
SetThreadPlan(const ThreadPlanSP & lldb_object_wp)151 void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_wp) {
152 m_opaque_wp = lldb_object_wp;
153 }
154
SetPlanComplete(bool success)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
IsPlanComplete()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
IsPlanStale()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
IsValid()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(nullptr);
187 return false;
188 }
189
GetStopOthers()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
SetStopOthers(bool stop_others)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
QueueThreadPlanForStepOverRange(SBAddress & sb_start_address,lldb::addr_t size)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(sb_start_address, size, error);
220 }
221
QueueThreadPlanForStepOverRange(SBAddress & sb_start_address,lldb::addr_t size,SBError & error)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);
236 Status plan_status;
237
238 SBThreadPlan plan = SBThreadPlan(
239 thread_plan_sp->GetThread().QueueThreadPlanForStepOverRange(
240 false, range, sc, eAllThreads, 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
QueueThreadPlanForStepInRange(SBAddress & sb_start_address,lldb::addr_t size)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(sb_start_address, size, error);
259 }
260
261 SBThreadPlan
QueueThreadPlanForStepInRange(SBAddress & sb_start_address,lldb::addr_t size,SBError & error)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);
276
277 Status plan_status;
278 SBThreadPlan plan =
279 SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepInRange(
280 false, range, sc, nullptr, eAllThreads, 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
QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,bool first_insn)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
QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,bool first_insn,SBError & error)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(0)->GetSymbolContext(
310 lldb::eSymbolContextEverything);
311
312 Status plan_status;
313 SBThreadPlan plan =
314 SBThreadPlan(thread_plan_sp->GetThread().QueueThreadPlanForStepOut(
315 false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion,
316 frame_idx_to_step_to, 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
QueueThreadPlanForRunToAddress(SBAddress sb_address)329 SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) {
330 LLDB_INSTRUMENT_VA(this, sb_address);
331
332 SBError error;
333 return QueueThreadPlanForRunToAddress(sb_address, error);
334 }
335
QueueThreadPlanForRunToAddress(SBAddress sb_address,SBError & error)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 false, *address, false, 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
QueueThreadPlanForStepScripted(const char * script_class_name)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
QueueThreadPlanForStepScripted(const char * script_class_name,SBError & error)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 false, script_class_name, empty_args, false, 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
QueueThreadPlanForStepScripted(const char * script_class_name,lldb::SBStructuredData & args_data,SBError & error)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 false, script_class_name, args_obj, false, 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