diff options
Diffstat (limited to 'source/Plugins/Architecture/Mips/ArchitectureMips.cpp')
| -rw-r--r-- | source/Plugins/Architecture/Mips/ArchitectureMips.cpp | 241 | 
1 files changed, 241 insertions, 0 deletions
diff --git a/source/Plugins/Architecture/Mips/ArchitectureMips.cpp b/source/Plugins/Architecture/Mips/ArchitectureMips.cpp new file mode 100644 index 0000000000000..0cbbd99223213 --- /dev/null +++ b/source/Plugins/Architecture/Mips/ArchitectureMips.cpp @@ -0,0 +1,241 @@ +//===-- ArchitectureMips.cpp -------------------------------------*- C++ -*-===// +// +//                     The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/Architecture/Mips/ArchitectureMips.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Log.h" + +using namespace lldb_private; +using namespace lldb; + +ConstString ArchitectureMips::GetPluginNameStatic() { +  return ConstString("mips"); +} + +void ArchitectureMips::Initialize() { +  PluginManager::RegisterPlugin(GetPluginNameStatic(), +                                "Mips-specific algorithms", +                                &ArchitectureMips::Create); +} + +void ArchitectureMips::Terminate() { +  PluginManager::UnregisterPlugin(&ArchitectureMips::Create); +} + +std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) { +  return arch.IsMIPS() ? +      std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr; +} + +ConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ArchitectureMips::GetPluginVersion() { return 1; } + +addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr, +                                                AddressClass addr_class) const { +  bool is_alternate_isa = false; + +  switch (addr_class) { +  case AddressClass::eData: +  case AddressClass::eDebug: +    return LLDB_INVALID_ADDRESS; +  case AddressClass::eCodeAlternateISA: +    is_alternate_isa = true; +    break; +  default: break; +  } + +  if ((code_addr & 2ull) || is_alternate_isa) +    return code_addr | 1u; +  return code_addr; +} + +addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr, +                                              AddressClass addr_class) const { +  switch (addr_class) { +  case AddressClass::eData: +  case AddressClass::eDebug: +    return LLDB_INVALID_ADDRESS; +  default: break; +  } +  return opcode_addr & ~(1ull); +} + +lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr, +                                                       Target &target) const { + +  Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + +  Address resolved_addr; + +  SectionLoadList §ion_load_list = target.GetSectionLoadList(); +  if (section_load_list.IsEmpty()) +    // No sections are loaded, so we must assume we are not running yet and +    // need to operate only on file address. +    target.ResolveFileAddress(addr, resolved_addr); +  else +    target.ResolveLoadAddress(addr, resolved_addr); + +  addr_t current_offset = 0; + +  // Get the function boundaries to make sure we don't scan back before the +  // beginning of the current function. +  ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); +  if (temp_addr_module_sp) { +    SymbolContext sc; +    SymbolContextItem resolve_scope = +        eSymbolContextFunction | eSymbolContextSymbol; +    temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, +      resolve_scope, sc); +    Address sym_addr; +    if (sc.function) +      sym_addr = sc.function->GetAddressRange().GetBaseAddress(); +    else if (sc.symbol) +      sym_addr = sc.symbol->GetAddress(); + +    addr_t function_start = sym_addr.GetLoadAddress(&target); +    if (function_start == LLDB_INVALID_ADDRESS) +      function_start = sym_addr.GetFileAddress(); + +    if (function_start) +      current_offset = addr - function_start; +  } + +  // If breakpoint address is start of function then we dont have to do +  // anything. +  if (current_offset == 0) +    return addr; + +  ExecutionContext ctx; +  target.CalculateExecutionContext(ctx); +  auto insn = GetInstructionAtAddress(ctx, current_offset, addr); + +  if (nullptr == insn || !insn->HasDelaySlot()) +    return addr; + +  // Adjust the breakable address +  uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize(); +  if (log) +    log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64 +      " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", +      __FUNCTION__, addr, breakable_addr); + +  return breakable_addr; +} + +Instruction *ArchitectureMips::GetInstructionAtAddress( +    const ExecutionContext &exe_ctx, const Address &resolved_addr, +    addr_t symbol_offset) const { + +  auto loop_count = symbol_offset / 2; + +  uint32_t arch_flags = m_arch.GetFlags(); +  bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; +  bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; + +  if (loop_count > 3) { +    // Scan previous 6 bytes +    if (IsMips16 | IsMicromips) +      loop_count = 3; +    // For mips-only, instructions are always 4 bytes, so scan previous 4 +    // bytes only. +    else +      loop_count = 2; +  } + +  // Create Disassembler Instance +  lldb::DisassemblerSP disasm_sp( +    Disassembler::FindPlugin(m_arch, nullptr, nullptr)); + +  InstructionList instruction_list; +  InstructionSP prev_insn; +  bool prefer_file_cache = true; // Read from file +  uint32_t inst_to_choose = 0; + +  Address addr = resolved_addr; + +  for (uint32_t i = 1; i <= loop_count; i++) { +    // Adjust the address to read from. +    addr.Slide(-2); +    AddressRange range(addr, i * 2); +    uint32_t insn_size = 0; + +    disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); + +    uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); +    if (num_insns) { +      prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); +      insn_size = prev_insn->GetOpcode().GetByteSize(); +      if (i == 1 && insn_size == 2) { +        // This looks like a valid 2-byte instruction (but it could be a part +        // of upper 4 byte instruction). +        instruction_list.Append(prev_insn); +        inst_to_choose = 1; +      } +      else if (i == 2) { +        // Here we may get one 4-byte instruction or two 2-byte instructions. +        if (num_insns == 2) { +          // Looks like there are two 2-byte instructions above our +          // breakpoint target address. Now the upper 2-byte instruction is +          // either a valid 2-byte instruction or could be a part of it's +          // upper 4-byte instruction. In both cases we don't care because in +          // this case lower 2-byte instruction is definitely a valid +          // instruction and whatever i=1 iteration has found out is true. +          inst_to_choose = 1; +          break; +        } +        else if (insn_size == 4) { +          // This instruction claims its a valid 4-byte instruction. But it +          // could be a part of it's upper 4-byte instruction. Lets try +          // scanning upper 2 bytes to verify this. +          instruction_list.Append(prev_insn); +          inst_to_choose = 2; +        } +      } +      else if (i == 3) { +        if (insn_size == 4) +          // FIXME: We reached here that means instruction at [target - 4] has +          // already claimed to be a 4-byte instruction, and now instruction +          // at [target - 6] is also claiming that it's a 4-byte instruction. +          // This can not be true. In this case we can not decide the valid +          // previous instruction so we let lldb set the breakpoint at the +          // address given by user. +          inst_to_choose = 0; +        else +          // This is straight-forward +          inst_to_choose = 2; +        break; +      } +    } +    else { +      // Decode failed, bytes do not form a valid instruction. So whatever +      // previous iteration has found out is true. +      if (i > 1) { +        inst_to_choose = i - 1; +        break; +      } +    } +  } + +  // Check if we are able to find any valid instruction. +  if (inst_to_choose) { +    if (inst_to_choose > instruction_list.GetSize()) +      inst_to_choose--; +    return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get(); +  } + +  return nullptr; +}  | 
