From 252d6a385c78f8a827a55002cd03a00170ae4ae6 Mon Sep 17 00:00:00 2001 From: Jason Molenda Date: Sat, 9 Mar 2013 07:03:32 +0000 Subject: [PATCH] Remove use of the ARMDisassembler framework from DNBArchImplARM. This framework is no longer around; all armv7 devices support using hardware breakpoints to instruction single step. llvm-svn: 176761 --- .../debugserver/source/MacOSX/arm/DNBArchImpl.cpp | 1428 +------------------- .../debugserver/source/MacOSX/arm/DNBArchImpl.h | 3 - 2 files changed, 2 insertions(+), 1429 deletions(-) diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp index 2ae5dd78..a3a867b 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.cpp @@ -346,13 +346,6 @@ DNBArchMachARM::ThreadWillResume() DNBLogThreaded("DNBArchMachARM::ThreadWillResume() failed to enable hardware single step"); } } - else - { - if (SetSingleStepSoftwareBreakpoints() != KERN_SUCCESS) - { - DNBLogThreaded("DNBArchMachARM::ThreadWillResume() failed to enable software single step"); - } - } } // Disable the triggered watchpoint temporarily before we resume. @@ -469,13 +462,6 @@ DNBArchMachARM::ThreadDidStop() } m_sw_single_step_itblock_break_count = 0; -#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) - - // Decode instructions up to the current PC to ensure the internal decoder state is valid for the IT block - // The decoder has to decode each instruction in the IT block even if it is not executed so that - // the fields are correctly updated - DecodeITBlockInstructions(m_state.context.gpr.__pc); -#endif } } @@ -552,64 +538,6 @@ DNBArchMachARM::StepNotComplete () } -#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) - -void -DNBArchMachARM::DecodeITBlockInstructions(nub_addr_t curr_pc) - -{ - uint16_t opcode16; - uint32_t opcode32; - nub_addr_t next_pc_in_itblock; - nub_addr_t pc_in_itblock = m_last_decode_pc; - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc); - - // Decode IT block instruction from the instruction following the m_last_decoded_instruction at - // PC m_last_decode_pc upto and including the instruction at curr_pc - if (m_thread->Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2) - { - opcode32 = opcode16; - pc_in_itblock += 2; - // Check for 32 bit thumb opcode and read the upper 16 bits if needed - if (((opcode32 & 0xE000) == 0xE000) && opcode32 & 0x1800) - { - // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for - // a 32 bit Thumb opcode - // Read bits 31:16 of a 32 bit Thumb opcode - if (m_thread->Process()->Task().ReadMemory(pc_in_itblock, 2, &opcode16) == 2) - { - pc_in_itblock += 2; - // 32 bit thumb opcode - opcode32 = (opcode32 << 16) | opcode16; - } - else - { - DNBLogError("%s: Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8llx", __FUNCTION__, (uint64_t)pc_in_itblock); - } - } - } - else - { - DNBLogError("%s: Error reading 16-bit Thumb instruction at pc=0x%8.8x", __FUNCTION__, pc_in_itblock); - } - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: pc_in_itblock=0x%8.8x, curr_pc=0x%8.8x", __FUNCTION__, pc_in_itblock, curr_pc); - - next_pc_in_itblock = pc_in_itblock; - while (next_pc_in_itblock <= curr_pc) - { - arm_error_t decodeError; - - m_last_decode_pc = pc_in_itblock; - decodeError = DecodeInstructionUsingDisassembler(pc_in_itblock, m_state.context.gpr.__cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc_in_itblock); - - pc_in_itblock = next_pc_in_itblock; - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: next_pc_in_itblock=0x%8.8x", __FUNCTION__, next_pc_in_itblock); - } -} -#endif - // Set the single step bit in the processor status register. kern_return_t DNBArchMachARM::EnableHardwareSingleStep (bool enable) @@ -773,1157 +701,8 @@ DNBArchMachARM::ConditionPassed(uint8_t condition, uint32_t cpsr) return false; } -#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) - -bool -DNBArchMachARM::ComputeNextPC(nub_addr_t currentPC, arm_decoded_instruction_t decodedInstruction, bool currentPCIsThumb, nub_addr_t *targetPC) -{ - nub_addr_t myTargetPC, addressWherePCLives; - pid_t mypid; - - uint32_t cpsr_c = bit(m_state.context.gpr.__cpsr, 29); // Carry condition code flag - - uint32_t firstOperand=0, secondOperand=0, shiftAmount=0, secondOperandAfterShift=0, immediateValue=0; - uint32_t halfwords=0, baseAddress=0, immediateOffset=0, addressOffsetFromRegister=0, addressOffsetFromRegisterAfterShift; - uint32_t baseAddressIndex=INVALID_NUB_HW_INDEX; - uint32_t firstOperandIndex=INVALID_NUB_HW_INDEX; - uint32_t secondOperandIndex=INVALID_NUB_HW_INDEX; - uint32_t addressOffsetFromRegisterIndex=INVALID_NUB_HW_INDEX; - uint32_t shiftRegisterIndex=INVALID_NUB_HW_INDEX; - uint16_t registerList16, registerList16NoPC; - uint8_t registerList8; - uint32_t numRegistersToLoad=0; - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: instruction->code=%d", __FUNCTION__, decodedInstruction.instruction->code); - - // Get the following in this switch statement: - // - firstOperand, secondOperand, immediateValue, shiftAmount: For arithmetic, logical and move instructions - // - baseAddress, immediateOffset, shiftAmount: For LDR - // - numRegistersToLoad: For LDM and POP instructions - switch (decodedInstruction.instruction->code) - { - // Arithmetic operations that can change the PC - case ARM_INST_ADC: - case ARM_INST_ADCS: - case ARM_INST_ADD: - case ARM_INST_ADDS: - case ARM_INST_AND: - case ARM_INST_ANDS: - case ARM_INST_ASR: - case ARM_INST_ASRS: - case ARM_INST_BIC: - case ARM_INST_BICS: - case ARM_INST_EOR: - case ARM_INST_EORS: - case ARM_INST_ORR: - case ARM_INST_ORRS: - case ARM_INST_RSB: - case ARM_INST_RSBS: - case ARM_INST_RSC: - case ARM_INST_RSCS: - case ARM_INST_SBC: - case ARM_INST_SBCS: - case ARM_INST_SUB: - case ARM_INST_SUBS: - switch (decodedInstruction.addressMode) - { - case ARM_ADDR_DATA_IMM: - if (decodedInstruction.numOperands != 3) - { - DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get firstOperand register value (at index=1) - firstOperandIndex = decodedInstruction.op[1].value; // first operand register index - firstOperand = m_state.context.gpr.__r[firstOperandIndex]; - - // Get immediateValue (at index=2) - immediateValue = decodedInstruction.op[2].value; - - break; - - case ARM_ADDR_DATA_REG: - if (decodedInstruction.numOperands != 3) - { - DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get firstOperand register value (at index=1) - firstOperandIndex = decodedInstruction.op[1].value; // first operand register index - firstOperand = m_state.context.gpr.__r[firstOperandIndex]; - - // Get secondOperand register value (at index=2) - secondOperandIndex = decodedInstruction.op[2].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - break; - - case ARM_ADDR_DATA_SCALED_IMM: - if (decodedInstruction.numOperands != 4) - { - DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get firstOperand register value (at index=1) - firstOperandIndex = decodedInstruction.op[1].value; // first operand register index - firstOperand = m_state.context.gpr.__r[firstOperandIndex]; - - // Get secondOperand register value (at index=2) - secondOperandIndex = decodedInstruction.op[2].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - // Get shiftAmount as immediate value (at index=3) - shiftAmount = decodedInstruction.op[3].value; - - break; - - - case ARM_ADDR_DATA_SCALED_REG: - if (decodedInstruction.numOperands != 4) - { - DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get firstOperand register value (at index=1) - firstOperandIndex = decodedInstruction.op[1].value; // first operand register index - firstOperand = m_state.context.gpr.__r[firstOperandIndex]; - - // Get secondOperand register value (at index=2) - secondOperandIndex = decodedInstruction.op[2].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - // Get shiftAmount from register (at index=3) - shiftRegisterIndex = decodedInstruction.op[3].value; // second operand register index - shiftAmount = m_state.context.gpr.__r[shiftRegisterIndex]; - - break; - - case THUMB_ADDR_HR_HR: - if (decodedInstruction.numOperands != 2) - { - DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get firstOperand register value (at index=0) - firstOperandIndex = decodedInstruction.op[0].value; // first operand register index - firstOperand = m_state.context.gpr.__r[firstOperandIndex]; - - // Get secondOperand register value (at index=1) - secondOperandIndex = decodedInstruction.op[1].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - break; - - default: - break; - } - break; - - // Logical shifts and move operations that can change the PC - case ARM_INST_LSL: - case ARM_INST_LSLS: - case ARM_INST_LSR: - case ARM_INST_LSRS: - case ARM_INST_MOV: - case ARM_INST_MOVS: - case ARM_INST_MVN: - case ARM_INST_MVNS: - case ARM_INST_ROR: - case ARM_INST_RORS: - case ARM_INST_RRX: - case ARM_INST_RRXS: - // In these cases, the firstOperand is always 0, as if it does not exist - switch (decodedInstruction.addressMode) - { - case ARM_ADDR_DATA_IMM: - if (decodedInstruction.numOperands != 2) - { - DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get immediateValue (at index=1) - immediateValue = decodedInstruction.op[1].value; - - break; - - case ARM_ADDR_DATA_REG: - if (decodedInstruction.numOperands != 2) - { - DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get secondOperand register value (at index=1) - secondOperandIndex = decodedInstruction.op[1].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - break; - - case ARM_ADDR_DATA_SCALED_IMM: - if (decodedInstruction.numOperands != 3) - { - DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get secondOperand register value (at index=1) - secondOperandIndex = decodedInstruction.op[2].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - // Get shiftAmount as immediate value (at index=2) - shiftAmount = decodedInstruction.op[2].value; - - break; - - - case ARM_ADDR_DATA_SCALED_REG: - if (decodedInstruction.numOperands != 3) - { - DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get secondOperand register value (at index=1) - secondOperandIndex = decodedInstruction.op[1].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - // Get shiftAmount from register (at index=2) - shiftRegisterIndex = decodedInstruction.op[2].value; // second operand register index - shiftAmount = m_state.context.gpr.__r[shiftRegisterIndex]; - - break; - - case THUMB_ADDR_HR_HR: - if (decodedInstruction.numOperands != 2) - { - DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - if (decodedInstruction.op[0].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - - // Get secondOperand register value (at index=1) - secondOperandIndex = decodedInstruction.op[1].value; // second operand register index - secondOperand = m_state.context.gpr.__r[secondOperandIndex]; - - break; - - default: - break; - } - - break; - - // Simple branches, used to hop around within a routine - case ARM_INST_B: - *targetPC = decodedInstruction.targetPC; // Known targetPC - return true; - break; - - // Branch-and-link, used to call ARM subroutines - case ARM_INST_BL: - *targetPC = decodedInstruction.targetPC; // Known targetPC - return true; - break; - - // Branch-and-link with exchange, used to call opposite-mode subroutines - case ARM_INST_BLX: - if ((decodedInstruction.addressMode == ARM_ADDR_BRANCH_IMM) || - (decodedInstruction.addressMode == THUMB_ADDR_UNCOND)) - { - *targetPC = decodedInstruction.targetPC; // Known targetPC - return true; - } - else // addressMode == ARM_ADDR_BRANCH_REG - { - // Unknown target unless we're branching to the PC itself, - // although this may not work properly with BLX - if (decodedInstruction.op[REG_RD].value == PC_REG) - { - // this should (almost) never happen - *targetPC = decodedInstruction.targetPC; // Known targetPC - return true; - } - - // Get the branch address and return - if (decodedInstruction.numOperands != 1) - { - DNBLogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - // Get branch address in register (at index=0) - *targetPC = m_state.context.gpr.__r[decodedInstruction.op[0].value]; - return true; - } - break; - - // Branch with exchange, used to hop to opposite-mode code - // Branch to Jazelle code, used to execute Java; included here since it - // acts just like BX unless the Jazelle unit is active and JPC is - // already loaded into it. - case ARM_INST_BX: - case ARM_INST_BXJ: - // Unknown target unless we're branching to the PC itself, - // although this can never switch to Thumb mode and is - // therefore pretty much useless - if (decodedInstruction.op[REG_RD].value == PC_REG) - { - // this should (almost) never happen - *targetPC = decodedInstruction.targetPC; // Known targetPC - return true; - } - - // Get the branch address and return - if (decodedInstruction.numOperands != 1) - { - DNBLogError("Expected 1 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - // Get branch address in register (at index=0) - *targetPC = m_state.context.gpr.__r[decodedInstruction.op[0].value]; - return true; - break; - - // Compare and branch on zero/non-zero (Thumb-16 only) - // Unusual condition check built into the instruction - case ARM_INST_CBZ: - case ARM_INST_CBNZ: - // Branch address is known at compile time - // Get the branch address and return - if (decodedInstruction.numOperands != 2) - { - DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - // Get branch address as an immediate value (at index=1) - *targetPC = decodedInstruction.op[1].value; - return true; - break; - - // Load register can be used to load PC, usually with a function pointer - case ARM_INST_LDR: - if (decodedInstruction.op[REG_RD].value != PC_REG) - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - switch (decodedInstruction.addressMode) - { - case ARM_ADDR_LSWUB_IMM: - case ARM_ADDR_LSWUB_IMM_PRE: - case ARM_ADDR_LSWUB_IMM_POST: - if (decodedInstruction.numOperands != 3) - { - DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - // Get baseAddress from register (at index=1) - baseAddressIndex = decodedInstruction.op[1].value; - baseAddress = m_state.context.gpr.__r[baseAddressIndex]; - - // Get immediateOffset (at index=2) - immediateOffset = decodedInstruction.op[2].value; - break; - - case ARM_ADDR_LSWUB_REG: - case ARM_ADDR_LSWUB_REG_PRE: - case ARM_ADDR_LSWUB_REG_POST: - if (decodedInstruction.numOperands != 3) - { - DNBLogError("Expected 3 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - // Get baseAddress from register (at index=1) - baseAddressIndex = decodedInstruction.op[1].value; - baseAddress = m_state.context.gpr.__r[baseAddressIndex]; - - // Get immediateOffset from register (at index=2) - addressOffsetFromRegisterIndex = decodedInstruction.op[2].value; - addressOffsetFromRegister = m_state.context.gpr.__r[addressOffsetFromRegisterIndex]; - - break; - - case ARM_ADDR_LSWUB_SCALED: - case ARM_ADDR_LSWUB_SCALED_PRE: - case ARM_ADDR_LSWUB_SCALED_POST: - if (decodedInstruction.numOperands != 4) - { - DNBLogError("Expected 4 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - // Get baseAddress from register (at index=1) - baseAddressIndex = decodedInstruction.op[1].value; - baseAddress = m_state.context.gpr.__r[baseAddressIndex]; - - // Get immediateOffset from register (at index=2) - addressOffsetFromRegisterIndex = decodedInstruction.op[2].value; - addressOffsetFromRegister = m_state.context.gpr.__r[addressOffsetFromRegisterIndex]; - - // Get shiftAmount (at index=3) - shiftAmount = decodedInstruction.op[3].value; - - break; - - default: - break; - } - break; - - // 32b load multiple operations can load the PC along with everything else, - // usually to return from a function call - case ARM_INST_LDMDA: - case ARM_INST_LDMDB: - case ARM_INST_LDMIA: - case ARM_INST_LDMIB: - if (decodedInstruction.op[LDM_REGLIST].value & PC_REGLIST_BIT) - { - if (decodedInstruction.numOperands != 2) - { - DNBLogError("Expected 2 operands in decoded instruction structure. numOperands is %d!", decodedInstruction.numOperands); - return false; - } - - // Get baseAddress from register (at index=0) - baseAddressIndex = decodedInstruction.op[0].value; - baseAddress = m_state.context.gpr.__r[baseAddressIndex]; - - // Get registerList from register (at index=1) - registerList16 = (uint16_t)decodedInstruction.op[1].value; - - // Count number of registers to load in the multiple register list excluding the PC - registerList16NoPC = registerList16&0x3FFF; // exclude the PC - numRegistersToLoad=0; - for (int i = 0; i < 16; i++) - { - if (registerList16NoPC & 0x1) numRegistersToLoad++; - registerList16NoPC = registerList16NoPC >> 1; - } - } - else - { - DNBLogError("Destination register is not a PC! %s routine should be called on on instructions that modify the PC. Destination register is R%d!", __FUNCTION__, decodedInstruction.op[0].value); - return false; - } - break; - - // Normal 16-bit LD multiple can't touch R15, but POP can - case ARM_INST_POP: // Can also get the PC & updates SP - // Get baseAddress from SP (at index=0) - baseAddress = m_state.context.gpr.__sp; - - if (decodedInstruction.thumb16b) - { - // Get registerList from register (at index=0) - registerList8 = (uint8_t)decodedInstruction.op[0].value; - - // Count number of registers to load in the multiple register list - numRegistersToLoad=0; - for (int i = 0; i < 8; i++) - { - if (registerList8 & 0x1) numRegistersToLoad++; - registerList8 = registerList8 >> 1; - } - } - else - { - // Get registerList from register (at index=0) - registerList16 = (uint16_t)decodedInstruction.op[0].value; - - // Count number of registers to load in the multiple register list excluding the PC - registerList16NoPC = registerList16&0x3FFF; // exclude the PC - numRegistersToLoad=0; - for (int i = 0; i < 16; i++) - { - if (registerList16NoPC & 0x1) numRegistersToLoad++; - registerList16NoPC = registerList16NoPC >> 1; - } - } - break; - - // 16b TBB and TBH instructions load a jump address from a table - case ARM_INST_TBB: - case ARM_INST_TBH: - // Get baseAddress from register (at index=0) - baseAddressIndex = decodedInstruction.op[0].value; - baseAddress = m_state.context.gpr.__r[baseAddressIndex]; - - // Get immediateOffset from register (at index=1) - addressOffsetFromRegisterIndex = decodedInstruction.op[1].value; - addressOffsetFromRegister = m_state.context.gpr.__r[addressOffsetFromRegisterIndex]; - break; - - // ThumbEE branch-to-handler instructions: Jump to handlers at some offset - // from a special base pointer register (which is unknown at disassembly time) - case ARM_INST_HB: - case ARM_INST_HBP: -// TODO: ARM_INST_HB, ARM_INST_HBP - break; - - case ARM_INST_HBL: - case ARM_INST_HBLP: -// TODO: ARM_INST_HBL, ARM_INST_HBLP - break; - - // Breakpoint and software interrupt jump to interrupt handler (always ARM) - case ARM_INST_BKPT: - case ARM_INST_SMC: - case ARM_INST_SVC: - - // Return from exception, obviously modifies PC [interrupt only!] - case ARM_INST_RFEDA: - case ARM_INST_RFEDB: - case ARM_INST_RFEIA: - case ARM_INST_RFEIB: - - // Other instructions either can't change R15 or are "undefined" if you do, - // so no sane compiler should ever generate them & we don't care here. - // Also, R15 can only legally be used in a read-only manner for the - // various ARM addressing mode (to get PC-relative addressing of constants), - // but can NOT be used with any of the update modes. - default: - DNBLogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code); - return false; - break; - } - - // Adjust PC if PC is one of the input operands - if (baseAddressIndex == PC_REG) - { - if (currentPCIsThumb) - baseAddress += 4; - else - baseAddress += 8; - } - - if (firstOperandIndex == PC_REG) - { - if (currentPCIsThumb) - firstOperand += 4; - else - firstOperand += 8; - } - - if (secondOperandIndex == PC_REG) - { - if (currentPCIsThumb) - secondOperand += 4; - else - secondOperand += 8; - } - - if (addressOffsetFromRegisterIndex == PC_REG) - { - if (currentPCIsThumb) - addressOffsetFromRegister += 4; - else - addressOffsetFromRegister += 8; - } - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, - "%s: firstOperand=%8.8x, secondOperand=%8.8x, immediateValue = %d, shiftAmount = %d, baseAddress = %8.8x, addressOffsetFromRegister = %8.8x, immediateOffset = %d, numRegistersToLoad = %d", - __FUNCTION__, - firstOperand, - secondOperand, - immediateValue, - shiftAmount, - baseAddress, - addressOffsetFromRegister, - immediateOffset, - numRegistersToLoad); - - - // Calculate following values after applying shiftAmount: - // - immediateOffsetAfterShift, secondOperandAfterShift - - switch (decodedInstruction.scaleMode) - { - case ARM_SCALE_NONE: - addressOffsetFromRegisterAfterShift = addressOffsetFromRegister; - secondOperandAfterShift = secondOperand; - break; - - case ARM_SCALE_LSL: // Logical shift left - addressOffsetFromRegisterAfterShift = addressOffsetFromRegister << shiftAmount; - secondOperandAfterShift = secondOperand << shiftAmount; - break; - - case ARM_SCALE_LSR: // Logical shift right - addressOffsetFromRegisterAfterShift = addressOffsetFromRegister >> shiftAmount; - secondOperandAfterShift = secondOperand >> shiftAmount; - break; - - case ARM_SCALE_ASR: // Arithmetic shift right - asm("mov %0, %1, asr %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount)); - asm("mov %0, %1, asr %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount)); - break; - - case ARM_SCALE_ROR: // Rotate right - asm("mov %0, %1, ror %2" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister), "r" (shiftAmount)); - asm("mov %0, %1, ror %2" : "=r" (secondOperandAfterShift) : "r" (secondOperand), "r" (shiftAmount)); - break; - - case ARM_SCALE_RRX: // Rotate right, pulling in carry (1-bit shift only) - asm("mov %0, %1, rrx" : "=r" (addressOffsetFromRegisterAfterShift) : "r" (addressOffsetFromRegister)); - asm("mov %0, %1, rrx" : "=r" (secondOperandAfterShift) : "r" (secondOperand)); - break; - } - - // Emulate instruction to calculate targetPC - // All branches are already handled in the first switch statement. A branch should not reach this switch - switch (decodedInstruction.instruction->code) - { - // Arithmetic operations that can change the PC - case ARM_INST_ADC: - case ARM_INST_ADCS: - // Add with Carry - *targetPC = firstOperand + (secondOperandAfterShift + immediateValue) + cpsr_c; - break; - - case ARM_INST_ADD: - case ARM_INST_ADDS: - *targetPC = firstOperand + (secondOperandAfterShift + immediateValue); - break; - - case ARM_INST_AND: - case ARM_INST_ANDS: - *targetPC = firstOperand & (secondOperandAfterShift + immediateValue); - break; - - case ARM_INST_ASR: - case ARM_INST_ASRS: - asm("mov %0, %1, asr %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue)); - *targetPC = myTargetPC; - break; - - case ARM_INST_BIC: - case ARM_INST_BICS: - asm("bic %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue)); - *targetPC = myTargetPC; - break; - - case ARM_INST_EOR: - case ARM_INST_EORS: - asm("eor %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue)); - *targetPC = myTargetPC; - break; - - case ARM_INST_ORR: - case ARM_INST_ORRS: - asm("orr %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue)); - *targetPC = myTargetPC; - break; - - case ARM_INST_RSB: - case ARM_INST_RSBS: - asm("rsb %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue)); - *targetPC = myTargetPC; - break; - - case ARM_INST_RSC: - case ARM_INST_RSCS: - myTargetPC = secondOperandAfterShift - (firstOperand + !cpsr_c); - *targetPC = myTargetPC; - break; - - case ARM_INST_SBC: - case ARM_INST_SBCS: - asm("sbc %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue + !cpsr_c)); - *targetPC = myTargetPC; - break; - - case ARM_INST_SUB: - case ARM_INST_SUBS: - asm("sub %0, %1, %2" : "=r" (myTargetPC) : "r" (firstOperand), "r" (secondOperandAfterShift + immediateValue)); - *targetPC = myTargetPC; - break; - - // Logical shifts and move operations that can change the PC - case ARM_INST_LSL: - case ARM_INST_LSLS: - case ARM_INST_LSR: - case ARM_INST_LSRS: - case ARM_INST_MOV: - case ARM_INST_MOVS: - case ARM_INST_ROR: - case ARM_INST_RORS: - case ARM_INST_RRX: - case ARM_INST_RRXS: - myTargetPC = secondOperandAfterShift + immediateValue; - *targetPC = myTargetPC; - break; - - case ARM_INST_MVN: - case ARM_INST_MVNS: - myTargetPC = !(secondOperandAfterShift + immediateValue); - *targetPC = myTargetPC; - break; - - // Load register can be used to load PC, usually with a function pointer - case ARM_INST_LDR: - switch (decodedInstruction.addressMode) { - case ARM_ADDR_LSWUB_IMM_POST: - case ARM_ADDR_LSWUB_REG_POST: - case ARM_ADDR_LSWUB_SCALED_POST: - addressWherePCLives = baseAddress; - break; - - case ARM_ADDR_LSWUB_IMM: - case ARM_ADDR_LSWUB_REG: - case ARM_ADDR_LSWUB_SCALED: - case ARM_ADDR_LSWUB_IMM_PRE: - case ARM_ADDR_LSWUB_REG_PRE: - case ARM_ADDR_LSWUB_SCALED_PRE: - addressWherePCLives = baseAddress + (addressOffsetFromRegisterAfterShift + immediateOffset); - break; - - default: - break; - } - - mypid = m_thread->ProcessID(); - if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t)) - { - DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives); - return false; - } - - *targetPC = myTargetPC; - break; - - // 32b load multiple operations can load the PC along with everything else, - // usually to return from a function call - case ARM_INST_LDMDA: - mypid = m_thread->ProcessID(); - addressWherePCLives = baseAddress; - if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t)) - { - DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives); - return false; - } - - *targetPC = myTargetPC; - break; - - case ARM_INST_LDMDB: - mypid = m_thread->ProcessID(); - addressWherePCLives = baseAddress - 4; - if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t)) - { - DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives); - return false; - } - - *targetPC = myTargetPC; - break; - - case ARM_INST_LDMIB: - mypid = m_thread->ProcessID(); - addressWherePCLives = baseAddress + numRegistersToLoad*4 + 4; - if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t)) - { - DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives); - return false; - } - - *targetPC = myTargetPC; - break; - - case ARM_INST_LDMIA: // same as pop - // Normal 16-bit LD multiple can't touch R15, but POP can - case ARM_INST_POP: // Can also get the PC & updates SP - mypid = m_thread->ProcessID(); - addressWherePCLives = baseAddress + numRegistersToLoad*4; - if (DNBProcessMemoryRead(mypid, addressWherePCLives, sizeof(nub_addr_t), &myTargetPC) != sizeof(nub_addr_t)) - { - DNBLogError("Could not read memory at %8.8x to get targetPC when processing the pop instruction!", addressWherePCLives); - return false; - } - - *targetPC = myTargetPC; - break; - - // 16b TBB and TBH instructions load a jump address from a table - case ARM_INST_TBB: - mypid = m_thread->ProcessID(); - addressWherePCLives = baseAddress + addressOffsetFromRegisterAfterShift; - if (DNBProcessMemoryRead(mypid, addressWherePCLives, 1, &halfwords) != 1) - { - DNBLogError("Could not read memory at %8.8x to get targetPC when processing the TBB instruction!", addressWherePCLives); - return false; - } - // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords - *targetPC = (currentPC + 4) + 2*halfwords; - break; - - case ARM_INST_TBH: - mypid = m_thread->ProcessID(); - addressWherePCLives = ((baseAddress + (addressOffsetFromRegisterAfterShift << 1)) & ~0x1); - if (DNBProcessMemoryRead(mypid, addressWherePCLives, 2, &halfwords) != 2) - { - DNBLogError("Could not read memory at %8.8x to get targetPC when processing the TBH instruction!", addressWherePCLives); - return false; - } - // add 4 to currentPC since we are in Thumb mode and then add 2*halfwords - *targetPC = (currentPC + 4) + 2*halfwords; - break; - - // ThumbEE branch-to-handler instructions: Jump to handlers at some offset - // from a special base pointer register (which is unknown at disassembly time) - case ARM_INST_HB: - case ARM_INST_HBP: - // TODO: ARM_INST_HB, ARM_INST_HBP - break; - - case ARM_INST_HBL: - case ARM_INST_HBLP: - // TODO: ARM_INST_HBL, ARM_INST_HBLP - break; - - // Breakpoint and software interrupt jump to interrupt handler (always ARM) - case ARM_INST_BKPT: - case ARM_INST_SMC: - case ARM_INST_SVC: - // TODO: ARM_INST_BKPT, ARM_INST_SMC, ARM_INST_SVC - break; - - // Return from exception, obviously modifies PC [interrupt only!] - case ARM_INST_RFEDA: - case ARM_INST_RFEDB: - case ARM_INST_RFEIA: - case ARM_INST_RFEIB: - // TODO: ARM_INST_RFEDA, ARM_INST_RFEDB, ARM_INST_RFEIA, ARM_INST_RFEIB - break; - - // Other instructions either can't change R15 or are "undefined" if you do, - // so no sane compiler should ever generate them & we don't care here. - // Also, R15 can only legally be used in a read-only manner for the - // various ARM addressing mode (to get PC-relative addressing of constants), - // but can NOT be used with any of the update modes. - default: - DNBLogError("%s should not be called for instruction code %d!", __FUNCTION__, decodedInstruction.instruction->code); - return false; - break; - } - - return true; -} - -void -DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup(nub_addr_t currentPC, uint32_t cpsr, bool currentPCIsThumb, nub_addr_t *nextPC, bool *nextPCIsThumb) -{ - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "DNBArchMachARM::EvaluateNextInstructionForSoftwareBreakpointSetup() called"); - - nub_addr_t targetPC = INVALID_NUB_ADDRESS; - uint32_t registerValue; - arm_error_t decodeError; - nub_addr_t currentPCInITBlock, nextPCInITBlock; - int i; - bool last_decoded_instruction_executes = true; - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: default nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM"); - - // Update *nextPC and *nextPCIsThumb for special cases - if (m_last_decode_thumb.itBlockRemaining) // we are in an IT block - { - // Set the nextPC to the PC of the instruction which will execute in the IT block - // If none of the instruction execute in the IT block based on the condition flags, - // then point to the instruction immediately following the IT block - const int itBlockRemaining = m_last_decode_thumb.itBlockRemaining; - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: itBlockRemaining=%8.8x", __FUNCTION__, itBlockRemaining); - - // Determine the PC at which the next instruction resides - if (m_last_decode_arm.thumb16b) - currentPCInITBlock = currentPC + 2; - else - currentPCInITBlock = currentPC + 4; - - for (i = 0; i < itBlockRemaining; i++) - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: currentPCInITBlock=%8.8x", __FUNCTION__, currentPCInITBlock); - decodeError = DecodeInstructionUsingDisassembler(currentPCInITBlock, cpsr, &m_last_decode_arm, &m_last_decode_thumb, &nextPCInITBlock); - - if (decodeError != ARM_SUCCESS) - DNBLogError("unable to disassemble instruction at 0x%8.8llx", (uint64_t)currentPCInITBlock); - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: condition=%d", __FUNCTION__, m_last_decode_arm.condition); - if (ConditionPassed(m_last_decode_arm.condition, cpsr)) - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition codes matched for instruction %d", __FUNCTION__, i); - break; // break from the for loop - } - else - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition codes DID NOT matched for instruction %d", __FUNCTION__, i); - } - - // update currentPC and nextPCInITBlock - currentPCInITBlock = nextPCInITBlock; - } - - if (i == itBlockRemaining) // We came out of the IT block without executing any instructions - last_decoded_instruction_executes = false; - - *nextPC = currentPCInITBlock; - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: After IT block step-through: *nextPC=%8.8x", __FUNCTION__, *nextPC); - } - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, - "%s: cpsr = %8.8x, thumb16b = %d, thumb = %d, branch = %d, conditional = %d, knownTarget = %d, links = %d, canSwitchMode = %d, doesSwitchMode = %d", - __FUNCTION__, - cpsr, - m_last_decode_arm.thumb16b, - m_last_decode_arm.thumb, - m_last_decode_arm.branch, - m_last_decode_arm.conditional, - m_last_decode_arm.knownTarget, - m_last_decode_arm.links, - m_last_decode_arm.canSwitchMode, - m_last_decode_arm.doesSwitchMode); - - - if (last_decoded_instruction_executes && // Was this a conditional instruction that did execute? - m_last_decode_arm.branch && // Can this instruction change the PC? - (m_last_decode_arm.instruction->code != ARM_INST_SVC)) // If this instruction is not an SVC instruction - { - // Set targetPC. Compute if needed. - if (m_last_decode_arm.knownTarget) - { - // Fixed, known PC-relative - targetPC = m_last_decode_arm.targetPC; - } - else - { - // if targetPC is not known at compile time (PC-relative target), compute targetPC - if (!ComputeNextPC(currentPC, m_last_decode_arm, currentPCIsThumb, &targetPC)) - { - DNBLogError("%s: Unable to compute targetPC for instruction at 0x%8.8llx", __FUNCTION__, (uint64_t)currentPC); - targetPC = INVALID_NUB_ADDRESS; - } - } - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: targetPC=0x%8.8x, cpsr=0x%8.8x, condition=0x%hhx", __FUNCTION__, targetPC, cpsr, m_last_decode_arm.condition); - - // Refine nextPC computation - if ((m_last_decode_arm.instruction->code == ARM_INST_CBZ) || - (m_last_decode_arm.instruction->code == ARM_INST_CBNZ)) - { - // Compare and branch on zero/non-zero (Thumb-16 only) - // Unusual condition check built into the instruction - registerValue = m_state.context.gpr.__r[m_last_decode_arm.op[REG_RD].value]; - - if (m_last_decode_arm.instruction->code == ARM_INST_CBZ) - { - if (registerValue == 0) - *nextPC = targetPC; - } - else - { - if (registerValue != 0) - *nextPC = targetPC; - } - } - else if (m_last_decode_arm.conditional) // Is the change conditional on flag results? - { - if (ConditionPassed(m_last_decode_arm.condition, cpsr)) // conditions match - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition matched!", __FUNCTION__); - *nextPC = targetPC; - } - else - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Condition did not match!", __FUNCTION__); - } - } - else - { - *nextPC = targetPC; - } - - // Refine nextPCIsThumb computation - if (m_last_decode_arm.doesSwitchMode) - { - *nextPCIsThumb = !currentPCIsThumb; - } - else if (m_last_decode_arm.canSwitchMode) - { - // Legal to switch ARM <--> Thumb mode with this branch - // dependent on bit[0] of targetPC - *nextPCIsThumb = (*nextPC & 1u) != 0; - } - else - { - *nextPCIsThumb = currentPCIsThumb; - } - } - - DNBLogThreadedIf(LOG_STEP, "%s: calculated nextPC=0x%8.8x (%s)", __FUNCTION__, *nextPC, *nextPCIsThumb ? "Thumb" : "ARM"); -} - - -arm_error_t -DNBArchMachARM::DecodeInstructionUsingDisassembler(nub_addr_t curr_pc, uint32_t curr_cpsr, arm_decoded_instruction_t *decodedInstruction, thumb_static_data_t *thumbStaticData, nub_addr_t *next_pc) -{ - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: pc=0x%8.8x, cpsr=0x%8.8x", __FUNCTION__, curr_pc, curr_cpsr); - - const uint32_t isetstate_mask = MASK_CPSR_T | MASK_CPSR_J; - const uint32_t curr_isetstate = curr_cpsr & isetstate_mask; - uint32_t opcode32; - nub_addr_t nextPC = curr_pc; - arm_error_t decodeReturnCode = ARM_SUCCESS; - - m_last_decode_pc = curr_pc; - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: last_decode_pc=0x%8.8x", __FUNCTION__, m_last_decode_pc); - - switch (curr_isetstate) { - case 0x0: // ARM Instruction - // Read the ARM opcode - if (m_thread->Process()->Task().ReadMemory(curr_pc, 4, &opcode32) != 4) - { - DNBLogError("unable to read opcode bits 31:0 for an ARM opcode at 0x%8.8llx", (uint64_t)curr_pc); - decodeReturnCode = ARM_ERROR; - } - else - { - nextPC += 4; - decodeReturnCode = ArmDisassembler((uint64_t)curr_pc, opcode32, false, decodedInstruction, NULL, 0, NULL, 0); - - if (decodeReturnCode != ARM_SUCCESS) - DNBLogError("Unable to decode ARM instruction 0x%8.8x at 0x%8.8llx", opcode32, (uint64_t)curr_pc); - } - break; - - case 0x20: // Thumb Instruction - uint16_t opcode16; - // Read the a 16 bit Thumb opcode - if (m_thread->Process()->Task().ReadMemory(curr_pc, 2, &opcode16) != 2) - { - DNBLogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8llx", (uint64_t)curr_pc); - decodeReturnCode = ARM_ERROR; - } - else - { - nextPC += 2; - opcode32 = opcode16; - - decodeReturnCode = ThumbDisassembler((uint64_t)curr_pc, opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0); - - switch (decodeReturnCode) { - case ARM_SKIP: - // 32 bit thumb opcode - nextPC += 2; - if (m_thread->Process()->Task().ReadMemory(curr_pc+2, 2, &opcode16) != 2) - { - DNBLogError("unable to read opcode bits 15:0 for a thumb opcode at 0x%8.8llx", (uint64_t)curr_pc+2); - } - else - { - opcode32 = (opcode32 << 16) | opcode16; - - decodeReturnCode = ThumbDisassembler((uint64_t)(curr_pc+2), opcode16, false, false, thumbStaticData, decodedInstruction, NULL, 0, NULL, 0); - - if (decodeReturnCode != ARM_SUCCESS) - DNBLogError("Unable to decode 2nd half of Thumb instruction 0x%8.4hx at 0x%8.8llx", opcode16, (uint64_t)curr_pc+2); - break; - } - break; - - case ARM_SUCCESS: - // 16 bit thumb opcode; at this point we are done decoding the opcode - break; - - default: - DNBLogError("Unable to decode Thumb instruction 0x%8.4hx at 0x%8.8llx", opcode16, (uint64_t)curr_pc); - decodeReturnCode = ARM_ERROR; - break; - } - } - break; - - default: - break; - } - - if (next_pc) - *next_pc = nextPC; - - return decodeReturnCode; -} - -#endif - -nub_bool_t -DNBArchMachARM::BreakpointHit (nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton) +nub_bool_t +DNBArchMachARM::BreakpointHit (nub_process_t pid, nub_thread_t tid, nub_break_t breakID, void *baton) { nub_addr_t bkpt_pc = (nub_addr_t)baton; DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s(pid = %i, tid = %4.4x, breakID = %u, baton = %p): Setting PC to 0x%8.8x", __FUNCTION__, pid, tid, breakID, baton, bkpt_pc); @@ -1934,209 +713,6 @@ DNBArchMachARM::BreakpointHit (nub_process_t pid, nub_thread_t tid, nub_break_t return DNBThreadSetRegisterValueByID (pid, tid, REGISTER_SET_GENERIC, GENERIC_REGNUM_PC, &pc_value); } -// Set the single step bit in the processor status register. -kern_return_t -DNBArchMachARM::SetSingleStepSoftwareBreakpoints() -{ - DNBError err; - -#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) - err = GetGPRState(false); - - if (err.Fail()) - { - err.LogThreaded("%s: failed to read the GPR registers", __FUNCTION__); - return err.Error(); - } - - nub_addr_t curr_pc = m_state.context.gpr.__pc; - uint32_t curr_cpsr = m_state.context.gpr.__cpsr; - nub_addr_t next_pc = curr_pc; - - bool curr_pc_is_thumb = (m_state.context.gpr.__cpsr & 0x20) != 0; - bool next_pc_is_thumb = curr_pc_is_thumb; - - uint32_t curr_itstate = ((curr_cpsr & 0x6000000) >> 25) | ((curr_cpsr & 0xFC00) >> 8); - bool inITBlock = (curr_itstate & 0xF) ? 1 : 0; - bool lastInITBlock = ((curr_itstate & 0xF) == 0x8) ? 1 : 0; - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: curr_pc=0x%8.8x (%s), curr_itstate=0x%x, inITBlock=%d, lastInITBlock=%d", __FUNCTION__, curr_pc, curr_pc_is_thumb ? "Thumb" : "ARM", curr_itstate, inITBlock, lastInITBlock); - - // If the instruction is not in the IT block, then decode using the Disassembler and compute next_pc - if (!inITBlock) - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Decoding an instruction NOT in the IT block", __FUNCTION__); - - arm_error_t decodeReturnCode = DecodeInstructionUsingDisassembler(curr_pc, curr_cpsr, &m_last_decode_arm, &m_last_decode_thumb, &next_pc); - - if (decodeReturnCode != ARM_SUCCESS) - { - err = KERN_INVALID_ARGUMENT; - DNBLogError("DNBArchMachARM::SetSingleStepSoftwareBreakpoints: Unable to disassemble instruction at 0x%8.8llx", (uint64_t)curr_pc); - } - } - else - { - next_pc = curr_pc + ((m_last_decode_arm.thumb16b) ? 2 : 4); - } - - // Instruction is NOT in the IT block OR - if (!inITBlock) - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: normal instruction", __FUNCTION__); - EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.context.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb); - } - else if (inITBlock && !m_last_decode_arm.setsFlags) - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: IT instruction that doesn't set flags", __FUNCTION__); - EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.context.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb); - } - else if (lastInITBlock && m_last_decode_arm.branch) - { - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: IT instruction which last in the IT block and is a branch", __FUNCTION__); - EvaluateNextInstructionForSoftwareBreakpointSetup(curr_pc, m_state.context.gpr.__cpsr, curr_pc_is_thumb, &next_pc, &next_pc_is_thumb); - } - else - { - // Instruction is in IT block and can modify the CPSR flags - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: IT instruction that sets flags", __FUNCTION__); - - // NOTE: When this point of code is reached, the instruction at curr_pc has already been decoded - // inside the function ThreadDidStop(). Therefore m_last_decode_arm, m_last_decode_thumb - // reflect the decoded instruction at curr_pc - - // If we find an instruction inside the IT block which will set/modify the condition flags (NZCV bits in CPSR), - // we set breakpoints at all remaining instructions inside the IT block starting from the instruction immediately - // following this one AND a breakpoint at the instruction immediately following the IT block. We do this because - // we cannot determine the next_pc until the instruction at which we are currently stopped executes. Hence we - // insert (m_last_decode_thumb.itBlockRemaining+1) 16-bit Thumb breakpoints at consecutive memory locations - // starting at addrOfNextInstructionInITBlock. We record these breakpoints in class variable m_sw_single_step_itblock_break_id[], - // and also record the total number of IT breakpoints set in the variable 'm_sw_single_step_itblock_break_count'. - - // The instructions inside the IT block, which are replaced by the 16-bit Thumb breakpoints (opcode=0xDEFE) - // instructions, can be either Thumb-16 or Thumb-32. When a Thumb-32 instruction (say, inst#1) is replaced Thumb - // by a 16-bit breakpoint (OS only supports 16-bit breakpoints in Thumb mode and 32-bit breakpoints in ARM mode), the - // breakpoint for the next instruction (say instr#2) is saved in the upper half of this Thumb-32 (instr#1) - // instruction. Hence if the execution stops at Breakpoint2 corresponding to instr#2, the PC is offset by 16-bits. - // We therefore have to keep track of PC of each instruction in the IT block that is being replaced with the 16-bit - // Thumb breakpoint, to ensure that when the breakpoint is hit, the PC is adjusted to the correct value. We save - // the actual PC corresponding to each instruction in the IT block by associating a call back with each breakpoint - // we set and passing it as a baton. When the breakpoint hits and the callback routine is called, the routine - // adjusts the PC based on the baton that is passed to it. - - nub_addr_t addrOfNextInstructionInITBlock, pcInITBlock, nextPCInITBlock, bpAddressInITBlock; - uint16_t opcode16; - uint32_t opcode32; - - addrOfNextInstructionInITBlock = (m_last_decode_arm.thumb16b) ? curr_pc + 2 : curr_pc + 4; - - pcInITBlock = addrOfNextInstructionInITBlock; - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: itBlockRemaining=%d", __FUNCTION__, m_last_decode_thumb.itBlockRemaining); - - m_sw_single_step_itblock_break_count = 0; - for (int i = 0; i <= m_last_decode_thumb.itBlockRemaining; i++) - { - if (NUB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i])) - { - DNBLogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Array m_sw_single_step_itblock_break_id should not contain any valid breakpoint IDs at this point. But found a valid breakID=%d at index=%d", m_sw_single_step_itblock_break_id[i], i); - } - else - { - nextPCInITBlock = pcInITBlock; - // Compute nextPCInITBlock based on opcode present at pcInITBlock - if (m_thread->Process()->Task().ReadMemory(pcInITBlock, 2, &opcode16) == 2) - { - opcode32 = opcode16; - nextPCInITBlock += 2; - - // Check for 32 bit thumb opcode and read the upper 16 bits if needed - if (((opcode32 & 0xE000) == 0xE000) && (opcode32 & 0x1800)) - { - // Adjust 'next_pc_in_itblock' to point to the default next Thumb instruction for - // a 32 bit Thumb opcode - // Read bits 31:16 of a 32 bit Thumb opcode - if (m_thread->Process()->Task().ReadMemory(pcInITBlock+2, 2, &opcode16) == 2) - { - // 32 bit thumb opcode - opcode32 = (opcode32 << 16) | opcode16; - nextPCInITBlock += 2; - } - else - { - DNBLogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Unable to read opcode bits 31:16 for a 32 bit thumb opcode at pc=0x%8.8llx", (uint64_t)nextPCInITBlock); - } - } - } - else - { - DNBLogError("FunctionProfiler::SetSingleStepSoftwareBreakpoints(): Error reading 16-bit Thumb instruction at pc=0x%8.8x", nextPCInITBlock); - } - - - // Set breakpoint and associate a callback function with it - bpAddressInITBlock = addrOfNextInstructionInITBlock + 2*i; - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Setting IT breakpoint[%d] at address: 0x%8.8x", __FUNCTION__, i, bpAddressInITBlock); - - m_sw_single_step_itblock_break_id[i] = m_thread->Process()->CreateBreakpoint(bpAddressInITBlock, 2, false, m_thread->ThreadID()); - if (!NUB_BREAK_ID_IS_VALID(m_sw_single_step_itblock_break_id[i])) - err = KERN_INVALID_ARGUMENT; - else - { - DNBLogThreadedIf(LOG_STEP, "%s: Set IT breakpoint[%i]=%d set at 0x%8.8x for instruction at 0x%8.8x", __FUNCTION__, i, m_sw_single_step_itblock_break_id[i], bpAddressInITBlock, pcInITBlock); - - // Set the breakpoint callback for these special IT breakpoints - // so that if one of these breakpoints gets hit, it knows to - // update the PC to the original address of the conditional - // IT instruction. - DNBBreakpointSetCallback(m_thread->ProcessID(), m_sw_single_step_itblock_break_id[i], DNBArchMachARM::BreakpointHit, (void*)pcInITBlock); - m_sw_single_step_itblock_break_count++; - } - } - - pcInITBlock = nextPCInITBlock; - } - - DNBLogThreadedIf(LOG_STEP | LOG_VERBOSE, "%s: Set %u IT software single breakpoints.", __FUNCTION__, m_sw_single_step_itblock_break_count); - - } - - DNBLogThreadedIf(LOG_STEP, "%s: next_pc=0x%8.8x (%s)", __FUNCTION__, next_pc, next_pc_is_thumb ? "Thumb" : "ARM"); - - if (next_pc & 0x1) - { - assert(next_pc_is_thumb); - } - - if (next_pc_is_thumb) - { - next_pc &= ~0x1; - } - else - { - assert((next_pc & 0x3) == 0); - } - - if (!inITBlock || (inITBlock && !m_last_decode_arm.setsFlags) || (lastInITBlock && m_last_decode_arm.branch)) - { - err = KERN_SUCCESS; - - const DNBBreakpoint *bp = m_thread->Process()->Breakpoints().FindByAddress(next_pc); - - if (bp == NULL) - { - m_sw_single_step_break_id = m_thread->Process()->CreateBreakpoint(next_pc, next_pc_is_thumb ? 2 : 4, false, m_thread->ThreadID()); - if (!NUB_BREAK_ID_IS_VALID(m_sw_single_step_break_id)) - err = KERN_INVALID_ARGUMENT; - DNBLogThreadedIf(LOG_STEP, "%s: software single step breakpoint with breakID=%d set at 0x%8.8x", __FUNCTION__, m_sw_single_step_break_id, next_pc); - } - } -#else - err.LogThreaded("%s: ARMDisassembler.framework support is disabled", __FUNCTION__); -#endif - return err.Error(); -} - uint32_t DNBArchMachARM::NumSupportedHardwareBreakpoints() { diff --git a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h index 3fac4d9..39f5088 100644 --- a/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h +++ b/lldb/tools/debugserver/source/MacOSX/arm/DNBArchImpl.h @@ -17,9 +17,6 @@ #if defined (__arm__) #include "DNBArch.h" -#if defined (USE_ARM_DISASSEMBLER_FRAMEWORK) -#include -#endif class MachThread; -- 2.7.4