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