brintos

brintos / llvm-project-archived public Read only

0
0
Text · 10.5 KiB · 5921511 Raw
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