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