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