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
53 SBThreadPlan::SBThreadPlan() { LLDB_INSTRUMENT_VA(this); }
54 
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 
60 SBThreadPlan::SBThreadPlan(const SBThreadPlan &rhs)
61     : m_opaque_wp(rhs.m_opaque_wp) {
62   LLDB_INSTRUMENT_VA(this, rhs);
63 }
64 
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 
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 
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 
96 bool SBThreadPlan::IsValid() const {
97   LLDB_INSTRUMENT_VA(this);
98   return this->operator bool();
99 }
100 SBThreadPlan::operator bool() const {
101   LLDB_INSTRUMENT_VA(this);
102 
103   return static_cast<bool>(GetSP());
104 }
105 
106 void SBThreadPlan::Clear() {
107   LLDB_INSTRUMENT_VA(this);
108 
109   m_opaque_wp.reset();
110 }
111 
112 lldb::StopReason SBThreadPlan::GetStopReason() {
113   LLDB_INSTRUMENT_VA(this);
114 
115   return eStopReasonNone;
116 }
117 
118 size_t SBThreadPlan::GetStopReasonDataCount() {
119   LLDB_INSTRUMENT_VA(this);
120 
121   return 0;
122 }
123 
124 uint64_t SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) {
125   LLDB_INSTRUMENT_VA(this, idx);
126 
127   return 0;
128 }
129 
130 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 
140 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 
152 void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_wp) {
153   m_opaque_wp = lldb_object_wp;
154 }
155 
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 
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 
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 
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 
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 
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
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 
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
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
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
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
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
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 
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
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
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
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