Index: lldb/trunk/cmake/LLDBDependencies.cmake =================================================================== --- lldb/trunk/cmake/LLDBDependencies.cmake +++ lldb/trunk/cmake/LLDBDependencies.cmake @@ -54,6 +54,7 @@ lldbPluginABISysV_ppc64 lldbPluginInstructionARM lldbPluginInstructionARM64 + lldbPluginInstructionMIPS lldbPluginInstructionMIPS64 lldbPluginObjectFilePECOFF lldbPluginOSPython Index: lldb/trunk/lib/Makefile =================================================================== --- lldb/trunk/lib/Makefile +++ lldb/trunk/lib/Makefile @@ -48,6 +48,7 @@ lldbPluginDynamicLoaderMacOSX.a \ lldbPluginEmulateInstructionARM.a \ lldbPluginEmulateInstructionARM64.a \ + lldbPluginEmulateInstructionMIPS.a \ lldbPluginEmulateInstructionMIPS64.a \ lldbPluginInstrumentationRuntimeAddressSanitizer.a \ lldbPluginLanguageRuntimeCPlusPlusItaniumABI.a \ Index: lldb/trunk/source/Initialization/SystemInitializerCommon.cpp =================================================================== --- lldb/trunk/source/Initialization/SystemInitializerCommon.cpp +++ lldb/trunk/source/Initialization/SystemInitializerCommon.cpp @@ -18,6 +18,7 @@ #include "Plugins/DynamicLoader/MacOSX-DYLD/DynamicLoaderMacOSXDYLD.h" #include "Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h" #include "Plugins/Instruction/ARM/EmulateInstructionARM.h" +#include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h" #include "Plugins/Instruction/MIPS64/EmulateInstructionMIPS64.h" #include "Plugins/ObjectContainer/BSD-Archive/ObjectContainerBSDArchive.h" #include "Plugins/ObjectContainer/Universal-Mach-O/ObjectContainerUniversalMachO.h" @@ -113,6 +114,7 @@ platform_android::PlatformAndroid::Initialize(); EmulateInstructionARM::Initialize(); + EmulateInstructionMIPS::Initialize(); EmulateInstructionMIPS64::Initialize(); //---------------------------------------------------------------------- @@ -163,6 +165,7 @@ PlatformiOSSimulator::Terminate(); EmulateInstructionARM::Terminate(); + EmulateInstructionMIPS::Terminate(); EmulateInstructionMIPS64::Terminate(); #if defined(__APPLE__) Index: lldb/trunk/source/Plugins/Instruction/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/Instruction/CMakeLists.txt +++ lldb/trunk/source/Plugins/Instruction/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(ARM) add_subdirectory(ARM64) +add_subdirectory(MIPS) add_subdirectory(MIPS64) Index: lldb/trunk/source/Plugins/Instruction/MIPS/CMakeLists.txt =================================================================== --- lldb/trunk/source/Plugins/Instruction/MIPS/CMakeLists.txt +++ lldb/trunk/source/Plugins/Instruction/MIPS/CMakeLists.txt @@ -0,0 +1,5 @@ +set(LLVM_NO_RTTI 1) + +add_lldb_library(lldbPluginInstructionMIPS + EmulateInstructionMIPS.cpp + ) Index: lldb/trunk/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h =================================================================== --- lldb/trunk/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h +++ lldb/trunk/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.h @@ -0,0 +1,148 @@ +//===-- EmulateInstructionMIPS.h ------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef EmulateInstructionMIPS_h_ +#define EmulateInstructionMIPS_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" + +class EmulateInstructionMIPS : public lldb_private::EmulateInstruction +{ +public: + static void + Initialize (); + + static void + Terminate (); + + static lldb_private::ConstString + GetPluginNameStatic (); + + static const char * + GetPluginDescriptionStatic (); + + static lldb_private::EmulateInstruction * + CreateInstance (const lldb_private::ArchSpec &arch, + lldb_private::InstructionType inst_type); + + static bool + SupportsEmulatingInstructionsOfTypeStatic (lldb_private::InstructionType inst_type) + { + switch (inst_type) + { + case lldb_private::eInstructionTypeAny: + case lldb_private::eInstructionTypePrologueEpilogue: + case lldb_private::eInstructionTypePCModifying: + return true; + + case lldb_private::eInstructionTypeAll: + return false; + } + return false; + } + + virtual lldb_private::ConstString + GetPluginName(); + + virtual lldb_private::ConstString + GetShortPluginName() + { + return GetPluginNameStatic(); + } + + virtual uint32_t + GetPluginVersion() + { + return 1; + } + + bool + SetTargetTriple (const lldb_private::ArchSpec &arch); + + EmulateInstructionMIPS (const lldb_private::ArchSpec &arch); + + virtual bool + SupportsEmulatingInstructionsOfType (lldb_private::InstructionType inst_type) + { + return SupportsEmulatingInstructionsOfTypeStatic (inst_type); + } + + virtual bool + ReadInstruction (); + + virtual bool + EvaluateInstruction (uint32_t evaluate_options); + + virtual bool + TestEmulation (lldb_private::Stream *out_stream, + lldb_private::ArchSpec &arch, + lldb_private::OptionValueDictionary *test_data) + { + return false; + } + + virtual bool + GetRegisterInfo (lldb::RegisterKind reg_kind, + uint32_t reg_num, + lldb_private::RegisterInfo ®_info); + + virtual bool + CreateFunctionEntryUnwind (lldb_private::UnwindPlan &unwind_plan); + + +protected: + + typedef struct + { + const char *op_name; + bool (EmulateInstructionMIPS::*callback) (llvm::MCInst& insn); + const char *insn_name; + } MipsOpcode; + + static MipsOpcode* + GetOpcodeForInstruction (const char *op_name); + + bool + Emulate_ADDiu (llvm::MCInst& insn); + + bool + Emulate_SW (llvm::MCInst& insn); + + bool + Emulate_LW (llvm::MCInst& insn); + + bool + nonvolatile_reg_p (uint32_t regnum); + + 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 // EmulateInstructionMIPS_h_ Index: lldb/trunk/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp =================================================================== --- lldb/trunk/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp +++ lldb/trunk/source/Plugins/Instruction/MIPS/EmulateInstructionMIPS.cpp @@ -0,0 +1,591 @@ +//===-- EmulateInstructionMIPS.cpp -------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "EmulateInstructionMIPS.h" + +#include + +#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 "Plugins/Process/Utility/InstructionUtils.h" +#include "Plugins/Process/Utility/RegisterContext_mips64.h" //mips32 has same registers nos as mips64 + +using namespace lldb; +using namespace lldb_private; + +#define UInt(x) ((uint64_t)x) +#define integer int64_t + + +//---------------------------------------------------------------------- +// +// EmulateInstructionMIPS implementation +// +//---------------------------------------------------------------------- + +#ifdef __mips__ +extern "C" { + void LLVMInitializeMipsTargetInfo (); + void LLVMInitializeMipsTarget (); + void LLVMInitializeMipsAsmPrinter (); + void LLVMInitializeMipsTargetMC (); + void LLVMInitializeMipsDisassembler (); +} +#endif + +EmulateInstructionMIPS::EmulateInstructionMIPS (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; + } + + 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, "")); + 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 +EmulateInstructionMIPS::Initialize () +{ + PluginManager::RegisterPlugin (GetPluginNameStatic (), + GetPluginDescriptionStatic (), + CreateInstance); +} + +void +EmulateInstructionMIPS::Terminate () +{ + PluginManager::UnregisterPlugin (CreateInstance); +} + +ConstString +EmulateInstructionMIPS::GetPluginNameStatic () +{ + ConstString g_plugin_name ("lldb.emulate-instruction.mips32"); + return g_plugin_name; +} + +lldb_private::ConstString +EmulateInstructionMIPS::GetPluginName() +{ + static ConstString g_plugin_name ("EmulateInstructionMIPS"); + return g_plugin_name; +} + +const char * +EmulateInstructionMIPS::GetPluginDescriptionStatic () +{ + return "Emulate instructions for the MIPS32 architecture."; +} + +EmulateInstruction * +EmulateInstructionMIPS::CreateInstance (const ArchSpec &arch, InstructionType inst_type) +{ + if (EmulateInstructionMIPS::SupportsEmulatingInstructionsOfTypeStatic(inst_type)) + { + if (arch.GetTriple().getArch() == llvm::Triple::mips + || arch.GetTriple().getArch() == llvm::Triple::mipsel) + { + std::auto_ptr emulate_insn_ap (new EmulateInstructionMIPS (arch)); + if (emulate_insn_ap.get()) + return emulate_insn_ap.release(); + } + } + + return NULL; +} + +bool +EmulateInstructionMIPS::SetTargetTriple (const ArchSpec &arch) +{ + if (arch.GetTriple().getArch () == llvm::Triple::mips + || arch.GetTriple().getArch () == llvm::Triple::mipsel) + return true; + return false; +} + +const char * +EmulateInstructionMIPS::GetRegisterName (unsigned reg_num, bool alternate_name) +{ + if (alternate_name) + { + switch (reg_num) + { + case gcc_dwarf_sp_mips64: return "r29"; + case gcc_dwarf_r30_mips64: return "r30"; + case gcc_dwarf_ra_mips64: return "r31"; + default: + break; + } + return nullptr; + } + + switch (reg_num) + { + case gcc_dwarf_zero_mips64: return "r0"; + case gcc_dwarf_r1_mips64: return "r1"; + case gcc_dwarf_r2_mips64: return "r2"; + case gcc_dwarf_r3_mips64: return "r3"; + case gcc_dwarf_r4_mips64: return "r4"; + case gcc_dwarf_r5_mips64: return "r5"; + case gcc_dwarf_r6_mips64: return "r6"; + case gcc_dwarf_r7_mips64: return "r7"; + case gcc_dwarf_r8_mips64: return "r8"; + case gcc_dwarf_r9_mips64: return "r9"; + case gcc_dwarf_r10_mips64: return "r10"; + case gcc_dwarf_r11_mips64: return "r11"; + case gcc_dwarf_r12_mips64: return "r12"; + case gcc_dwarf_r13_mips64: return "r13"; + case gcc_dwarf_r14_mips64: return "r14"; + case gcc_dwarf_r15_mips64: return "r15"; + case gcc_dwarf_r16_mips64: return "r16"; + case gcc_dwarf_r17_mips64: return "r17"; + case gcc_dwarf_r18_mips64: return "r18"; + case gcc_dwarf_r19_mips64: return "r19"; + case gcc_dwarf_r20_mips64: return "r20"; + case gcc_dwarf_r21_mips64: return "r21"; + case gcc_dwarf_r22_mips64: return "r22"; + case gcc_dwarf_r23_mips64: return "r23"; + case gcc_dwarf_r24_mips64: return "r24"; + case gcc_dwarf_r25_mips64: return "r25"; + case gcc_dwarf_r26_mips64: return "r26"; + case gcc_dwarf_r27_mips64: return "r27"; + case gcc_dwarf_gp_mips64: return "gp"; + case gcc_dwarf_sp_mips64: return "sp"; + case gcc_dwarf_r30_mips64: return "fp"; + case gcc_dwarf_ra_mips64: return "ra"; + case gcc_dwarf_sr_mips64: return "sr"; + case gcc_dwarf_lo_mips64: return "lo"; + case gcc_dwarf_hi_mips64: return "hi"; + case gcc_dwarf_bad_mips64: return "bad"; + case gcc_dwarf_cause_mips64: return "cause"; + case gcc_dwarf_pc_mips64: return "pc"; + + } + return nullptr; +} + +bool +EmulateInstructionMIPS::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 = gcc_dwarf_pc_mips64; break; + case LLDB_REGNUM_GENERIC_SP: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_sp_mips64; break; + case LLDB_REGNUM_GENERIC_FP: reg_kind = eRegisterKindDWARF; reg_num = gcc_dwarf_r30_mips64; break; + 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; + default: + return false; + } + } + + if (reg_kind == eRegisterKindDWARF) + { + ::memset (®_info, 0, sizeof(RegisterInfo)); + ::memset (reg_info.kinds, LLDB_INVALID_REGNUM, sizeof(reg_info.kinds)); + + if ((int)reg_num >= gcc_dwarf_zero_mips64 && (int)reg_num <= gcc_dwarf_pc_mips64) + { + reg_info.byte_size = 4; + reg_info.format = eFormatHex; + reg_info.encoding = eEncodingUint; + reg_info.name = GetRegisterName (reg_num, false); + reg_info.alt_name = GetRegisterName (reg_num, true); + reg_info.kinds[eRegisterKindDWARF] = reg_num; + } + else + { + return false; + } + + switch (reg_num) + { + case gcc_dwarf_r30_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FP; break; + case gcc_dwarf_ra_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_RA; break; + case gcc_dwarf_sp_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_SP; break; + case gcc_dwarf_pc_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_PC; break; + case gcc_dwarf_sr_mips64: reg_info.kinds[eRegisterKindGeneric] = LLDB_REGNUM_GENERIC_FLAGS; break; + default: break; + } + return true; + } + return false; +} + +EmulateInstructionMIPS::MipsOpcode* +EmulateInstructionMIPS::GetOpcodeForInstruction (const char *op_name) +{ + static EmulateInstructionMIPS::MipsOpcode + g_opcodes[] = + { + //---------------------------------------------------------------------- + // Prologue/Epilogue instructions + //---------------------------------------------------------------------- + { "ADDiu", &EmulateInstructionMIPS::Emulate_ADDiu, "ADDIU rt,rs,immediate" }, + { "SW", &EmulateInstructionMIPS::Emulate_SW, "SW rt,offset(rs)" }, + { "LW", &EmulateInstructionMIPS::Emulate_LW, "LW rt,offset(base)" }, + }; + + 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 +EmulateInstructionMIPS::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 +EmulateInstructionMIPS::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 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:: 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, 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; +} + +bool +EmulateInstructionMIPS::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(gcc_dwarf_sp_mips64, 0); + + // Our previous PC is in the RA + row->SetRegisterLocationToRegister(gcc_dwarf_pc_mips64, gcc_dwarf_ra_mips64, can_replace); + + unwind_plan.AppendRow (row); + + // All other registers are the same. + unwind_plan.SetSourceName ("EmulateInstructionMIPS"); + unwind_plan.SetSourcedFromCompiler (eLazyBoolNo); + unwind_plan.SetUnwindPlanValidAtAllInstructions (eLazyBoolYes); + + return true; +} + +bool +EmulateInstructionMIPS::nonvolatile_reg_p (uint32_t regnum) +{ + switch (regnum) + { + case gcc_dwarf_r16_mips64: + case gcc_dwarf_r17_mips64: + case gcc_dwarf_r18_mips64: + case gcc_dwarf_r19_mips64: + case gcc_dwarf_r20_mips64: + 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: + return true; + default: + return false; + } + return false; +} + +bool +EmulateInstructionMIPS::Emulate_ADDiu (llvm::MCInst& insn) +{ + bool success = false; + const uint32_t imm16 = insn.getOperand(2).getImm(); + uint32_t imm = SignedBits(imm16, 15, 0); + uint64_t result; + uint32_t src, dst; + + dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); + + /* Check if this is addiu 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; + + Context context; + RegisterInfo reg_info_sp; + if (GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_sp_mips64, reg_info_sp)) + context.SetRegisterPlusOffset (reg_info_sp, imm); + + /* We are allocating bytes on stack */ + context.type = eContextAdjustStackPointer; + + WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_sp_mips64, result); + } + + return true; +} + +bool +EmulateInstructionMIPS::Emulate_SW (llvm::MCInst& insn) +{ + bool success = false; + uint32_t imm16 = insn.getOperand(2).getImm(); + uint32_t imm = SignedBits(imm16, 15, 0); + uint32_t src, base; + + src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); + base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); + + /* We look for sp based non-volatile register stores */ + if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src)) + { + uint32_t address; + RegisterInfo reg_info_base; + RegisterInfo reg_info_src; + + if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base) + || !GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src)) + return false; + + /* read SP */ + address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success); + if (!success) + 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 +EmulateInstructionMIPS::Emulate_LW (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; +} Index: lldb/trunk/source/Plugins/Instruction/MIPS/Makefile =================================================================== --- lldb/trunk/source/Plugins/Instruction/MIPS/Makefile +++ lldb/trunk/source/Plugins/Instruction/MIPS/Makefile @@ -0,0 +1,14 @@ +##===- source/Plugins/Instruction/MIPS/Makefile -------------*- Makefile -*-===## +# +# The LLVM Compiler Infrastructure +# +# This file is distributed under the University of Illinois Open Source +# License. See LICENSE.TXT for details. +# +##===----------------------------------------------------------------------===## + +LLDB_LEVEL := ../../../.. +LIBRARYNAME := lldbPluginEmulateInstructionMIPS +BUILD_ARCHIVE = 1 + +include $(LLDB_LEVEL)/Makefile Index: lldb/trunk/source/Plugins/Makefile =================================================================== --- lldb/trunk/source/Plugins/Makefile +++ lldb/trunk/source/Plugins/Makefile @@ -19,7 +19,7 @@ ObjectContainer/Universal-Mach-O ObjectFile/Mach-O \ ObjectFile/JIT SymbolFile/DWARF SymbolFile/Symtab Process/Utility \ DynamicLoader/Static Platform Process/gdb-remote \ - Instruction/ARM Instruction/ARM64 Instruction/MIPS64 \ + Instruction/ARM Instruction/ARM64 Instruction/MIPS Instruction/MIPS64 \ UnwindAssembly/InstEmulation UnwindAssembly/x86 \ LanguageRuntime/CPlusPlus/ItaniumABI \ LanguageRuntime/ObjC/AppleObjCRuntime \ Index: lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp =================================================================== --- lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp +++ lldb/trunk/source/Plugins/Platform/Linux/PlatformLinux.cpp @@ -614,6 +614,7 @@ } } break; + case llvm::Triple::mips: case llvm::Triple::mips64: { static const uint8_t g_hex_opcode[] = { 0x00, 0x00, 0x00, 0x0d }; @@ -621,6 +622,7 @@ trap_opcode_size = sizeof(g_hex_opcode); } break; + case llvm::Triple::mipsel: case llvm::Triple::mips64el: { static const uint8_t g_hex_opcode[] = { 0x0d, 0x00, 0x00, 0x00 }; Index: lldb/trunk/source/Target/Thread.cpp =================================================================== --- lldb/trunk/source/Target/Thread.cpp +++ lldb/trunk/source/Target/Thread.cpp @@ -2320,6 +2320,8 @@ case llvm::Triple::arm: case llvm::Triple::aarch64: case llvm::Triple::thumb: + case llvm::Triple::mips: + case llvm::Triple::mipsel: case llvm::Triple::mips64: case llvm::Triple::mips64el: case llvm::Triple::ppc: