| //===-- EmulateInstructionMIPS64.cpp -------------------------------*- C++ -*-===// |
| // |
| // The LLVM Compiler Infrastructure |
| // |
| // This file is distributed under the University of Illinois Open Source |
| // License. See LICENSE.TXT for details. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #include "EmulateInstructionMIPS64.h" |
| |
| #include <stdlib.h> |
| |
| #include "llvm-c/Disassembler.h" |
| #include "llvm/Support/TargetSelect.h" |
| #include "llvm/Support/TargetRegistry.h" |
| #include "llvm/MC/MCAsmInfo.h" |
| #include "llvm/MC/MCInst.h" |
| #include "llvm/MC/MCInstrInfo.h" |
| #include "llvm/MC/MCDisassembler/MCDisassembler.h" |
| #include "llvm/MC/MCRegisterInfo.h" |
| #include "llvm/MC/MCSubtargetInfo.h" |
| #include "llvm/MC/MCContext.h" |
| #include "lldb/Core/Address.h" |
| #include "lldb/Core/Opcode.h" |
| #include "lldb/Core/ArchSpec.h" |
| #include "lldb/Core/ConstString.h" |
| #include "lldb/Core/PluginManager.h" |
| #include "lldb/Core/DataExtractor.h" |
| #include "lldb/Core/Stream.h" |
| #include "lldb/Symbol/UnwindPlan.h" |
| |
| #include "llvm/ADT/STLExtras.h" |
| |
| #include "Plugins/Process/Utility/InstructionUtils.h" |
| #include "Plugins/Process/Utility/RegisterContext_mips.h" |
| |
| using namespace lldb; |
| using namespace lldb_private; |
| |
| #define UInt(x) ((uint64_t)x) |
| #define integer int64_t |
| |
| |
| //---------------------------------------------------------------------- |
| // |
| // EmulateInstructionMIPS64 implementation |
| // |
| //---------------------------------------------------------------------- |
| |
| #ifdef __mips__ |
| extern "C" { |
| void LLVMInitializeMipsTargetInfo (); |
| void LLVMInitializeMipsTarget (); |
| void LLVMInitializeMipsAsmPrinter (); |
| void LLVMInitializeMipsTargetMC (); |
| void LLVMInitializeMipsDisassembler (); |
| } |
| #endif |
| |
| EmulateInstructionMIPS64::EmulateInstructionMIPS64 (const lldb_private::ArchSpec &arch) : |
| EmulateInstruction (arch) |
| { |
| /* Create instance of llvm::MCDisassembler */ |
| std::string Error; |
| llvm::Triple triple = arch.GetTriple(); |
| const llvm::Target *target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error); |
| |
| /* |
| * If we fail to get the target then we haven't registered it. The SystemInitializerCommon |
| * does not initialize targets, MCs and disassemblers. However we need the MCDisassembler |
| * to decode the instructions so that the decoding complexity stays with LLVM. |
| * Initialize the MIPS targets and disassemblers. |
| */ |
| #ifdef __mips__ |
| if (!target) |
| { |
| LLVMInitializeMipsTargetInfo (); |
| LLVMInitializeMipsTarget (); |
| LLVMInitializeMipsAsmPrinter (); |
| LLVMInitializeMipsTargetMC (); |
| LLVMInitializeMipsDisassembler (); |
| target = llvm::TargetRegistry::lookupTarget (triple.getTriple(), Error); |
| } |
| #endif |
| |
| assert (target); |
| |
| llvm::StringRef cpu; |
| |
| switch (arch.GetCore()) |
| { |
| case ArchSpec::eCore_mips32: |
| case ArchSpec::eCore_mips32el: |
| cpu = "mips32"; break; |
| case ArchSpec::eCore_mips32r2: |
| case ArchSpec::eCore_mips32r2el: |
| cpu = "mips32r2"; break; |
| case ArchSpec::eCore_mips32r3: |
| case ArchSpec::eCore_mips32r3el: |
| cpu = "mips32r3"; break; |
| case ArchSpec::eCore_mips32r5: |
| case ArchSpec::eCore_mips32r5el: |
| cpu = "mips32r5"; break; |
| case ArchSpec::eCore_mips32r6: |
| case ArchSpec::eCore_mips32r6el: |
| cpu = "mips32r6"; break; |
| case ArchSpec::eCore_mips64: |
| case ArchSpec::eCore_mips64el: |
| cpu = "mips64"; break; |
| case ArchSpec::eCore_mips64r2: |
| case ArchSpec::eCore_mips64r2el: |
| cpu = "mips64r2"; break; |
| case ArchSpec::eCore_mips64r3: |
| case ArchSpec::eCore_mips64r3el: |
| cpu = "mips64r3"; break; |
| case ArchSpec::eCore_mips64r5: |
| case ArchSpec::eCore_mips64r5el: |
| cpu = "mips64r5"; break; |
| case ArchSpec::eCore_mips64r6: |
| case ArchSpec::eCore_mips64r6el: |
| cpu = "mips64r6"; break; |
| default: |
| cpu = "generic"; break; |
| } |
| |
| std::string features = ""; |
| uint32_t arch_flags = arch.GetFlags (); |
| if (arch_flags & ArchSpec::eMIPSAse_msa) |
| features += "+msa,"; |
| if (arch_flags & ArchSpec::eMIPSAse_dsp) |
| features += "+dsp,"; |
| if (arch_flags & ArchSpec::eMIPSAse_dspr2) |
| features += "+dspr2,"; |
| if (arch_flags & ArchSpec::eMIPSAse_mips16) |
| features += "+mips16,"; |
| if (arch_flags & ArchSpec::eMIPSAse_micromips) |
| features += "+micromips,"; |
| |
| m_reg_info.reset (target->createMCRegInfo (triple.getTriple())); |
| assert (m_reg_info.get()); |
| |
| m_insn_info.reset (target->createMCInstrInfo()); |
| assert (m_insn_info.get()); |
| |
| m_asm_info.reset (target->createMCAsmInfo (*m_reg_info, triple.getTriple())); |
| m_subtype_info.reset (target->createMCSubtargetInfo (triple.getTriple(), cpu, features)); |
| assert (m_asm_info.get() && m_subtype_info.get()); |
| |
| m_context.reset (new llvm::MCContext (m_asm_info.get(), m_reg_info.get(), nullptr)); |
| assert (m_context.get()); |
| |
| m_disasm.reset (target->createMCDisassembler (*m_subtype_info, *m_context)); |
| assert (m_disasm.get()); |
| } |
| |
| void |
| EmulateInstructionMIPS64::Initialize () |
| { |
| PluginManager::RegisterPlugin (GetPluginNameStatic (), |
| GetPluginDescriptionStatic (), |
| CreateInstance); |
| } |
| |
| void |
| EmulateInstructionMIPS64::Terminate () |
| { |
| PluginManager::UnregisterPlugin (CreateInstance); |
| } |
| |
| ConstString |
| EmulateInstructionMIPS64::GetPluginNameStatic () |
| { |
| ConstString g_plugin_name ("lldb.emulate-instruction.mips64"); |
| return g_plugin_name; |
| } |
| |
| lldb_private::ConstString |
| EmulateInstructionMIPS64::GetPluginName() |
| { |
| static ConstString g_plugin_name ("EmulateInstructionMIPS64"); |
| return g_plugin_name; |
| } |
| |
| const char * |
| EmulateInstructionMIPS64::GetPluginDescriptionStatic () |
| { |
| return "Emulate instructions for the MIPS64 architecture."; |
| } |
| |
| EmulateInstruction * |
| EmulateInstructionMIPS64::CreateInstance (const ArchSpec &arch, InstructionType inst_type) |
| { |
| if (EmulateInstructionMIPS64::SupportsEmulatingInstructionsOfTypeStatic(inst_type)) |
| { |
| if (arch.GetTriple().getArch() == llvm::Triple::mips64 |
| || arch.GetTriple().getArch() == llvm::Triple::mips64el) |
| { |
| std::auto_ptr<EmulateInstructionMIPS64> emulate_insn_ap (new EmulateInstructionMIPS64 (arch)); |
| if (emulate_insn_ap.get()) |
| return emulate_insn_ap.release(); |
| } |
| } |
| |
| return NULL; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::SetTargetTriple (const ArchSpec &arch) |
| { |
| if (arch.GetTriple().getArch () == llvm::Triple::mips64 |
| || arch.GetTriple().getArch () == llvm::Triple::mips64el) |
| return true; |
| return false; |
| } |
| |
| const char * |
| EmulateInstructionMIPS64::GetRegisterName (unsigned reg_num, bool alternate_name) |
| { |
| if (alternate_name) |
| { |
| switch (reg_num) |
| { |
| case dwarf_sp_mips64: return "r29"; |
| case dwarf_r30_mips64: return "r30"; |
| case dwarf_ra_mips64: return "r31"; |
| case dwarf_f0_mips64: return "f0"; |
| case dwarf_f1_mips64: return "f1"; |
| case dwarf_f2_mips64: return "f2"; |
| case dwarf_f3_mips64: return "f3"; |
| case dwarf_f4_mips64: return "f4"; |
| case dwarf_f5_mips64: return "f5"; |
| case dwarf_f6_mips64: return "f6"; |
| case dwarf_f7_mips64: return "f7"; |
| case dwarf_f8_mips64: return "f8"; |
| case dwarf_f9_mips64: return "f9"; |
| case dwarf_f10_mips64: return "f10"; |
| case dwarf_f11_mips64: return "f11"; |
| case dwarf_f12_mips64: return "f12"; |
| case dwarf_f13_mips64: return "f13"; |
| case dwarf_f14_mips64: return "f14"; |
| case dwarf_f15_mips64: return "f15"; |
| case dwarf_f16_mips64: return "f16"; |
| case dwarf_f17_mips64: return "f17"; |
| case dwarf_f18_mips64: return "f18"; |
| case dwarf_f19_mips64: return "f19"; |
| case dwarf_f20_mips64: return "f20"; |
| case dwarf_f21_mips64: return "f21"; |
| case dwarf_f22_mips64: return "f22"; |
| case dwarf_f23_mips64: return "f23"; |
| case dwarf_f24_mips64: return "f24"; |
| case dwarf_f25_mips64: return "f25"; |
| case dwarf_f26_mips64: return "f26"; |
| case dwarf_f27_mips64: return "f27"; |
| case dwarf_f28_mips64: return "f28"; |
| case dwarf_f29_mips64: return "f29"; |
| case dwarf_f30_mips64: return "f30"; |
| case dwarf_f31_mips64: return "f31"; |
| case dwarf_w0_mips64: return "w0"; |
| case dwarf_w1_mips64: return "w1"; |
| case dwarf_w2_mips64: return "w2"; |
| case dwarf_w3_mips64: return "w3"; |
| case dwarf_w4_mips64: return "w4"; |
| case dwarf_w5_mips64: return "w5"; |
| case dwarf_w6_mips64: return "w6"; |
| case dwarf_w7_mips64: return "w7"; |
| case dwarf_w8_mips64: return "w8"; |
| case dwarf_w9_mips64: return "w9"; |
| case dwarf_w10_mips64: return "w10"; |
| case dwarf_w11_mips64: return "w11"; |
| case dwarf_w12_mips64: return "w12"; |
| case dwarf_w13_mips64: return "w13"; |
| case dwarf_w14_mips64: return "w14"; |
| case dwarf_w15_mips64: return "w15"; |
| case dwarf_w16_mips64: return "w16"; |
| case dwarf_w17_mips64: return "w17"; |
| case dwarf_w18_mips64: return "w18"; |
| case dwarf_w19_mips64: return "w19"; |
| case dwarf_w20_mips64: return "w20"; |
| case dwarf_w21_mips64: return "w21"; |
| case dwarf_w22_mips64: return "w22"; |
| case dwarf_w23_mips64: return "w23"; |
| case dwarf_w24_mips64: return "w24"; |
| case dwarf_w25_mips64: return "w25"; |
| case dwarf_w26_mips64: return "w26"; |
| case dwarf_w27_mips64: return "w27"; |
| case dwarf_w28_mips64: return "w28"; |
| case dwarf_w29_mips64: return "w29"; |
| case dwarf_w30_mips64: return "w30"; |
| case dwarf_w31_mips64: return "w31"; |
| case dwarf_mir_mips64: return "mir"; |
| case dwarf_mcsr_mips64: return "mcsr"; |
| case dwarf_config5_mips64: return "config5"; |
| default: |
| break; |
| } |
| return nullptr; |
| } |
| |
| switch (reg_num) |
| { |
| case dwarf_zero_mips64: return "r0"; |
| case dwarf_r1_mips64: return "r1"; |
| case dwarf_r2_mips64: return "r2"; |
| case dwarf_r3_mips64: return "r3"; |
| case dwarf_r4_mips64: return "r4"; |
| case dwarf_r5_mips64: return "r5"; |
| case dwarf_r6_mips64: return "r6"; |
| case dwarf_r7_mips64: return "r7"; |
| case dwarf_r8_mips64: return "r8"; |
| case dwarf_r9_mips64: return "r9"; |
| case dwarf_r10_mips64: return "r10"; |
| case dwarf_r11_mips64: return "r11"; |
| case dwarf_r12_mips64: return "r12"; |
| case dwarf_r13_mips64: return "r13"; |
| case dwarf_r14_mips64: return "r14"; |
| case dwarf_r15_mips64: return "r15"; |
| case dwarf_r16_mips64: return "r16"; |
| case dwarf_r17_mips64: return "r17"; |
| case dwarf_r18_mips64: return "r18"; |
| case dwarf_r19_mips64: return "r19"; |
| case dwarf_r20_mips64: return "r20"; |
| case dwarf_r21_mips64: return "r21"; |
| case dwarf_r22_mips64: return "r22"; |
| case dwarf_r23_mips64: return "r23"; |
| case dwarf_r24_mips64: return "r24"; |
| case dwarf_r25_mips64: return "r25"; |
| case dwarf_r26_mips64: return "r26"; |
| case dwarf_r27_mips64: return "r27"; |
| case dwarf_gp_mips64: return "gp"; |
| case dwarf_sp_mips64: return "sp"; |
| case dwarf_r30_mips64: return "fp"; |
| case dwarf_ra_mips64: return "ra"; |
| case dwarf_sr_mips64: return "sr"; |
| case dwarf_lo_mips64: return "lo"; |
| case dwarf_hi_mips64: return "hi"; |
| case dwarf_bad_mips64: return "bad"; |
| case dwarf_cause_mips64: return "cause"; |
| case dwarf_pc_mips64: return "pc"; |
| case dwarf_f0_mips64: return "f0"; |
| case dwarf_f1_mips64: return "f1"; |
| case dwarf_f2_mips64: return "f2"; |
| case dwarf_f3_mips64: return "f3"; |
| case dwarf_f4_mips64: return "f4"; |
| case dwarf_f5_mips64: return "f5"; |
| case dwarf_f6_mips64: return "f6"; |
| case dwarf_f7_mips64: return "f7"; |
| case dwarf_f8_mips64: return "f8"; |
| case dwarf_f9_mips64: return "f9"; |
| case dwarf_f10_mips64: return "f10"; |
| case dwarf_f11_mips64: return "f11"; |
| case dwarf_f12_mips64: return "f12"; |
| case dwarf_f13_mips64: return "f13"; |
| case dwarf_f14_mips64: return "f14"; |
| case dwarf_f15_mips64: return "f15"; |
| case dwarf_f16_mips64: return "f16"; |
| case dwarf_f17_mips64: return "f17"; |
| case dwarf_f18_mips64: return "f18"; |
| case dwarf_f19_mips64: return "f19"; |
| case dwarf_f20_mips64: return "f20"; |
| case dwarf_f21_mips64: return "f21"; |
| case dwarf_f22_mips64: return "f22"; |
| case dwarf_f23_mips64: return "f23"; |
| case dwarf_f24_mips64: return "f24"; |
| case dwarf_f25_mips64: return "f25"; |
| case dwarf_f26_mips64: return "f26"; |
| case dwarf_f27_mips64: return "f27"; |
| case dwarf_f28_mips64: return "f28"; |
| case dwarf_f29_mips64: return "f29"; |
| case dwarf_f30_mips64: return "f30"; |
| case dwarf_f31_mips64: return "f31"; |
| case dwarf_fcsr_mips64: return "fcsr"; |
| case dwarf_fir_mips64: return "fir"; |
| case dwarf_w0_mips64: return "w0"; |
| case dwarf_w1_mips64: return "w1"; |
| case dwarf_w2_mips64: return "w2"; |
| case dwarf_w3_mips64: return "w3"; |
| case dwarf_w4_mips64: return "w4"; |
| case dwarf_w5_mips64: return "w5"; |
| case dwarf_w6_mips64: return "w6"; |
| case dwarf_w7_mips64: return "w7"; |
| case dwarf_w8_mips64: return "w8"; |
| case dwarf_w9_mips64: return "w9"; |
| case dwarf_w10_mips64: return "w10"; |
| case dwarf_w11_mips64: return "w11"; |
| case dwarf_w12_mips64: return "w12"; |
| case dwarf_w13_mips64: return "w13"; |
| case dwarf_w14_mips64: return "w14"; |
| case dwarf_w15_mips64: return "w15"; |
| case dwarf_w16_mips64: return "w16"; |
| case dwarf_w17_mips64: return "w17"; |
| case dwarf_w18_mips64: return "w18"; |
| case dwarf_w19_mips64: return "w19"; |
| case dwarf_w20_mips64: return "w20"; |
| case dwarf_w21_mips64: return "w21"; |
| case dwarf_w22_mips64: return "w22"; |
| case dwarf_w23_mips64: return "w23"; |
| case dwarf_w24_mips64: return "w24"; |
| case dwarf_w25_mips64: return "w25"; |
| case dwarf_w26_mips64: return "w26"; |
| case dwarf_w27_mips64: return "w27"; |
| case dwarf_w28_mips64: return "w28"; |
| case dwarf_w29_mips64: return "w29"; |
| case dwarf_w30_mips64: return "w30"; |
| case dwarf_w31_mips64: return "w31"; |
| case dwarf_mcsr_mips64: return "mcsr"; |
| case dwarf_mir_mips64: return "mir"; |
| case dwarf_config5_mips64: return "config5"; |
| } |
| return nullptr; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::GetRegisterInfo (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo ®_info) |
| { |
| if (reg_kind == eRegisterKindGeneric) |
| { |
| switch (reg_num) |
| { |
| case LLDB_REGNUM_GENERIC_PC: reg_kind = eRegisterKindDWARF; reg_num = dwarf_pc_mips64; break; |
| case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sp_mips64; break; |
| case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = dwarf_r30_mips64; break; |
| case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = dwarf_ra_mips64; break; |
| case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = dwarf_sr_mips64; break; |
| default: |
| return false; |
| } |
| } |
| |
| if (reg_kind == eRegisterKindDWARF) |
| { |
| ::memset (®_info, 0, sizeof(RegisterInfo)); |
| ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds)); |
| |
| if (reg_num == dwarf_sr_mips64 || reg_num == dwarf_fcsr_mips64 || reg_num == dwarf_fir_mips64 || reg_num == dwarf_mcsr_mips64 || reg_num == dwarf_mir_mips64 || reg_num == dwarf_config5_mips64) |
| { |
| reg_info.byte_size = 4; |
| reg_info.format = eFormatHex; |
| reg_info.encoding = eEncodingUint; |
| } |
| else if ((int)reg_num >= dwarf_zero_mips64 && (int)reg_num <= dwarf_f31_mips64) |
| { |
| reg_info.byte_size = 8; |
| reg_info.format = eFormatHex; |
| reg_info.encoding = eEncodingUint; |
| } |
| else if ((int)reg_num >= dwarf_w0_mips64 && (int)reg_num <= dwarf_w31_mips64) |
| { |
| reg_info.byte_size = 16; |
| reg_info.format = eFormatVectorOfUInt8; |
| reg_info.encoding = eEncodingVector; |
| } |
| else |
| { |
| return false; |
| } |
| |
| reg_info.name = GetRegisterName (reg_num, false); |
| reg_info.alt_name = GetRegisterName (reg_num, true); |
| reg_info.kinds[eRegisterKindDWARF] = reg_num; |
| |
| switch (reg_num) |
| { |
| case dwarf_r30_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break; |
| case dwarf_ra_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break; |
| case dwarf_sp_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break; |
| case dwarf_pc_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break; |
| case dwarf_sr_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; break; |
| default: break; |
| } |
| return true; |
| } |
| return false; |
| } |
| |
| EmulateInstructionMIPS64::MipsOpcode* |
| EmulateInstructionMIPS64::GetOpcodeForInstruction (const char *op_name) |
| { |
| static EmulateInstructionMIPS64::MipsOpcode |
| g_opcodes[] = |
| { |
| //---------------------------------------------------------------------- |
| // Prologue/Epilogue instructions |
| //---------------------------------------------------------------------- |
| { "DADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "DADDIU rt, rs, immediate" }, |
| { "ADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "ADDIU rt, rs, immediate" }, |
| { "SD", &EmulateInstructionMIPS64::Emulate_SD, "SD rt, offset(rs)" }, |
| { "LD", &EmulateInstructionMIPS64::Emulate_LD, "LD rt, offset(base)" }, |
| { "DSUBU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "DSUBU rd, rs, rt" }, |
| { "SUBU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "SUBU rd, rs, rt" }, |
| { "DADDU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "DADDU rd, rs, rt" }, |
| { "ADDU", &EmulateInstructionMIPS64::Emulate_DSUBU_DADDU, "ADDU rd, rs, rt" }, |
| { "LUI", &EmulateInstructionMIPS64::Emulate_LUI, "LUI rt, immediate" }, |
| |
| |
| |
| |
| //---------------------------------------------------------------------- |
| // Load/Store instructions |
| //---------------------------------------------------------------------- |
| /* Following list of emulated instructions are required by implementation of hardware watchpoint |
| for MIPS in lldb. As we just need the address accessed by instructions, we have generalised |
| all these instructions in 2 functions depending on their addressing modes */ |
| |
| { "LB", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LB rt, offset(base)" }, |
| { "LBE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LBE rt, offset(base)" }, |
| { "LBU", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LBU rt, offset(base)" }, |
| { "LBUE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LBUE rt, offset(base)" }, |
| { "LDC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDC1 ft, offset(base)" }, |
| { "LDL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDL rt, offset(base)" }, |
| { "LDR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDR rt, offset(base)" }, |
| { "LLD", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LLD rt, offset(base)" }, |
| { "LDC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LDC2 rt, offset(base)" }, |
| { "LDXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "LDXC1 fd, index (base)" }, |
| { "LH", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LH rt, offset(base)" }, |
| { "LHE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LHE rt, offset(base)" }, |
| { "LHU", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LHU rt, offset(base)" }, |
| { "LHUE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LHUE rt, offset(base)" }, |
| { "LL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LL rt, offset(base)" }, |
| { "LLE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LLE rt, offset(base)" }, |
| { "LUXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "LUXC1 fd, index (base)" }, |
| { "LW", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LW rt, offset(rs)" }, |
| { "LWC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWC1 ft, offset(base)" }, |
| { "LWC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWC2 rt, offset(base)" }, |
| { "LWE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWE rt, offset(base)" }, |
| { "LWL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWL rt, offset(base)" }, |
| { "LWLE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWLE rt, offset(base)" }, |
| { "LWR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWR rt, offset(base)" }, |
| { "LWRE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "LWRE rt, offset(base)" }, |
| { "LWXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "LWXC1 fd, index (base)" }, |
| |
| { "SB", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SB rt, offset(base)" }, |
| { "SBE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SBE rt, offset(base)" }, |
| { "SC", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SC rt, offset(base)" }, |
| { "SCE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SCE rt, offset(base)" }, |
| { "SCD", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SCD rt, offset(base)" }, |
| { "SDL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDL rt, offset(base)" }, |
| { "SDR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDR rt, offset(base)" }, |
| { "SDC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDC1 ft, offset(base)" }, |
| { "SDC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SDC2 rt, offset(base)" }, |
| { "SDXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "SDXC1 fs, index (base)" }, |
| { "SH", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SH rt, offset(base)" }, |
| { "SHE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SHE rt, offset(base)" }, |
| { "SUXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "SUXC1 fs, index (base)" }, |
| { "SW", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SW rt, offset(rs)" }, |
| { "SWC1", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWC1 ft, offset(base)" }, |
| { "SWC2", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWC2 rt, offset(base)" }, |
| { "SWE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWE rt, offset(base)" }, |
| { "SWL", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWL rt, offset(base)" }, |
| { "SWLE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWLE rt, offset(base)" }, |
| { "SWR", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWR rt, offset(base)" }, |
| { "SWRE", &EmulateInstructionMIPS64::Emulate_LDST_Imm, "SWRE rt, offset(base)" }, |
| { "SWXC1", &EmulateInstructionMIPS64::Emulate_LDST_Reg, "SWXC1 fs, index (base)" }, |
| |
| //---------------------------------------------------------------------- |
| // Branch instructions |
| //---------------------------------------------------------------------- |
| { "BEQ", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BEQ rs,rt,offset" }, |
| { "BNE", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BNE rs,rt,offset" }, |
| { "BEQL", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BEQL rs,rt,offset" }, |
| { "BNEL", &EmulateInstructionMIPS64::Emulate_BXX_3ops, "BNEL rs,rt,offset" }, |
| { "BGEZALL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BGEZALL rt,offset" }, |
| { "BAL", &EmulateInstructionMIPS64::Emulate_BAL, "BAL offset" }, |
| { "BGEZAL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BGEZAL rs,offset" }, |
| { "BALC", &EmulateInstructionMIPS64::Emulate_BALC, "BALC offset" }, |
| { "BC", &EmulateInstructionMIPS64::Emulate_BC, "BC offset" }, |
| { "BGEZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGEZ rs,offset" }, |
| { "BLEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BLEZALC rs,offset" }, |
| { "BGEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BGEZALC rs,offset" }, |
| { "BLTZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BLTZALC rs,offset" }, |
| { "BGTZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BGTZALC rs,offset" }, |
| { "BEQZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BEQZALC rs,offset" }, |
| { "BNEZALC", &EmulateInstructionMIPS64::Emulate_Bcond_Link_C,"BNEZALC rs,offset" }, |
| { "BEQC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BEQC rs,rt,offset" }, |
| { "BNEC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BNEC rs,rt,offset" }, |
| { "BLTC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BLTC rs,rt,offset" }, |
| { "BGEC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BGEC rs,rt,offset" }, |
| { "BLTUC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BLTUC rs,rt,offset" }, |
| { "BGEUC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BGEUC rs,rt,offset" }, |
| { "BLTZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BLTZC rt,offset" }, |
| { "BLEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BLEZC rt,offset" }, |
| { "BGEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BGEZC rt,offset" }, |
| { "BGTZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BGTZC rt,offset" }, |
| { "BEQZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BEQZC rt,offset" }, |
| { "BNEZC", &EmulateInstructionMIPS64::Emulate_BXX_2ops_C, "BNEZC rt,offset" }, |
| { "BGEZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGEZL rt,offset" }, |
| { "BGTZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGTZ rt,offset" }, |
| { "BGTZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BGTZL rt,offset" }, |
| { "BLEZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLEZ rt,offset" }, |
| { "BLEZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLEZL rt,offset" }, |
| { "BLTZ", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLTZ rt,offset" }, |
| { "BLTZAL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BLTZAL rt,offset" }, |
| { "BLTZALL", &EmulateInstructionMIPS64::Emulate_Bcond_Link, "BLTZALL rt,offset" }, |
| { "BLTZL", &EmulateInstructionMIPS64::Emulate_BXX_2ops, "BLTZL rt,offset" }, |
| { "BOVC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BOVC rs,rt,offset" }, |
| { "BNVC", &EmulateInstructionMIPS64::Emulate_BXX_3ops_C, "BNVC rs,rt,offset" }, |
| { "J", &EmulateInstructionMIPS64::Emulate_J, "J target" }, |
| { "JAL", &EmulateInstructionMIPS64::Emulate_JAL, "JAL target" }, |
| { "JALX", &EmulateInstructionMIPS64::Emulate_JAL, "JALX target" }, |
| { "JALR", &EmulateInstructionMIPS64::Emulate_JALR, "JALR target" }, |
| { "JALR_HB", &EmulateInstructionMIPS64::Emulate_JALR, "JALR.HB target" }, |
| { "JIALC", &EmulateInstructionMIPS64::Emulate_JIALC, "JIALC rt,offset" }, |
| { "JIC", &EmulateInstructionMIPS64::Emulate_JIC, "JIC rt,offset" }, |
| { "JR", &EmulateInstructionMIPS64::Emulate_JR, "JR target" }, |
| { "JR_HB", &EmulateInstructionMIPS64::Emulate_JR, "JR.HB target" }, |
| { "BC1F", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1F cc, offset" }, |
| { "BC1T", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1T cc, offset" }, |
| { "BC1FL", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1FL cc, offset" }, |
| { "BC1TL", &EmulateInstructionMIPS64::Emulate_FP_branch, "BC1TL cc, offset" }, |
| { "BC1EQZ", &EmulateInstructionMIPS64::Emulate_BC1EQZ, "BC1EQZ ft, offset" }, |
| { "BC1NEZ", &EmulateInstructionMIPS64::Emulate_BC1NEZ, "BC1NEZ ft, offset" }, |
| { "BC1ANY2F", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY2F cc, offset" }, |
| { "BC1ANY2T", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY2T cc, offset" }, |
| { "BC1ANY4F", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY4F cc, offset" }, |
| { "BC1ANY4T", &EmulateInstructionMIPS64::Emulate_3D_branch, "BC1ANY4T cc, offset" }, |
| { "BNZ_B", &EmulateInstructionMIPS64::Emulate_BNZB, "BNZ.b wt,s16" }, |
| { "BNZ_H", &EmulateInstructionMIPS64::Emulate_BNZH, "BNZ.h wt,s16" }, |
| { "BNZ_W", &EmulateInstructionMIPS64::Emulate_BNZW, "BNZ.w wt,s16" }, |
| { "BNZ_D", &EmulateInstructionMIPS64::Emulate_BNZD, "BNZ.d wt,s16" }, |
| { "BZ_B", &EmulateInstructionMIPS64::Emulate_BZB, "BZ.b wt,s16" }, |
| { "BZ_H", &EmulateInstructionMIPS64::Emulate_BZH, "BZ.h wt,s16" }, |
| { "BZ_W", &EmulateInstructionMIPS64::Emulate_BZW, "BZ.w wt,s16" }, |
| { "BZ_D", &EmulateInstructionMIPS64::Emulate_BZD, "BZ.d wt,s16" }, |
| { "BNZ_V", &EmulateInstructionMIPS64::Emulate_BNZV, "BNZ.V wt,s16" }, |
| { "BZ_V", &EmulateInstructionMIPS64::Emulate_BZV, "BZ.V wt,s16" }, |
| }; |
| |
| static const size_t k_num_mips_opcodes = llvm::array_lengthof(g_opcodes); |
| |
| for (size_t i = 0; i < k_num_mips_opcodes; ++i) |
| { |
| if (! strcasecmp (g_opcodes[i].op_name, op_name)) |
| return &g_opcodes[i]; |
| } |
| |
| return NULL; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::ReadInstruction () |
| { |
| bool success = false; |
| m_addr = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, LLDB_INVALID_ADDRESS, &success); |
| if (success) |
| { |
| Context read_inst_context; |
| read_inst_context.type = eContextReadOpcode; |
| read_inst_context.SetNoArgs (); |
| m_opcode.SetOpcode32 (ReadMemoryUnsigned (read_inst_context, m_addr, 4, 0, &success), GetByteOrder()); |
| } |
| if (!success) |
| m_addr = LLDB_INVALID_ADDRESS; |
| return success; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::EvaluateInstruction (uint32_t evaluate_options) |
| { |
| bool success = false; |
| llvm::MCInst mc_insn; |
| uint64_t insn_size; |
| DataExtractor data; |
| |
| /* Keep the complexity of the decode logic with the llvm::MCDisassembler class. */ |
| if (m_opcode.GetData (data)) |
| { |
| llvm::MCDisassembler::DecodeStatus decode_status; |
| llvm::ArrayRef<uint8_t> raw_insn (data.GetDataStart(), data.GetByteSize()); |
| decode_status = m_disasm->getInstruction (mc_insn, insn_size, raw_insn, m_addr, llvm::nulls(), llvm::nulls()); |
| if (decode_status != llvm::MCDisassembler::Success) |
| return false; |
| } |
| |
| /* |
| * mc_insn.getOpcode() returns decoded opcode. However to make use |
| * of llvm::Mips::<insn> we would need "MipsGenInstrInfo.inc". |
| */ |
| const char *op_name = m_insn_info->getName (mc_insn.getOpcode ()); |
| |
| if (op_name == NULL) |
| return false; |
| |
| /* |
| * Decoding has been done already. Just get the call-back function |
| * and emulate the instruction. |
| */ |
| MipsOpcode *opcode_data = GetOpcodeForInstruction (op_name); |
| |
| if (opcode_data == NULL) |
| return false; |
| |
| uint64_t old_pc = 0, new_pc = 0; |
| const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; |
| |
| if (auto_advance_pc) |
| { |
| old_pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| } |
| |
| /* emulate instruction */ |
| success = (this->*opcode_data->callback) (mc_insn); |
| if (!success) |
| return false; |
| |
| if (auto_advance_pc) |
| { |
| new_pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| /* If we haven't changed the PC, change it here */ |
| if (old_pc == new_pc) |
| { |
| new_pc += 4; |
| Context context; |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, new_pc)) |
| return false; |
| } |
| } |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::CreateFunctionEntryUnwind (UnwindPlan &unwind_plan) |
| { |
| unwind_plan.Clear(); |
| unwind_plan.SetRegisterKind (eRegisterKindDWARF); |
| |
| UnwindPlan::RowSP row(new UnwindPlan::Row); |
| const bool can_replace = false; |
| |
| // Our previous Call Frame Address is the stack pointer |
| row->GetCFAValue().SetIsRegisterPlusOffset(dwarf_sp_mips64, 0); |
| |
| // Our previous PC is in the RA |
| row->SetRegisterLocationToRegister(dwarf_pc_mips64, dwarf_ra_mips64, can_replace); |
| |
| unwind_plan.AppendRow (row); |
| |
| // All other registers are the same. |
| unwind_plan.SetSourceName ("EmulateInstructionMIPS64"); |
| unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); |
| unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); |
| unwind_plan.SetReturnAddressRegister (dwarf_ra_mips64); |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::nonvolatile_reg_p (uint64_t regnum) |
| { |
| switch (regnum) |
| { |
| case dwarf_r16_mips64: |
| case dwarf_r17_mips64: |
| case dwarf_r18_mips64: |
| case dwarf_r19_mips64: |
| case dwarf_r20_mips64: |
| case dwarf_r21_mips64: |
| case dwarf_r22_mips64: |
| case dwarf_r23_mips64: |
| case dwarf_gp_mips64: |
| case dwarf_sp_mips64: |
| case dwarf_r30_mips64: |
| case dwarf_ra_mips64: |
| return true; |
| default: |
| return false; |
| } |
| return false; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_DADDiu (llvm::MCInst& insn) |
| { |
| // DADDIU rt, rs, immediate |
| // GPR[rt] <- GPR[rs] + sign_extend(immediate) |
| |
| uint8_t dst, src; |
| bool success = false; |
| const uint32_t imm16 = insn.getOperand(2).getImm(); |
| int64_t imm = SignedBits(imm16, 15, 0); |
| |
| dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); |
| |
| // If immediate is greater than 2^16 - 1 then clang generate |
| // LUI, (D)ADDIU,(D)SUBU instructions in prolog. |
| // Example |
| // lui $1, 0x2 |
| // daddiu $1, $1, -0x5920 |
| // dsubu $sp, $sp, $1 |
| // In this case, (D)ADDIU dst and src will be same and not equal to sp |
| if (dst == src) |
| { |
| Context context; |
| |
| /* read <src> register */ |
| const int64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); |
| if (!success) |
| return false; |
| |
| /* Check if this is daddiu sp, sp, imm16 */ |
| if (dst == dwarf_sp_mips64) |
| { |
| uint64_t result = src_opd_val + imm; |
| RegisterInfo reg_info_sp; |
| |
| if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips64, reg_info_sp)) |
| context.SetRegisterPlusOffset (reg_info_sp, imm); |
| |
| /* We are allocating bytes on stack */ |
| context.type = eContextAdjustStackPointer; |
| |
| WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips64, result); |
| return true; |
| } |
| |
| imm += src_opd_val; |
| context.SetImmediateSigned (imm); |
| context.type = eContextImmediate; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + dst, imm)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_SD (llvm::MCInst& insn) |
| { |
| uint64_t address; |
| RegisterInfo reg_info_base; |
| RegisterInfo reg_info_src; |
| bool success = false; |
| uint32_t imm16 = insn.getOperand(2).getImm(); |
| uint64_t imm = SignedBits(imm16, 15, 0); |
| uint32_t src, base; |
| Context bad_vaddr_context; |
| |
| src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); |
| |
| if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + base, reg_info_base) |
| || !GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + src, reg_info_src)) |
| return false; |
| |
| /* read SP */ |
| address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + base, 0, &success); |
| if (!success) |
| return false; |
| |
| /* destination address */ |
| address = address + imm; |
| |
| /* We look for sp based non-volatile register stores */ |
| if (nonvolatile_reg_p (src)) |
| { |
| Context context; |
| RegisterValue data_src; |
| context.type = eContextPushRegisterOnStack; |
| context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0); |
| |
| uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; |
| Error error; |
| |
| if (!ReadRegister (®_info_base, data_src)) |
| return false; |
| |
| if (data_src.GetAsMemoryData (®_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0) |
| return false; |
| |
| if (!WriteMemory (context, address, buffer, reg_info_src.byte_size)) |
| return false; |
| } |
| |
| /* Set the bad_vaddr register with base address used in the instruction */ |
| bad_vaddr_context.type = eContextInvalid; |
| WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips64, address); |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_LD (llvm::MCInst& insn) |
| { |
| bool success =false; |
| uint32_t src, base; |
| int64_t imm, address; |
| Context bad_vaddr_context; |
| |
| src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); |
| imm = insn.getOperand(2).getImm(); |
| |
| RegisterInfo reg_info_base; |
| if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + base, reg_info_base)) |
| return false; |
| |
| /* read base register */ |
| address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + base, 0, &success); |
| if (!success) |
| return false; |
| |
| /* destination address */ |
| address = address + imm; |
| |
| /* Set the bad_vaddr register with base address used in the instruction */ |
| bad_vaddr_context.type = eContextInvalid; |
| WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips64, address); |
| |
| |
| if (nonvolatile_reg_p (src)) |
| { |
| RegisterValue data_src; |
| RegisterInfo reg_info_src; |
| |
| if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips64 + src, reg_info_src)) |
| return false; |
| |
| Context context; |
| context.type = eContextRegisterLoad; |
| |
| if (!WriteRegister (context, ®_info_src, data_src)) |
| return false; |
| |
| return true; |
| } |
| |
| return false; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_LUI (llvm::MCInst& insn) |
| { |
| // LUI rt, immediate |
| // GPR[rt] <- sign_extend(immediate << 16) |
| |
| const uint32_t imm32 = insn.getOperand(1).getImm() << 16; |
| int64_t imm = SignedBits(imm32, 31, 0); |
| uint8_t rt; |
| Context context; |
| |
| rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| context.SetImmediateSigned (imm); |
| context.type = eContextImmediate; |
| |
| if (WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + rt, imm)) |
| return true; |
| |
| return false; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_DSUBU_DADDU (llvm::MCInst& insn) |
| { |
| // DSUBU sp, <src>, <rt> |
| // DADDU sp, <src>, <rt> |
| // DADDU dst, sp, <rt> |
| |
| bool success = false; |
| uint64_t result; |
| uint8_t src, dst, rt; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| |
| dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); |
| |
| /* Check if sp is destination register */ |
| if (dst == dwarf_sp_mips64) |
| { |
| rt = m_reg_info->getEncodingValue (insn.getOperand(2).getReg()); |
| |
| /* read <src> register */ |
| uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); |
| if (!success) |
| return false; |
| |
| /* read <rt > register */ |
| uint64_t rt_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); |
| if (!success) |
| return false; |
| |
| if (!strcasecmp (op_name, "DSUBU") || !strcasecmp (op_name, "SUBU")) |
| result = src_opd_val - rt_opd_val; |
| else |
| result = src_opd_val + rt_opd_val; |
| |
| Context context; |
| RegisterInfo reg_info_sp; |
| if (GetRegisterInfo (eRegisterKindDWARF, dwarf_sp_mips64, reg_info_sp)) |
| context.SetRegisterPlusOffset (reg_info_sp, rt_opd_val); |
| |
| /* We are allocating bytes on stack */ |
| context.type = eContextAdjustStackPointer; |
| |
| WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_sp_mips64, result); |
| |
| return true; |
| } |
| else if (src == dwarf_sp_mips64) |
| { |
| rt = m_reg_info->getEncodingValue (insn.getOperand(2).getReg()); |
| |
| /* read <src> register */ |
| uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + src, 0, &success); |
| if (!success) |
| return false; |
| |
| /* read <rt> register */ |
| uint64_t rt_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); |
| if (!success) |
| return false; |
| |
| Context context; |
| |
| if (!strcasecmp (op_name, "DSUBU") || !strcasecmp (op_name, "SUBU")) |
| result = src_opd_val - rt_opd_val; |
| else |
| result = src_opd_val + rt_opd_val; |
| |
| context.SetImmediateSigned (result); |
| context.type = eContextImmediate; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + dst, result)) |
| return false; |
| } |
| |
| return true; |
| } |
| |
| /* |
| Emulate below MIPS branch instructions. |
| BEQ, BNE : Branch on condition |
| BEQL, BNEL : Branch likely |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_BXX_3ops (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs, rt; |
| int64_t offset, pc, rs_val, rt_val, target = 0; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| |
| rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); |
| offset = insn.getOperand(2).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); |
| if (!success) |
| return false; |
| |
| if (!strcasecmp (op_name, "BEQ") || |
| !strcasecmp (op_name, "BEQL")) |
| { |
| if (rs_val == rt_val) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BNE") || |
| !strcasecmp (op_name, "BNEL")) |
| { |
| if (rs_val != rt_val) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| |
| Context context; |
| context.type = eContextRelativeBranchImmediate; |
| context.SetImmediate (offset); |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| Emulate below MIPS Non-Compact conditional branch and link instructions. |
| BLTZAL, BGEZAL : |
| BLTZALL, BGEZALL : Branch likely |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_Bcond_Link (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs; |
| int64_t offset, pc, target = 0; |
| int64_t rs_val; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| |
| rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| if (!strcasecmp (op_name, "BLTZAL") || |
| !strcasecmp (op_name, "BLTZALL")) |
| { |
| if (rs_val < 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BGEZAL") || |
| !strcasecmp (op_name, "BGEZALL")) |
| { |
| if (rs_val >= 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BAL (llvm::MCInst& insn) |
| { |
| bool success = false; |
| int64_t offset, pc, target; |
| |
| /* |
| * BAL offset |
| * offset = sign_ext (offset << 2) |
| * RA = PC + 8 |
| * PC = PC + offset |
| */ |
| offset = insn.getOperand(0).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| target = pc + offset; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BALC (llvm::MCInst& insn) |
| { |
| bool success = false; |
| int64_t offset, pc, target; |
| |
| /* |
| * BALC offset |
| * offset = sign_ext (offset << 2) |
| * RA = PC + 4 |
| * PC = PC + 4 + offset |
| */ |
| offset = insn.getOperand(0).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| target = pc + offset; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| Emulate below MIPS conditional branch and link instructions. |
| BLEZALC, BGEZALC, BLTZALC, BGTZALC, BEQZALC, BNEZALC : Compact branches |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_Bcond_Link_C (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs; |
| int64_t offset, pc, rs_val, target = 0; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| |
| rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| if (!strcasecmp (op_name, "BLEZALC")) |
| { |
| if (rs_val <= 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BGEZALC")) |
| { |
| if (rs_val >= 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BLTZALC")) |
| { |
| if (rs_val < 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BGTZALC")) |
| { |
| if (rs_val > 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BEQZALC")) |
| { |
| if (rs_val == 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BNEZALC")) |
| { |
| if (rs_val != 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| Emulate below MIPS branch instructions. |
| BLTZL, BGEZL, BGTZL, BLEZL : Branch likely |
| BLTZ, BGEZ, BGTZ, BLEZ : Non-compact branches |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_BXX_2ops (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs; |
| int64_t offset, pc, rs_val, target = 0; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| |
| rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| if (!strcasecmp (op_name, "BLTZL") || |
| !strcasecmp (op_name, "BLTZ")) |
| { |
| if (rs_val < 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BGEZL") || |
| !strcasecmp (op_name, "BGEZ")) |
| { |
| if (rs_val >= 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BGTZL") || |
| !strcasecmp (op_name, "BGTZ")) |
| { |
| if (rs_val > 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BLEZL") || |
| !strcasecmp (op_name, "BLEZ")) |
| { |
| if (rs_val <= 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| |
| Context context; |
| context.type = eContextRelativeBranchImmediate; |
| context.SetImmediate (offset); |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BC (llvm::MCInst& insn) |
| { |
| bool success = false; |
| int64_t offset, pc, target; |
| |
| /* |
| * BC offset |
| * offset = sign_ext (offset << 2) |
| * PC = PC + 4 + offset |
| */ |
| offset = insn.getOperand(0).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| target = pc + offset; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| static int |
| IsAdd64bitOverflow (int64_t a, int64_t b) |
| { |
| int64_t r = (uint64_t) a + (uint64_t) b; |
| return (a < 0 && b < 0 && r >= 0) || (a >= 0 && b >= 0 && r < 0); |
| } |
| |
| /* |
| Emulate below MIPS branch instructions. |
| BEQC, BNEC, BLTC, BGEC, BLTUC, BGEUC, BOVC, BNVC: Compact branch instructions with no delay slot |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_BXX_3ops_C (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs, rt; |
| int64_t offset, pc, rs_val, rt_val, target = 0; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); |
| |
| rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| rt = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); |
| offset = insn.getOperand(2).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); |
| if (!success) |
| return false; |
| |
| if (!strcasecmp (op_name, "BEQC")) |
| { |
| if (rs_val == rt_val) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BNEC")) |
| { |
| if (rs_val != rt_val) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BLTC")) |
| { |
| if (rs_val < rt_val) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BGEC")) |
| { |
| if (rs_val >= rt_val) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BLTUC")) |
| { |
| if (rs_val < rt_val) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BGEUC")) |
| { |
| if ((uint32_t)rs_val >= (uint32_t)rt_val) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BOVC")) |
| { |
| if (IsAdd64bitOverflow (rs_val, rt_val)) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BNVC")) |
| { |
| if (!IsAdd64bitOverflow (rs_val, rt_val)) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| |
| Context context; |
| context.type = eContextRelativeBranchImmediate; |
| context.SetImmediate (current_inst_size + offset); |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| Emulate below MIPS branch instructions. |
| BLTZC, BLEZC, BGEZC, BGTZC, BEQZC, BNEZC : Compact Branches |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_BXX_2ops_C (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs; |
| int64_t offset, pc, target = 0; |
| int64_t rs_val; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| uint32_t current_inst_size = m_insn_info->get(insn.getOpcode()).getSize(); |
| |
| rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rs_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| if (!strcasecmp (op_name, "BLTZC")) |
| { |
| if (rs_val < 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BLEZC")) |
| { |
| if (rs_val <= 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BGEZC")) |
| { |
| if (rs_val >= 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BGTZC")) |
| { |
| if (rs_val > 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BEQZC")) |
| { |
| if (rs_val == 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| else if (!strcasecmp (op_name, "BNEZC")) |
| { |
| if (rs_val != 0) |
| target = pc + offset; |
| else |
| target = pc + 4; |
| } |
| |
| Context context; |
| context.type = eContextRelativeBranchImmediate; |
| context.SetImmediate (current_inst_size + offset); |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_J (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint64_t offset, pc; |
| |
| /* |
| * J offset |
| * offset = sign_ext (offset << 2) |
| * PC = PC[63-28] | offset |
| */ |
| offset = insn.getOperand(0).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| /* This is a PC-region branch and not PC-relative */ |
| pc = (pc & 0xFFFFFFFFF0000000ULL) | offset; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, pc)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_JAL (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint64_t offset, target, pc; |
| |
| /* |
| * JAL offset |
| * offset = sign_ext (offset << 2) |
| * PC = PC[63-28] | offset |
| */ |
| offset = insn.getOperand(0).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| /* This is a PC-region branch and not PC-relative */ |
| target = (pc & 0xFFFFFFFFF0000000ULL) | offset; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 8)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_JALR (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs, rt; |
| uint64_t pc, rs_val; |
| |
| /* |
| * JALR rt, rs |
| * GPR[rt] = PC + 8 |
| * PC = GPR[rs] |
| */ |
| rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| rs = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, rs_val)) |
| return false; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_zero_mips64 + rt, pc + 8)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_JIALC (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rt; |
| int64_t target, offset, pc, rt_val; |
| |
| /* |
| * JIALC rt, offset |
| * offset = sign_ext (offset) |
| * PC = GPR[rt] + offset |
| * RA = PC + 4 |
| */ |
| rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); |
| if (!success) |
| return false; |
| |
| target = rt_val + offset; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_ra_mips64, pc + 4)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_JIC (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rt; |
| int64_t target, offset, rt_val; |
| |
| /* |
| * JIC rt, offset |
| * offset = sign_ext (offset) |
| * PC = GPR[rt] + offset |
| */ |
| rt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| rt_val = (int64_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rt, 0, &success); |
| if (!success) |
| return false; |
| |
| target = rt_val + offset; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_JR (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t rs; |
| uint64_t rs_val; |
| |
| /* |
| * JR rs |
| * PC = GPR[rs] |
| */ |
| rs = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| |
| rs_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + rs, 0, &success); |
| if (!success) |
| return false; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, rs_val)) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| Emulate Branch on FP True/False |
| BC1F, BC1FL : Branch on FP False (L stands for branch likely) |
| BC1T, BC1TL : Branch on FP True (L stands for branch likely) |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_FP_branch (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t cc, fcsr; |
| int64_t pc, offset, target = 0; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| |
| /* |
| * BC1F cc, offset |
| * condition <- (FPConditionCode(cc) == 0) |
| * if condition then |
| * offset = sign_ext (offset) |
| * PC = PC + offset |
| */ |
| cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| fcsr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| /* fcsr[23], fcsr[25-31] are vaild condition bits */ |
| fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); |
| |
| if (!strcasecmp (op_name, "BC1F") || |
| !strcasecmp (op_name, "BC1FL")) |
| { |
| if ((fcsr & (1 << cc)) == 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BC1T") || |
| !strcasecmp (op_name, "BC1TL")) |
| { |
| if ((fcsr & (1 << cc)) != 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BC1EQZ (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t ft; |
| uint64_t ft_val; |
| int64_t target, pc, offset; |
| |
| /* |
| * BC1EQZ ft, offset |
| * condition <- (FPR[ft].bit0 == 0) |
| * if condition then |
| * offset = sign_ext (offset) |
| * PC = PC + 4 + offset |
| */ |
| ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + ft, 0, &success); |
| if (!success) |
| return false; |
| |
| if ((ft_val & 1) == 0) |
| target = pc + 4 + offset; |
| else |
| target = pc + 8; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BC1NEZ (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t ft; |
| uint64_t ft_val; |
| int64_t target, pc, offset; |
| |
| /* |
| * BC1NEZ ft, offset |
| * condition <- (FPR[ft].bit0 != 0) |
| * if condition then |
| * offset = sign_ext (offset) |
| * PC = PC + 4 + offset |
| */ |
| ft = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| ft_val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips64 + ft, 0, &success); |
| if (!success) |
| return false; |
| |
| if ((ft_val & 1) != 0) |
| target = pc + 4 + offset; |
| else |
| target = pc + 8; |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| /* |
| Emulate MIPS-3D Branch instructions |
| BC1ANY2F, BC1ANY2T : Branch on Any of Two Floating Point Condition Codes False/True |
| BC1ANY4F, BC1ANY4T : Branch on Any of Four Floating Point Condition Codes False/True |
| */ |
| bool |
| EmulateInstructionMIPS64::Emulate_3D_branch (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t cc, fcsr; |
| int64_t pc, offset, target = 0; |
| const char *op_name = m_insn_info->getName (insn.getOpcode ()); |
| |
| cc = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| offset = insn.getOperand(1).getImm(); |
| |
| pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| fcsr = (uint32_t) ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_fcsr_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| /* fcsr[23], fcsr[25-31] are vaild condition bits */ |
| fcsr = ((fcsr >> 24) & 0xfe) | ((fcsr >> 23) & 0x01); |
| |
| if (!strcasecmp (op_name, "BC1ANY2F")) |
| { |
| /* if any one bit is 0 */ |
| if (((fcsr >> cc) & 3) != 3) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BC1ANY2T")) |
| { |
| /* if any one bit is 1 */ |
| if (((fcsr >> cc) & 3) != 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BC1ANY4F")) |
| { |
| /* if any one bit is 0 */ |
| if (((fcsr >> cc) & 0xf) != 0xf) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| else if (!strcasecmp (op_name, "BC1ANY4T")) |
| { |
| /* if any one bit is 1 */ |
| if (((fcsr >> cc) & 0xf) != 0) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| } |
| |
| Context context; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BNZB (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 1, true); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BNZH (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 2, true); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BNZW (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 4, true); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BNZD (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 8, true); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BZB (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 1, false); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BZH (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 2, false); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BZW (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 4, false); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BZD (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_DF(insn, 8, false); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_MSA_Branch_DF (llvm::MCInst& insn, int element_byte_size, bool bnz) |
| { |
| bool success = false, branch_hit = true; |
| int64_t target = 0; |
| RegisterValue reg_value; |
| const uint8_t *ptr = NULL; |
| |
| uint32_t wt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| int64_t offset = insn.getOperand(1).getImm(); |
| |
| int64_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| if (ReadRegister (eRegisterKindDWARF, dwarf_w0_mips64 + wt, reg_value)) |
| ptr = (const uint8_t *)reg_value.GetBytes(); |
| else |
| return false; |
| |
| for(int i = 0; i < 16 / element_byte_size; i++) |
| { |
| switch(element_byte_size) |
| { |
| case 1: |
| if((*ptr == 0 && bnz) || (*ptr != 0 && !bnz) ) |
| branch_hit = false; |
| break; |
| case 2: |
| if ((*(const uint16_t *)ptr == 0 && bnz) || (*(const uint16_t *)ptr != 0 && !bnz)) |
| branch_hit = false; |
| break; |
| case 4: |
| if ((*(const uint32_t *)ptr == 0 && bnz) || (*(const uint32_t *)ptr != 0 && !bnz)) |
| branch_hit = false; |
| break; |
| case 8: |
| if ((*(const uint64_t *)ptr == 0 && bnz) || (*(const uint64_t *)ptr != 0 && !bnz)) |
| branch_hit = false; |
| break; |
| } |
| if(!branch_hit) |
| break; |
| ptr = ptr + element_byte_size; |
| } |
| |
| if(branch_hit) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| |
| Context context; |
| context.type = eContextRelativeBranchImmediate; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BNZV (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_V (insn, true); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_BZV (llvm::MCInst& insn) |
| { |
| return Emulate_MSA_Branch_V (insn, false); |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_MSA_Branch_V (llvm::MCInst& insn, bool bnz) |
| { |
| bool success = false; |
| int64_t target = 0; |
| llvm::APInt wr_val = llvm::APInt::getNullValue(128); |
| llvm::APInt fail_value = llvm::APInt::getMaxValue(128); |
| llvm::APInt zero_value = llvm::APInt::getNullValue(128); |
| RegisterValue reg_value; |
| |
| uint32_t wt = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); |
| int64_t offset = insn.getOperand(1).getImm(); |
| |
| int64_t pc = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_pc_mips64, 0, &success); |
| if (!success) |
| return false; |
| |
| if (ReadRegister (eRegisterKindDWARF, dwarf_w0_mips64 + wt, reg_value)) |
| wr_val = reg_value.GetAsUInt128(fail_value); |
| else |
| return false; |
| |
| if((llvm::APInt::isSameValue(zero_value, wr_val) && !bnz) || (!llvm::APInt::isSameValue(zero_value, wr_val) && bnz)) |
| target = pc + offset; |
| else |
| target = pc + 8; |
| |
| Context context; |
| context.type = eContextRelativeBranchImmediate; |
| |
| if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_pc_mips64, target)) |
| return false; |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_LDST_Imm (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t base; |
| int64_t imm, address; |
| Context bad_vaddr_context; |
| |
| uint32_t num_operands = insn.getNumOperands(); |
| base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); |
| imm = insn.getOperand(num_operands-1).getImm(); |
| |
| RegisterInfo reg_info_base; |
| if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) |
| return false; |
| |
| /* read base register */ |
| address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); |
| if (!success) |
| return false; |
| |
| /* destination address */ |
| address = address + imm; |
| |
| /* Set the bad_vaddr register with base address used in the instruction */ |
| bad_vaddr_context.type = eContextInvalid; |
| WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); |
| |
| return true; |
| } |
| |
| bool |
| EmulateInstructionMIPS64::Emulate_LDST_Reg (llvm::MCInst& insn) |
| { |
| bool success = false; |
| uint32_t base, index; |
| int64_t address, index_address; |
| Context bad_vaddr_context; |
| |
| uint32_t num_operands = insn.getNumOperands(); |
| base = m_reg_info->getEncodingValue (insn.getOperand(num_operands-2).getReg()); |
| index = m_reg_info->getEncodingValue (insn.getOperand(num_operands-1).getReg()); |
| |
| RegisterInfo reg_info_base, reg_info_index; |
| if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + base, reg_info_base)) |
| return false; |
| |
| if (!GetRegisterInfo (eRegisterKindDWARF, dwarf_zero_mips + index, reg_info_index)) |
| return false; |
| |
| /* read base register */ |
| address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + base, 0, &success); |
| if (!success) |
| return false; |
| |
| /* read index register */ |
| index_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_zero_mips + index, 0, &success); |
| if (!success) |
| return false; |
| |
| /* destination address */ |
| address = address + index_address; |
| |
| /* Set the bad_vaddr register with base address used in the instruction */ |
| bad_vaddr_context.type = eContextInvalid; |
| WriteRegisterUnsigned (bad_vaddr_context, eRegisterKindDWARF, dwarf_bad_mips, address); |
| |
| return true; |
| } |