From cc13e4c62ebf0066216bb946667daac534c2800c Mon Sep 17 00:00:00 2001 From: Johnny Chen Date: Thu, 10 Feb 2011 01:52:38 +0000 Subject: [PATCH] Add EmulateLDRRtRnImm() for EncodingT1 of LDR (immediate, Thumb) to the g_thumb_opcodes table, and a helper method UnalignedSupport(). llvm-svn: 125258 --- .../Instruction/ARM/EmulateInstructionARM.cpp | 115 +++++++++++++++++- .../Instruction/ARM/EmulateInstructionARM.h | 6 + 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index bfc6827ad7f2..05cf271e2d49 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -1982,6 +1982,109 @@ EmulateInstructionARM::EmulateLDMIB (ARMEncoding encoding) return true; } +// Load Register (immediate) calculates an address from a base register value and +// an immediate offset, loads a word from memory, and writes to a register. +// LDR (immediate, Thumb) +bool +EmulateInstructionARM::EmulateLDRRtRnImm (ARMEncoding encoding) +{ +#if 0 + // ARM pseudo code... + if (ConditionPassed()) + { + EncodingSpecificOperations(); NullCheckIfThumbEE(15); + offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); + address = if index then offset_addr else R[n]; + data = MemU[address,4]; + if wback then R[n] = offset_addr; + if t == 15 then + if address<1:0> == '00' then LoadWritePC(data); else UNPREDICTABLE; + elsif UnalignedSupport() || address<1:0> = '00' then + R[t] = data; + else R[t] = bits(32) UNKNOWN; // Can only apply before ARMv7 + } +#endif + + bool success = false; + const uint32_t opcode = OpcodeAsUnsigned (&success); + if (!success) + return false; + + if (ConditionPassed()) + { + uint32_t Rt; // the destination register + uint32_t Rn; // the base register + uint32_t imm32; // the immediate offset used to form the address + addr_t offset_addr; // the offset address + addr_t address; // the calculated address + uint32_t data; // the literal data value from memory load + bool add, index, wback; + switch (encoding) { + case eEncodingT1: + Rt = Bits32(opcode, 5, 3); + Rn = Bits32(opcode, 2, 0); + imm32 = Bits32(opcode, 10, 6) << 2; // imm32 = ZeroExtend(imm5:'00', 32); + // index = TRUE; add = TRUE; wback = FALSE + add = true; + index = true; + wback = false; + break; + default: + return false; + } + uint32_t base = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); + if (!success) + return false; + if (add) + offset_addr = base + imm32; + else + offset_addr = base - imm32; + + address = (index ? offset_addr : base); + + if (wback) + { + EmulateInstruction::Context ctx = { EmulateInstruction::eContextRegisterPlusOffset, + eRegisterKindDWARF, + dwarf_r0 + Rn, + (int32_t) (offset_addr - base)}; + if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr)) + return false; + } + + // Prepare to write to the Rt register. + EmulateInstruction::Context context = {EmulateInstruction::eContextImmediate, + 0, + 0, + 0}; + + // Read memory from the address. + data = ReadMemoryUnsigned(context, address, 4, 0, &success); + if (!success) + return false; + context.arg0 = data; + + if (Rt == 15) + { + if (Bits32(address, 1, 0) == 0) + { + if (!LoadWritePC(context, data)) + return false; + } + else + return false; + } + else if (UnalignedSupport() || Bits32(address, 1, 0) == 0) + { + if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data)) + return false; + } + else + return false; + } + return true; +} + EmulateInstructionARM::ARMOpcode* EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode) { @@ -2140,7 +2243,8 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode) //---------------------------------------------------------------------- { 0xfffff800, 0x0000c800, ARMV4T_ABOVE, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDM, "ldm {!} " }, { 0xffd02000, 0xe8900000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateLDM, "ldm.w {!} " }, - { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb {!} " } + { 0xffd00000, 0xe9100000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateLDMDB, "ldmdb {!} " }, + { 0xfffff800, 0x00006800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateLDRRtRnImm, "ldr , [{,#imm}]"} }; @@ -2431,6 +2535,15 @@ EmulateInstructionARM::SelectInstrSet (Mode arm_or_thumb) return true; } +// This function returns TRUE if the processor currently provides support for +// unaligned memory accesses, or FALSE otherwise. This is always TRUE in ARMv7, +// controllable by the SCTLR.U bit in ARMv6, and always FALSE before ARMv6. +bool +EmulateInstructionARM::UnalignedSupport() +{ + return (ArchVersion() >= ARMv7); +} + bool EmulateInstructionARM::EvaluateInstruction () { diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index 1401b12c87b2..eca630a7a58e 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -166,6 +166,9 @@ public: bool SelectInstrSet(Mode arm_or_thumb); + bool + UnalignedSupport(); + protected: // Typedef for the callback function used during the emulation. @@ -267,6 +270,9 @@ protected: bool EmulateLDMIB (ARMEncoding encoding); + bool + EmulateLDRRtRnImm (ARMEncoding encoding); + uint32_t m_arm_isa; Mode m_inst_mode; uint32_t m_inst_cpsr;