//===-- EmulateInstructionARM.cpp -------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include #include "EmulateInstructionARM.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/ConstString.h" #include "Plugins/Process/Utility/ARMDefines.h" #include "Plugins/Process/Utility/ARMUtils.h" #include "Utility/ARM_DWARF_Registers.h" #include "llvm/Support/MathExtras.h" // for SignExtend32 template function // and CountTrailingZeros_32 function using namespace lldb; using namespace lldb_private; // Convenient macro definitions. #define APSR_C Bit32(m_inst_cpsr, CPSR_C) #define APSR_V Bit32(m_inst_cpsr, CPSR_V) //---------------------------------------------------------------------- // // ITSession implementation // //---------------------------------------------------------------------- // A8.6.50 // Valid return values are {1, 2, 3, 4}, with 0 signifying an error condition. static unsigned short CountITSize(unsigned ITMask) { // First count the trailing zeros of the IT mask. unsigned TZ = llvm::CountTrailingZeros_32(ITMask); if (TZ > 3) { printf("Encoding error: IT Mask '0000'\n"); return 0; } return (4 - TZ); } // Init ITState. Note that at least one bit is always 1 in mask. bool ITSession::InitIT(unsigned short bits7_0) { ITCounter = CountITSize(Bits32(bits7_0, 3, 0)); if (ITCounter == 0) return false; // A8.6.50 IT unsigned short FirstCond = Bits32(bits7_0, 7, 4); if (FirstCond == 0xF) { printf("Encoding error: IT FirstCond '1111'\n"); return false; } if (FirstCond == 0xE && ITCounter != 1) { printf("Encoding error: IT FirstCond '1110' && Mask != '1000'\n"); return false; } ITState = bits7_0; return true; } // Update ITState if necessary. void ITSession::ITAdvance() { assert(ITCounter); --ITCounter; if (ITCounter == 0) ITState = 0; else { unsigned short NewITState4_0 = Bits32(ITState, 4, 0) << 1; SetBits32(ITState, 4, 0, NewITState4_0); } } // Return true if we're inside an IT Block. bool ITSession::InITBlock() { return ITCounter != 0; } // Return true if we're the last instruction inside an IT Block. bool ITSession::LastInITBlock() { return ITCounter == 1; } // Get condition bits for the current thumb instruction. uint32_t ITSession::GetCond() { if (InITBlock()) return Bits32(ITState, 7, 4); else return COND_AL; } // ARM constants used during decoding #define REG_RD 0 #define LDM_REGLIST 1 #define PC_REG 15 #define PC_REGLIST_BIT 0x8000 #define ARMv4 (1u << 0) #define ARMv4T (1u << 1) #define ARMv5T (1u << 2) #define ARMv5TE (1u << 3) #define ARMv5TEJ (1u << 4) #define ARMv6 (1u << 5) #define ARMv6K (1u << 6) #define ARMv6T2 (1u << 7) #define ARMv7 (1u << 8) #define ARMv8 (1u << 9) #define ARMvAll (0xffffffffu) #define ARMV4T_ABOVE (ARMv4T|ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8) #define ARMV5_ABOVE (ARMv5T|ARMv5TE|ARMv5TEJ|ARMv6|ARMv6K|ARMv6T2|ARMv7|ARMv8) #define ARMV6T2_ABOVE (ARMv6T2|ARMv7|ARMv8) //---------------------------------------------------------------------- // // EmulateInstructionARM implementation // //---------------------------------------------------------------------- void EmulateInstructionARM::Initialize () { } void EmulateInstructionARM::Terminate () { } // Write "bits (32) UNKNOWN" to memory address "address". Helper function for many ARM instructions. bool EmulateInstructionARM::WriteBits32UnknownToMemory (addr_t address) { EmulateInstruction::Context context; context.type = EmulateInstruction::eContextWriteMemoryRandomBits; context.SetNoArgs (); uint32_t random_data = rand (); const uint32_t addr_byte_size = GetAddressByteSize(); if (!MemAWrite (context, address, random_data, addr_byte_size)) return false; return true; } // Write "bits (32) UNKNOWN" to register n. Helper function for many ARM instructions. bool EmulateInstructionARM::WriteBits32Unknown (int n) { EmulateInstruction::Context context; context.type = EmulateInstruction::eContextWriteRegisterRandomBits; context.SetNoArgs (); bool success; uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) return false; return true; } // Push Multiple Registers stores multiple registers to the stack, storing to // consecutive memory locations ending just below the address in SP, and updates // SP to point to the start of the stored data. bool EmulateInstructionARM::EmulatePUSH (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); NullCheckIfThumbEE(13); address = SP - 4*BitCount(registers); for (i = 0 to 14) { if (registers == ’1’) { if i == 13 && i != LowestSetBit(registers) // Only possible for encoding A1 MemA[address,4] = bits(32) UNKNOWN; else MemA[address,4] = R[i]; address = address + 4; } } if (registers<15> == ’1’) // Only possible for encoding A1 or A2 MemA[address,4] = PCStoreValue(); SP = SP - 4*BitCount(registers); } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const uint32_t addr_byte_size = GetAddressByteSize(); const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t registers = 0; uint32_t Rt; // the source register switch (encoding) { case eEncodingT1: registers = Bits32(opcode, 7, 0); // The M bit represents LR. if (Bit32(opcode, 8)) registers |= (1u << 14); // if BitCount(registers) < 1 then UNPREDICTABLE; if (BitCount(registers) < 1) return false; break; case eEncodingT2: // Ignore bits 15 & 13. registers = Bits32(opcode, 15, 0) & ~0xa000; // if BitCount(registers) < 2 then UNPREDICTABLE; if (BitCount(registers) < 2) return false; break; case eEncodingT3: Rt = Bits32(opcode, 15, 12); // if BadReg(t) then UNPREDICTABLE; if (BadReg(Rt)) return false; registers = (1u << Rt); break; case eEncodingA1: registers = Bits32(opcode, 15, 0); // Instead of return false, let's handle the following case as well, // which amounts to pushing one reg onto the full descending stacks. // if BitCount(register_list) < 2 then SEE STMDB / STMFD; break; case eEncodingA2: Rt = Bits32(opcode, 15, 12); // if t == 13 then UNPREDICTABLE; if (Rt == dwarf_sp) return false; registers = (1u << Rt); break; default: return false; } addr_t sp_offset = addr_byte_size * BitCount (registers); addr_t addr = sp - sp_offset; uint32_t i; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextPushRegisterOnStack; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, 0); for (i=0; i<15; ++i) { if (BitIsSet (registers, i)) { dwarf_reg.num = dwarf_r0 + i; context.SetRegisterPlusOffset (dwarf_reg, addr - sp); uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_reg.num, 0, &success); if (!success) return false; if (!MemAWrite (context, addr, reg_value, addr_byte_size)) return false; addr += addr_byte_size; } } if (BitIsSet (registers, 15)) { dwarf_reg.num = dwarf_pc; context.SetRegisterPlusOffset (dwarf_reg, addr - sp); const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; if (!MemAWrite (context, addr, pc + 8, addr_byte_size)) return false; } context.type = EmulateInstruction::eContextAdjustStackPointer; context.SetImmediateSigned (-sp_offset); if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset)) return false; } return true; } // Pop Multiple Registers loads multiple registers from the stack, loading from // consecutive memory locations staring at the address in SP, and updates // SP to point just above the loaded data. bool EmulateInstructionARM::EmulatePOP (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); NullCheckIfThumbEE(13); address = SP; for i = 0 to 14 if registers == ‘1’ then R[i} = if UnalignedAllowed then MemU[address,4] else MemA[address,4]; address = address + 4; if registers<15> == ‘1’ then if UnalignedAllowed then LoadWritePC(MemU[address,4]); else LoadWritePC(MemA[address,4]); if registers<13> == ‘0’ then SP = SP + 4*BitCount(registers); if registers<13> == ‘1’ then SP = bits(32) UNKNOWN; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const uint32_t addr_byte_size = GetAddressByteSize(); const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t registers = 0; uint32_t Rt; // the destination register switch (encoding) { case eEncodingT1: registers = Bits32(opcode, 7, 0); // The P bit represents PC. if (Bit32(opcode, 8)) registers |= (1u << 15); // if BitCount(registers) < 1 then UNPREDICTABLE; if (BitCount(registers) < 1) return false; break; case eEncodingT2: // Ignore bit 13. registers = Bits32(opcode, 15, 0) & ~0x2000; // if BitCount(registers) < 2 || (P == '1' && M == '1') then UNPREDICTABLE; if (BitCount(registers) < 2 || (Bit32(opcode, 15) && Bit32(opcode, 14))) return false; // if registers<15> == '1' && InITBlock() && !LastInITBlock() then UNPREDICTABLE; if (BitIsSet(registers, 15) && InITBlock() && !LastInITBlock()) return false; break; case eEncodingT3: Rt = Bits32(opcode, 15, 12); // if t == 13 || (t == 15 && InITBlock() && !LastInITBlock()) then UNPREDICTABLE; if (Rt == 13) return false; if (Rt == 15 && InITBlock() && !LastInITBlock()) return false; registers = (1u << Rt); break; case eEncodingA1: registers = Bits32(opcode, 15, 0); // Instead of return false, let's handle the following case as well, // which amounts to popping one reg from the full descending stacks. // if BitCount(register_list) < 2 then SEE LDM / LDMIA / LDMFD; // if registers<13> == ‘1’ && ArchVersion() >= 7 then UNPREDICTABLE; if (BitIsSet(opcode, 13) && ArchVersion() >= ARMv7) return false; break; case eEncodingA2: Rt = Bits32(opcode, 15, 12); // if t == 13 then UNPREDICTABLE; if (Rt == dwarf_sp) return false; registers = (1u << Rt); break; default: return false; } addr_t sp_offset = addr_byte_size * BitCount (registers); addr_t addr = sp; uint32_t i, data; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextPopRegisterOffStack; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, 0); for (i=0; i<15; ++i) { if (BitIsSet (registers, i)) { dwarf_reg.num = dwarf_r0 + i; context.SetRegisterPlusOffset (dwarf_reg, addr - sp); data = MemARead(context, addr, 4, 0, &success); if (!success) return false; if (!WriteRegisterUnsigned(context, eRegisterKindDWARF, dwarf_reg.num, data)) return false; addr += addr_byte_size; } } if (BitIsSet (registers, 15)) { dwarf_reg.num = dwarf_pc; context.SetRegisterPlusOffset (dwarf_reg, addr - sp); data = MemARead(context, addr, 4, 0, &success); if (!success) return false; // In ARMv5T and above, this is an interworking branch. if (!LoadWritePC(context, data)) return false; addr += addr_byte_size; } context.type = EmulateInstruction::eContextAdjustStackPointer; context.SetImmediateSigned (sp_offset); if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp + sp_offset)) return false; } return true; } // Set r7 or ip to point to saved value residing within the stack. // ADD (SP plus immediate) bool EmulateInstructionARM::EmulateADDRdSPImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’); if d == 15 then ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t Rd; // the destination register uint32_t imm32; switch (encoding) { case eEncodingT1: Rd = 7; imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32) break; case eEncodingA1: Rd = Bits32(opcode, 15, 12); imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) break; default: return false; } addr_t sp_offset = imm32; addr_t addr = sp + sp_offset; // a pointer to the stack area EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register sp_reg; sp_reg.SetRegister (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); context.SetRegisterPlusOffset (sp_reg, sp_offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, addr)) return false; } return true; } // Set r7 or ip to the current stack pointer. // MOV (register) bool EmulateInstructionARM::EmulateMOVRdSP (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); result = R[m]; if d == 15 then ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); // APSR.C unchanged // APSR.V unchanged } #endif bool success = false; //const uint32_t opcode = OpcodeAsUnsigned (&success); //if (!success) // return false; if (ConditionPassed()) { const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t Rd; // the destination register switch (encoding) { case eEncodingT1: Rd = 7; break; case eEncodingA1: Rd = 12; break; default: return false; } EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register sp_reg; sp_reg.SetRegister (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); context.SetRegisterPlusOffset (sp_reg, 0); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rd, sp)) return false; } return true; } // Move from high register (r8-r15) to low register (r0-r7). // MOV (register) bool EmulateInstructionARM::EmulateMOVLowHigh (ARMEncoding encoding) { return EmulateMOVRdRm (encoding); } // Move from register to register. // MOV (register) bool EmulateInstructionARM::EmulateMOVRdRm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); result = R[m]; if d == 15 then ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); // APSR.C unchanged // APSR.V unchanged } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rm; // the source register uint32_t Rd; // the destination register bool setflags; switch (encoding) { case eEncodingT1: Rm = Bits32(opcode, 6, 3); Rd = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 1); setflags = false; break; case eEncodingT2: Rm = Bits32(opcode, 5, 3); Rd = Bits32(opcode, 2, 1); setflags = true; break; default: return false; } uint32_t result = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; // The context specifies that Rm is to be moved into Rd. EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + Rm); context.SetRegisterPlusOffset (dwarf_reg, 0); if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags)) return false; } return true; } // Move (immediate) writes an immediate value to the destination register. It // can optionally update the condition flags based on the value. // MOV (immediate) bool EmulateInstructionARM::EmulateMOVRdImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); result = imm32; if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd; // the destination register uint32_t imm12; // some intermediate result uint32_t imm32; // the immediate value to be written to Rd uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C. bool setflags; switch (encoding) { case eEncodingT1: Rd = Bits32(opcode, 11, 8); setflags = !InITBlock(); imm32 = Bits32(opcode, 7, 0); // imm32 = ZeroExtend(imm8, 32) carry = APSR_C; break; case eEncodingT2: Rd = Bits32(opcode, 15, 12); setflags = BitIsSet(opcode, 20); imm12 = Bit32(opcode, 26) << 11 | Bits32(opcode, 14, 12) << 8 | Bits32(opcode, 7, 0); imm32 = ThumbExpandImm_C(imm12, APSR_C, carry); if (BadReg(Rd)) return false; break; default: return false; } uint32_t result = imm32; // The context specifies that an immediate is to be moved into Rd. EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) return false; } return true; } // Bitwise NOT (immediate) writes the bitwise inverse of an immediate value to // the destination register. It can optionally update the condition flags based // on the value. // MVN (immediate) bool EmulateInstructionARM::EmulateMVNRdImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); result = NOT(imm32); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd; // the destination register uint32_t imm12; // the first operand to ThumbExpandImm_C or ARMExpandImm_C uint32_t imm32; // the output after ThumbExpandImm_C or ARMExpandImm_C uint32_t carry; // the carry bit after ThumbExpandImm_C or ARMExpandImm_C bool setflags; switch (encoding) { case eEncodingT1: Rd = Bits32(opcode, 11, 8); setflags = BitIsSet(opcode, 20); imm12 = Bit32(opcode, 26) << 11 | Bits32(opcode, 14, 12) << 8 | Bits32(opcode, 7, 0); imm32 = ThumbExpandImm_C(imm12, APSR_C, carry); break; case eEncodingA1: Rd = Bits32(opcode, 15, 12); setflags = BitIsSet(opcode, 20); imm12 = Bits32(opcode, 11, 0); imm32 = ARMExpandImm_C(imm12, APSR_C, carry); break; default: return false; } uint32_t result = ~imm32; // The context specifies that an immediate is to be moved into Rd. EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) return false; } return true; } // PC relative immediate load into register, possibly followed by ADD (SP plus register). // LDR (literal) bool EmulateInstructionARM::EmulateLDRRtPCRelative (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); NullCheckIfThumbEE(15); base = Align(PC,4); address = if add then (base + imm32) else (base - imm32); data = MemU[address,4]; 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 // Can only apply before ARMv7 if CurrentInstrSet() == InstrSet_ARM then R[t] = ROR(data, 8*UInt(address<1:0>)); else R[t] = bits(32) UNKNOWN; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; // PC relative immediate load context EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register pc_reg; pc_reg.SetRegister (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); context.SetRegisterPlusOffset (pc_reg, 0); uint32_t Rt; // the destination register uint32_t imm32; // immediate offset from the PC bool add; // +imm32 or -imm32? addr_t base; // the base address addr_t address; // the PC relative address uint32_t data; // the literal data value from the PC relative load switch (encoding) { case eEncodingT1: Rt = Bits32(opcode, 10, 8); imm32 = Bits32(opcode, 7, 0) << 2; // imm32 = ZeroExtend(imm8:'00', 32); add = true; base = Align(pc + 4, 4); context.SetRegisterPlusOffset (pc_reg, 4 + imm32); break; case eEncodingT2: Rt = Bits32(opcode, 15, 12); imm32 = Bits32(opcode, 11, 0) << 2; // imm32 = ZeroExtend(imm12, 32); add = BitIsSet(opcode, 23); if (Rt == 15 && InITBlock() && !LastInITBlock()) return false; base = Align(pc + 4, 4); context.SetRegisterPlusOffset (pc_reg, 4 + imm32); break; default: return false; } if (add) address = base + imm32; else address = base - imm32; data = MemURead(context, address, 4, 0, &success); if (!success) return false; if (Rt == 15) { if (Bits32(address, 1, 0) == 0) { // In ARMv5T and above, this is an interworking branch. 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 // We don't handle ARM for now. return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + Rt, data)) return false; } return true; } // An add operation to adjust the SP. // ADD (SP plus immediate) bool EmulateInstructionARM::EmulateADDSPImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); (result, carry, overflow) = AddWithCarry(SP, imm32, ‘0’); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t imm32; // the immediate operand switch (encoding) { case eEncodingT2: imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) break; default: return false; } addr_t sp_offset = imm32; addr_t addr = sp + sp_offset; // the adjusted stack pointer value EmulateInstruction::Context context; context.type = EmulateInstruction::eContextAdjustStackPointer; context.SetImmediateSigned (sp_offset); if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr)) return false; } return true; } // An add operation to adjust the SP. // ADD (SP plus register) bool EmulateInstructionARM::EmulateADDSPRm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); shifted = Shift(R[m], shift_t, shift_n, APSR.C); (result, carry, overflow) = AddWithCarry(SP, shifted, ‘0’); if d == 15 then ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t Rm; // the second operand switch (encoding) { case eEncodingT2: Rm = Bits32(opcode, 6, 3); break; default: return false; } int32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; addr_t addr = (int32_t)sp + reg_value; // the adjusted stack pointer value EmulateInstruction::Context context; context.type = EmulateInstruction::eContextAdjustStackPointer; context.SetImmediateSigned (reg_value); if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr)) return false; } return true; } // Branch with Link and Exchange Instruction Sets (immediate) calls a subroutine // at a PC-relative address, and changes instruction set from ARM to Thumb, or // from Thumb to ARM. // BLX (immediate) bool EmulateInstructionARM::EmulateBLXImmediate (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); if CurrentInstrSet() == InstrSet_ARM then LR = PC - 4; else LR = PC<31:1> : '1'; if targetInstrSet == InstrSet_ARM then targetAddress = Align(PC,4) + imm32; else targetAddress = PC + imm32; SelectInstrSet(targetInstrSet); BranchWritePC(targetAddress); } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRelativeBranchImmediate; const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; addr_t lr; // next instruction address addr_t target; // target address int32_t imm32; // PC-relative offset switch (encoding) { case eEncodingT1: { lr = (pc + 4) | 1u; // return address uint32_t S = Bit32(opcode, 26); uint32_t imm10 = Bits32(opcode, 25, 16); uint32_t J1 = Bit32(opcode, 13); uint32_t J2 = Bit32(opcode, 11); uint32_t imm11 = Bits32(opcode, 10, 0); uint32_t I1 = !(J1 ^ S); uint32_t I2 = !(J2 ^ S); uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); imm32 = llvm::SignExtend32<25>(imm25); target = pc + 4 + imm32; context.SetModeAndImmediateSigned (eModeThumb, 4 + imm32); if (InITBlock() && !LastInITBlock()) return false; break; } case eEncodingT2: { lr = (pc + 4) | 1u; // return address uint32_t S = Bit32(opcode, 26); uint32_t imm10H = Bits32(opcode, 25, 16); uint32_t J1 = Bit32(opcode, 13); uint32_t J2 = Bit32(opcode, 11); uint32_t imm10L = Bits32(opcode, 10, 1); uint32_t I1 = !(J1 ^ S); uint32_t I2 = !(J2 ^ S); uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10H << 12) | (imm10L << 2); imm32 = llvm::SignExtend32<25>(imm25); target = Align(pc + 4, 4) + imm32; context.SetModeAndImmediateSigned (eModeARM, 4 + imm32); if (InITBlock() && !LastInITBlock()) return false; break; } case eEncodingA1: lr = pc + 4; // return address imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2); target = Align(pc + 8, 4) + imm32; context.SetModeAndImmediateSigned (eModeARM, 8 + imm32); break; case eEncodingA2: lr = pc + 4; // return address imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2 | Bits32(opcode, 24, 24) << 1); target = pc + 8 + imm32; context.SetModeAndImmediateSigned (eModeThumb, 8 + imm32); break; default: return false; } if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr)) return false; if (!BranchWritePC(context, target)) return false; } return true; } // Branch with Link and Exchange (register) calls a subroutine at an address and // instruction set specified by a register. // BLX (register) bool EmulateInstructionARM::EmulateBLXRm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); target = R[m]; if CurrentInstrSet() == InstrSet_ARM then next_instr_addr = PC - 4; LR = next_instr_addr; else next_instr_addr = PC - 2; LR = next_instr_addr<31:1> : ‘1’; BXWritePC(target); } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { EmulateInstruction::Context context; context.type = EmulateInstruction::eContextAbsoluteBranchRegister; const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); addr_t lr; // next instruction address if (!success) return false; uint32_t Rm; // the register with the target address switch (encoding) { case eEncodingT1: lr = (pc + 2) | 1u; // return address Rm = Bits32(opcode, 6, 3); // if m == 15 then UNPREDICTABLE; if (Rm == 15) return false; if (InITBlock() && !LastInITBlock()) return false; break; case eEncodingA1: lr = pc + 4; // return address Rm = Bits32(opcode, 3, 0); // if m == 15 then UNPREDICTABLE; if (Rm == 15) return false; break; default: return false; } addr_t target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + Rm); context.SetRegister (dwarf_reg); if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA, lr)) return false; if (!BXWritePC(context, target)) return false; } return true; } // Branch and Exchange causes a branch to an address and instruction set specified by a register. // BX bool EmulateInstructionARM::EmulateBXRm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); BXWritePC(R[m]); } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { EmulateInstruction::Context context; context.type = EmulateInstruction::eContextAbsoluteBranchRegister; uint32_t Rm; // the register with the target address switch (encoding) { case eEncodingT1: Rm = Bits32(opcode, 6, 3); if (InITBlock() && !LastInITBlock()) return false; break; case eEncodingA1: Rm = Bits32(opcode, 3, 0); break; default: return false; } addr_t target = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + Rm); context.SetRegister (dwarf_reg); if (!BXWritePC(context, target)) return false; } return true; } // Set r7 to point to some ip offset. // SUB (immediate) bool EmulateInstructionARM::EmulateSUBR7IPImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const addr_t ip = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r12, 0, &success); if (!success) return false; uint32_t imm32; switch (encoding) { case eEncodingA1: imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) break; default: return false; } addr_t ip_offset = imm32; addr_t addr = ip - ip_offset; // the adjusted ip value EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r12); context.SetRegisterPlusOffset (dwarf_reg, -ip_offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r7, addr)) return false; } return true; } // Set ip to point to some stack offset. // SUB (SP minus immediate) bool EmulateInstructionARM::EmulateSUBIPSPImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t imm32; switch (encoding) { case eEncodingA1: imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) break; default: return false; } addr_t sp_offset = imm32; addr_t addr = sp - sp_offset; // the adjusted stack pointer value EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); context.SetRegisterPlusOffset (dwarf_reg, -sp_offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r12, addr)) return false; } return true; } // A sub operation to adjust the SP -- allocate space for local storage. bool EmulateInstructionARM::EmulateSUBSPImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); (result, carry, overflow) = AddWithCarry(SP, NOT(imm32), ‘1’); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t imm32; switch (encoding) { case eEncodingT1: imm32 = ThumbImmScaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) case eEncodingT2: imm32 = ThumbExpandImm(opcode); // imm32 = ThumbExpandImm(i:imm3:imm8) break; case eEncodingT3: imm32 = ThumbImm12(opcode); // imm32 = ZeroExtend(i:imm3:imm8, 32) break; case eEncodingA1: imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) break; default: return false; } addr_t sp_offset = imm32; addr_t addr = sp - sp_offset; // the adjusted stack pointer value EmulateInstruction::Context context; context.type = EmulateInstruction::eContextAdjustStackPointer; context.SetImmediateSigned (-sp_offset); if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, addr)) return false; } return true; } // A store operation to the stack that also updates the SP. bool EmulateInstructionARM::EmulateSTRRtSP (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); address = if index then offset_addr else R[n]; MemU[address,4] = if t == 15 then PCStoreValue() else R[t]; if wback then R[n] = offset_addr; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const uint32_t addr_byte_size = GetAddressByteSize(); const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; uint32_t Rt; // the source register uint32_t imm12; switch (encoding) { case eEncodingA1: Rt = Bits32(opcode, 15, 12); imm12 = Bits32(opcode, 11, 0); break; default: return false; } addr_t sp_offset = imm12; addr_t addr = sp - sp_offset; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextPushRegisterOnStack; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, 0); if (Rt != 15) { dwarf_reg.num = dwarf_r0 + Rt; context.SetRegisterPlusOffset (dwarf_reg, addr - sp); uint32_t reg_value = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_reg.num, 0, &success); if (!success) return false; if (!MemUWrite (context, addr, reg_value, addr_byte_size)) return false; } else { dwarf_reg.num = dwarf_pc; context.SetRegisterPlusOffset (dwarf_reg, addr - sp); const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; if (!MemUWrite (context, addr, pc + 8, addr_byte_size)) return false; } context.type = EmulateInstruction::eContextAdjustStackPointer; context.SetImmediateSigned (-sp_offset); if (!WriteRegisterUnsigned (context, eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, sp - sp_offset)) return false; } return true; } // Vector Push stores multiple extension registers to the stack. // It also updates SP to point to the start of the stored data. bool EmulateInstructionARM::EmulateVPUSH (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); CheckVFPEnabled(TRUE); NullCheckIfThumbEE(13); address = SP - imm32; SP = SP - imm32; if single_regs then for r = 0 to regs-1 MemA[address,4] = S[d+r]; address = address+4; else for r = 0 to regs-1 // Store as two word-aligned words in the correct order for current endianness. MemA[address,4] = if BigEndian() then D[d+r]<63:32> else D[d+r]<31:0>; MemA[address+4,4] = if BigEndian() then D[d+r]<31:0> else D[d+r]<63:32>; address = address+8; } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const uint32_t addr_byte_size = GetAddressByteSize(); const addr_t sp = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP, 0, &success); if (!success) return false; bool single_regs; uint32_t d; // UInt(D:Vd) or UInt(Vd:D) starting register uint32_t imm32; // stack offset uint32_t regs; // number of registers switch (encoding) { case eEncodingT1: case eEncodingA1: single_regs = false; d = Bit32(opcode, 22) << 4 | Bits32(opcode, 15, 12); imm32 = Bits32(opcode, 7, 0) * addr_byte_size; // If UInt(imm8) is odd, see "FSTMX". regs = Bits32(opcode, 7, 0) / 2; // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; if (regs == 0 || regs > 16 || (d + regs) > 32) return false; break; case eEncodingT2: case eEncodingA2: single_regs = true; d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22); imm32 = Bits32(opcode, 7, 0) * addr_byte_size; regs = Bits32(opcode, 7, 0); // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; if (regs == 0 || regs > 16 || (d + regs) > 32) return false; break; default: return false; } uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; addr_t sp_offset = imm32; addr_t addr = sp - sp_offset; uint32_t i; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextPushRegisterOnStack; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, 0); for (i=d; i 16 || (d+regs) > 32 then UNPREDICTABLE; if (regs == 0 || regs > 16 || (d + regs) > 32) return false; break; case eEncodingT2: case eEncodingA2: single_regs = true; d = Bits32(opcode, 15, 12) << 1 | Bit32(opcode, 22); imm32 = Bits32(opcode, 7, 0) * addr_byte_size; regs = Bits32(opcode, 7, 0); // if regs == 0 || regs > 16 || (d+regs) > 32 then UNPREDICTABLE; if (regs == 0 || regs > 16 || (d + regs) > 32) return false; break; default: return false; } uint32_t start_reg = single_regs ? dwarf_s0 : dwarf_d0; uint32_t reg_byte_size = single_regs ? addr_byte_size : addr_byte_size * 2; addr_t sp_offset = imm32; addr_t addr = sp; uint32_t i; uint64_t data; // uint64_t to accomodate 64-bit registers. EmulateInstruction::Context context; context.type = EmulateInstruction::eContextPopRegisterOffStack; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, 0); for (i=d; i = firstcond:mask; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; m_it_session.InitIT(Bits32(opcode, 7, 0)); return true; } // Branch causes a branch to a target address. bool EmulateInstructionARM::EmulateB (ARMEncoding encoding) { #if 0 // ARM pseudo code... if (ConditionPassed()) { EncodingSpecificOperations(); BranchWritePC(PC + imm32); } #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRelativeBranchImmediate; const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; addr_t target; // target address int32_t imm32; // PC-relative offset switch (encoding) { case eEncodingT1: // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). imm32 = llvm::SignExtend32<9>(Bits32(opcode, 7, 0) << 1); target = pc + 4 + imm32; context.SetModeAndImmediateSigned (eModeThumb, 4 + imm32); break; case eEncodingT2: imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0)); target = pc + 4 + imm32; context.SetModeAndImmediateSigned (eModeThumb, 4 + imm32); break; case eEncodingT3: // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). { uint32_t S = Bit32(opcode, 26); uint32_t imm6 = Bits32(opcode, 21, 16); uint32_t J1 = Bit32(opcode, 13); uint32_t J2 = Bit32(opcode, 11); uint32_t imm11 = Bits32(opcode, 10, 0); uint32_t imm21 = (S << 20) | (J2 << 19) | (J1 << 18) | (imm6 << 12) | (imm11 << 1); imm32 = llvm::SignExtend32<21>(imm21); target = pc + 4 + imm32; context.SetModeAndImmediateSigned (eModeThumb, 4 + imm32); break; } case eEncodingT4: { uint32_t S = Bit32(opcode, 26); uint32_t imm10 = Bits32(opcode, 25, 16); uint32_t J1 = Bit32(opcode, 13); uint32_t J2 = Bit32(opcode, 11); uint32_t imm11 = Bits32(opcode, 10, 0); uint32_t I1 = !(J1 ^ S); uint32_t I2 = !(J2 ^ S); uint32_t imm25 = (S << 24) | (I1 << 23) | (I2 << 22) | (imm10 << 12) | (imm11 << 1); imm32 = llvm::SignExtend32<25>(imm25); target = pc + 4 + imm32; context.SetModeAndImmediateSigned (eModeThumb, 4 + imm32); break; } case eEncodingA1: imm32 = llvm::SignExtend32<26>(Bits32(opcode, 23, 0) << 2); target = pc + 8 + imm32; context.SetModeAndImmediateSigned (eModeARM, 8 + imm32); break; default: return false; } if (!BranchWritePC(context, target)) return false; } return true; } // Compare and Branch on Nonzero and Compare and Branch on Zero compare the value in a register with // zero and conditionally branch forward a constant value. They do not affect the condition flags. // CBNZ, CBZ bool EmulateInstructionARM::EmulateCB (ARMEncoding encoding) { #if 0 // ARM pseudo code... EncodingSpecificOperations(); if nonzero ^ IsZero(R[n]) then BranchWritePC(PC + imm32); #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; // Read the register value from the operand register Rn. uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Bits32(opcode, 2, 0), 0, &success); if (!success) return false; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRelativeBranchImmediate; const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; addr_t target; // target address uint32_t imm32; // PC-relative offset to branch forward bool nonzero; switch (encoding) { case eEncodingT1: imm32 = Bit32(opcode, 9) << 6 | Bits32(opcode, 7, 3) << 1; nonzero = BitIsSet(opcode, 11); target = pc + 4 + imm32; context.SetModeAndImmediateSigned (eModeThumb, 4 + imm32); break; default: return false; } if (nonzero ^ (reg_val == 0)) if (!BranchWritePC(context, target)) return false; return true; } // Table Branch Byte causes a PC-relative forward branch using a table of single byte offsets. // A base register provides a pointer to the table, and a second register supplies an index into the table. // The branch length is twice the value of the byte returned from the table. // // Table Branch Halfword causes a PC-relative forward branch using a table of single halfword offsets. // A base register provides a pointer to the table, and a second register supplies an index into the table. // The branch length is twice the value of the halfword returned from the table. // TBB, TBH bool EmulateInstructionARM::EmulateTB (ARMEncoding encoding) { #if 0 // ARM pseudo code... EncodingSpecificOperations(); NullCheckIfThumbEE(n); if is_tbh then halfwords = UInt(MemU[R[n]+LSL(R[m],1), 2]); else halfwords = UInt(MemU[R[n]+R[m], 1]); BranchWritePC(PC + 2*halfwords); #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; uint32_t Rn; // the base register which contains the address of the table of branch lengths uint32_t Rm; // the index register which contains an integer pointing to a byte/halfword in the table bool is_tbh; // true if table branch halfword switch (encoding) { case eEncodingT1: Rn = Bits32(opcode, 19, 16); Rm = Bits32(opcode, 3, 0); is_tbh = BitIsSet(opcode, 4); if (Rn == 13 || BadReg(Rm)) return false; if (InITBlock() && !LastInITBlock()) return false; break; default: return false; } // Read the address of the table from the operand register Rn. // The PC can be used, in which case the table immediately follows this instruction. uint32_t base = Rn == 15 ? (ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success) + 4) : ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; // the table index uint32_t index = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; // the offsetted table address addr_t addr = base + (is_tbh ? index*2 : index); // PC-relative offset to branch forward EmulateInstruction::Context context; context.type = EmulateInstruction::eContextTableBranchReadMemory; uint32_t offset = MemURead(context, addr, is_tbh ? 2 : 1, 0, &success) * 2; if (!success) return false; const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; // target address addr_t target = pc + 4 + offset; context.type = EmulateInstruction::eContextRelativeBranchImmediate; context.SetModeAndImmediateSigned (eModeThumb, 4 + offset); if (!BranchWritePC(context, target)) return false; return true; } // This instruction adds an immediate value to a register value, and writes the result to the destination // register. It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateADDImmARM (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); if d == 15 then ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd, Rn; uint32_t imm32; // the immediate value to be added to the value obtained from Rn bool setflags; switch (encoding) { case eEncodingA1: Rd = Bits32(opcode, 15, 12); Rn = Bits32(opcode, 19, 16); setflags = BitIsSet(opcode, 20); imm32 = ARMExpandImm(opcode); // imm32 = ARMExpandImm(imm12) break; default: return false; } int32_t val1; // Read the first operand. if (Rn == 15) { val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (encoding == eEncodingT1 || encoding == eEncodingT2) val1 += 4; else val1 += 8; } else val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; AddWithCarryResult res = AddWithCarry(val1, imm32, 0); EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) return false; } return true; } // This instruction adds a register value and an optionally-shifted register value, and writes the result // to the destination register. It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateADDReg (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); shifted = Shift(R[m], shift_t, shift_n, APSR.C); (result, carry, overflow) = AddWithCarry(R[n], shifted, '0'); if d == 15 then ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd, Rn, Rm; ARM_ShifterType shift_t; uint32_t shift_n; // the shift applied to the value read from Rm bool setflags; switch (encoding) { case eEncodingT1: Rd = Bits32(opcode, 2, 0); Rn = Bits32(opcode, 5, 3); Rm = Bits32(opcode, 8, 6); setflags = !InITBlock(); shift_t = SRType_LSL; shift_n = 0; case eEncodingT2: Rd = Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); Rm = Bits32(opcode, 6, 3); setflags = false; shift_t = SRType_LSL; shift_n = 0; if (Rn == 15 && Rm == 15) return false; if (Rd == 15 && InITBlock() && !LastInITBlock()) return false; break; case eEncodingA1: Rd = Bits32(opcode, 15, 12); Rn = Bits32(opcode, 19, 16); Rm = Bits32(opcode, 3, 0); setflags = BitIsSet(opcode, 20); shift_n = DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t); break; default: return false; } int32_t val1, val2; // Read the first operand. if (Rn == 15) { val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (encoding == eEncodingT1 || encoding == eEncodingT2) val1 += 4; else val1 += 8; } else val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; // Read the second operand. if (Rm == 15) { val2 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (encoding == eEncodingT1 || encoding == eEncodingT2) val1 += 4; else val1 += 8; } else val2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; uint32_t shifted = Shift(val2, shift_t, shift_n, APSR_C); AddWithCarryResult res = AddWithCarry(val1, shifted, 0); EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, res.result, Rd, setflags, res.carry_out, res.overflow)) return false; } return true; } // CMP (immediate) bool EmulateInstructionARM::EmulateCMPRnImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (result, carry, overflow) = AddWithCarry(R[n], NOT(imm32), '1'); APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; uint32_t Rn; // the first operand uint32_t imm32; // the immediate value to be compared with switch (encoding) { case eEncodingT1: Rn = Bits32(opcode, 10, 8); imm32 = Bits32(opcode, 7, 0); break; default: return false; } // Read the register value from the operand register Rn. uint32_t reg_val = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; AddWithCarryResult res = AddWithCarry(reg_val, ~imm32, 1); EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) return false; return true; } // CMP (register) bool EmulateInstructionARM::EmulateCMPRnRm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); shifted = Shift(R[m], shift_t, shift_n, APSR.C); (result, carry, overflow) = AddWithCarry(R[n], NOT(shifted), '1'); APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; APSR.V = overflow; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; uint32_t Rn; // the first operand uint32_t Rm; // the second operand switch (encoding) { case eEncodingT1: Rn = Bits32(opcode, 2, 0); Rm = Bits32(opcode, 5, 3); break; case eEncodingT2: Rn = Bit32(opcode, 7) << 3 | Bits32(opcode, 2, 0); Rm = Bits32(opcode, 6, 3); if (Rn < 8 && Rm < 8) return false; if (Rn == 15 || Rm == 15) return false; break; default: return false; } // Read the register value from register Rn. uint32_t reg_val1 = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; // Read the register value from register Rm. // The register value is not being shifted since we don't handle ARM for now. uint32_t reg_val2 = ReadRegisterUnsigned(eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; AddWithCarryResult res = AddWithCarry(reg_val1, ~reg_val2, 1); EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs(); if (!WriteFlags(context, res.result, res.carry_out, res.overflow)) return false; return true; } // Arithmetic Shift Right (immediate) shifts a register value right by an immediate number of bits, // shifting in copies of its sign bit, and writes the result to the destination register. It can // optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateASRImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftImm(encoding, SRType_ASR); } // Arithmetic Shift Right (register) shifts a register value right by a variable number of bits, // shifting in copies of its sign bit, and writes the result to the destination register. // The variable number of bits is read from the bottom byte of a register. It can optionally update // the condition flags based on the result. bool EmulateInstructionARM::EmulateASRReg (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); shift_n = UInt(R[m]<7:0>); (result, carry) = Shift_C(R[m], SRType_ASR, shift_n, APSR.C); R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftReg(encoding, SRType_ASR); } // Logical Shift Left (immediate) shifts a register value left by an immediate number of bits, // shifting in zeros, and writes the result to the destination register. It can optionally // update the condition flags based on the result. bool EmulateInstructionARM::EmulateLSLImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftImm(encoding, SRType_LSL); } // Logical Shift Left (register) shifts a register value left by a variable number of bits, // shifting in zeros, and writes the result to the destination register. The variable number // of bits is read from the bottom byte of a register. It can optionally update the condition // flags based on the result. bool EmulateInstructionARM::EmulateLSLReg (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); shift_n = UInt(R[m]<7:0>); (result, carry) = Shift_C(R[m], SRType_LSL, shift_n, APSR.C); R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftReg(encoding, SRType_LSL); } // Logical Shift Right (immediate) shifts a register value right by an immediate number of bits, // shifting in zeros, and writes the result to the destination register. It can optionally // update the condition flags based on the result. bool EmulateInstructionARM::EmulateLSRImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftImm(encoding, SRType_LSR); } // Logical Shift Right (register) shifts a register value right by a variable number of bits, // shifting in zeros, and writes the result to the destination register. The variable number // of bits is read from the bottom byte of a register. It can optionally update the condition // flags based on the result. bool EmulateInstructionARM::EmulateLSRReg (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); shift_n = UInt(R[m]<7:0>); (result, carry) = Shift_C(R[m], SRType_LSR, shift_n, APSR.C); R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftReg(encoding, SRType_LSR); } // Rotate Right (immediate) provides the value of the contents of a register rotated by a constant value. // The bits that are rotated off the right end are inserted into the vacated bit positions on the left. // It can optionally update the condition flags based on the result. bool EmulateInstructionARM::EmulateRORImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftImm(encoding, SRType_ROR); } // Rotate Right (register) provides the value of the contents of a register rotated by a variable number of bits. // The bits that are rotated off the right end are inserted into the vacated bit positions on the left. // The variable number of bits is read from the bottom byte of a register. It can optionally update the condition // flags based on the result. bool EmulateInstructionARM::EmulateRORReg (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); shift_n = UInt(R[m]<7:0>); (result, carry) = Shift_C(R[m], SRType_ROR, shift_n, APSR.C); R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftReg(encoding, SRType_ROR); } // Rotate Right with Extend provides the value of the contents of a register shifted right by one place, // with the carry flag shifted into bit [31]. // // RRX can optionally update the condition flags based on the result. // In that case, bit [0] is shifted into the carry flag. bool EmulateInstructionARM::EmulateRRX (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (result, carry) = Shift_C(R[m], SRType_RRX, 1, APSR.C); if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif return EmulateShiftImm(encoding, SRType_RRX); } bool EmulateInstructionARM::EmulateShiftImm (ARMEncoding encoding, ARM_ShifterType shift_type) { assert(shift_type == SRType_ASR || shift_type == SRType_LSL || shift_type == SRType_LSR); bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd; // the destination register uint32_t Rm; // the first operand register uint32_t imm5; // encoding for the shift amount uint32_t carry; // the carry bit after the shift operation bool setflags; // Special case handling! // A8.6.139 ROR (immediate) -- Encoding T1 if (shift_type == SRType_ROR && encoding == eEncodingT1) { // Morph the T1 encoding from the ARM Architecture Manual into T2 encoding to // have the same decoding of bit fields as the other Thumb2 shift operations. encoding = eEncodingT2; } switch (encoding) { case eEncodingT1: // Due to the above special case handling! assert(shift_type != SRType_ROR); Rd = Bits32(opcode, 2, 0); Rm = Bits32(opcode, 5, 3); setflags = !InITBlock(); imm5 = Bits32(opcode, 10, 6); break; case eEncodingT2: // A8.6.141 RRX assert(shift_type != SRType_RRX); Rd = Bits32(opcode, 11, 8); Rm = Bits32(opcode, 3, 0); setflags = BitIsSet(opcode, 20); imm5 = Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6); if (BadReg(Rd) || BadReg(Rm)) return false; break; case eEncodingA1: Rd = Bits32(opcode, 15, 12); Rm = Bits32(opcode, 3, 0); setflags = BitIsSet(opcode, 20); imm5 = Bits32(opcode, 11, 7); break; default: return false; } // A8.6.139 ROR (immediate) if (shift_type == SRType_ROR && imm5 == 0) shift_type = SRType_RRX; // Get the first operand. uint32_t value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; // Decode the shift amount if not RRX. uint32_t amt = (shift_type == SRType_RRX ? 1 : DecodeImmShift(shift_type, imm5)); uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry); // The context specifies that an immediate is to be moved into Rd. EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) return false; } return true; } bool EmulateInstructionARM::EmulateShiftReg (ARMEncoding encoding, ARM_ShifterType shift_type) { assert(shift_type == SRType_ASR || shift_type == SRType_LSL || shift_type == SRType_LSR); bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd; // the destination register uint32_t Rn; // the first operand register uint32_t Rm; // the register whose bottom byte contains the amount to shift by uint32_t carry; // the carry bit after the shift operation bool setflags; switch (encoding) { case eEncodingT1: Rd = Bits32(opcode, 2, 0); Rn = Rd; Rm = Bits32(opcode, 5, 3); setflags = !InITBlock(); break; case eEncodingT2: Rd = Bits32(opcode, 11, 8); Rn = Bits32(opcode, 19, 16); Rm = Bits32(opcode, 3, 0); setflags = BitIsSet(opcode, 20); if (BadReg(Rd) || BadReg(Rn) || BadReg(Rm)) return false; break; case eEncodingA1: Rd = Bits32(opcode, 15, 12); Rn = Bits32(opcode, 3, 0); Rm = Bits32(opcode, 11, 8); setflags = BitIsSet(opcode, 20); if (Rd == 15 || Rn == 15 || Rm == 15) return false; break; default: return false; } // Get the first operand. uint32_t value = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; // Get the Rm register content. uint32_t val = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; // Get the shift amount. uint32_t amt = Bits32(val, 7, 0); uint32_t result = Shift_C(value, shift_type, amt, APSR_C, carry); // The context specifies that an immediate is to be moved into Rd. EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) return false; } return true; } // LDM loads multiple registers from consecutive memory locations, using an // address from a base register. Optionally the address just above the highest of those locations // can be written back to the base register. bool EmulateInstructionARM::EmulateLDM (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() EncodingSpecificOperations(); NullCheckIfThumbEE (n); address = R[n]; for i = 0 to 14 if registers == '1' then R[i] = MemA[address, 4]; address = address + 4; if registers<15> == '1' then LoadWritePC (MemA[address, 4]); if wback && registers == '0' then R[n] = R[n] + 4 * BitCount (registers); if wback && registers == '1' then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); switch (encoding) { case eEncodingT1: // n = UInt(Rn); registers = ’00000000’:register_list; wback = (registers == ’0’); n = Bits32 (opcode, 10, 8); registers = Bits32 (opcode, 7, 0); registers = registers & 0x00ff; // Make sure the top 8 bits are zeros. wback = BitIsClear (registers, n); // if BitCount(registers) < 1 then UNPREDICTABLE; if (BitCount(registers) < 1) return false; break; case eEncodingT2: // if W == ’1’ && Rn == ’1101’ then SEE POP; // n = UInt(Rn); registers = P:M:’0’:register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); registers = registers & 0xdfff; // Make sure bit 13 is zero. wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 2 || (P == ’1’ && M == ’1’) then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 2) || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15))) return false; // if registers<15> == ’1’ && InITBlock() && !LastInITBlock() then UNPREDICTABLE; if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock()) return false; // if wback && registers == ’1’ then UNPREDICTABLE; if (wback && BitIsSet (registers, n)) return false; break; case eEncodingA1: n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); if ((n == 15) || (BitCount (registers) < 1)) return false; break; default: return false; } int32_t offset = 0; const addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); context.SetRegisterPlusOffset (dwarf_reg, offset); for (int i = 0; i < 14; ++i) { if (BitIsSet (registers, i)) { context.type = EmulateInstruction::eContextRegisterPlusOffset; context.SetRegisterPlusOffset (dwarf_reg, offset); if (wback && (n == 13)) // Pop Instruction context.type = EmulateInstruction::eContextPopRegisterOffStack; // R[i] = MemA [address, 4]; address = address + 4; uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success); if (!success) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) return false; offset += addr_byte_size; } } if (BitIsSet (registers, 15)) { //LoadWritePC (MemA [address, 4]); context.type = EmulateInstruction::eContextRegisterPlusOffset; context.SetRegisterPlusOffset (dwarf_reg, offset); uint32_t data = MemARead (context, base_address + offset, addr_byte_size, 0, &success); if (!success) return false; // In ARMv5T and above, this is an interworking branch. if (!LoadWritePC(context, data)) return false; } if (wback && BitIsClear (registers, n)) { // R[n] = R[n] + 4 * BitCount (registers) int32_t offset = addr_byte_size * BitCount (registers); context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetRegisterPlusOffset (dwarf_reg, offset); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, base_address + offset)) return false; } if (wback && BitIsSet (registers, n)) // R[n] bits(32) UNKNOWN; return WriteBits32Unknown (n); } return true; } // LDMDA loads multiple registers from consecutive memory locations using an address from a base registers. // The consecutive memorty locations end at this address and the address just below the lowest of those locations // can optionally be written back tot he base registers. bool EmulateInstructionARM::EmulateLDMDA (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); address = R[n] - 4*BitCount(registers) + 4; for i = 0 to 14 if registers == ’1’ then R[i] = MemA[address,4]; address = address + 4; if registers<15> == ’1’ then LoadWritePC(MemA[address,4]); if wback && registers == ’0’ then R[n] = R[n] - 4*BitCount(registers); if wback && registers == ’1’ then R[n] = bits(32) UNKNOWN; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); // EncodingSpecificOperations(); switch (encoding) { case eEncodingA1: // n = UInt(Rn); registers = register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 1)) return false; break; default: return false; } // address = R[n] - 4*BitCount(registers) + 4; int32_t offset = 0; addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; address = address - (addr_byte_size * BitCount (registers)) + addr_byte_size; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); context.SetRegisterPlusOffset (dwarf_reg, offset); // for i = 0 to 14 for (int i = 0; i < 14; ++i) { // if registers == ’1’ then if (BitIsSet (registers, i)) { // R[i] = MemA[address,4]; address = address + 4; context.SetRegisterPlusOffset (dwarf_reg, offset); uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); if (!success) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) return false; offset += addr_byte_size; } } // if registers<15> == ’1’ then // LoadWritePC(MemA[address,4]); if (BitIsSet (registers, 15)) { context.SetRegisterPlusOffset (dwarf_reg, offset); uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); if (!success) return false; // In ARMv5T and above, this is an interworking branch. if (!LoadWritePC(context, data)) return false; } // if wback && registers == ’0’ then R[n] = R[n] - 4*BitCount(registers); if (wback && BitIsClear (registers, n)) { addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; offset = (addr_byte_size * BitCount (registers)) * -1; context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetImmediateSigned (offset); addr = addr + offset; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr)) return false; } // if wback && registers == ’1’ then R[n] = bits(32) UNKNOWN; if (wback && BitIsSet (registers, n)) return WriteBits32Unknown (n); } return true; } // LDMDB loads multiple registers from consecutive memory locations using an address from a base register. The // consecutive memory lcoations end just below this address, and the address of the lowest of those locations can // be optionally written back to the base register. bool EmulateInstructionARM::EmulateLDMDB (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); address = R[n] - 4*BitCount(registers); for i = 0 to 14 if registers == ’1’ then R[i] = MemA[address,4]; address = address + 4; if registers<15> == ’1’ then LoadWritePC(MemA[address,4]); if wback && registers == ’0’ then R[n] = R[n] - 4*BitCount(registers); if wback && registers == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); switch (encoding) { case eEncodingT1: // n = UInt(Rn); registers = P:M:’0’:register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); registers = registers & 0xdfff; // Make sure bit 13 is a zero. wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 2 || (P == ’1’ && M == ’1’) then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 2) || (BitIsSet (opcode, 14) && BitIsSet (opcode, 15))) return false; // if registers<15> == ’1’ && InITBlock() && !LastInITBlock() then UNPREDICTABLE; if (BitIsSet (registers, 15) && InITBlock() && !LastInITBlock()) return false; // if wback && registers == ’1’ then UNPREDICTABLE; if (wback && BitIsSet (registers, n)) return false; break; case eEncodingA1: // n = UInt(Rn); registers = register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 1)) return false; break; default: return false; } // address = R[n] - 4*BitCount(registers); int32_t offset = 0; addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; address = address - (addr_byte_size * BitCount (registers)); EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); context.SetRegisterPlusOffset (dwarf_reg, offset); for (int i = 0; i < 14; ++i) { if (BitIsSet (registers, i)) { // R[i] = MemA[address,4]; address = address + 4; context.SetRegisterPlusOffset (dwarf_reg, offset); uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); if (!success) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) return false; offset += addr_byte_size; } } // if registers<15> == ’1’ then // LoadWritePC(MemA[address,4]); if (BitIsSet (registers, 15)) { context.SetRegisterPlusOffset (dwarf_reg, offset); uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); if (!success) return false; // In ARMv5T and above, this is an interworking branch. if (!LoadWritePC(context, data)) return false; } // if wback && registers == ’0’ then R[n] = R[n] - 4*BitCount(registers); if (wback && BitIsClear (registers, n)) { addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; offset = (addr_byte_size * BitCount (registers)) * -1; context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetImmediateSigned (offset); addr = addr + offset; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr)) return false; } // if wback && registers == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 if (wback && BitIsSet (registers, n)) return WriteBits32Unknown (n); } return true; } // LDMIB loads multiple registers from consecutive memory locations using an address from a base register. The // consecutive memory locations start just above this address, and thea ddress of the last of those locations can // optinoally be written back to the base register. bool EmulateInstructionARM::EmulateLDMIB (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); address = R[n] + 4; for i = 0 to 14 if registers == ’1’ then R[i] = MemA[address,4]; address = address + 4; if registers<15> == ’1’ then LoadWritePC(MemA[address,4]); if wback && registers == ’0’ then R[n] = R[n] + 4*BitCount(registers); if wback && registers == ’1’ then R[n] = bits(32) UNKNOWN; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); switch (encoding) { case eEncodingA1: // n = UInt(Rn); registers = register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 1)) return false; break; default: return false; } // address = R[n] + 4; int32_t offset = 0; addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; address = address + addr_byte_size; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); context.SetRegisterPlusOffset (dwarf_reg, offset); for (int i = 0; i < 14; ++i) { if (BitIsSet (registers, i)) { // R[i] = MemA[address,4]; address = address + 4; context.SetRegisterPlusOffset (dwarf_reg, offset); uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); if (!success) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + i, data)) return false; offset += addr_byte_size; } } // if registers<15> == ’1’ then // LoadWritePC(MemA[address,4]); if (BitIsSet (registers, 15)) { context.SetRegisterPlusOffset (dwarf_reg, offset); uint32_t data = MemARead (context, address + offset, addr_byte_size, 0, &success); if (!success) return false; // In ARMv5T and above, this is an interworking branch. if (!LoadWritePC(context, data)) return false; } // if wback && registers == ’0’ then R[n] = R[n] + 4*BitCount(registers); if (wback && BitIsClear (registers, n)) { addr_t addr = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; offset = addr_byte_size * BitCount (registers); context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetImmediateSigned (offset); addr = addr + offset; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, addr)) return false; } // if wback && registers == ’1’ then R[n] = bits(32) UNKNOWN; // Only possible for encoding A1 if (wback && BitIsSet (registers, n)) return WriteBits32Unknown (n); } 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; ctx.type = EmulateInstruction::eContextRegisterPlusOffset; Register dwarf_reg; dwarf_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + Rn); ctx.SetRegisterPlusOffset (dwarf_reg, (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; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); // Read memory from the address. data = MemURead(context, address, 4, 0, &success); if (!success) return false; 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; } // STM (Store Multiple Increment After) stores multiple registers to consecutive memory locations using an address // from a base register. The consecutive memory locations start at this address, and teh address just above the last // of those locations can optionally be written back to the base register. bool EmulateInstructionARM::EmulateSTM (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); address = R[n]; for i = 0 to 14 if registers == ’1’ then if i == n && wback && i != LowestSetBit(registers) then MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1 else MemA[address,4] = R[i]; address = address + 4; if registers<15> == ’1’ then // Only possible for encoding A1 MemA[address,4] = PCStoreValue(); if wback then R[n] = R[n] + 4*BitCount(registers); #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed ()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); // EncodingSpecificOperations(); NullCheckIfThumbEE(n); switch (encoding) { case eEncodingT1: // n = UInt(Rn); registers = ’00000000’:register_list; wback = TRUE; n = Bits32 (opcode, 10, 8); registers = Bits32 (opcode, 7, 0); registers = registers & 0x00ff; // Make sure the top 8 bits are zeros. wback = true; // if BitCount(registers) < 1 then UNPREDICTABLE; if (BitCount (registers) < 1) return false; break; case eEncodingT2: // n = UInt(Rn); registers = ’0’:M:’0’:register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros. wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 2)) return false; // if wback && registers == ’1’ then UNPREDICTABLE; if (wback && BitIsSet (registers, n)) return false; break; case eEncodingA1: // n = UInt(Rn); registers = register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 1)) return false; break; default: return false; } // address = R[n]; int32_t offset = 0; const addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterStore; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); // for i = 0 to 14 for (int i = 0; i < 14; ++i) { int lowest_set_bit = 14; // if registers == ’1’ then if (BitIsSet (registers, i)) { if (i < lowest_set_bit) lowest_set_bit = i; // if i == n && wback && i != LowestSetBit(registers) then if ((i == n) && wback && (i != lowest_set_bit)) // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encodings T1 and A1 WriteBits32UnknownToMemory (address + offset); else { // MemA[address,4] = R[i]; uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); if (!success) return false; Register data_reg; data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + i); context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset); if (!MemAWrite (context, address + offset, data, addr_byte_size)) return false; } // address = address + 4; offset += addr_byte_size; } } // if registers<15> == ’1’ then // Only possible for encoding A1 // MemA[address,4] = PCStoreValue(); if (BitIsSet (registers, 15)) { Register pc_reg; pc_reg.SetRegister (eRegisterKindDWARF, dwarf_pc); context.SetRegisterPlusOffset (pc_reg, 8); const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; if (!MemAWrite (context, address + offset, pc + 8, addr_byte_size)) return false; } // if wback then R[n] = R[n] + 4*BitCount(registers); if (wback) { offset = addr_byte_size * BitCount (registers); context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetImmediateSigned (offset); addr_t data = address + offset; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) return false; } } return true; } // STMDA (Store Multiple Decrement After) stores multiple registers to consecutive memory locations using an address // from a base register. The consecutive memory locations end at this address, and the address just below the lowest // of those locations can optionally be written back to the base register. bool EmulateInstructionARM::EmulateSTMDA (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); address = R[n] - 4*BitCount(registers) + 4; for i = 0 to 14 if registers == ’1’ then if i == n && wback && i != LowestSetBit(registers) then MemA[address,4] = bits(32) UNKNOWN; else MemA[address,4] = R[i]; address = address + 4; if registers<15> == ’1’ then MemA[address,4] = PCStoreValue(); if wback then R[n] = R[n] - 4*BitCount(registers); #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed ()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); // EncodingSpecificOperations(); switch (encoding) { case eEncodingA1: // n = UInt(Rn); registers = register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if ((n == 15) || (BitCount (registers) < 1)) return false; break; default: return false; } // address = R[n] - 4*BitCount(registers) + 4; int32_t offset = 0; addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; address = address - (addr_byte_size * BitCount (registers)) + 4; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterStore; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); // for i = 0 to 14 for (int i = 0; i < 14; ++i) { int lowest_bit_set = 14; // if registers == ’1’ then if (BitIsSet (registers, i)) { if (i < lowest_bit_set) lowest_bit_set = i; //if i == n && wback && i != LowestSetBit(registers) then if ((i == n) && wback && (i != lowest_bit_set)) // MemA[address,4] = bits(32) UNKNOWN; WriteBits32UnknownToMemory (address + offset); else { // MemA[address,4] = R[i]; uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); if (!success) return false; Register data_reg; data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + i); context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset); if (!MemAWrite (context, address + offset, data, addr_byte_size)) return false; } // address = address + 4; offset += addr_byte_size; } } // if registers<15> == ’1’ then // MemA[address,4] = PCStoreValue(); if (BitIsSet (registers, 15)) { Register pc_reg; pc_reg.SetRegister (eRegisterKindDWARF, dwarf_pc); context.SetRegisterPlusOffset (pc_reg, 8); const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; if (!MemAWrite (context, address + offset, pc + 8, addr_byte_size)) return false; } // if wback then R[n] = R[n] - 4*BitCount(registers); if (wback) { offset = (addr_byte_size * BitCount (registers)) * -1; context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetImmediateSigned (offset); addr_t data = address + offset; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) return false; } } return true; } // STMDB (Store Multiple Decrement Before) stores multiple registers to consecutive memory locations using an address // from a base register. The consecutive memory locations end just below this address, and the address of the first of // those locations can optionally be written back to the base register. bool EmulateInstructionARM::EmulateSTMDB (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); address = R[n] - 4*BitCount(registers); for i = 0 to 14 if registers == ’1’ then if i == n && wback && i != LowestSetBit(registers) then MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1 else MemA[address,4] = R[i]; address = address + 4; if registers<15> == ’1’ then // Only possible for encoding A1 MemA[address,4] = PCStoreValue(); if wback then R[n] = R[n] - 4*BitCount(registers); #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed ()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); // EncodingSpecificOperations(); NullCheckIfThumbEE(n); switch (encoding) { case eEncodingT1: // if W == ’1’ && Rn == ’1101’ then SEE PUSH; if ((BitIsSet (opcode, 21)) && (Bits32 (opcode, 19, 16) == 13)) { // See PUSH } // n = UInt(Rn); registers = ’0’:M:’0’:register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); registers = registers & 0x5fff; // Make sure bits 15 & 13 are zeros. wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 2 then UNPREDICTABLE; if ((n == 15) || BitCount (registers) < 2) return false; // if wback && registers == ’1’ then UNPREDICTABLE; if (wback && BitIsSet (registers, n)) return false; break; case eEncodingA1: // if W == ’1’ && Rn == ’1101’ && BitCount(register_list) >= 2 then SEE PUSH; if (BitIsSet (opcode, 21) && (Bits32 (opcode, 19, 16) == 13) && BitCount (Bits32 (opcode, 15, 0)) >= 2) { // See Push } // n = UInt(Rn); registers = register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if ((n == 15) || BitCount (registers) < 1) return false; break; default: return false; } // address = R[n] - 4*BitCount(registers); int32_t offset = 0; addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; address = address - (addr_byte_size * BitCount (registers)); EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterStore; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); // for i = 0 to 14 for (int i = 0; i < 14; ++i) { uint32_t lowest_set_bit = 14; // if registers == ’1’ then if (BitIsSet (registers, i)) { if (i < lowest_set_bit) lowest_set_bit = i; // if i == n && wback && i != LowestSetBit(registers) then if ((i == n) && wback && (i != lowest_set_bit)) // MemA[address,4] = bits(32) UNKNOWN; // Only possible for encoding A1 WriteBits32UnknownToMemory (address + offset); else { // MemA[address,4] = R[i]; uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); if (!success) return false; Register data_reg; data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + i); context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset); if (!MemAWrite (context, address + offset, data, addr_byte_size)) return false; } // address = address + 4; offset += addr_byte_size; } } // if registers<15> == ’1’ then // Only possible for encoding A1 // MemA[address,4] = PCStoreValue(); if (BitIsSet (registers, 15)) { Register pc_reg; pc_reg.SetRegister (eRegisterKindDWARF, dwarf_pc); context.SetRegisterPlusOffset (pc_reg, 8); const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; if (!MemAWrite (context, address + offset, pc + 8, addr_byte_size)) return false; } // if wback then R[n] = R[n] - 4*BitCount(registers); if (wback) { offset = (addr_byte_size * BitCount (registers)) * -1; context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetImmediateSigned (offset); addr_t data = address + offset; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) return false; } } return true; } // STMIB (Store Multiple Increment Before) stores multiple registers to consecutive memory locations using an address // from a base register. The consecutive memory locations start just above this address, and the address of the last // of those locations can optionally be written back to the base register. bool EmulateInstructionARM::EmulateSTMIB (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); address = R[n] + 4; for i = 0 to 14 if registers == ’1’ then if i == n && wback && i != LowestSetBit(registers) then MemA[address,4] = bits(32) UNKNOWN; else MemA[address,4] = R[i]; address = address + 4; if registers<15> == ’1’ then MemA[address,4] = PCStoreValue(); if wback then R[n] = R[n] + 4*BitCount(registers); #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t n; uint32_t registers = 0; bool wback; const uint32_t addr_byte_size = GetAddressByteSize(); // EncodingSpecificOperations(); switch (encoding) { case eEncodingA1: // n = UInt(Rn); registers = register_list; wback = (W == ’1’); n = Bits32 (opcode, 19, 16); registers = Bits32 (opcode, 15, 0); wback = BitIsSet (opcode, 21); // if n == 15 || BitCount(registers) < 1 then UNPREDICTABLE; if ((n == 15) && (BitCount (registers) < 1)) return false; break; default: return false; } // address = R[n] + 4; int32_t offset = 0; addr_t address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; address = address + addr_byte_size; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextRegisterStore; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); uint32_t lowest_set_bit = 14; // for i = 0 to 14 for (int i = 0; i < 14; ++i) { // if registers == ’1’ then if (BitIsSet (registers, i)) { if (i < lowest_set_bit) lowest_set_bit = i; // if i == n && wback && i != LowestSetBit(registers) then if ((i == n) && wback && (i != lowest_set_bit)) // MemA[address,4] = bits(32) UNKNOWN; WriteBits32UnknownToMemory (address + offset); // else else { // MemA[address,4] = R[i]; uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + i, 0, &success); if (!success) return false; Register data_reg; data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + i); context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset); if (!MemAWrite (context, address + offset, data, addr_byte_size)) return false; } // address = address + 4; offset += addr_byte_size; } } // if registers<15> == ’1’ then // MemA[address,4] = PCStoreValue(); if (BitIsSet (registers, 15)) { Register pc_reg; pc_reg.SetRegister (eRegisterKindDWARF, dwarf_pc); context.SetRegisterPlusOffset (pc_reg, 8); const uint32_t pc = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (!success) return false; if (!MemAWrite (context, address + offset, pc + 8, addr_byte_size)) return false; } // if wback then R[n] = R[n] + 4*BitCount(registers); if (wback) { offset = addr_byte_size * BitCount (registers); context.type = EmulateInstruction::eContextAdjustBaseRegister; context.SetImmediateSigned (offset); addr_t data = address + offset; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, data)) return false; } } return true; } // STR (store immediate) calcualtes an address from a base register value and an immediate offset, and stores a word // from a register to memory. It can use offset, post-indexed, or pre-indexed addressing. bool EmulateInstructionARM::EmulateSTRThumb (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); address = if index then offset_addr else R[n]; if UnalignedSupport() || address<1:0> == ’00’ then MemU[address,4] = R[t]; else // Can only occur before ARMv7 MemU[address,4] = bits(32) UNKNOWN; if wback then R[n] = offset_addr; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const uint32_t addr_byte_size = GetAddressByteSize(); uint32_t t; uint32_t n; uint32_t imm32; bool index; bool add; bool wback; // EncodingSpecificOperations (); NullCheckIfThumbEE(n); switch (encoding) { case eEncodingT1: // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5:’00’, 32); t = Bits32 (opcode, 2, 0); n = Bits32 (opcode, 5, 3); imm32 = Bits32 (opcode, 10, 6) << 2; // index = TRUE; add = TRUE; wback = FALSE; index = true; add = false; wback = false; break; case eEncodingT2: // t = UInt(Rt); n = 13; imm32 = ZeroExtend(imm8:’00’, 32); t = Bits32 (opcode, 10, 8); n = 13; imm32 = Bits32 (opcode, 7, 0) << 2; // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; break; case eEncodingT3: // if Rn == ’1111’ then UNDEFINED; if (Bits32 (opcode, 19, 16) == 15) return false; // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 11, 0); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; // if t == 15 then UNPREDICTABLE; if (t == 15) return false; break; case eEncodingT4: // if P == ’1’ && U == ’1’ && W == ’0’ then SEE STRT; // if Rn == ’1101’ && P == ’1’ && U == ’0’ && W == ’1’ && imm8 == ’00000100’ then SEE PUSH; // if Rn == ’1111’ || (P == ’0’ && W == ’0’) then UNDEFINED; if ((Bits32 (opcode, 19, 16) == 15) || (BitIsClear (opcode, 10) && BitIsClear (opcode, 8))) return false; // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 7, 0); // index = (P == ’1’); add = (U == ’1’); wback = (W == ’1’); index = BitIsSet (opcode, 10); add = BitIsSet (opcode, 9); wback = BitIsSet (opcode, 8); // if t == 15 || (wback && n == t) then UNPREDICTABLE; if ((t == 15) || (wback && (n == t))) return false; break; default: return false; } addr_t offset_addr; addr_t address; // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); uint32_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; if (add) offset_addr = base_address + imm32; else offset_addr = base_address - imm32; // address = if index then offset_addr else R[n]; if (index) address = offset_addr; else address = base_address; EmulateInstruction::Context context; context.type = eContextRegisterStore; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); // if UnalignedSupport() || address<1:0> == ’00’ then if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0))) { // MemU[address,4] = R[t]; uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success); if (!success) return false; Register data_reg; data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + t); int32_t offset = address - base_address; context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, offset); if (!MemUWrite (context, address, data, addr_byte_size)) return false; } else { // MemU[address,4] = bits(32) UNKNOWN; WriteBits32UnknownToMemory (address); } // if wback then R[n] = offset_addr; if (wback) { context.type = eContextRegisterLoad; context.SetAddress (offset_addr); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) return false; } } return true; } // STR (Store Register) calculates an address from a base register value and an offset register value, stores a // word from a register to memory. The offset register value can optionally be shifted. bool EmulateInstructionARM::EmulateSTRRegister (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); offset = Shift(R[m], shift_t, shift_n, APSR.C); offset_addr = if add then (R[n] + offset) else (R[n] - offset); address = if index then offset_addr else R[n]; if t == 15 then // Only possible for encoding A1 data = PCStoreValue(); else data = R[t]; if UnalignedSupport() || address<1:0> == ’00’ || CurrentInstrSet() == InstrSet_ARM then MemU[address,4] = data; else // Can only occur before ARMv7 MemU[address,4] = bits(32) UNKNOWN; if wback then R[n] = offset_addr; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { const uint32_t addr_byte_size = GetAddressByteSize(); uint32_t t; uint32_t n; uint32_t m; ARM_ShifterType shift_t; uint32_t shift_n; bool index; bool add; bool wback; // EncodingSpecificOperations (); NullCheckIfThumbEE(n); switch (encoding) { case eEncodingT1: // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE"; // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); t = Bits32 (opcode, 2, 0); n = Bits32 (opcode, 5, 3); m = Bits32 (opcode, 8, 6); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; // (shift_t, shift_n) = (SRType_LSL, 0); shift_t = SRType_LSL; shift_n = 0; break; case eEncodingT2: // if Rn == ’1111’ then UNDEFINED; if (Bits32 (opcode, 19, 16) == 15) return false; // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); m = Bits32 (opcode, 3, 0); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); shift_t = SRType_LSL; shift_n = Bits32 (opcode, 5, 4); // if t == 15 || BadReg(m) then UNPREDICTABLE; if ((t == 15) || (BadReg (m))) return false; break; case eEncodingA1: { // if P == ’0’ && W == ’1’ then SEE STRT; // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); m = Bits32 (opcode, 3, 0); // index = (P == ’1’); add = (U == ’1’); wback = (P == ’0’) || (W == ’1’); index = BitIsSet (opcode, 24); add = BitIsSet (opcode, 23); wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); // (shift_t, shift_n) = DecodeImmShift(type, imm5); uint32_t typ = Bits32 (opcode, 6, 5); uint32_t imm5 = Bits32 (opcode, 11, 7); shift_n = DecodeImmShift(typ, imm5, shift_t); // if m == 15 then UNPREDICTABLE; if (m == 15) return false; // if wback && (n == 15 || n == t) then UNPREDICTABLE; if (wback && ((n == 15) || (n == t))) return false; break; } default: return false; } addr_t offset_addr; addr_t address; int32_t offset = 0; addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; uint32_t Rm_data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); if (!success) return false; // offset = Shift(R[m], shift_t, shift_n, APSR.C); offset = Shift (Rm_data, shift_t, shift_n, APSR_C); // offset_addr = if add then (R[n] + offset) else (R[n] - offset); if (add) offset_addr = base_address + offset; else offset_addr = base_address - offset; // address = if index then offset_addr else R[n]; if (index) address = offset_addr; else address = base_address; uint32_t data; // if t == 15 then // Only possible for encoding A1 if (t == 15) // data = PCStoreValue(); data = ReadRegisterUnsigned(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); else // data = R[t]; data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success); if (!success) return false; EmulateInstruction::Context context; context.type = eContextRegisterStore; // if UnalignedSupport() || address<1:0> == ’00’ || CurrentInstrSet() == InstrSet_ARM then if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0)) || CurrentInstrSet() == eModeARM) { // MemU[address,4] = data; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); Register data_reg; data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + t); context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address); if (!MemUWrite (context, address, data, addr_byte_size)) return false; } else // MemU[address,4] = bits(32) UNKNOWN; WriteBits32UnknownToMemory (address); // if wback then R[n] = offset_addr; if (wback) { context.type = eContextRegisterLoad; context.SetAddress (offset_addr); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) return false; } } return true; } bool EmulateInstructionARM::EmulateSTRBThumb (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); address = if index then offset_addr else R[n]; MemU[address,1] = R[t]<7:0>; if wback then R[n] = offset_addr; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed ()) { uint32_t t; uint32_t n; uint32_t imm32; bool index; bool add; bool wback; // EncodingSpecificOperations(); NullCheckIfThumbEE(n); switch (encoding) { case eEncodingT1: // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); t = Bits32 (opcode, 2, 0); n = Bits32 (opcode, 5, 3); imm32 = Bits32 (opcode, 10, 6); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; break; case eEncodingT2: // if Rn == ’1111’ then UNDEFINED; if (Bits32 (opcode, 19, 16) == 15) return false; // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 11, 0); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; // if BadReg(t) then UNPREDICTABLE; if (BadReg (t)) return false; break; case eEncodingT3: // if P == ’1’ && U == ’1’ && W == ’0’ then SEE STRBT; // if Rn == ’1111’ || (P == ’0’ && W == ’0’) then UNDEFINED; if (Bits32 (opcode, 19, 16) == 15) return false; // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 7, 0); // index = (P == ’1’); add = (U == ’1’); wback = (W == ’1’); index = BitIsSet (opcode, 10); add = BitIsSet (opcode, 9); wback = BitIsSet (opcode, 8); // if BadReg(t) || (wback && n == t) then UNPREDICTABLE if ((BadReg (t)) || (wback && (n == t))) return false; break; default: return false; } addr_t offset_addr; addr_t address; addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); if (add) offset_addr = base_address + imm32; else offset_addr = base_address - imm32; // address = if index then offset_addr else R[n]; if (index) address = offset_addr; else address = base_address; // MemU[address,1] = R[t]<7:0> Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); Register data_reg; data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + t); EmulateInstruction::Context context; context.type = eContextRegisterStore; context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - base_address); uint32_t data = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + t, 0, &success); if (!success) return false; data = Bits32 (data, 7, 0); if (!MemUWrite (context, address, data, 1)) return false; // if wback then R[n] = offset_addr; if (wback) { context.type = eContextRegisterLoad; context.SetAddress (offset_addr); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) 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 EmulateInstructionARM::EmulateANDImm (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); result = R[n] AND imm32; if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd, Rn; uint32_t imm32; // the immediate value to be ANDed to the value obtained from Rn bool setflags; uint32_t carry; // the carry bit after ARM/Thumb Expand operation switch (encoding) { case eEncodingT1: Rd = Bits32(opcode, 11, 8); Rn = Bits32(opcode, 19, 16); setflags = BitIsSet(opcode, 20); imm32 = ThumbExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ThumbExpandImm(i:imm3:imm8, APSR.C) // TODO: Emulate TST (immediate) if (Rd == 15 && setflags) return false; if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn)) return false; break; case eEncodingA1: Rd = Bits32(opcode, 15, 12); Rn = Bits32(opcode, 19, 16); setflags = BitIsSet(opcode, 20); imm32 = ARMExpandImm_C(opcode, APSR_C, carry); // (imm32, carry) = ARMExpandImm(imm12, APSR.C) // TODO: Emulate SUBS PC, LR and related instructions. if (Rd == 15 && setflags) return false; break; default: return false; } int32_t val1; // Read the first operand. if (Rn == 15) { val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (encoding == eEncodingT1) val1 += 4; else val1 += 8; } else val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; uint32_t result = val1 & imm32; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) return false; } return true; } // This instruction performs a bitwise AND of a register value and an optionally-shifted register value, // and writes the result to the destination register. It can optionally update the condition flags // based on the result. bool EmulateInstructionARM::EmulateANDReg (ARMEncoding encoding) { #if 0 // ARM pseudo code... if ConditionPassed() then EncodingSpecificOperations(); (shifted, carry) = Shift_C(R[m], shift_t, shift_n, APSR.C); result = R[n] AND shifted; if d == 15 then // Can only occur for ARM encoding ALUWritePC(result); // setflags is always FALSE here else R[d] = result; if setflags then APSR.N = result<31>; APSR.Z = IsZeroBit(result); APSR.C = carry; // APSR.V unchanged #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed()) { uint32_t Rd, Rn, Rm; ARM_ShifterType shift_t; uint32_t shift_n; // the shift applied to the value read from Rm bool setflags; uint32_t carry; switch (encoding) { case eEncodingT1: Rd = Rn = Bits32(opcode, 2, 0); Rm = Bits32(opcode, 5, 3); setflags = !InITBlock(); shift_t = SRType_LSL; shift_n = 0; case eEncodingT2: Rd = Bits32(opcode, 11, 8); Rn = Bits32(opcode, 19, 16); Rm = Bits32(opcode, 3, 0); setflags = BitIsSet(opcode, 20); shift_n = DecodeImmShift(Bits32(opcode, 5, 4), Bits32(opcode, 14, 12) << 2 | Bits32(opcode, 7, 6), shift_t); // TODO: Emulate TST (register) if (Rd == 15 && setflags) return false; if (Rd == 13 || (Rd == 15 && !setflags) || BadReg(Rn) || BadReg(Rm)) return false; break; case eEncodingA1: Rd = Bits32(opcode, 15, 12); Rn = Bits32(opcode, 19, 16); Rm = Bits32(opcode, 3, 0); setflags = BitIsSet(opcode, 20); shift_n = DecodeImmShift(Bits32(opcode, 6, 5), Bits32(opcode, 11, 7), shift_t); // TODO: Emulate SUBS PC, LR and related instructions. if (Rd == 15 && setflags) return false; break; default: return false; } int32_t val1, val2; // Read the first operand. if (Rn == 15) { val1 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (encoding == eEncodingT1 || encoding == eEncodingT2) val1 += 4; else val1 += 8; } else val1 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rn, 0, &success); if (!success) return false; // Read the second operand. if (Rm == 15) { val2 = ReadRegisterUnsigned (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC, 0, &success); if (encoding == eEncodingT1 || encoding == eEncodingT2) val1 += 4; else val1 += 8; } else val2 = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + Rm, 0, &success); if (!success) return false; uint32_t shifted = Shift_C(val2, shift_t, shift_n, APSR_C, carry); uint32_t result = val1 & shifted; EmulateInstruction::Context context; context.type = EmulateInstruction::eContextImmediate; context.SetNoArgs (); if (!WriteCoreRegOptionalFlags(context, result, Rd, setflags, carry)) return false; } return true; } // LDR (immediate, ARM) calculates an address from a base register value and an immediate offset, loads a word // from memory, and writes it to a register. It can use offset, post-indexed, or pre-indexed addressing. bool EmulateInstructionARM::EmulateLDRImmediateARM (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); 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 // Can only apply before ARMv7 R[t] = ROR(data, 8*UInt(address<1:0>)); #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed ()) { const uint32_t addr_byte_size = GetAddressByteSize(); uint32_t t; uint32_t n; uint32_t imm32; bool index; bool add; bool wback; switch (encoding) { case eEncodingA1: // if Rn == ’1111’ then SEE LDR (literal); // if P == ’0’ && W == ’1’ then SEE LDRT; // if Rn == ’1101’ && P == ’0’ && U == ’1’ && W == ’0’ && imm12 == ’000000000100’ then SEE POP; // t == UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 11, 0); // index = (P == ’1’); add = (U == ’1’); wback = (P == ’0’) || (W == ’1’); index = BitIsSet (opcode, 24); add = BitIsSet (opcode, 23); wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); // if wback && n == t then UNPREDICTABLE; if (wback && (n == t)) return false; break; default: return false; } addr_t address; addr_t offset_addr; addr_t base_address = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); if (add) offset_addr = base_address + imm32; else offset_addr = base_address - imm32; // address = if index then offset_addr else R[n]; if (index) address = offset_addr; else address = base_address; // data = MemU[address,4]; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); EmulateInstruction::Context context; context.type = eContextRegisterLoad; context.SetRegisterPlusOffset (base_reg, address - base_address); uint64_t data = MemURead (context, address, addr_byte_size, 0, &success); if (!success) return false; // if wback then R[n] = offset_addr; if (wback) { context.type = eContextAdjustBaseRegister; context.SetAddress (offset_addr); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) return false; } // if t == 15 then if (t == 15) { // if address<1:0> == ’00’ then LoadWritePC(data); else UNPREDICTABLE; if (BitIsClear (address, 1) && BitIsClear (address, 0)) { // LoadWritePC (data); context.type = eContextRegisterLoad; context.SetRegisterPlusOffset (base_reg, address - base_address); LoadWritePC (context, data); } else return false; } // elsif UnalignedSupport() || address<1:0> = ’00’ then else if (UnalignedSupport() || (BitIsClear (address, 1) && BitIsClear (address, 0))) { // R[t] = data; context.type = eContextRegisterLoad; context.SetRegisterPlusOffset (base_reg, address - base_address); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) return false; } // else // Can only apply before ARMv7 else { // R[t] = ROR(data, 8*UInt(address<1:0>)); data = ROR (data, Bits32 (address, 1, 0)); context.type = eContextRegisterLoad; context.SetImmediate (data); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) return false; } } return true; } // LDR (register) calculates an address from a base register value and an offset register value, loads a word // from memory, and writes it to a resgister. The offset register value can optionally be shifted. bool EmulateInstructionARM::EmulateLDRRegister (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); offset = Shift(R[m], shift_t, shift_n, APSR.C); offset_addr = if add then (R[n] + offset) else (R[n] - offset); 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 // Can only apply before ARMv7 if CurrentInstrSet() == InstrSet_ARM then R[t] = ROR(data, 8*UInt(address<1:0>)); else R[t] = bits(32) UNKNOWN; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed ()) { const uint32_t addr_byte_size = GetAddressByteSize(); uint32_t t; uint32_t n; uint32_t m; bool index; bool add; bool wback; ARM_ShifterType shift_t; uint32_t shift_n; switch (encoding) { case eEncodingT1: // if CurrentInstrSet() == InstrSet_ThumbEE then SEE "Modified operation in ThumbEE"; // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); t = Bits32 (opcode, 2, 0); n = Bits32 (opcode, 5, 3); m = Bits32 (opcode, 8, 6); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; // (shift_t, shift_n) = (SRType_LSL, 0); shift_t = SRType_LSL; shift_n = 0; break; case eEncodingT2: // if Rn == ’1111’ then SEE LDR (literal); // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); m = Bits32 (opcode, 3, 0); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); shift_t = SRType_LSL; shift_n = Bits32 (opcode, 5, 4); // if BadReg(m) then UNPREDICTABLE; if (BadReg (m)) return false; // if t == 15 && InITBlock() && !LastInITBlock() then UNPREDICTABLE; if ((t == 15) && InITBlock() && !LastInITBlock()) return false; break; case eEncodingA1: { // if P == ’0’ && W == ’1’ then SEE LDRT; // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); m = Bits32 (opcode, 3, 0); // index = (P == ’1’); add = (U == ’1’); wback = (P == ’0’) || (W == ’1’); index = BitIsSet (opcode, 24); add = BitIsSet (opcode, 23); wback = (BitIsClear (opcode, 24) || BitIsSet (opcode, 21)); // (shift_t, shift_n) = DecodeImmShift(type, imm5); uint32_t type = Bits32 (opcode, 6, 5); uint32_t imm5 = Bits32 (opcode, 11, 7); shift_n = DecodeImmShift (type, imm5, shift_t); // if m == 15 then UNPREDICTABLE; if (m == 15) return false; // if wback && (n == 15 || n == t) then UNPREDICTABLE; if (wback && ((n == 15) || (n == t))) return false; } break; default: return false; } uint32_t Rm = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + m, 0, &success); if (!success) return false; uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; addr_t offset_addr; addr_t address; // offset = Shift(R[m], shift_t, shift_n, APSR.C); -- Note "The APSR is an application level alias for the CPSR". addr_t offset = Shift (Rm, shift_t, shift_n, Bit32 (m_inst_cpsr, CPSR_C)); // offset_addr = if add then (R[n] + offset) else (R[n] - offset); if (add) offset_addr = Rn + offset; else offset_addr = Rn - offset; // address = if index then offset_addr else R[n]; if (index) address = offset_addr; else address = Rn; // data = MemU[address,4]; Register base_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); EmulateInstruction::Context context; context.type = eContextRegisterLoad; context.SetRegisterPlusOffset (base_reg, address - Rn); uint64_t data = MemURead (context, address, addr_byte_size, 0, &success); if (!success) return false; // if wback then R[n] = offset_addr; if (wback) { context.type = eContextAdjustBaseRegister; context.SetAddress (offset_addr); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) return false; } // if t == 15 then if (t == 15) { // if address<1:0> == ’00’ then LoadWritePC(data); else UNPREDICTABLE; if (BitIsClear (address, 1) && BitIsClear (address, 0)) { context.type = eContextRegisterLoad; context.SetRegisterPlusOffset (base_reg, address - Rn); LoadWritePC (context, data); } else return false; } // elsif UnalignedSupport() || address<1:0> = ’00’ then else if (UnalignedSupport () || (BitIsClear (address, 1) && BitIsClear (address, 0))) { // R[t] = data; context.type = eContextRegisterLoad; context.SetRegisterPlusOffset (base_reg, address - Rn); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) return false; } else // Can only apply before ARMv7 { // if CurrentInstrSet() == InstrSet_ARM then if (CurrentInstrSet () == eModeARM) { // R[t] = ROR(data, 8*UInt(address<1:0>)); data = ROR (data, Bits32 (address, 1, 0)); context.type = eContextRegisterLoad; context.SetImmediate (data); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) return false; } else { // R[t] = bits(32) UNKNOWN; WriteBits32Unknown (t); } } } return true; } // LDRB (immediate, Thumb) bool EmulateInstructionARM::EmulateLDRBImmediate (ARMEncoding encoding) { #if 0 if ConditionPassed() then EncodingSpecificOperations(); NullCheckIfThumbEE(n); offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); address = if index then offset_addr else R[n]; R[t] = ZeroExtend(MemU[address,1], 32); if wback then R[n] = offset_addr; #endif bool success = false; const uint32_t opcode = OpcodeAsUnsigned (&success); if (!success) return false; if (ConditionPassed ()) { uint32_t t; uint32_t n; uint32_t imm32; bool index; bool add; bool wback; // EncodingSpecificOperations(); NullCheckIfThumbEE(n); switch (encoding) { case eEncodingT1: // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm5, 32); t = Bits32 (opcode, 2, 0); n = Bits32 (opcode, 5, 3); imm32 = Bits32 (opcode, 10, 6); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback= false; break; case eEncodingT2: // if Rt == ’1111’ then SEE PLD; // if Rn == ’1111’ then SEE LDRB (literal); // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm12, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 11, 0); // index = TRUE; add = TRUE; wback = FALSE; index = true; add = true; wback = false; // if t == 13 then UNPREDICTABLE; if (t == 13) return false; break; case eEncodingT3: // if Rt == ’1111’ && P == ’1’ && U == ’0’ && W == ’0’ then SEE PLD; // if Rn == ’1111’ then SEE LDRB (literal); // if P == ’1’ && U == ’1’ && W == ’0’ then SEE LDRBT; // if P == ’0’ && W == ’0’ then UNDEFINED; if (BitIsClear (opcode, 10) && BitIsClear (opcode, 8)) return false; // t = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 7, 0); // index = (P == ’1’); add = (U == ’1’); wback = (W == ’1’); index = BitIsSet (opcode, 10); add = BitIsSet (opcode, 9); wback = BitIsSet (opcode, 8); // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; if (BadReg (t) || (wback && (n == t))) return false; break; default: return false; } uint32_t Rn = ReadRegisterUnsigned (eRegisterKindDWARF, dwarf_r0 + n, 0, &success); if (!success) return false; addr_t address; addr_t offset_addr; // offset_addr = if add then (R[n] + imm32) else (R[n] - imm32); if (add) offset_addr = Rn + imm32; else offset_addr = Rn - imm32; // address = if index then offset_addr else R[n]; if (index) address = offset_addr; else address = Rn; // R[t] = ZeroExtend(MemU[address,1], 32); Register base_reg; Register data_reg; base_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + n); data_reg.SetRegister (eRegisterKindDWARF, dwarf_r0 + t); EmulateInstruction::Context context; context.type = eContextRegisterLoad; context.SetRegisterToRegisterPlusOffset (data_reg, base_reg, address - Rn); uint64_t data = MemURead (context, address, 1, 0, &success); if (!success) return false; if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + t, data)) return false; // if wback then R[n] = offset_addr; if (wback) { context.type = eContextAdjustBaseRegister; context.SetAddress (offset_addr); if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + n, offset_addr)) return false; } } return true; } EmulateInstructionARM::ARMOpcode* EmulateInstructionARM::GetARMOpcodeForInstruction (const uint32_t opcode) { static ARMOpcode g_arm_opcodes[] = { //---------------------------------------------------------------------- // Prologue instructions //---------------------------------------------------------------------- // push register(s) { 0x0fff0000, 0x092d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePUSH, "push " }, { 0x0fff0fff, 0x052d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePUSH, "push " }, // set r7 to point to a stack offset { 0x0ffff000, 0x028d7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add r7, sp, #" }, { 0x0ffff000, 0x024c7000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSUBR7IPImm, "sub r7, ip, #"}, // copy the stack pointer to ip { 0x0fffffff, 0x01a0c00d, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateMOVRdSP, "mov ip, sp" }, { 0x0ffff000, 0x028dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateADDRdSPImm, "add ip, sp, #" }, { 0x0ffff000, 0x024dc000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSUBIPSPImm, "sub ip, sp, #"}, // adjust the stack pointer { 0x0ffff000, 0x024dd000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSUBSPImm, "sub sp, sp, #"}, // push one register // if Rn == '1101' && imm12 == '000000000100' then SEE PUSH; { 0x0fff0000, 0x052d0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSTRRtSP, "str Rt, [sp, #-imm12]!" }, // vector push consecutive extension register(s) { 0x0fbf0f00, 0x0d2d0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.64 "}, { 0x0fbf0f00, 0x0d2d0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPUSH, "vpush.32 "}, //---------------------------------------------------------------------- // Epilogue instructions //---------------------------------------------------------------------- { 0x0fff0000, 0x08bd0000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulatePOP, "pop "}, { 0x0fff0fff, 0x049d0004, ARMvAll, eEncodingA2, eSize32, &EmulateInstructionARM::EmulatePOP, "pop "}, { 0x0fbf0f00, 0x0cbd0b00, ARMV6T2_ABOVE, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.64 "}, { 0x0fbf0f00, 0x0cbd0a00, ARMV6T2_ABOVE, eEncodingA2, eSize32, &EmulateInstructionARM::EmulateVPOP, "vpop.32 "}, //---------------------------------------------------------------------- // Supervisor Call (previously Software Interrupt) //---------------------------------------------------------------------- { 0x0f000000, 0x0f000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "svc #imm24"}, //---------------------------------------------------------------------- // Branch instructions //---------------------------------------------------------------------- { 0x0f000000, 0x0a000000, ARMvAll, eEncodingA1, eSize32, &EmulateInstructionARM::EmulateSVC, "b #imm24"}, // To resolve ambiguity, "blx