Index: source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp =================================================================== --- source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp +++ source/Plugins/Instruction/ARM/EmulateInstructionARM.cpp @@ -1333,28 +1333,44 @@ return false; uint32_t imm32; // the immediate operand uint32_t d; - //bool setflags = false; // Add this back if/when support eEncodingT3 eEncodingA1 + bool setflags; switch (encoding) { case eEncodingT1: // d = UInt(Rd); setflags = FALSE; imm32 = ZeroExtend(imm8:'00', 32); d = Bits32 (opcode, 10, 8); imm32 = (Bits32 (opcode, 7, 0) << 2); - + setflags = false; break; case eEncodingT2: // d = 13; setflags = FALSE; imm32 = ZeroExtend(imm7:'00', 32); d = 13; - imm32 = ThumbImm7Scaled(opcode); // imm32 = ZeroExtend(imm7:'00', 32) - + imm32 = ThumbImm7Scaled (opcode); // imm32 = ZeroExtend(imm7:'00', 32) + setflags = false; + break; + + case eEncodingT3: + // d = UInt(Rd); setflags = (S == "1"); imm32 = ThumbExpandImm(i:imm3:imm8); + d = Bits32 (opcode, 11, 8); + imm32 = ThumbExpandImm (opcode); + setflags = Bit32 (opcode, 20); + + // if Rd == "1111" && S == "1" then SEE CMN (immediate); + if (d == 15 && setflags == 1) + return false; // CMN (immediate) not yet supported + + // if d == 15 && S == "0" then UNPREDICTABLE; + if (d == 15 && setflags == 0) + return false; + break; default: return false; } - addr_t sp_offset = imm32; - addr_t addr = sp + sp_offset; // the adjusted stack pointer value + // (result, carry, overflow) = AddWithCarry(R[n], imm32, '0'); + AddWithCarryResult res = AddWithCarry (sp, imm32, 0); EmulateInstruction::Context context; if (d == 13) @@ -1364,26 +1380,23 @@ RegisterInfo sp_reg; GetRegisterInfo (eRegisterKindDWARF, dwarf_sp, sp_reg); - context.SetRegisterPlusOffset (sp_reg, sp_offset); + context.SetRegisterPlusOffset (sp_reg, res.result - sp); if (d == 15) { - if (!ALUWritePC (context, addr)) + if (!ALUWritePC (context, res.result)) return false; } else { - if (!WriteRegisterUnsigned (context, eRegisterKindDWARF, dwarf_r0 + d, addr)) + //R[d] = result; + //if setflags then + //APSR.N = result<31>; + //APSR.Z = IsZeroBit(result); + //APSR.C = carry; + //APSR.V = overflow; + if (!WriteCoreRegOptionalFlags (context, res.result, d, setflags, res.carry_out, res.overflow)) return false; - - // Add this back if/when support eEncodingT3 eEncodingA1 - //if (setflags) - //{ - // APSR.N = result<31>; - // APSR.Z = IsZeroBit(result); - // APSR.C = carry; - // APSR.V = overflow; - //} } } return true; @@ -2312,13 +2325,16 @@ context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); break; case eEncodingT2: - imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0)); + imm32 = llvm::SignExtend32<12>(Bits32(opcode, 10, 0) << 1); target = pc + imm32; context.SetISAAndImmediateSigned (eModeThumb, 4 + imm32); break; case eEncodingT3: // The 'cond' field is handled in EmulateInstructionARM::CurrentCond(). { + if (Bits32(opcode, 25, 23) == 7) + return false; // See Branches and miscellaneous control on page A6-235. + uint32_t S = Bit32(opcode, 26); uint32_t imm6 = Bits32(opcode, 21, 16); uint32_t J1 = Bit32(opcode, 13); @@ -2428,55 +2444,58 @@ bool success = 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()) + if (ConditionPassed(opcode)) + { + 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; - 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 = ReadCoreReg(Rm, &success); - if (!success) - 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 = ReadCoreReg(Rn, &success); + if (!success) + return false; - // the table index - uint32_t index = ReadCoreReg(Rm, &success); - if (!success) - return false; + // the table index + uint32_t index = ReadCoreReg(Rm, &success); + if (!success) + return false; - // the offsetted table address - addr_t addr = base + (is_tbh ? index*2 : index); + // 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; + // 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 = ReadCoreReg(PC_REG, &success); - if (!success) - return false; + const uint32_t pc = ReadCoreReg(PC_REG, &success); + if (!success) + return false; - // target address - addr_t target = pc + offset; - context.type = EmulateInstruction::eContextRelativeBranchImmediate; - context.SetISAAndImmediateSigned (eModeThumb, 4 + offset); + // target address + addr_t target = pc + offset; + context.type = EmulateInstruction::eContextRelativeBranchImmediate; + context.SetISAAndImmediateSigned (eModeThumb, 4 + offset); - if (!BranchWritePC(context, target)) - return false; + if (!BranchWritePC(context, target)) + return false; + } return true; } @@ -2531,12 +2550,15 @@ case eEncodingT3: // if Rd == '1111' && S == '1' then SEE CMN (immediate); - // if Rn == '1101' then SEE ADD (SP plus immediate); // d = UInt(Rd); n = UInt(Rn); setflags = (S == '1'); imm32 = ThumbExpandImm(i:imm3:imm8); d = Bits32 (opcode, 11, 8); n = Bits32 (opcode, 19, 16); setflags = BitIsSet (opcode, 20); imm32 = ThumbExpandImm_C (opcode, APSR_C, carry_out); + + // if Rn == '1101' then SEE ADD (SP plus immediate); + if (n == 13) + return EmulateADDSPImm(opcode, eEncodingT3); // if BadReg(d) || n == 15 then UNPREDICTABLE; if (BadReg (d) || (n == 15)) @@ -2547,7 +2569,6 @@ case eEncodingT4: { // if Rn == '1111' then SEE ADR; - // if Rn == '1101' then SEE ADD (SP plus immediate); // d = UInt(Rd); n = UInt(Rn); setflags = FALSE; imm32 = ZeroExtend(i:imm3:imm8, 32); d = Bits32 (opcode, 11, 8); n = Bits32 (opcode, 19, 16); @@ -2557,6 +2578,10 @@ uint32_t imm8 = Bits32 (opcode, 7, 0); imm32 = (i << 11) | (imm3 << 8) | imm8; + // if Rn == '1101' then SEE ADD (SP plus immediate); + if (n == 13) + return EmulateADDSPImm(opcode, eEncodingT4); + // if BadReg(d) then UNPREDICTABLE; if (BadReg (d)) return false; @@ -2962,6 +2987,13 @@ if (Rn == 15 || Rm == 15) return false; break; + case eEncodingT3: + Rn = Bits32(opcode, 19, 16); + Rm = Bits32(opcode, 3, 0); + shift_n = DecodeImmShiftThumb(opcode, shift_t); + if (Rn == 15 || BadReg(Rm)) + return false; + break; case eEncodingA1: Rn = Bits32(opcode, 19, 16); Rm = Bits32(opcode, 3, 0); @@ -4010,8 +4042,22 @@ if (wback) { EmulateInstruction::Context ctx; - ctx.type = EmulateInstruction::eContextAdjustBaseRegister; - ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base)); + if (Rn == 13) + { + ctx.type = eContextAdjustStackPointer; + ctx.SetImmediateSigned((int32_t) (offset_addr - base)); + } + else if (Rn == GetFramePointerRegisterNumber()) + { + ctx.type = eContextSetFramePointer; + ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base)); + } + else + { + ctx.type = EmulateInstruction::eContextAdjustBaseRegister; + ctx.SetRegisterPlusOffset (base_reg, (int32_t) (offset_addr - base)); + } + if (!WriteRegisterUnsigned (ctx, eRegisterKindDWARF, dwarf_r0 + Rn, offset_addr)) return false; @@ -6210,8 +6256,6 @@ 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); @@ -6221,7 +6265,15 @@ index = true; add = true; wback = false; - + + // if Rt == '1111' then SEE PLD; + if (t == 15) + return false; // PLD is not implemented yet + + // if Rn == '1111' then SEE LDRB (literal); + if (n == 15) + return EmulateLDRBLiteral(opcode, eEncodingT1); + // if t == 13 then UNPREDICTABLE; if (t == 13) return false; @@ -6229,14 +6281,12 @@ 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 = UInt(Rt); n = UInt(Rn); imm32 = ZeroExtend(imm8, 32); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); imm32 = Bits32 (opcode, 7, 0); @@ -6245,7 +6295,15 @@ index = BitIsSet (opcode, 10); add = BitIsSet (opcode, 9); wback = BitIsSet (opcode, 8); - + + // if Rt == '1111' && P == '1' && U == '0' && W == '0' then SEE PLD; + if (t == 15) + return false; // PLD is not implemented yet + + // if Rn == '1111' then SEE LDRB (literal); + if (n == 15) + return EmulateLDRBLiteral(opcode, eEncodingT1); + // if BadReg(t) || (wback && n == t) then UNPREDICTABLE; if (BadReg (t) || (wback && (n == t))) return false; @@ -6327,11 +6385,14 @@ switch (encoding) { case eEncodingT1: - // if Rt == '1111' then SEE PLD; // t = UInt(Rt); imm32 = ZeroExtend(imm12, 32); add = (U == '1'); t = Bits32 (opcode, 15, 12); imm32 = Bits32 (opcode, 11, 0); add = BitIsSet (opcode, 23); + + // if Rt == '1111' then SEE PLD; + if (t == 15) + return false; // PLD is not implemented yet // if t == 13 then UNPREDICTABLE; if (t == 13) @@ -6432,8 +6493,6 @@ break; case eEncodingT2: - // if Rt == '1111' then SEE PLD; - // if Rn == '1111' then SEE LDRB (literal); // t = UInt(Rt); n = UInt(Rn); m = UInt(Rm); t = Bits32 (opcode, 15, 12); n = Bits32 (opcode, 19, 16); @@ -6447,6 +6506,14 @@ // (shift_t, shift_n) = (SRType_LSL, UInt(imm2)); shift_t = SRType_LSL; shift_n = Bits32 (opcode, 5, 4); + + // if Rt == '1111' then SEE PLD; + if (t == 15) + return false; // PLD is not implemented yet + + // if Rn == '1111' then SEE LDRB (literal); + if (n == 15) + return EmulateLDRBLiteral(opcode, eEncodingT1); // if t == 13 || BadReg(m) then UNPREDICTABLE; if ((t == 13) || BadReg (m)) @@ -9720,14 +9787,20 @@ break; case eEncodingT2: - // if Rd == ヤ1111ユ && S == ヤ1ユ then SEE CMP (register); - // if Rn == ヤ1101ユ then SEE SUB (SP minus register); - // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S == ヤ1ユ); + // d = UInt(Rd); n = UInt(Rn); m = UInt(Rm); setflags = (S =="1"); d = Bits32 (opcode, 11, 8); n = Bits32 (opcode, 19, 16); m = Bits32 (opcode, 3, 0); setflags = BitIsSet (opcode, 20); + + // if Rd == "1111" && S == "1" then SEE CMP (register); + if (d == 15 && setflags == 1) + return EmulateCMPImm (opcode, eEncodingT3); + // if Rn == "1101" then SEE SUB (SP minus register); + if (n == 13) + return EmulateSUBSPReg (opcode, eEncodingT1); + // (shift_t, shift_n) = DecodeImmShift(type, imm3:imm2); shift_n = DecodeImmShiftThumb (opcode, shift_t); @@ -12734,6 +12807,7 @@ { 0xffffffc0, 0x00004280, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp , "}, // cmp (register) (Rn and Rm not both from r0-r7) { 0xffffff00, 0x00004500, ARMvAll, eEncodingT2, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp , "}, + { 0xfff08f00, 0xebb00f00, ARMvAll, eEncodingT3, No_VFP, eSize16, &EmulateInstructionARM::EmulateCMPReg, "cmp.w , {, }"}, // asr (immediate) { 0xfffff800, 0x00001000, ARMvAll, eEncodingT1, No_VFP, eSize16, &EmulateInstructionARM::EmulateASRImm, "asrs|asr , , #imm"}, { 0xffef8030, 0xea4f0020, ARMV6T2_ABOVE, eEncodingT2, No_VFP, eSize32, &EmulateInstructionARM::EmulateASRImm, "asr{s}.w , , #imm"}, Index: source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp =================================================================== --- source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp +++ source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp @@ -106,18 +106,16 @@ *newrow = *last_row.get(); m_curr_row.reset(newrow); - // Once we've seen the initial prologue instructions complete, save a - // copy of the CFI at that point into prologue_completed_row for possible - // use later. - int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update - - bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI - - bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate - - bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet - - UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI + // Once we've seen the initial prologue instructions complete, + // save a copy of the CFI and the register values at that + // point into prologue_completed_row and into + // prologue_completed_register_values for possible use later. + int instructions_since_last_prologue_insn = 0; // # of insns since last CFI was update + bool reinstate_prologue_next_instruction = false; // Next iteration, re-install the prologue row of CFI + bool last_instruction_restored_return_addr_reg = false; // re-install the prologue row of CFI if the next instruction is a branch immediate + bool return_address_register_has_been_saved = false; // if we've seen the ra register get saved yet + UnwindPlan::RowSP prologue_completed_row; // copy of prologue row of CFI + RegisterValueMap prologue_completed_register_values; // copy of register values at the end of the prologue // cache the pc register number (in whatever register numbering this UnwindPlan uses) for // quick reference during instruction parsing. @@ -172,12 +170,17 @@ UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *prologue_completed_row.get(); m_curr_row.reset(newrow); - m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() - base_addr); + if (reinstate_prologue_next_instruction) + m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() - base_addr); + else + m_curr_row->SetOffset (inst->GetAddress().GetFileAddress() + inst->GetOpcode().GetByteSize() - base_addr); unwind_plan.AppendRow(m_curr_row); newrow = new UnwindPlan::Row; *newrow = *m_curr_row.get(); m_curr_row.reset(newrow); + m_register_values = prologue_completed_register_values; + reinstate_prologue_next_instruction = false; last_instruction_restored_return_addr_reg = false; @@ -261,6 +264,7 @@ UnwindPlan::Row *newrow = new UnwindPlan::Row; *newrow = *m_curr_row.get(); prologue_completed_row.reset(newrow); + prologue_completed_register_values = m_register_values; if (log && log->GetVerbose()) log->Printf("UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly -- saving a copy of the current row as the prologue row."); } @@ -681,7 +685,6 @@ break; case EmulateInstruction::eContextSetFramePointer: - if (!m_fp_is_cfa) { m_fp_is_cfa = true; m_cfa_reg_info = *reg_info;