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 "lldb/API/SBThread.h"
10 
11 #include "lldb/API/SBFileSpec.h"
12 #include "lldb/API/SBStream.h"
13 #include "lldb/API/SBSymbolContext.h"
14 #include "lldb/Breakpoint/BreakpointLocation.h"
15 #include "lldb/Core/Debugger.h"
16 #include "lldb/Core/StreamFile.h"
17 #include "lldb/Interpreter/CommandInterpreter.h"
18 #include "lldb/Symbol/CompileUnit.h"
19 #include "lldb/Symbol/SymbolContext.h"
20 #include "lldb/Target/Process.h"
21 #include "lldb/Target/Queue.h"
22 #include "lldb/Target/StopInfo.h"
23 #include "lldb/Target/SystemRuntime.h"
24 #include "lldb/Target/Target.h"
25 #include "lldb/Target/Thread.h"
26 #include "lldb/Target/ThreadPlan.h"
27 #include "lldb/Target/ThreadPlanPython.h"
28 #include "lldb/Target/ThreadPlanStepInRange.h"
29 #include "lldb/Target/ThreadPlanStepInstruction.h"
30 #include "lldb/Target/ThreadPlanStepOut.h"
31 #include "lldb/Target/ThreadPlanStepRange.h"
32 #include "lldb/Utility/State.h"
33 #include "lldb/Utility/Stream.h"
34 #include "lldb/Utility/StructuredData.h"
35 
36 #include "lldb/API/SBAddress.h"
37 #include "lldb/API/SBDebugger.h"
38 #include "lldb/API/SBEvent.h"
39 #include "lldb/API/SBFrame.h"
40 #include "lldb/API/SBProcess.h"
41 #include "lldb/API/SBThreadPlan.h"
42 #include "lldb/API/SBValue.h"
43 
44 using namespace lldb;
45 using namespace lldb_private;
46 
47 //----------------------------------------------------------------------
48 // Constructors
49 //----------------------------------------------------------------------
50 SBThreadPlan::SBThreadPlan() {}
51 
52 SBThreadPlan::SBThreadPlan(const ThreadPlanSP &lldb_object_sp)
53     : m_opaque_sp(lldb_object_sp) {}
54 
55 SBThreadPlan::SBThreadPlan(const SBThreadPlan &rhs)
56     : m_opaque_sp(rhs.m_opaque_sp) {}
57 
58 SBThreadPlan::SBThreadPlan(lldb::SBThread &sb_thread, const char *class_name) {
59   Thread *thread = sb_thread.get();
60   if (thread)
61     m_opaque_sp.reset(new ThreadPlanPython(*thread, class_name));
62 }
63 
64 //----------------------------------------------------------------------
65 // Assignment operator
66 //----------------------------------------------------------------------
67 
68 const lldb::SBThreadPlan &SBThreadPlan::operator=(const SBThreadPlan &rhs) {
69   if (this != &rhs)
70     m_opaque_sp = rhs.m_opaque_sp;
71   return *this;
72 }
73 //----------------------------------------------------------------------
74 // Destructor
75 //----------------------------------------------------------------------
76 SBThreadPlan::~SBThreadPlan() {}
77 
78 lldb_private::ThreadPlan *SBThreadPlan::get() { return m_opaque_sp.get(); }
79 
80 bool SBThreadPlan::IsValid() const { return m_opaque_sp.get() != NULL; }
81 
82 void SBThreadPlan::Clear() { m_opaque_sp.reset(); }
83 
84 lldb::StopReason SBThreadPlan::GetStopReason() { return eStopReasonNone; }
85 
86 size_t SBThreadPlan::GetStopReasonDataCount() { return 0; }
87 
88 uint64_t SBThreadPlan::GetStopReasonDataAtIndex(uint32_t idx) { return 0; }
89 
90 SBThread SBThreadPlan::GetThread() const {
91   if (m_opaque_sp) {
92     return SBThread(m_opaque_sp->GetThread().shared_from_this());
93   } else
94     return SBThread();
95 }
96 
97 bool SBThreadPlan::GetDescription(lldb::SBStream &description) const {
98   if (m_opaque_sp) {
99     m_opaque_sp->GetDescription(description.get(), eDescriptionLevelFull);
100   } else {
101     description.Printf("Empty SBThreadPlan");
102   }
103   return true;
104 }
105 
106 void SBThreadPlan::SetThreadPlan(const ThreadPlanSP &lldb_object_sp) {
107   m_opaque_sp = lldb_object_sp;
108 }
109 
110 void SBThreadPlan::SetPlanComplete(bool success) {
111   if (m_opaque_sp)
112     m_opaque_sp->SetPlanComplete(success);
113 }
114 
115 bool SBThreadPlan::IsPlanComplete() {
116   if (m_opaque_sp)
117     return m_opaque_sp->IsPlanComplete();
118   else
119     return true;
120 }
121 
122 bool SBThreadPlan::IsPlanStale() {
123   if (m_opaque_sp)
124     return m_opaque_sp->IsPlanStale();
125   else
126     return true;
127 }
128 
129 bool SBThreadPlan::IsValid() {
130   if (m_opaque_sp)
131     return m_opaque_sp->ValidatePlan(nullptr);
132   else
133     return false;
134 }
135 
136 // This section allows an SBThreadPlan to push another of the common types of
137 // plans...
138 //
139 // FIXME, you should only be able to queue thread plans from inside the methods
140 // of a Scripted Thread Plan.  Need a way to enforce that.
141 
142 SBThreadPlan
143 SBThreadPlan::QueueThreadPlanForStepOverRange(SBAddress &sb_start_address,
144                                               lldb::addr_t size) {
145   SBError error;
146   return QueueThreadPlanForStepOverRange(sb_start_address, size, error);
147 }
148 
149 SBThreadPlan SBThreadPlan::QueueThreadPlanForStepOverRange(
150     SBAddress &sb_start_address, lldb::addr_t size, SBError &error) {
151   if (m_opaque_sp) {
152     Address *start_address = sb_start_address.get();
153     if (!start_address) {
154       return SBThreadPlan();
155     }
156 
157     AddressRange range(*start_address, size);
158     SymbolContext sc;
159     start_address->CalculateSymbolContext(&sc);
160     Status plan_status;
161 
162     SBThreadPlan plan =
163         SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOverRange(
164             false, range, sc, eAllThreads, plan_status));
165 
166     if (plan_status.Fail())
167       error.SetErrorString(plan_status.AsCString());
168 
169     return plan;
170   } else {
171     return SBThreadPlan();
172   }
173 }
174 
175 SBThreadPlan
176 SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address,
177                                             lldb::addr_t size) {
178   SBError error;
179   return QueueThreadPlanForStepInRange(sb_start_address, size, error);
180 }
181 
182 SBThreadPlan
183 SBThreadPlan::QueueThreadPlanForStepInRange(SBAddress &sb_start_address,
184                                             lldb::addr_t size, SBError &error) {
185   if (m_opaque_sp) {
186     Address *start_address = sb_start_address.get();
187     if (!start_address) {
188       return SBThreadPlan();
189     }
190 
191     AddressRange range(*start_address, size);
192     SymbolContext sc;
193     start_address->CalculateSymbolContext(&sc);
194 
195     Status plan_status;
196     SBThreadPlan plan =
197         SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepInRange(
198             false, range, sc, NULL, eAllThreads, plan_status));
199 
200     if (plan_status.Fail())
201       error.SetErrorString(plan_status.AsCString());
202 
203     return plan;
204   } else {
205     return SBThreadPlan();
206   }
207 }
208 
209 SBThreadPlan
210 SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
211                                         bool first_insn) {
212   SBError error;
213   return QueueThreadPlanForStepOut(frame_idx_to_step_to, first_insn, error);
214 }
215 
216 SBThreadPlan
217 SBThreadPlan::QueueThreadPlanForStepOut(uint32_t frame_idx_to_step_to,
218                                         bool first_insn, SBError &error) {
219   if (m_opaque_sp) {
220     SymbolContext sc;
221     sc = m_opaque_sp->GetThread().GetStackFrameAtIndex(0)->GetSymbolContext(
222         lldb::eSymbolContextEverything);
223 
224     Status plan_status;
225     SBThreadPlan plan =
226         SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepOut(
227             false, &sc, first_insn, false, eVoteYes, eVoteNoOpinion,
228             frame_idx_to_step_to, plan_status));
229 
230     if (plan_status.Fail())
231       error.SetErrorString(plan_status.AsCString());
232 
233     return plan;
234   } else {
235     return SBThreadPlan();
236   }
237 }
238 
239 SBThreadPlan
240 SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address) {
241   SBError error;
242   return QueueThreadPlanForRunToAddress(sb_address, error);
243 }
244 
245 SBThreadPlan SBThreadPlan::QueueThreadPlanForRunToAddress(SBAddress sb_address,
246                                                           SBError &error) {
247   if (m_opaque_sp) {
248     Address *address = sb_address.get();
249     if (!address)
250       return SBThreadPlan();
251 
252     Status plan_status;
253     SBThreadPlan plan =
254         SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForRunToAddress(
255             false, *address, false, plan_status));
256 
257     if (plan_status.Fail())
258       error.SetErrorString(plan_status.AsCString());
259 
260     return plan;
261   } else {
262     return SBThreadPlan();
263   }
264 }
265 
266 SBThreadPlan
267 SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name) {
268   SBError error;
269   return QueueThreadPlanForStepScripted(script_class_name, error);
270 }
271 
272 SBThreadPlan
273 SBThreadPlan::QueueThreadPlanForStepScripted(const char *script_class_name,
274                                              SBError &error) {
275   if (m_opaque_sp) {
276     Status plan_status;
277     SBThreadPlan plan =
278         SBThreadPlan(m_opaque_sp->GetThread().QueueThreadPlanForStepScripted(
279             false, script_class_name, false, plan_status));
280 
281     if (plan_status.Fail())
282       error.SetErrorString(plan_status.AsCString());
283 
284     return plan;
285   } else {
286     return SBThreadPlan();
287   }
288 }
289