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