1 //===-- SBInstruction.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/SBInstruction.h"
10 #include "lldb/Utility/Instrumentation.h"
11 
12 #include "lldb/API/SBAddress.h"
13 #include "lldb/API/SBFrame.h"
14 #include "lldb/API/SBFile.h"
15 
16 #include "lldb/API/SBInstruction.h"
17 #include "lldb/API/SBStream.h"
18 #include "lldb/API/SBTarget.h"
19 #include "lldb/Core/Disassembler.h"
20 #include "lldb/Core/EmulateInstruction.h"
21 #include "lldb/Core/Module.h"
22 #include "lldb/Host/HostInfo.h"
23 #include "lldb/Host/StreamFile.h"
24 #include "lldb/Target/ExecutionContext.h"
25 #include "lldb/Target/StackFrame.h"
26 #include "lldb/Target/Target.h"
27 #include "lldb/Utility/ArchSpec.h"
28 #include "lldb/Utility/DataBufferHeap.h"
29 #include "lldb/Utility/DataExtractor.h"
30 
31 #include <memory>
32 
33 // We recently fixed a leak in one of the Instruction subclasses where the
34 // instruction will only hold a weak reference to the disassembler to avoid a
35 // cycle that was keeping both objects alive (leak) and we need the
36 // InstructionImpl class to make sure our public API behaves as users would
37 // expect. Calls in our public API allow clients to do things like:
38 //
39 // 1  lldb::SBInstruction inst;
40 // 2  inst = target.ReadInstructions(pc, 1).GetInstructionAtIndex(0)
41 // 3  if (inst.DoesBranch())
42 // 4  ...
43 //
44 // There was a temporary lldb::DisassemblerSP object created in the
45 // SBInstructionList that was returned by lldb.target.ReadInstructions() that
46 // will go away after line 2 but the "inst" object should be able to still
47 // answer questions about itself. So we make sure that any SBInstruction
48 // objects that are given out have a strong reference to the disassembler and
49 // the instruction so that the object can live and successfully respond to all
50 // queries.
51 class InstructionImpl {
52 public:
InstructionImpl(const lldb::DisassemblerSP & disasm_sp,const lldb::InstructionSP & inst_sp)53   InstructionImpl(const lldb::DisassemblerSP &disasm_sp,
54                   const lldb::InstructionSP &inst_sp)
55       : m_disasm_sp(disasm_sp), m_inst_sp(inst_sp) {}
56 
GetSP() const57   lldb::InstructionSP GetSP() const { return m_inst_sp; }
58 
IsValid() const59   bool IsValid() const { return (bool)m_inst_sp; }
60 
61 protected:
62   lldb::DisassemblerSP m_disasm_sp; // Can be empty/invalid
63   lldb::InstructionSP m_inst_sp;
64 };
65 
66 using namespace lldb;
67 using namespace lldb_private;
68 
SBInstruction()69 SBInstruction::SBInstruction() { LLDB_INSTRUMENT_VA(this); }
70 
SBInstruction(const lldb::DisassemblerSP & disasm_sp,const lldb::InstructionSP & inst_sp)71 SBInstruction::SBInstruction(const lldb::DisassemblerSP &disasm_sp,
72                              const lldb::InstructionSP &inst_sp)
73     : m_opaque_sp(new InstructionImpl(disasm_sp, inst_sp)) {}
74 
SBInstruction(const SBInstruction & rhs)75 SBInstruction::SBInstruction(const SBInstruction &rhs)
76     : m_opaque_sp(rhs.m_opaque_sp) {
77   LLDB_INSTRUMENT_VA(this, rhs);
78 }
79 
operator =(const SBInstruction & rhs)80 const SBInstruction &SBInstruction::operator=(const SBInstruction &rhs) {
81   LLDB_INSTRUMENT_VA(this, rhs);
82 
83   if (this != &rhs)
84     m_opaque_sp = rhs.m_opaque_sp;
85   return *this;
86 }
87 
88 SBInstruction::~SBInstruction() = default;
89 
IsValid()90 bool SBInstruction::IsValid() {
91   LLDB_INSTRUMENT_VA(this);
92   return this->operator bool();
93 }
operator bool() const94 SBInstruction::operator bool() const {
95   LLDB_INSTRUMENT_VA(this);
96 
97   return m_opaque_sp && m_opaque_sp->IsValid();
98 }
99 
GetAddress()100 SBAddress SBInstruction::GetAddress() {
101   LLDB_INSTRUMENT_VA(this);
102 
103   SBAddress sb_addr;
104   lldb::InstructionSP inst_sp(GetOpaque());
105   if (inst_sp && inst_sp->GetAddress().IsValid())
106     sb_addr.SetAddress(inst_sp->GetAddress());
107   return sb_addr;
108 }
109 
GetMnemonic(SBTarget target)110 const char *SBInstruction::GetMnemonic(SBTarget target) {
111   LLDB_INSTRUMENT_VA(this, target);
112 
113   lldb::InstructionSP inst_sp(GetOpaque());
114   if (!inst_sp)
115     return nullptr;
116 
117   ExecutionContext exe_ctx;
118   TargetSP target_sp(target.GetSP());
119   std::unique_lock<std::recursive_mutex> lock;
120   if (target_sp) {
121     lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
122 
123     target_sp->CalculateExecutionContext(exe_ctx);
124     exe_ctx.SetProcessSP(target_sp->GetProcessSP());
125   }
126   return ConstString(inst_sp->GetMnemonic(&exe_ctx)).GetCString();
127 }
128 
GetOperands(SBTarget target)129 const char *SBInstruction::GetOperands(SBTarget target) {
130   LLDB_INSTRUMENT_VA(this, target);
131 
132   lldb::InstructionSP inst_sp(GetOpaque());
133   if (!inst_sp)
134     return nullptr;
135 
136   ExecutionContext exe_ctx;
137   TargetSP target_sp(target.GetSP());
138   std::unique_lock<std::recursive_mutex> lock;
139   if (target_sp) {
140     lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
141 
142     target_sp->CalculateExecutionContext(exe_ctx);
143     exe_ctx.SetProcessSP(target_sp->GetProcessSP());
144   }
145   return ConstString(inst_sp->GetOperands(&exe_ctx)).GetCString();
146 }
147 
GetComment(SBTarget target)148 const char *SBInstruction::GetComment(SBTarget target) {
149   LLDB_INSTRUMENT_VA(this, target);
150 
151   lldb::InstructionSP inst_sp(GetOpaque());
152   if (!inst_sp)
153     return nullptr;
154 
155   ExecutionContext exe_ctx;
156   TargetSP target_sp(target.GetSP());
157   std::unique_lock<std::recursive_mutex> lock;
158   if (target_sp) {
159     lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
160 
161     target_sp->CalculateExecutionContext(exe_ctx);
162     exe_ctx.SetProcessSP(target_sp->GetProcessSP());
163   }
164   return ConstString(inst_sp->GetComment(&exe_ctx)).GetCString();
165 }
166 
GetControlFlowKind(lldb::SBTarget target)167 lldb::InstructionControlFlowKind SBInstruction::GetControlFlowKind(lldb::SBTarget target) {
168   LLDB_INSTRUMENT_VA(this, target);
169 
170   lldb::InstructionSP inst_sp(GetOpaque());
171   if (inst_sp) {
172     ExecutionContext exe_ctx;
173     TargetSP target_sp(target.GetSP());
174     std::unique_lock<std::recursive_mutex> lock;
175     if (target_sp) {
176       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
177 
178       target_sp->CalculateExecutionContext(exe_ctx);
179       exe_ctx.SetProcessSP(target_sp->GetProcessSP());
180     }
181     return inst_sp->GetControlFlowKind(&exe_ctx);
182   }
183   return lldb::eInstructionControlFlowKindUnknown;
184 }
185 
GetByteSize()186 size_t SBInstruction::GetByteSize() {
187   LLDB_INSTRUMENT_VA(this);
188 
189   lldb::InstructionSP inst_sp(GetOpaque());
190   if (inst_sp)
191     return inst_sp->GetOpcode().GetByteSize();
192   return 0;
193 }
194 
GetData(SBTarget target)195 SBData SBInstruction::GetData(SBTarget target) {
196   LLDB_INSTRUMENT_VA(this, target);
197 
198   lldb::SBData sb_data;
199   lldb::InstructionSP inst_sp(GetOpaque());
200   if (inst_sp) {
201     DataExtractorSP data_extractor_sp(new DataExtractor());
202     if (inst_sp->GetData(*data_extractor_sp)) {
203       sb_data.SetOpaque(data_extractor_sp);
204     }
205   }
206   return sb_data;
207 }
208 
DoesBranch()209 bool SBInstruction::DoesBranch() {
210   LLDB_INSTRUMENT_VA(this);
211 
212   lldb::InstructionSP inst_sp(GetOpaque());
213   if (inst_sp)
214     return inst_sp->DoesBranch();
215   return false;
216 }
217 
HasDelaySlot()218 bool SBInstruction::HasDelaySlot() {
219   LLDB_INSTRUMENT_VA(this);
220 
221   lldb::InstructionSP inst_sp(GetOpaque());
222   if (inst_sp)
223     return inst_sp->HasDelaySlot();
224   return false;
225 }
226 
CanSetBreakpoint()227 bool SBInstruction::CanSetBreakpoint() {
228   LLDB_INSTRUMENT_VA(this);
229 
230   lldb::InstructionSP inst_sp(GetOpaque());
231   if (inst_sp)
232     return inst_sp->CanSetBreakpoint();
233   return false;
234 }
235 
GetOpaque()236 lldb::InstructionSP SBInstruction::GetOpaque() {
237   if (m_opaque_sp)
238     return m_opaque_sp->GetSP();
239   else
240     return lldb::InstructionSP();
241 }
242 
SetOpaque(const lldb::DisassemblerSP & disasm_sp,const lldb::InstructionSP & inst_sp)243 void SBInstruction::SetOpaque(const lldb::DisassemblerSP &disasm_sp,
244                               const lldb::InstructionSP &inst_sp) {
245   m_opaque_sp = std::make_shared<InstructionImpl>(disasm_sp, inst_sp);
246 }
247 
GetDescription(lldb::SBStream & s)248 bool SBInstruction::GetDescription(lldb::SBStream &s) {
249   LLDB_INSTRUMENT_VA(this, s);
250 
251   lldb::InstructionSP inst_sp(GetOpaque());
252   if (inst_sp) {
253     SymbolContext sc;
254     const Address &addr = inst_sp->GetAddress();
255     ModuleSP module_sp(addr.GetModule());
256     if (module_sp)
257       module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,
258                                                 sc);
259     // Use the "ref()" instead of the "get()" accessor in case the SBStream
260     // didn't have a stream already created, one will get created...
261     FormatEntity::Entry format;
262     FormatEntity::Parse("${addr}: ", format);
263     inst_sp->Dump(&s.ref(), 0, true, false, /*show_control_flow_kind=*/false,
264                   nullptr, &sc, nullptr, &format, 0);
265     return true;
266   }
267   return false;
268 }
269 
Print(FILE * outp)270 void SBInstruction::Print(FILE *outp) {
271   LLDB_INSTRUMENT_VA(this, outp);
272   FileSP out = std::make_shared<NativeFile>(outp, /*take_ownership=*/false);
273   Print(out);
274 }
275 
Print(SBFile out)276 void SBInstruction::Print(SBFile out) {
277   LLDB_INSTRUMENT_VA(this, out);
278   Print(out.m_opaque_sp);
279 }
280 
Print(FileSP out_sp)281 void SBInstruction::Print(FileSP out_sp) {
282   LLDB_INSTRUMENT_VA(this, out_sp);
283 
284   if (!out_sp || !out_sp->IsValid())
285     return;
286 
287   lldb::InstructionSP inst_sp(GetOpaque());
288   if (inst_sp) {
289     SymbolContext sc;
290     const Address &addr = inst_sp->GetAddress();
291     ModuleSP module_sp(addr.GetModule());
292     if (module_sp)
293       module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,
294                                                 sc);
295     StreamFile out_stream(out_sp);
296     FormatEntity::Entry format;
297     FormatEntity::Parse("${addr}: ", format);
298     inst_sp->Dump(&out_stream, 0, true, false, /*show_control_flow_kind=*/false,
299                   nullptr, &sc, nullptr, &format, 0);
300   }
301 }
302 
EmulateWithFrame(lldb::SBFrame & frame,uint32_t evaluate_options)303 bool SBInstruction::EmulateWithFrame(lldb::SBFrame &frame,
304                                      uint32_t evaluate_options) {
305   LLDB_INSTRUMENT_VA(this, frame, evaluate_options);
306 
307   lldb::InstructionSP inst_sp(GetOpaque());
308   if (inst_sp) {
309     lldb::StackFrameSP frame_sp(frame.GetFrameSP());
310 
311     if (frame_sp) {
312       lldb_private::ExecutionContext exe_ctx;
313       frame_sp->CalculateExecutionContext(exe_ctx);
314       lldb_private::Target *target = exe_ctx.GetTargetPtr();
315       lldb_private::ArchSpec arch = target->GetArchitecture();
316 
317       return inst_sp->Emulate(
318           arch, evaluate_options, (void *)frame_sp.get(),
319           &lldb_private::EmulateInstruction::ReadMemoryFrame,
320           &lldb_private::EmulateInstruction::WriteMemoryFrame,
321           &lldb_private::EmulateInstruction::ReadRegisterFrame,
322           &lldb_private::EmulateInstruction::WriteRegisterFrame);
323     }
324   }
325   return false;
326 }
327 
DumpEmulation(const char * triple)328 bool SBInstruction::DumpEmulation(const char *triple) {
329   LLDB_INSTRUMENT_VA(this, triple);
330 
331   lldb::InstructionSP inst_sp(GetOpaque());
332   if (inst_sp && triple) {
333     return inst_sp->DumpEmulation(HostInfo::GetAugmentedArchSpec(triple));
334   }
335   return false;
336 }
337 
TestEmulation(lldb::SBStream & output_stream,const char * test_file)338 bool SBInstruction::TestEmulation(lldb::SBStream &output_stream,
339                                   const char *test_file) {
340   LLDB_INSTRUMENT_VA(this, output_stream, test_file);
341 
342   if (!m_opaque_sp)
343     SetOpaque(lldb::DisassemblerSP(),
344               lldb::InstructionSP(new PseudoInstruction()));
345 
346   lldb::InstructionSP inst_sp(GetOpaque());
347   if (inst_sp)
348     return inst_sp->TestEmulation(output_stream.ref(), test_file);
349   return false;
350 }
351