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 98 return m_opaque_sp && m_opaque_sp->IsValid(); 99 } 100 101 SBAddress SBInstruction::GetAddress() { 102 LLDB_RECORD_METHOD_NO_ARGS(lldb::SBAddress, SBInstruction, GetAddress); 103 104 SBAddress sb_addr; 105 lldb::InstructionSP inst_sp(GetOpaque()); 106 if (inst_sp && inst_sp->GetAddress().IsValid()) 107 sb_addr.SetAddress(&inst_sp->GetAddress()); 108 return LLDB_RECORD_RESULT(sb_addr); 109 } 110 111 const char *SBInstruction::GetMnemonic(SBTarget target) { 112 LLDB_RECORD_METHOD(const char *, SBInstruction, GetMnemonic, (lldb::SBTarget), 113 target); 114 115 lldb::InstructionSP inst_sp(GetOpaque()); 116 if (inst_sp) { 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 inst_sp->GetMnemonic(&exe_ctx); 127 } 128 return NULL; 129 } 130 131 const char *SBInstruction::GetOperands(SBTarget target) { 132 LLDB_RECORD_METHOD(const char *, SBInstruction, GetOperands, (lldb::SBTarget), 133 target); 134 135 lldb::InstructionSP inst_sp(GetOpaque()); 136 if (inst_sp) { 137 ExecutionContext exe_ctx; 138 TargetSP target_sp(target.GetSP()); 139 std::unique_lock<std::recursive_mutex> lock; 140 if (target_sp) { 141 lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex()); 142 143 target_sp->CalculateExecutionContext(exe_ctx); 144 exe_ctx.SetProcessSP(target_sp->GetProcessSP()); 145 } 146 return inst_sp->GetOperands(&exe_ctx); 147 } 148 return NULL; 149 } 150 151 const char *SBInstruction::GetComment(SBTarget target) { 152 LLDB_RECORD_METHOD(const char *, SBInstruction, GetComment, (lldb::SBTarget), 153 target); 154 155 lldb::InstructionSP inst_sp(GetOpaque()); 156 if (inst_sp) { 157 ExecutionContext exe_ctx; 158 TargetSP target_sp(target.GetSP()); 159 std::unique_lock<std::recursive_mutex> lock; 160 if (target_sp) { 161 lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex()); 162 163 target_sp->CalculateExecutionContext(exe_ctx); 164 exe_ctx.SetProcessSP(target_sp->GetProcessSP()); 165 } 166 return inst_sp->GetComment(&exe_ctx); 167 } 168 return NULL; 169 } 170 171 size_t SBInstruction::GetByteSize() { 172 LLDB_RECORD_METHOD_NO_ARGS(size_t, SBInstruction, GetByteSize); 173 174 lldb::InstructionSP inst_sp(GetOpaque()); 175 if (inst_sp) 176 return inst_sp->GetOpcode().GetByteSize(); 177 return 0; 178 } 179 180 SBData SBInstruction::GetData(SBTarget target) { 181 LLDB_RECORD_METHOD(lldb::SBData, SBInstruction, GetData, (lldb::SBTarget), 182 target); 183 184 lldb::SBData sb_data; 185 lldb::InstructionSP inst_sp(GetOpaque()); 186 if (inst_sp) { 187 DataExtractorSP data_extractor_sp(new DataExtractor()); 188 if (inst_sp->GetData(*data_extractor_sp)) { 189 sb_data.SetOpaque(data_extractor_sp); 190 } 191 } 192 return LLDB_RECORD_RESULT(sb_data); 193 } 194 195 bool SBInstruction::DoesBranch() { 196 LLDB_RECORD_METHOD_NO_ARGS(bool, SBInstruction, DoesBranch); 197 198 lldb::InstructionSP inst_sp(GetOpaque()); 199 if (inst_sp) 200 return inst_sp->DoesBranch(); 201 return false; 202 } 203 204 bool SBInstruction::HasDelaySlot() { 205 LLDB_RECORD_METHOD_NO_ARGS(bool, SBInstruction, HasDelaySlot); 206 207 lldb::InstructionSP inst_sp(GetOpaque()); 208 if (inst_sp) 209 return inst_sp->HasDelaySlot(); 210 return false; 211 } 212 213 bool SBInstruction::CanSetBreakpoint() { 214 LLDB_RECORD_METHOD_NO_ARGS(bool, SBInstruction, CanSetBreakpoint); 215 216 lldb::InstructionSP inst_sp(GetOpaque()); 217 if (inst_sp) 218 return inst_sp->CanSetBreakpoint(); 219 return false; 220 } 221 222 lldb::InstructionSP SBInstruction::GetOpaque() { 223 if (m_opaque_sp) 224 return m_opaque_sp->GetSP(); 225 else 226 return lldb::InstructionSP(); 227 } 228 229 void SBInstruction::SetOpaque(const lldb::DisassemblerSP &disasm_sp, 230 const lldb::InstructionSP &inst_sp) { 231 m_opaque_sp = std::make_shared<InstructionImpl>(disasm_sp, inst_sp); 232 } 233 234 bool SBInstruction::GetDescription(lldb::SBStream &s) { 235 LLDB_RECORD_METHOD(bool, SBInstruction, GetDescription, (lldb::SBStream &), 236 s); 237 238 lldb::InstructionSP inst_sp(GetOpaque()); 239 if (inst_sp) { 240 SymbolContext sc; 241 const Address &addr = inst_sp->GetAddress(); 242 ModuleSP module_sp(addr.GetModule()); 243 if (module_sp) 244 module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, 245 sc); 246 // Use the "ref()" instead of the "get()" accessor in case the SBStream 247 // didn't have a stream already created, one will get created... 248 FormatEntity::Entry format; 249 FormatEntity::Parse("${addr}: ", format); 250 inst_sp->Dump(&s.ref(), 0, true, false, NULL, &sc, NULL, &format, 0); 251 return true; 252 } 253 return false; 254 } 255 256 void SBInstruction::Print(FILE *out) { 257 LLDB_RECORD_METHOD(void, SBInstruction, Print, (FILE *), out); 258 259 if (out == NULL) 260 return; 261 262 lldb::InstructionSP inst_sp(GetOpaque()); 263 if (inst_sp) { 264 SymbolContext sc; 265 const Address &addr = inst_sp->GetAddress(); 266 ModuleSP module_sp(addr.GetModule()); 267 if (module_sp) 268 module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything, 269 sc); 270 StreamFile out_stream(out, false); 271 FormatEntity::Entry format; 272 FormatEntity::Parse("${addr}: ", format); 273 inst_sp->Dump(&out_stream, 0, true, false, NULL, &sc, NULL, &format, 0); 274 } 275 } 276 277 bool SBInstruction::EmulateWithFrame(lldb::SBFrame &frame, 278 uint32_t evaluate_options) { 279 LLDB_RECORD_METHOD(bool, SBInstruction, EmulateWithFrame, 280 (lldb::SBFrame &, uint32_t), frame, evaluate_options); 281 282 lldb::InstructionSP inst_sp(GetOpaque()); 283 if (inst_sp) { 284 lldb::StackFrameSP frame_sp(frame.GetFrameSP()); 285 286 if (frame_sp) { 287 lldb_private::ExecutionContext exe_ctx; 288 frame_sp->CalculateExecutionContext(exe_ctx); 289 lldb_private::Target *target = exe_ctx.GetTargetPtr(); 290 lldb_private::ArchSpec arch = target->GetArchitecture(); 291 292 return inst_sp->Emulate( 293 arch, evaluate_options, (void *)frame_sp.get(), 294 &lldb_private::EmulateInstruction::ReadMemoryFrame, 295 &lldb_private::EmulateInstruction::WriteMemoryFrame, 296 &lldb_private::EmulateInstruction::ReadRegisterFrame, 297 &lldb_private::EmulateInstruction::WriteRegisterFrame); 298 } 299 } 300 return false; 301 } 302 303 bool SBInstruction::DumpEmulation(const char *triple) { 304 LLDB_RECORD_METHOD(bool, SBInstruction, DumpEmulation, (const char *), 305 triple); 306 307 lldb::InstructionSP inst_sp(GetOpaque()); 308 if (inst_sp && triple) { 309 return inst_sp->DumpEmulation(HostInfo::GetAugmentedArchSpec(triple)); 310 } 311 return false; 312 } 313 314 bool SBInstruction::TestEmulation(lldb::SBStream &output_stream, 315 const char *test_file) { 316 LLDB_RECORD_METHOD(bool, SBInstruction, TestEmulation, 317 (lldb::SBStream &, const char *), output_stream, 318 test_file); 319 320 if (!m_opaque_sp) 321 SetOpaque(lldb::DisassemblerSP(), 322 lldb::InstructionSP(new PseudoInstruction())); 323 324 lldb::InstructionSP inst_sp(GetOpaque()); 325 if (inst_sp) 326 return inst_sp->TestEmulation(output_stream.get(), test_file); 327 return false; 328 } 329