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