brintos

brintos / llvm-project-archived public Read only

0
0
Text · 7.6 KiB · 3748be0 Raw
232 lines · cpp
1//===-- ArchitectureMips.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 "Plugins/Architecture/Mips/ArchitectureMips.h"10#include "lldb/Core/Address.h"11#include "lldb/Core/Disassembler.h"12#include "lldb/Core/Module.h"13#include "lldb/Core/PluginManager.h"14#include "lldb/Symbol/Function.h"15#include "lldb/Symbol/SymbolContext.h"16#include "lldb/Target/SectionLoadList.h"17#include "lldb/Target/Target.h"18#include "lldb/Utility/ArchSpec.h"19#include "lldb/Utility/LLDBLog.h"20#include "lldb/Utility/Log.h"21 22using namespace lldb_private;23using namespace lldb;24 25LLDB_PLUGIN_DEFINE(ArchitectureMips)26 27void ArchitectureMips::Initialize() {28  PluginManager::RegisterPlugin(GetPluginNameStatic(),29                                "Mips-specific algorithms",30                                &ArchitectureMips::Create);31}32 33void ArchitectureMips::Terminate() {34  PluginManager::UnregisterPlugin(&ArchitectureMips::Create);35}36 37std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) {38  return arch.IsMIPS() ?39      std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr;40}41 42addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr,43                                                AddressClass addr_class) const {44  bool is_alternate_isa = false;45 46  switch (addr_class) {47  case AddressClass::eData:48  case AddressClass::eDebug:49    return LLDB_INVALID_ADDRESS;50  case AddressClass::eCodeAlternateISA:51    is_alternate_isa = true;52    break;53  default: break;54  }55 56  if ((code_addr & 2ull) || is_alternate_isa)57    return code_addr | 1u;58  return code_addr;59}60 61addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr,62                                              AddressClass addr_class) const {63  switch (addr_class) {64  case AddressClass::eData:65  case AddressClass::eDebug:66    return LLDB_INVALID_ADDRESS;67  default: break;68  }69  return opcode_addr & ~(1ull);70}71 72lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr,73                                                       Target &target) const {74 75  Log *log = GetLog(LLDBLog::Breakpoints);76 77  Address resolved_addr;78 79  if (!target.HasLoadedSections())80    // No sections are loaded, so we must assume we are not running yet and81    // need to operate only on file address.82    target.ResolveFileAddress(addr, resolved_addr);83  else84    target.ResolveLoadAddress(addr, resolved_addr);85 86  addr_t current_offset = 0;87 88  // Get the function boundaries to make sure we don't scan back before the89  // beginning of the current function.90  ModuleSP temp_addr_module_sp(resolved_addr.GetModule());91  if (temp_addr_module_sp) {92    SymbolContext sc;93    SymbolContextItem resolve_scope =94        eSymbolContextFunction | eSymbolContextSymbol;95    temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr,96      resolve_scope, sc);97    Address sym_addr;98    if (sc.function)99      sym_addr = sc.function->GetAddress();100    else if (sc.symbol)101      sym_addr = sc.symbol->GetAddress();102 103    addr_t function_start = sym_addr.GetLoadAddress(&target);104    if (function_start == LLDB_INVALID_ADDRESS)105      function_start = sym_addr.GetFileAddress();106 107    if (function_start)108      current_offset = addr - function_start;109  }110 111  // If breakpoint address is start of function then we dont have to do112  // anything.113  if (current_offset == 0)114    return addr;115 116  auto insn = GetInstructionAtAddress(target, current_offset, addr);117 118  if (nullptr == insn || !insn->HasDelaySlot())119    return addr;120 121  // Adjust the breakable address122  uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize();123  LLDB_LOGF(log,124            "Target::%s Breakpoint at 0x%8.8" PRIx64125            " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n",126            __FUNCTION__, addr, breakable_addr);127 128  return breakable_addr;129}130 131Instruction *ArchitectureMips::GetInstructionAtAddress(132    Target &target, const Address &resolved_addr, addr_t symbol_offset) const {133 134  auto loop_count = symbol_offset / 2;135 136  uint32_t arch_flags = m_arch.GetFlags();137  bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16;138  bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips;139 140  if (loop_count > 3) {141    // Scan previous 6 bytes142    if (IsMips16 | IsMicromips)143      loop_count = 3;144    // For mips-only, instructions are always 4 bytes, so scan previous 4145    // bytes only.146    else147      loop_count = 2;148  }149 150  // Create Disassembler Instance151  lldb::DisassemblerSP disasm_sp(152      Disassembler::FindPlugin(m_arch, nullptr, nullptr, nullptr, nullptr));153 154  InstructionList instruction_list;155  InstructionSP prev_insn;156  uint32_t inst_to_choose = 0;157 158  Address addr = resolved_addr;159 160  for (uint32_t i = 1; i <= loop_count; i++) {161    // Adjust the address to read from.162    addr.Slide(-2);163    uint32_t insn_size = 0;164 165    disasm_sp->ParseInstructions(target, addr,166                                 {Disassembler::Limit::Bytes, i * 2}, nullptr);167 168    uint32_t num_insns = disasm_sp->GetInstructionList().GetSize();169    if (num_insns) {170      prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0);171      insn_size = prev_insn->GetOpcode().GetByteSize();172      if (i == 1 && insn_size == 2) {173        // This looks like a valid 2-byte instruction (but it could be a part174        // of upper 4 byte instruction).175        instruction_list.Append(prev_insn);176        inst_to_choose = 1;177      }178      else if (i == 2) {179        // Here we may get one 4-byte instruction or two 2-byte instructions.180        if (num_insns == 2) {181          // Looks like there are two 2-byte instructions above our182          // breakpoint target address. Now the upper 2-byte instruction is183          // either a valid 2-byte instruction or could be a part of it's184          // upper 4-byte instruction. In both cases we don't care because in185          // this case lower 2-byte instruction is definitely a valid186          // instruction and whatever i=1 iteration has found out is true.187          inst_to_choose = 1;188          break;189        }190        else if (insn_size == 4) {191          // This instruction claims its a valid 4-byte instruction. But it192          // could be a part of it's upper 4-byte instruction. Lets try193          // scanning upper 2 bytes to verify this.194          instruction_list.Append(prev_insn);195          inst_to_choose = 2;196        }197      }198      else if (i == 3) {199        if (insn_size == 4)200          // FIXME: We reached here that means instruction at [target - 4] has201          // already claimed to be a 4-byte instruction, and now instruction202          // at [target - 6] is also claiming that it's a 4-byte instruction.203          // This can not be true. In this case we can not decide the valid204          // previous instruction so we let lldb set the breakpoint at the205          // address given by user.206          inst_to_choose = 0;207        else208          // This is straight-forward209          inst_to_choose = 2;210        break;211      }212    }213    else {214      // Decode failed, bytes do not form a valid instruction. So whatever215      // previous iteration has found out is true.216      if (i > 1) {217        inst_to_choose = i - 1;218        break;219      }220    }221  }222 223  // Check if we are able to find any valid instruction.224  if (inst_to_choose) {225    if (inst_to_choose > instruction_list.GetSize())226      inst_to_choose--;227    return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get();228  }229 230  return nullptr;231}232