Path: blob/main/contrib/llvm-project/lldb/source/API/SBInstruction.cpp
39587 views
//===-- SBInstruction.cpp -------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "lldb/API/SBInstruction.h"9#include "lldb/Utility/Instrumentation.h"1011#include "lldb/API/SBAddress.h"12#include "lldb/API/SBFrame.h"13#include "lldb/API/SBFile.h"1415#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/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"2930#include <memory>3132// 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:52InstructionImpl(const lldb::DisassemblerSP &disasm_sp,53const lldb::InstructionSP &inst_sp)54: m_disasm_sp(disasm_sp), m_inst_sp(inst_sp) {}5556lldb::InstructionSP GetSP() const { return m_inst_sp; }5758bool IsValid() const { return (bool)m_inst_sp; }5960protected:61lldb::DisassemblerSP m_disasm_sp; // Can be empty/invalid62lldb::InstructionSP m_inst_sp;63};6465using namespace lldb;66using namespace lldb_private;6768SBInstruction::SBInstruction() { LLDB_INSTRUMENT_VA(this); }6970SBInstruction::SBInstruction(const lldb::DisassemblerSP &disasm_sp,71const lldb::InstructionSP &inst_sp)72: m_opaque_sp(new InstructionImpl(disasm_sp, inst_sp)) {}7374SBInstruction::SBInstruction(const SBInstruction &rhs)75: m_opaque_sp(rhs.m_opaque_sp) {76LLDB_INSTRUMENT_VA(this, rhs);77}7879const SBInstruction &SBInstruction::operator=(const SBInstruction &rhs) {80LLDB_INSTRUMENT_VA(this, rhs);8182if (this != &rhs)83m_opaque_sp = rhs.m_opaque_sp;84return *this;85}8687SBInstruction::~SBInstruction() = default;8889bool SBInstruction::IsValid() {90LLDB_INSTRUMENT_VA(this);91return this->operator bool();92}93SBInstruction::operator bool() const {94LLDB_INSTRUMENT_VA(this);9596return m_opaque_sp && m_opaque_sp->IsValid();97}9899SBAddress SBInstruction::GetAddress() {100LLDB_INSTRUMENT_VA(this);101102SBAddress sb_addr;103lldb::InstructionSP inst_sp(GetOpaque());104if (inst_sp && inst_sp->GetAddress().IsValid())105sb_addr.SetAddress(inst_sp->GetAddress());106return sb_addr;107}108109const char *SBInstruction::GetMnemonic(SBTarget target) {110LLDB_INSTRUMENT_VA(this, target);111112lldb::InstructionSP inst_sp(GetOpaque());113if (!inst_sp)114return nullptr;115116ExecutionContext exe_ctx;117TargetSP target_sp(target.GetSP());118std::unique_lock<std::recursive_mutex> lock;119if (target_sp) {120lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());121122target_sp->CalculateExecutionContext(exe_ctx);123exe_ctx.SetProcessSP(target_sp->GetProcessSP());124}125return ConstString(inst_sp->GetMnemonic(&exe_ctx)).GetCString();126}127128const char *SBInstruction::GetOperands(SBTarget target) {129LLDB_INSTRUMENT_VA(this, target);130131lldb::InstructionSP inst_sp(GetOpaque());132if (!inst_sp)133return nullptr;134135ExecutionContext exe_ctx;136TargetSP target_sp(target.GetSP());137std::unique_lock<std::recursive_mutex> lock;138if (target_sp) {139lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());140141target_sp->CalculateExecutionContext(exe_ctx);142exe_ctx.SetProcessSP(target_sp->GetProcessSP());143}144return ConstString(inst_sp->GetOperands(&exe_ctx)).GetCString();145}146147const char *SBInstruction::GetComment(SBTarget target) {148LLDB_INSTRUMENT_VA(this, target);149150lldb::InstructionSP inst_sp(GetOpaque());151if (!inst_sp)152return nullptr;153154ExecutionContext exe_ctx;155TargetSP target_sp(target.GetSP());156std::unique_lock<std::recursive_mutex> lock;157if (target_sp) {158lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());159160target_sp->CalculateExecutionContext(exe_ctx);161exe_ctx.SetProcessSP(target_sp->GetProcessSP());162}163return ConstString(inst_sp->GetComment(&exe_ctx)).GetCString();164}165166lldb::InstructionControlFlowKind SBInstruction::GetControlFlowKind(lldb::SBTarget target) {167LLDB_INSTRUMENT_VA(this, target);168169lldb::InstructionSP inst_sp(GetOpaque());170if (inst_sp) {171ExecutionContext exe_ctx;172TargetSP target_sp(target.GetSP());173std::unique_lock<std::recursive_mutex> lock;174if (target_sp) {175lock = std::unique_lock<std::recursive_mutex>(target_sp->GetAPIMutex());176177target_sp->CalculateExecutionContext(exe_ctx);178exe_ctx.SetProcessSP(target_sp->GetProcessSP());179}180return inst_sp->GetControlFlowKind(&exe_ctx);181}182return lldb::eInstructionControlFlowKindUnknown;183}184185size_t SBInstruction::GetByteSize() {186LLDB_INSTRUMENT_VA(this);187188lldb::InstructionSP inst_sp(GetOpaque());189if (inst_sp)190return inst_sp->GetOpcode().GetByteSize();191return 0;192}193194SBData SBInstruction::GetData(SBTarget target) {195LLDB_INSTRUMENT_VA(this, target);196197lldb::SBData sb_data;198lldb::InstructionSP inst_sp(GetOpaque());199if (inst_sp) {200DataExtractorSP data_extractor_sp(new DataExtractor());201if (inst_sp->GetData(*data_extractor_sp)) {202sb_data.SetOpaque(data_extractor_sp);203}204}205return sb_data;206}207208bool SBInstruction::DoesBranch() {209LLDB_INSTRUMENT_VA(this);210211lldb::InstructionSP inst_sp(GetOpaque());212if (inst_sp)213return inst_sp->DoesBranch();214return false;215}216217bool SBInstruction::HasDelaySlot() {218LLDB_INSTRUMENT_VA(this);219220lldb::InstructionSP inst_sp(GetOpaque());221if (inst_sp)222return inst_sp->HasDelaySlot();223return false;224}225226bool SBInstruction::CanSetBreakpoint() {227LLDB_INSTRUMENT_VA(this);228229lldb::InstructionSP inst_sp(GetOpaque());230if (inst_sp)231return inst_sp->CanSetBreakpoint();232return false;233}234235lldb::InstructionSP SBInstruction::GetOpaque() {236if (m_opaque_sp)237return m_opaque_sp->GetSP();238else239return lldb::InstructionSP();240}241242void SBInstruction::SetOpaque(const lldb::DisassemblerSP &disasm_sp,243const lldb::InstructionSP &inst_sp) {244m_opaque_sp = std::make_shared<InstructionImpl>(disasm_sp, inst_sp);245}246247bool SBInstruction::GetDescription(lldb::SBStream &s) {248LLDB_INSTRUMENT_VA(this, s);249250lldb::InstructionSP inst_sp(GetOpaque());251if (inst_sp) {252SymbolContext sc;253const Address &addr = inst_sp->GetAddress();254ModuleSP module_sp(addr.GetModule());255if (module_sp)256module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,257sc);258// Use the "ref()" instead of the "get()" accessor in case the SBStream259// didn't have a stream already created, one will get created...260FormatEntity::Entry format;261FormatEntity::Parse("${addr}: ", format);262inst_sp->Dump(&s.ref(), 0, true, false, /*show_control_flow_kind=*/false,263nullptr, &sc, nullptr, &format, 0);264return true;265}266return false;267}268269void SBInstruction::Print(FILE *outp) {270LLDB_INSTRUMENT_VA(this, outp);271FileSP out = std::make_shared<NativeFile>(outp, /*take_ownership=*/false);272Print(out);273}274275void SBInstruction::Print(SBFile out) {276LLDB_INSTRUMENT_VA(this, out);277Print(out.m_opaque_sp);278}279280void SBInstruction::Print(FileSP out_sp) {281LLDB_INSTRUMENT_VA(this, out_sp);282283if (!out_sp || !out_sp->IsValid())284return;285286lldb::InstructionSP inst_sp(GetOpaque());287if (inst_sp) {288SymbolContext sc;289const Address &addr = inst_sp->GetAddress();290ModuleSP module_sp(addr.GetModule());291if (module_sp)292module_sp->ResolveSymbolContextForAddress(addr, eSymbolContextEverything,293sc);294StreamFile out_stream(out_sp);295FormatEntity::Entry format;296FormatEntity::Parse("${addr}: ", format);297inst_sp->Dump(&out_stream, 0, true, false, /*show_control_flow_kind=*/false,298nullptr, &sc, nullptr, &format, 0);299}300}301302bool SBInstruction::EmulateWithFrame(lldb::SBFrame &frame,303uint32_t evaluate_options) {304LLDB_INSTRUMENT_VA(this, frame, evaluate_options);305306lldb::InstructionSP inst_sp(GetOpaque());307if (inst_sp) {308lldb::StackFrameSP frame_sp(frame.GetFrameSP());309310if (frame_sp) {311lldb_private::ExecutionContext exe_ctx;312frame_sp->CalculateExecutionContext(exe_ctx);313lldb_private::Target *target = exe_ctx.GetTargetPtr();314lldb_private::ArchSpec arch = target->GetArchitecture();315316return inst_sp->Emulate(317arch, evaluate_options, (void *)frame_sp.get(),318&lldb_private::EmulateInstruction::ReadMemoryFrame,319&lldb_private::EmulateInstruction::WriteMemoryFrame,320&lldb_private::EmulateInstruction::ReadRegisterFrame,321&lldb_private::EmulateInstruction::WriteRegisterFrame);322}323}324return false;325}326327bool SBInstruction::DumpEmulation(const char *triple) {328LLDB_INSTRUMENT_VA(this, triple);329330lldb::InstructionSP inst_sp(GetOpaque());331if (inst_sp && triple) {332return inst_sp->DumpEmulation(HostInfo::GetAugmentedArchSpec(triple));333}334return false;335}336337bool SBInstruction::TestEmulation(lldb::SBStream &output_stream,338const char *test_file) {339LLDB_INSTRUMENT_VA(this, output_stream, test_file);340341if (!m_opaque_sp)342SetOpaque(lldb::DisassemblerSP(),343lldb::InstructionSP(new PseudoInstruction()));344345lldb::InstructionSP inst_sp(GetOpaque());346if (inst_sp)347return inst_sp->TestEmulation(output_stream.ref(), test_file);348return false;349}350351352