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