Index: lldb/trunk/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h =================================================================== --- lldb/trunk/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h +++ lldb/trunk/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h @@ -10,6 +10,17 @@ #ifndef EmulateInstructionMIPS64_h_ #define EmulateInstructionMIPS64_h_ +namespace llvm +{ + class MCDisassembler; + class MCSubtargetInfo; + class MCRegisterInfo; + class MCAsmInfo; + class MCContext; + class MCInstrInfo; + class MCInst; +} + #include "lldb/Core/EmulateInstruction.h" #include "lldb/Core/Error.h" #include "lldb/Interpreter/OptionValue.h" @@ -67,10 +78,7 @@ bool SetTargetTriple (const lldb_private::ArchSpec &arch); - EmulateInstructionMIPS64 (const lldb_private::ArchSpec &arch) : - EmulateInstruction (arch) - { - } + EmulateInstructionMIPS64 (const lldb_private::ArchSpec &arch); virtual bool SupportsEmulatingInstructionsOfType (lldb_private::InstructionType inst_type) @@ -105,23 +113,31 @@ typedef struct { - uint32_t mask; - uint32_t value; - bool (EmulateInstructionMIPS64::*callback) (const uint32_t opcode); - const char *name; - } Opcode; + const char *op_name; + bool (EmulateInstructionMIPS64::*callback) (llvm::MCInst& insn); + const char *insn_name; + } MipsOpcode; - static Opcode* - GetOpcodeForInstruction (const uint32_t opcode); + static MipsOpcode* + GetOpcodeForInstruction (const char *op_name); + + bool + Emulate_DADDiu (llvm::MCInst& insn); + + bool + Emulate_SD (llvm::MCInst& insn); + + bool + Emulate_LD (llvm::MCInst& insn); bool - Emulate_addsp_imm (const uint32_t opcode); + Emulate_B (llvm::MCInst& insn); bool - Emulate_store (const uint32_t opcode); + Emulate_BAL (llvm::MCInst& insn); bool - Emulate_load (const uint32_t opcode); + Emulate_BALC (llvm::MCInst& insn); bool nonvolatile_reg_p (uint64_t regnum); @@ -129,6 +145,13 @@ const char * GetRegisterName (unsigned reg_num, bool altnernate_name); +private: + std::unique_ptr m_disasm; + std::unique_ptr m_subtype_info; + std::unique_ptr m_reg_info; + std::unique_ptr m_asm_info; + std::unique_ptr m_context; + std::unique_ptr m_insn_info; }; #endif // EmulateInstructionMIPS64_h_ Index: lldb/trunk/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp =================================================================== --- lldb/trunk/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp +++ lldb/trunk/source/Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.cpp @@ -11,15 +11,26 @@ #include -#include "lldb/Core/ArchSpec.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.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 "llvm/Support/MathExtras.h" // for SignExtend32 template function #include "Plugins/Process/Utility/InstructionUtils.h" #include "Plugins/Process/Utility/RegisterContext_mips64.h" @@ -37,6 +48,32 @@ // //---------------------------------------------------------------------- +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); + assert (target); + + 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(), "", "")); + 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 () { @@ -171,8 +208,8 @@ case LLDB_REGNUM_GENERIC_RA: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_ra_mips64; break; case LLDB_REGNUM_GENERIC_FLAGS: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_sr_mips64; break; return true; - - default: return false; + default: + return false; } } @@ -187,7 +224,7 @@ reg_info.format = eFormatHex; reg_info.encoding = eEncodingUint; } - else if (reg_num >= gcc_dwarf_zero_mips64 && reg_num <= gcc_dwarf_pc_mips64) + else if ((int)reg_num >= gcc_dwarf_zero_mips64 && (int)reg_num <= gcc_dwarf_pc_mips64) { reg_info.byte_size = 8; reg_info.format = eFormatHex; @@ -216,33 +253,35 @@ return false; } -EmulateInstructionMIPS64::Opcode* -EmulateInstructionMIPS64::GetOpcodeForInstruction (const uint32_t opcode) +EmulateInstructionMIPS64::MipsOpcode* +EmulateInstructionMIPS64::GetOpcodeForInstruction (const char *op_name) { - static EmulateInstructionMIPS64::Opcode + static EmulateInstructionMIPS64::MipsOpcode g_opcodes[] = { //---------------------------------------------------------------------- // Prologue/Epilogue instructions //---------------------------------------------------------------------- + { "DADDiu", &EmulateInstructionMIPS64::Emulate_DADDiu, "DADDIU rt,rs,immediate" }, + { "SD", &EmulateInstructionMIPS64::Emulate_SD, "SD rt,offset(rs)" }, + { "LD", &EmulateInstructionMIPS64::Emulate_LD, "LD rt,offset(base)" }, - // stack adjustment - { 0xffff0000, 0x67bd0000, &EmulateInstructionMIPS64::Emulate_addsp_imm, "DADDIU rt, rs, immediate" }, - - // store register - { 0xfc000000, 0xfc000000, &EmulateInstructionMIPS64::Emulate_store, "SD rt, offset(Rn)" }, - - // Load register - { 0xfc000000, 0xdc000000, &EmulateInstructionMIPS64::Emulate_load, "LD rt, offset(base)" }, - + //---------------------------------------------------------------------- + // Branch instructions + //---------------------------------------------------------------------- + { "B", &EmulateInstructionMIPS64::Emulate_B, "B offset" }, + { "BAL", &EmulateInstructionMIPS64::Emulate_BAL, "BAL offset" }, + { "BALC", &EmulateInstructionMIPS64::Emulate_BALC, "BALC offset" }, }; + static const size_t k_num_mips_opcodes = llvm::array_lengthof(g_opcodes); - for (size_t i=0; i 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; + } - Opcode *opcode_data = GetOpcodeForInstruction(opcode); - bool success = false; + /* + * mc_insn.getOpcode() returns decoded opcode. However to make use + * of llvm::Mips:: 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; - // Call the Emulate... function. - success = (this->*opcode_data->callback) (opcode); + uint64_t old_pc = 0, new_pc = 0; + const bool auto_advance_pc = evaluate_options & eEmulateInstructionOptionAutoAdvancePC; + + if (auto_advance_pc) + { + old_pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_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, gcc_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, gcc_dwarf_pc_mips64, new_pc)) + return false; + } + } + return true; } @@ -303,7 +390,6 @@ unwind_plan.AppendRow (row); // All other registers are the same. - unwind_plan.SetSourceName ("EmulateInstructionMIPS64"); unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); @@ -324,6 +410,7 @@ case gcc_dwarf_r21_mips64: case gcc_dwarf_r22_mips64: case gcc_dwarf_r23_mips64: + case gcc_dwarf_gp_mips64: case gcc_dwarf_sp_mips64: case gcc_dwarf_r30_mips64: case gcc_dwarf_ra_mips64: @@ -335,111 +422,209 @@ } bool -EmulateInstructionMIPS64::Emulate_addsp_imm (const uint32_t opcode) +EmulateInstructionMIPS64::Emulate_DADDiu (llvm::MCInst& insn) { - - /* Get immediate operand */ - const uint32_t imm16 = Bits32(opcode, 15, 0); - bool success = false; - uint64_t result; + const uint32_t imm16 = insn.getOperand(2).getImm(); uint64_t imm = SignedBits(imm16, 15, 0); + uint64_t result; + uint32_t src, dst; - uint64_t operand1 = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_sp_mips64, 0, &success); - uint64_t operand2 = imm; + dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - result = operand1 + operand2; - - Context context; - RegisterInfo reg_info_Rn; - if (GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_sp_mips64, reg_info_Rn)) - context.SetRegisterPlusOffset (reg_info_Rn, imm); + /* Check if this is daddiu sp,,imm16 */ + if (dst == gcc_dwarf_sp_mips64) + { + /* read register */ + uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, 0, &success); + if (!success) + return false; + + result = src_opd_val + imm; - /* We are allocating bytes on stack */ - context.type = eContextAdjustStackPointer; + Context context; + RegisterInfo reg_info_sp; + if (GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_sp_mips64, reg_info_sp)) + context.SetRegisterPlusOffset (reg_info_sp, imm); - WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_sp_mips64, result); + /* We are allocating bytes on stack */ + context.type = eContextAdjustStackPointer; + + WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_sp_mips64, result); + } return true; } bool -EmulateInstructionMIPS64::Emulate_store (const uint32_t opcode) +EmulateInstructionMIPS64::Emulate_SD (llvm::MCInst& insn) { - uint32_t imm16 = Bits32(opcode, 15, 0); - uint32_t Rt = Bits32(opcode, 20, 16); - uint32_t base = Bits32(opcode, 25, 21); + bool success = false; + uint32_t imm16 = insn.getOperand(2).getImm(); uint64_t imm = SignedBits(imm16, 15, 0); - uint64_t address; + uint32_t src, base; - integer n = UInt(base); - integer t = UInt(Rt); + src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); - RegisterValue data_Rt; + /* We look for sp based non-volatile register stores */ + if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src)) + { + uint64_t address; + RegisterInfo reg_info_base; + RegisterInfo reg_info_src; - RegisterInfo reg_info_base; - RegisterInfo reg_info_Rt; + if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base) + || !GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src)) + return false; - if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + n, reg_info_base)) - return false; + /* read SP */ + address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success); + if (!success) + return false; - if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + t, reg_info_Rt)) - return false; + /* destination address */ + address = address + imm; + 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; + + return true; + } + + return false; +} + +bool +EmulateInstructionMIPS64::Emulate_LD (llvm::MCInst& insn) +{ + uint32_t src, base; + + src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); + + if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src)) + { + RegisterValue data_src; + RegisterInfo reg_info_src; + + if (!GetRegisterInfo (eRegisterKindDWARF, gcc_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_B (llvm::MCInst& insn) +{ bool success = false; - Context context_t; + uint64_t offset, pc, target; - /* We look for sp based non-volatile register stores */ - if (n == 29 && nonvolatile_reg_p(t)) - address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_sp_mips64, 0, &success); - else + /* + * B offset + * PC = PC + sign_ext (offset << 2) + */ + offset = insn.getOperand(0).getImm() << 2; + offset = SignedBits (offset, 17, 0); + + pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success); + if (!success) return false; - /* Calculate address to store */ - address = address + imm; + target = pc + offset; - context_t.type = eContextPushRegisterOnStack; - context_t.SetRegisterToRegisterPlusOffset (reg_info_Rt, reg_info_base, 0); + Context context; + context.type = eContextRelativeBranchImmediate; - uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; - Error error; + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target)) + return false; - if (!ReadRegister (®_info_Rt, data_Rt)) + return true; +} + +bool +EmulateInstructionMIPS64::Emulate_BAL (llvm::MCInst& insn) +{ + bool success = false; + uint64_t offset, pc, target; + + /* + * BAL offset + * offset = sign_ext (offset << 2) + * RA = PC + 8 + * PC = PC + offset + */ + offset = insn.getOperand(0).getImm() << 2; + offset = SignedBits (offset, 17, 0); + + pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success); + if (!success) return false; - if (data_Rt.GetAsMemoryData(®_info_Rt, buffer, reg_info_Rt.byte_size, eByteOrderLittle, error) == 0) + target = pc + offset; + + Context context; + + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target)) return false; - if (!WriteMemory(context_t, address, buffer, reg_info_Rt.byte_size)) + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 8)) return false; return true; } bool -EmulateInstructionMIPS64::Emulate_load (const uint32_t opcode) +EmulateInstructionMIPS64::Emulate_BALC (llvm::MCInst& insn) { - uint32_t Rt = Bits32(opcode, 20, 16); - uint32_t base = Bits32(opcode, 25, 21); + bool success = false; + uint64_t offset, pc, target; - integer n = UInt(base); - integer t = UInt(Rt); - - RegisterValue data_Rt; - RegisterInfo reg_info_Rt; + /* + * BALC offset + * offset = sign_ext (offset << 2) + * RA = PC + 4 + * PC = PC + 4 + offset + */ + offset = insn.getOperand(0).getImm() << 2; + offset = SignedBits (offset, 17, 0); - if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + t, reg_info_Rt)) + pc = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_pc_mips64, 0, &success); + if (!success) return false; - Context context_t; + target = pc + 4 + offset; - /* We are looking for "saved register" being restored from stack */ - if (!(n == 29) || !nonvolatile_reg_p(t)) - return false; + Context context; - context_t.type = eContextRegisterLoad; + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_pc_mips64, target)) + return false; - if (!WriteRegister (context_t, ®_info_Rt, data_Rt)) + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_ra_mips64, pc + 4)) return false; return true;