1 //===-- SBInstruction.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/SBInstruction.h"
10 #include "SBReproducerPrivate.h"
11 
12 #include "lldb/API/SBAddress.h"
13 #include "lldb/API/SBFrame.h"
14 
15 #include "lldb/API/SBInstruction.h"
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/Core/StreamFile.h"
22 #include "lldb/Host/HostInfo.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 //----------------------------------------------------------------------
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 //----------------------------------------------------------------------
52 class InstructionImpl {
53 public:
54   InstructionImpl(const lldb::DisassemblerSP &disasm_sp,
55                   const lldb::InstructionSP &inst_sp)
56       : m_disasm_sp(disasm_sp), m_inst_sp(inst_sp) {}
57 
58   lldb::InstructionSP GetSP() const { return m_inst_sp; }
59 
60   bool IsValid() const { return (bool)m_inst_sp; }
61 
62 protected:
63   lldb::DisassemblerSP m_disasm_sp; // Can be empty/invalid
64   lldb::InstructionSP m_inst_sp;
65 };
66 
67 using namespace lldb;
68 using namespace lldb_private;
69 
70 SBInstruction::SBInstruction() : m_opaque_sp() {
71   LLDB_RECORD_CONSTRUCTOR_NO_ARGS(SBInstruction);
72 }
73 
74 SBInstruction::SBInstruction(const lldb::DisassemblerSP &disasm_sp,
75                              const lldb::InstructionSP &inst_sp)
76     : m_opaque_sp(new InstructionImpl(disasm_sp, inst_sp)) {}
77 
78 SBInstruction::SBInstruction(const SBInstruction &rhs)
79     : m_opaque_sp(rhs.m_opaque_sp) {
80   LLDB_RECORD_CONSTRUCTOR(SBInstruction, (const lldb::SBInstruction &), rhs);
81 }
82 
83 const SBInstruction &SBInstruction::operator=(const SBInstruction &rhs) {
84   LLDB_RECORD_METHOD(const lldb::SBInstruction &,
85                      SBInstruction, operator=,(const lldb::SBInstruction &),
86                      rhs);
87 
88   if (this != &rhs)
89     m_opaque_sp = rhs.m_opaque_sp;
90   return *this;
91 }
92 
93 SBInstruction::~SBInstruction() {}
94 
95 bool SBInstruction::IsValid() {
96   LLDB_RECORD_METHOD_NO_ARGS(bool, SBInstruction, IsValid);
97   return this->operator bool();
98 }
99 SBInstruction::operator bool() const {
100   LLDB_RECORD_METHOD_CONST_NO_ARGS(bool, SBInstruction, operator bool);
101 
102   return m_opaque_sp && m_opaque_sp->IsValid();
103 }
104 
105 SBAddress SBInstruction::GetAddress() {
106   LLDB_RECORD_METHOD_NO_ARGS(lldb::SBAddress, SBInstruction, GetAddress);
107 
108   SBAddress sb_addr;
109   lldb::InstructionSP inst_sp(GetOpaque());
110   if (inst_sp && inst_sp->GetAddress().IsValid())
111     sb_addr.SetAddress(&inst_sp->GetAddress());
112   return LLDB_RECORD_RESULT(sb_addr);
113 }
114 
115 const char *SBInstruction::GetMnemonic(SBTarget target) {
116   LLDB_RECORD_METHOD(const char *, SBInstruction, GetMnemonic, (lldb::SBTarget),
117                      target);
118 
119   lldb::InstructionSP inst_sp(GetOpaque());
120   if (inst_sp) {
121     ExecutionContext exe_ctx;
122     TargetSP target_sp(target.GetSP());
123     std::unique_lock<std::recursive_mutex> lock;
124     if (target_sp) {
125       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
126 
127       target_sp->CalculateExecutionContext(exe_ctx);
128       exe_ctx.SetProcessSP(target_sp->GetProcessSP());
129     }
130     return inst_sp->GetMnemonic(&exe_ctx);
131   }
132   return NULL;
133 }
134 
135 const char *SBInstruction::GetOperands(SBTarget target) {
136   LLDB_RECORD_METHOD(const char *, SBInstruction, GetOperands, (lldb::SBTarget),
137                      target);
138 
139   lldb::InstructionSP inst_sp(GetOpaque());
140   if (inst_sp) {
141     ExecutionContext exe_ctx;
142     TargetSP target_sp(target.GetSP());
143     std::unique_lock<std::recursive_mutex> lock;
144     if (target_sp) {
145       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
146 
147       target_sp->CalculateExecutionContext(exe_ctx);
148       exe_ctx.SetProcessSP(target_sp->GetProcessSP());
149     }
150     return inst_sp->GetOperands(&exe_ctx);
151   }
152   return NULL;
153 }
154 
155 const char *SBInstruction::GetComment(SBTarget target) {
156   LLDB_RECORD_METHOD(const char *, SBInstruction, GetComment, (lldb::SBTarget),
157                      target);
158 
159   lldb::InstructionSP inst_sp(GetOpaque());
160   if (inst_sp) {
161     ExecutionContext exe_ctx;
162     TargetSP target_sp(target.GetSP());
163     std::unique_lock<std::recursive_mutex> lock;
164     if (target_sp) {
165       lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());
166 
167       target_sp->CalculateExecutionContext(exe_ctx);
168       exe_ctx.SetProcessSP(target_sp->GetProcessSP());
169     }
170     return inst_sp->GetComment(&exe_ctx);
171   }
172   return NULL;
173 }
174 
175 size_t SBInstruction::GetByteSize() {
176   LLDB_RECORD_METHOD_NO_ARGS(size_t, SBInstruction, GetByteSize);
177 
178   lldb::InstructionSP inst_sp(GetOpaque());
179   if (inst_sp)
180     return inst_sp->GetOpcode().GetByteSize();
181   return 0;
182 }
183 
184 SBData SBInstruction::GetData(SBTarget target) {
185   LLDB_RECORD_METHOD(lldb::SBData, SBInstruction, GetData, (lldb::SBTarget),
186                      target);
187 
188   lldb::SBData sb_data;
189   lldb::InstructionSP inst_sp(GetOpaque());
190   if (inst_sp) {
191     DataExtractorSP data_extractor_sp(new DataExtractor());
192     if (inst_sp->GetData(*data_extractor_sp)) {
193       sb_data.SetOpaque(data_extractor_sp);
194     }
195   }
196   return LLDB_RECORD_RESULT(sb_data);
197 }
198 
199 bool SBInstruction::DoesBranch() {
200   LLDB_RECORD_METHOD_NO_ARGS(bool, SBInstruction, DoesBranch);
201 
202   lldb::InstructionSP inst_sp(GetOpaque());
203   if (inst_sp)
204     return inst_sp->DoesBranch();
205   return false;
206 }
207 
208 bool SBInstruction::HasDelaySlot() {
209   LLDB_RECORD_METHOD_NO_ARGS(bool, SBInstruction, HasDelaySlot);
210 
211   lldb::InstructionSP inst_sp(GetOpaque());
212   if (inst_sp)
213     return inst_sp->HasDelaySlot();
214   return false;
215 }
216 
217 bool SBInstruction::CanSetBreakpoint() {
218   LLDB_RECORD_METHOD_NO_ARGS(bool, SBInstruction, CanSetBreakpoint);
219 
220   lldb::InstructionSP inst_sp(GetOpaque());
221   if (inst_sp)
222     return inst_sp->CanSetBreakpoint();
223   return false;
224 }
225 
226 lldb::InstructionSP SBInstruction::GetOpaque() {
227   if (m_opaque_sp)
228     return m_opaque_sp->GetSP();
229   else
230     return lldb::InstructionSP();
231 }
232 
233 void SBInstruction::SetOpaque(const lldb::DisassemblerSP &disasm_sp,
234                               const lldb::InstructionSP &inst_sp) {
235   m_opaque_sp = std::make_shared<InstructionImpl>(disasm_sp, inst_sp);
236 }
237 
238 bool SBInstruction::GetDescription(lldb::SBStream &s) {
239   LLDB_RECORD_METHOD(bool, SBInstruction, GetDescription, (lldb::SBStream &),
240                      s);
241 
242   lldb::InstructionSP inst_sp(GetOpaque());
243   if (inst_sp) {
244     SymbolContext sc;
245     const Address &addr = inst_sp->GetAddress();
246     ModuleSP module_sp(addr.GetModule());
247     if (module_sp)
248       module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,
249                                                 sc);
250     // Use the "ref()" instead of the "get()" accessor in case the SBStream
251     // didn't have a stream already created, one will get created...
252     FormatEntity::Entry format;
253     FormatEntity::Parse("${addr}: ", format);
254     inst_sp->Dump(&s.ref(), 0, true, false, NULL, &sc, NULL, &format, 0);
255     return true;
256   }
257   return false;
258 }
259 
260 void SBInstruction::Print(FILE *out) {
261   LLDB_RECORD_METHOD(void, SBInstruction, Print, (FILE *), out);
262 
263   if (out == NULL)
264     return;
265 
266   lldb::InstructionSP inst_sp(GetOpaque());
267   if (inst_sp) {
268     SymbolContext sc;
269     const Address &addr = inst_sp->GetAddress();
270     ModuleSP module_sp(addr.GetModule());
271     if (module_sp)
272       module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,
273                                                 sc);
274     StreamFile out_stream(out, false);
275     FormatEntity::Entry format;
276     FormatEntity::Parse("${addr}: ", format);
277     inst_sp->Dump(&out_stream, 0, true, false, NULL, &sc, NULL, &format, 0);
278   }
279 }
280 
281 bool SBInstruction::EmulateWithFrame(lldb::SBFrame &frame,
282                                      uint32_t evaluate_options) {
283   LLDB_RECORD_METHOD(bool, SBInstruction, EmulateWithFrame,
284                      (lldb::SBFrame &, uint32_t), frame, evaluate_options);
285 
286   lldb::InstructionSP inst_sp(GetOpaque());
287   if (inst_sp) {
288     lldb::StackFrameSP frame_sp(frame.GetFrameSP());
289 
290     if (frame_sp) {
291       lldb_private::ExecutionContext exe_ctx;
292       frame_sp->CalculateExecutionContext(exe_ctx);
293       lldb_private::Target *target = exe_ctx.GetTargetPtr();
294       lldb_private::ArchSpec arch = target->GetArchitecture();
295 
296       return inst_sp->Emulate(
297           arch, evaluate_options, (void *)frame_sp.get(),
298           &lldb_private::EmulateInstruction::ReadMemoryFrame,
299           &lldb_private::EmulateInstruction::WriteMemoryFrame,
300           &lldb_private::EmulateInstruction::ReadRegisterFrame,
301           &lldb_private::EmulateInstruction::WriteRegisterFrame);
302     }
303   }
304   return false;
305 }
306 
307 bool SBInstruction::DumpEmulation(const char *triple) {
308   LLDB_RECORD_METHOD(bool, SBInstruction, DumpEmulation, (const char *),
309                      triple);
310 
311   lldb::InstructionSP inst_sp(GetOpaque());
312   if (inst_sp && triple) {
313     return inst_sp->DumpEmulation(HostInfo::GetAugmentedArchSpec(triple));
314   }
315   return false;
316 }
317 
318 bool SBInstruction::TestEmulation(lldb::SBStream &output_stream,
319                                   const char *test_file) {
320   LLDB_RECORD_METHOD(bool, SBInstruction, TestEmulation,
321                      (lldb::SBStream &, const char *), output_stream,
322                      test_file);
323 
324   if (!m_opaque_sp)
325     SetOpaque(lldb::DisassemblerSP(),
326               lldb::InstructionSP(new PseudoInstruction()));
327 
328   lldb::InstructionSP inst_sp(GetOpaque());
329   if (inst_sp)
330     return inst_sp->TestEmulation(output_stream.get(), test_file);
331   return false;
332 }
333 
334 namespace lldb_private {
335 namespace repro {
336 
337 template <>
338 void RegisterMethods<SBInstruction>(Registry &R) {
339   LLDB_REGISTER_CONSTRUCTOR(SBInstruction, ());
340   LLDB_REGISTER_CONSTRUCTOR(SBInstruction, (const lldb::SBInstruction &));
341   LLDB_REGISTER_METHOD(
342       const lldb::SBInstruction &,
343       SBInstruction, operator=,(const lldb::SBInstruction &));
344   LLDB_REGISTER_METHOD(bool, SBInstruction, IsValid, ());
345   LLDB_REGISTER_METHOD_CONST(bool, SBInstruction, operator bool, ());
346   LLDB_REGISTER_METHOD(lldb::SBAddress, SBInstruction, GetAddress, ());
347   LLDB_REGISTER_METHOD(const char *, SBInstruction, GetMnemonic,
348                        (lldb::SBTarget));
349   LLDB_REGISTER_METHOD(const char *, SBInstruction, GetOperands,
350                        (lldb::SBTarget));
351   LLDB_REGISTER_METHOD(const char *, SBInstruction, GetComment,
352                        (lldb::SBTarget));
353   LLDB_REGISTER_METHOD(size_t, SBInstruction, GetByteSize, ());
354   LLDB_REGISTER_METHOD(lldb::SBData, SBInstruction, GetData,
355                        (lldb::SBTarget));
356   LLDB_REGISTER_METHOD(bool, SBInstruction, DoesBranch, ());
357   LLDB_REGISTER_METHOD(bool, SBInstruction, HasDelaySlot, ());
358   LLDB_REGISTER_METHOD(bool, SBInstruction, CanSetBreakpoint, ());
359   LLDB_REGISTER_METHOD(bool, SBInstruction, GetDescription,
360                        (lldb::SBStream &));
361   LLDB_REGISTER_METHOD(void, SBInstruction, Print, (FILE *));
362   LLDB_REGISTER_METHOD(bool, SBInstruction, EmulateWithFrame,
363                        (lldb::SBFrame &, uint32_t));
364   LLDB_REGISTER_METHOD(bool, SBInstruction, DumpEmulation, (const char *));
365   LLDB_REGISTER_METHOD(bool, SBInstruction, TestEmulation,
366                        (lldb::SBStream &, const char *));
367 }
368 
369 }
370 }
371