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