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