diff options
3 files changed, 111 insertions, 6 deletions
diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp index 2df182bcbc5..9dcd4e5d653 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -1000,7 +1000,7 @@ EmulateInstructionARM::EmulateADDSPImm (ARMEncoding encoding) uint32_t imm32; // the immediate operand switch (encoding) { case eEncodingT2: - imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) + imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) break; default: return false; @@ -1450,7 +1450,7 @@ EmulateInstructionARM::EmulateSUBSPImm (ARMEncoding encoding) case eEncodingT1: Rd = 13; setflags = false; - imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) + imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) break; case eEncodingT2: Rd = Bits32(opcode, 11, 8); @@ -4664,6 +4664,73 @@ EmulateInstructionARM::EmulateADCReg (ARMEncoding encoding) return true; } +// This instruction adds an immediate value to the PC value to form a PC-relative address, +// and writes the result to the destination register. +bool +EmulateInstructionARM::EmulateADR (ARMEncoding encoding) +{ +#if 0 + // ARM pseudo code... + if ConditionPassed() then + EncodingSpecificOperations(); + result = if add then (Align(PC,4) + imm32) else (Align(PC,4) - imm32); + if d == 15 then // Can only occur for ARM encodings + ALUWritePC(result); + else + R[d] = result; +#endif + + bool success = false; + const uint32_t opcode = OpcodeAsUnsigned (&success); + if (!success) + return false; + + if (ConditionPassed()) + { + uint32_t Rd; + uint32_t imm32; // the immediate value to be added/subtracted to/from the PC + bool add; + switch (encoding) + { + case eEncodingT1: + Rd = Bits32(opcode, 10, 8); + imm32 = ThumbImm8Scaled(opcode); // imm32 = ZeroExtend(imm8:'00', 32) + break; + case eEncodingT2: + case eEncodingT3: + Rd = Bits32(opcode, 11, 8); + imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) + add = (Bits32(opcode, 24, 21) == 0); // 0b0000 => ADD; 0b0101 => SUB + if (BadReg(Rd)) + return false; + break; + case eEncodingA1: + case eEncodingA2: + Rd = Bits32(opcode, 15, 12); + imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) + add = (Bits32(opcode, 24, 21) == 0x4); // 0b0100 => ADD; 0b0010 => SUB + break; + default: + return false; + } + + // Read the PC value. + uint32_t pc = ReadCoreReg(PC_REG, &success); + if (!success) + return false; + + uint32_t result = (add ? Align(pc, 4) + imm32 : Align(pc, 4) - imm32); + + EmulateInstruction::Context context; + context.type = EmulateInstruction::eContextImmediate; + context.SetNoArgs (); + + if (!WriteCoreReg(context, result, Rd)) + return false; + } + return true; +} + // This instruction performs a bitwise AND of a register value and an immediate value, and writes the result // to the destination register. It can optionally update the condition flags based on the result. bool @@ -6679,6 +6746,9 @@ EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode) { 0x0fe00000, 0x02800000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateADDImmARM, "add{s}<c> <Rd>, <Rn>, #const"}, // add (register) { 0x0fe00010, 0x00800000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateADDReg, "add{s}<c> <Rd>, <Rn>, <Rm> {,<shift>}"}, + // adr + { 0x0fff0000, 0x028f0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, + { 0x0fff0000, 0x024f0000, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"}, // and (immediate) { 0x0fe00000, 0x02000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #const"}, // and (register) @@ -6871,6 +6941,10 @@ EmulateInstructionARM::GetThumbOpcodeForInstruction (const uint32_t opcode) { 0xfffffe00, 0x00001800, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateADDReg, "adds|add<c> <Rd>, <Rn>, <Rm>"}, // Make sure "add sp, <Rm>" comes before this instruction, so there's no ambiguity decoding the two. { 0xffffff00, 0x00004400, ARMvAll, eEncodingT2, eSize16, &EmulateInstructionARM::EmulateADDReg, "add<c> <Rdn>, <Rm>"}, + // adr + { 0xfffff800, 0x0000a000, ARMvAll, eEncodingT1, eSize16, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, + { 0xfbff8000, 0xf2af0000, ARMV6T2_ABOVE, eEncodingT2, eSize32, &EmulateInstructionARM::EmulateADR, "sub<c> <Rd>, PC, #<const>"}, + { 0xfbff8000, 0xf20f0000, ARMV6T2_ABOVE, eEncodingT3, eSize32, &EmulateInstructionARM::EmulateADR, "add<c> <Rd>, PC, #<const>"}, // and (immediate) { 0xfbe08000, 0xf0000000, ARMV6T2_ABOVE, eEncodingT1, eSize32, &EmulateInstructionARM::EmulateANDImm, "and{s}<c> <Rd>, <Rn>, #<const>"}, // and (register) @@ -7397,7 +7471,22 @@ EmulateInstructionARM::WriteCoreRegOptionalFlags (Context &context, } else { - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, result)) + uint32_t reg_kind, reg_num; + switch (Rd) + { + case SP_REG: + reg_kind = eRegisterKindGeneric; + reg_num = LLDB_REGNUM_GENERIC_SP; + break; + case LR_REG: + reg_kind = eRegisterKindGeneric; + reg_num = LLDB_REGNUM_GENERIC_RA; + break; + default: + reg_kind = eRegisterKindDWARF; + reg_num = dwarf_r0 + Rd; + } + if (!WriteRegisterUnsigned (context, reg_kind, reg_num, result)) return false; if (setflags) return WriteFlags (context, result, carry, overflow); diff --git a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h index 60780a76560..c982e78463c 100644 --- a/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h +++ b/lldb/source/Plugins/Instruction/ARM/EmulateInstructionARM.h @@ -207,6 +207,15 @@ public: const uint32_t carry = ~0u, const uint32_t overflow = ~0u); + bool + WriteCoreReg (Context &context, + const uint32_t result, + const uint32_t Rd) + { + // Don't set the flags. + return WriteCoreRegOptionalFlags(context, result, Rd, false); + } + // See A8.6.35 CMP (immediate) Operation. // Default arguments are specified for carry and overflow parameters, which means // not to update the respective flags. @@ -679,11 +688,11 @@ protected: // A8.6.211 SUB (immediate, Thumb) - Encoding T1, T2 bool - EmulateSUBImmediateThumb (ARMEncoding encoding); + EmulateSUBImmThumb (ARMEncoding encoding); // A8.6.212 SUB (immediate, ARM) - Encoding A1 bool - EmulateSUBImmediateARM (ARMEncoding encoding); + EmulateSUBImmARM (ARMEncoding encoding); // A8.6.222 SXTB - Encoding T1 bool diff --git a/lldb/source/Plugins/Process/Utility/ARMUtils.h b/lldb/source/Plugins/Process/Utility/ARMUtils.h index 093fe3bbf85..7b614d876ad 100644 --- a/lldb/source/Plugins/Process/Utility/ARMUtils.h +++ b/lldb/source/Plugins/Process/Utility/ARMUtils.h @@ -314,12 +314,19 @@ static inline uint32_t ThumbImm12(uint32_t opcode) } // imm32 = ZeroExtend(imm7:'00', 32) -static inline uint32_t ThumbImmScaled(uint32_t opcode) +static inline uint32_t ThumbImm7Scaled(uint32_t opcode) { const uint32_t imm7 = bits(opcode, 6, 0); return imm7 * 4; } +// imm32 = ZeroExtend(imm8:'00', 32) +static inline uint32_t ThumbImm8Scaled(uint32_t opcode) +{ + const uint32_t imm8 = bits(opcode, 7, 0); + return imm8 * 4; +} + // This function performs the check for the register numbers 13 and 15 that are // not permitted for many Thumb register specifiers. static inline bool BadReg(uint32_t n) { return n == 13 || n == 15; } |