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