351 lines · cpp
1//===-- SBInstruction.cpp -------------------------------------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "lldb/API/SBInstruction.h"10#include "lldb/Utility/Instrumentation.h"11 12#include "lldb/API/SBAddress.h"13#include "lldb/API/SBFile.h"14#include "lldb/API/SBFrame.h"15 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/Host/HostInfo.h"22#include "lldb/Host/StreamFile.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 the33// instruction will only hold a weak reference to the disassembler to avoid a34// cycle that was keeping both objects alive (leak) and we need the35// InstructionImpl class to make sure our public API behaves as users would36// 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 the44// SBInstructionList that was returned by lldb.target.ReadInstructions() that45// will go away after line 2 but the "inst" object should be able to still46// answer questions about itself. So we make sure that any SBInstruction47// objects that are given out have a strong reference to the disassembler and48// the instruction so that the object can live and successfully respond to all49// queries.50class InstructionImpl {51public: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 60protected:61 lldb::DisassemblerSP m_disasm_sp; // Can be empty/invalid62 lldb::InstructionSP m_inst_sp;63};64 65using namespace lldb;66using namespace lldb_private;67 68SBInstruction::SBInstruction() { LLDB_INSTRUMENT_VA(this); }69 70SBInstruction::SBInstruction(const lldb::DisassemblerSP &disasm_sp,71 const lldb::InstructionSP &inst_sp)72 : m_opaque_sp(new InstructionImpl(disasm_sp, inst_sp)) {}73 74SBInstruction::SBInstruction(const SBInstruction &rhs)75 : m_opaque_sp(rhs.m_opaque_sp) {76 LLDB_INSTRUMENT_VA(this, rhs);77}78 79const SBInstruction &SBInstruction::operator=(const SBInstruction &rhs) {80 LLDB_INSTRUMENT_VA(this, rhs);81 82 if (this != &rhs)83 m_opaque_sp = rhs.m_opaque_sp;84 return *this;85}86 87SBInstruction::~SBInstruction() = default;88 89bool SBInstruction::IsValid() {90 LLDB_INSTRUMENT_VA(this);91 return this->operator bool();92}93SBInstruction::operator bool() const {94 LLDB_INSTRUMENT_VA(this);95 96 return m_opaque_sp && m_opaque_sp->IsValid();97}98 99SBAddress SBInstruction::GetAddress() {100 LLDB_INSTRUMENT_VA(this);101 102 SBAddress sb_addr;103 lldb::InstructionSP inst_sp(GetOpaque());104 if (inst_sp && inst_sp->GetAddress().IsValid())105 sb_addr.SetAddress(inst_sp->GetAddress());106 return sb_addr;107}108 109const char *SBInstruction::GetMnemonic(SBTarget target) {110 LLDB_INSTRUMENT_VA(this, target);111 112 lldb::InstructionSP inst_sp(GetOpaque());113 if (!inst_sp)114 return nullptr;115 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 ConstString(inst_sp->GetMnemonic(&exe_ctx)).GetCString();126}127 128const char *SBInstruction::GetOperands(SBTarget target) {129 LLDB_INSTRUMENT_VA(this, target);130 131 lldb::InstructionSP inst_sp(GetOpaque());132 if (!inst_sp)133 return nullptr;134 135 ExecutionContext exe_ctx;136 TargetSP target_sp(target.GetSP());137 std::unique_lock<std::recursive_mutex> lock;138 if (target_sp) {139 lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());140 141 target_sp->CalculateExecutionContext(exe_ctx);142 exe_ctx.SetProcessSP(target_sp->GetProcessSP());143 }144 return ConstString(inst_sp->GetOperands(&exe_ctx)).GetCString();145}146 147const char *SBInstruction::GetComment(SBTarget target) {148 LLDB_INSTRUMENT_VA(this, target);149 150 lldb::InstructionSP inst_sp(GetOpaque());151 if (!inst_sp)152 return nullptr;153 154 ExecutionContext exe_ctx;155 TargetSP target_sp(target.GetSP());156 std::unique_lock<std::recursive_mutex> lock;157 if (target_sp) {158 lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());159 160 target_sp->CalculateExecutionContext(exe_ctx);161 exe_ctx.SetProcessSP(target_sp->GetProcessSP());162 }163 return ConstString(inst_sp->GetComment(&exe_ctx)).GetCString();164}165 166lldb::InstructionControlFlowKind SBInstruction::GetControlFlowKind(lldb::SBTarget target) {167 LLDB_INSTRUMENT_VA(this, target);168 169 lldb::InstructionSP inst_sp(GetOpaque());170 if (inst_sp) {171 ExecutionContext exe_ctx;172 TargetSP target_sp(target.GetSP());173 std::unique_lock<std::recursive_mutex> lock;174 if (target_sp) {175 lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());176 177 target_sp->CalculateExecutionContext(exe_ctx);178 exe_ctx.SetProcessSP(target_sp->GetProcessSP());179 }180 return inst_sp->GetControlFlowKind(&exe_ctx);181 }182 return lldb::eInstructionControlFlowKindUnknown;183}184 185size_t SBInstruction::GetByteSize() {186 LLDB_INSTRUMENT_VA(this);187 188 lldb::InstructionSP inst_sp(GetOpaque());189 if (inst_sp)190 return inst_sp->GetOpcode().GetByteSize();191 return 0;192}193 194SBData SBInstruction::GetData(SBTarget target) {195 LLDB_INSTRUMENT_VA(this, target);196 197 lldb::SBData sb_data;198 lldb::InstructionSP inst_sp(GetOpaque());199 if (inst_sp) {200 DataExtractorSP data_extractor_sp(new DataExtractor());201 if (inst_sp->GetData(*data_extractor_sp)) {202 sb_data.SetOpaque(data_extractor_sp);203 }204 }205 return sb_data;206}207 208bool SBInstruction::DoesBranch() {209 LLDB_INSTRUMENT_VA(this);210 211 lldb::InstructionSP inst_sp(GetOpaque());212 if (inst_sp)213 return inst_sp->DoesBranch();214 return false;215}216 217bool SBInstruction::HasDelaySlot() {218 LLDB_INSTRUMENT_VA(this);219 220 lldb::InstructionSP inst_sp(GetOpaque());221 if (inst_sp)222 return inst_sp->HasDelaySlot();223 return false;224}225 226bool SBInstruction::CanSetBreakpoint() {227 LLDB_INSTRUMENT_VA(this);228 229 lldb::InstructionSP inst_sp(GetOpaque());230 if (inst_sp)231 return inst_sp->CanSetBreakpoint();232 return false;233}234 235lldb::InstructionSP SBInstruction::GetOpaque() {236 if (m_opaque_sp)237 return m_opaque_sp->GetSP();238 else239 return lldb::InstructionSP();240}241 242void SBInstruction::SetOpaque(const lldb::DisassemblerSP &disasm_sp,243 const lldb::InstructionSP &inst_sp) {244 m_opaque_sp = std::make_shared<InstructionImpl>(disasm_sp, inst_sp);245}246 247bool SBInstruction::GetDescription(lldb::SBStream &s) {248 LLDB_INSTRUMENT_VA(this, s);249 250 lldb::InstructionSP inst_sp(GetOpaque());251 if (inst_sp) {252 SymbolContext sc;253 const Address &addr = inst_sp->GetAddress();254 ModuleSP module_sp(addr.GetModule());255 if (module_sp)256 module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,257 sc);258 // Use the "ref()" instead of the "get()" accessor in case the SBStream259 // didn't have a stream already created, one will get created...260 FormatEntity::Entry format;261 FormatEntity::Parse("${addr}: ", format);262 inst_sp->Dump(&s.ref(), 0, true, false, /*show_control_flow_kind=*/false,263 nullptr, &sc, nullptr, &format, 0);264 return true;265 }266 return false;267}268 269void SBInstruction::Print(FILE *outp) {270 LLDB_INSTRUMENT_VA(this, outp);271 FileSP out = std::make_shared<NativeFile>(outp, File::eOpenOptionWriteOnly,272 /*take_ownership=*/false);273 Print(out);274}275 276void SBInstruction::Print(SBFile out) {277 LLDB_INSTRUMENT_VA(this, out);278 Print(out.m_opaque_sp);279}280 281void SBInstruction::Print(FileSP out_sp) {282 LLDB_INSTRUMENT_VA(this, out_sp);283 284 if (!out_sp || !out_sp->IsValid())285 return;286 287 lldb::InstructionSP inst_sp(GetOpaque());288 if (inst_sp) {289 SymbolContext sc;290 const Address &addr = inst_sp->GetAddress();291 ModuleSP module_sp(addr.GetModule());292 if (module_sp)293 module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,294 sc);295 StreamFile out_stream(out_sp);296 FormatEntity::Entry format;297 FormatEntity::Parse("${addr}: ", format);298 inst_sp->Dump(&out_stream, 0, true, false, /*show_control_flow_kind=*/false,299 nullptr, &sc, nullptr, &format, 0);300 }301}302 303bool SBInstruction::EmulateWithFrame(lldb::SBFrame &frame,304 uint32_t evaluate_options) {305 LLDB_INSTRUMENT_VA(this, frame, evaluate_options);306 307 lldb::InstructionSP inst_sp(GetOpaque());308 if (inst_sp) {309 lldb::StackFrameSP frame_sp(frame.GetFrameSP());310 311 if (frame_sp) {312 lldb_private::ExecutionContext exe_ctx;313 frame_sp->CalculateExecutionContext(exe_ctx);314 lldb_private::Target *target = exe_ctx.GetTargetPtr();315 lldb_private::ArchSpec arch = target->GetArchitecture();316 317 return inst_sp->Emulate(318 arch, evaluate_options, (void *)frame_sp.get(),319 &lldb_private::EmulateInstruction::ReadMemoryFrame,320 &lldb_private::EmulateInstruction::WriteMemoryFrame,321 &lldb_private::EmulateInstruction::ReadRegisterFrame,322 &lldb_private::EmulateInstruction::WriteRegisterFrame);323 }324 }325 return false;326}327 328bool SBInstruction::DumpEmulation(const char *triple) {329 LLDB_INSTRUMENT_VA(this, triple);330 331 lldb::InstructionSP inst_sp(GetOpaque());332 if (inst_sp && triple) {333 return inst_sp->DumpEmulation(HostInfo::GetAugmentedArchSpec(triple));334 }335 return false;336}337 338bool SBInstruction::TestEmulation(lldb::SBStream &output_stream,339 const char *test_file) {340 LLDB_INSTRUMENT_VA(this, output_stream, test_file);341 342 if (!m_opaque_sp)343 SetOpaque(lldb::DisassemblerSP(),344 lldb::InstructionSP(new PseudoInstruction()));345 346 lldb::InstructionSP inst_sp(GetOpaque());347 if (inst_sp)348 return inst_sp->TestEmulation(output_stream.ref(), test_file);349 return false;350}351