From c086800e5819beece1f6fe357f53db20b6e0f6ee Mon Sep 17 00:00:00 2001 From: Lars Rademacher Date: Thu, 7 Nov 2013 13:42:05 +0100 Subject: [PATCH] openocd: added opcode parser Added opcode parser of the F.E.H.L.E.R-project for analysis of memory access in mmu-abort handling, tracing, etc. Change-Id: I5912fa4a4d51ee0501817c43bae05e87ac0e9b90 --- cmake/panda.cmake | 13 +- .../openocd/opcode_parser/arm-addressmode.c | 509 ++++++++++++++++++ .../openocd/opcode_parser/arm-condition.c | 82 +++ .../opcode_parser/arm-opcode-coprocessor.c | 142 +++++ .../openocd/opcode_parser/arm-opcode-data.c | 481 +++++++++++++++++ .../opcode_parser/arm-opcode-ldmstm-branch.c | 135 +++++ .../openocd/opcode_parser/arm-opcode-ldrstr.c | 373 +++++++++++++ debuggers/openocd/opcode_parser/arm-opcode.c | 111 ++++ debuggers/openocd/opcode_parser/arm-opcode.h | 120 +++++ debuggers/openocd/opcode_parser/arm_opcodes.h | 274 ++++++++++ debuggers/openocd/openocd_wrapper.cc | 246 ++++++--- 11 files changed, 2422 insertions(+), 64 deletions(-) create mode 100644 debuggers/openocd/opcode_parser/arm-addressmode.c create mode 100644 debuggers/openocd/opcode_parser/arm-condition.c create mode 100644 debuggers/openocd/opcode_parser/arm-opcode-coprocessor.c create mode 100644 debuggers/openocd/opcode_parser/arm-opcode-data.c create mode 100644 debuggers/openocd/opcode_parser/arm-opcode-ldmstm-branch.c create mode 100644 debuggers/openocd/opcode_parser/arm-opcode-ldrstr.c create mode 100644 debuggers/openocd/opcode_parser/arm-opcode.c create mode 100644 debuggers/openocd/opcode_parser/arm-opcode.h create mode 100644 debuggers/openocd/opcode_parser/arm_opcodes.h diff --git a/cmake/panda.cmake b/cmake/panda.cmake index 959b56b5..6fa24780 100644 --- a/cmake/panda.cmake +++ b/cmake/panda.cmake @@ -28,7 +28,18 @@ if(BUILD_PANDA) #include_directories(${PROJECT_SOURCE_DIR}/src/core ${CMAKE_BINARY_DIR}/src/core) # an executable needs at least one source file, so we hand over an empty .cc file to make cmake happy. - add_executable(fail-client ${openocd_src_dir}/openocd_wrapper.cc) + set(srces ${openocd_src_dir}/openocd_wrapper.cc) + + set (srces ${srces} + ${openocd_src_dir}/opcode_parser/arm-addressmode.c + ${openocd_src_dir}/opcode_parser/arm-condition.c + ${openocd_src_dir}/opcode_parser/arm-opcode-coprocessor.c + ${openocd_src_dir}/opcode_parser/arm-opcode-data.c + ${openocd_src_dir}/opcode_parser/arm-opcode-ldmstm-branch.c + ${openocd_src_dir}/opcode_parser/arm-opcode-ldrstr.c + ${openocd_src_dir}/opcode_parser/arm-opcode.c) + + add_executable(fail-client ${srces}) target_link_libraries(fail-client ${openocd_src_dir}/src/.libs/libopenocd.a ${openocd_src_dir}/jimtcl/libjim.a fail ${openocd_library_dependencies}) add_dependencies(fail-client libfailopenocd_external) diff --git a/debuggers/openocd/opcode_parser/arm-addressmode.c b/debuggers/openocd/opcode_parser/arm-addressmode.c new file mode 100644 index 00000000..8697ac70 --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-addressmode.c @@ -0,0 +1,509 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#include +#include "arm-opcode.h" + +/** + * @brief Parse addressing mode 1 - Data-processing operands + */ +uint32_t decode_addressing_mode1(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* possible registers */ + // uint32_t rn = (inst >> 16) & 0xF; + // uint32_t rd = (inst >> 12) & 0xF; + uint32_t rs = (inst >> 8) & 0xF; + uint32_t rm = (inst) & 0xF; + + if(I_SET) + { + /* Immediate */ + uint32_t immed_8 = inst & 0xFF; + uint32_t rotate_imm = ((inst & 0xF00) >> 8) * 2; + uint32_t immediate = (immed_8 >> rotate_imm) | (immed_8 << (32 - rotate_imm)); + OP_PRINTF("#%d", (int)immediate) + return immediate; + } + + if((inst & 0x0E000FF0) == 0x00000000) + { + /* Register */ + arm_op_add_reg_r(op, rm); + OP_PRINTF("R%d", (int)rm) + return op->regs->r[rm]; + } + if((inst & 0x0E000070) == 0x00000000) + { + /* Logical shift left by immediate */ + arm_op_add_reg_r(op, rm); + uint32_t shift_imm = (inst >> 7) & 0x1F; + uint32_t shifter_operand = op->regs->r[rm]; + if(rm == 15) + shifter_operand += 8; + shifter_operand <<= shift_imm; + OP_PRINTF("R%d, LSL #%d [Operand2: %d]", (int)rm, (int) shift_imm, (int)shifter_operand) + return shifter_operand; + } + if((inst & 0x0E0000F0) == 0x00000010) + { + /* Logical shift left by register */ + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rs); + uint32_t shift_reg = op->regs->r[rs]; + uint32_t shifter_operand = op->regs->r[rm]; + + if(shift_reg != 0) + { + if(shift_reg < 32) + { + shifter_operand <<= (shift_reg & 0xFF); + } + else + { + shifter_operand = 0; + } + } + + OP_PRINTF("R%d, LSL R%d [Operand2: %d]", (int)rm, (int)rs, (int)shifter_operand) + return shifter_operand; + } + if((inst & 0x0E000070) == 0x00000020) + { + /* Logical shift right by immediate */ + arm_op_add_reg_r(op, rm); + uint32_t shift_imm = (inst >> 7) & 0x1F; + uint32_t shifter_operand = op->regs->r[rm]; + if(rm == 15) + shifter_operand += 8; + if(shift_imm == 0) + { + shifter_operand = 0; + shift_imm = 32; + } + else + shifter_operand >>= shift_imm; + OP_PRINTF("R%d, LSR #%d [Operand2: %d]", (int)rm, (int) shift_imm, (int)shifter_operand) + return shifter_operand; + } + if((inst & 0x0E0000F0) == 0x00000030) + { + /* Logical shift right by register */ + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rs); + uint32_t shift_reg = op->regs->r[rs]; + uint32_t shifter_operand = op->regs->r[rm]; + + if(shift_reg != 0) + { + if(shift_reg < 32) + { + shifter_operand >>= (shift_reg & 0xFF); + } + else + { + shifter_operand = 0; + } + } + + OP_PRINTF("R%d, LSL R%d [Operand2: %d]", (int)rm, (int)rs, (int)shifter_operand) + return shifter_operand; + } + if((inst & 0x0E000070) == 0x00000040) + { + /* Arithmetic shift right by immediate */ + arm_op_add_reg_r(op, rm); + uint32_t shift_imm = (inst >> 7) & 0x1F; + uint32_t shifter_operand = op->regs->r[rm]; + if(rm == 15) + shifter_operand += 8; + if(shift_imm == 0) + { + if(shifter_operand & 0x80000000) + shifter_operand = 0xFFFFFFFF; + else + shifter_operand = 0; + shift_imm = 32; + } + else + shifter_operand = (uint32_t)((int32_t)shifter_operand >> (int32_t)shift_imm); + OP_PRINTF("R%d, ASR #%d [Operand2: %d]", (int)rm, (int) shift_imm, (int)shifter_operand) + return shifter_operand; + } + if((inst & 0x0E0000F0) == 0x00000050) + { + /* Arithmetic shift right by register */ + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rs); + uint32_t shift_reg = op->regs->r[rs]; + uint32_t shifter_operand = op->regs->r[rm]; + + if(shift_reg != 0) + { + if(shift_reg < 32) + { + shifter_operand = (uint32_t)((int32_t)shifter_operand >> (int32_t)(shift_reg & 0xFF)); + } + else + { + if(shifter_operand & 0x80000000) + shifter_operand = 0xFFFFFFFF; + else + shifter_operand = 0; + } + } + + OP_PRINTF("R%d, ASR R%d [Operand2: %d]", (int)rm, (int)rs, (int)shifter_operand) + return shifter_operand; + } + if((inst & 0x0E000070) == 0x00000060) + { + /* Rotate right by immediate */ + arm_op_add_reg_r(op, rm); + uint32_t shift_imm = (inst >> 7) & 0x1F; + uint32_t shifter_operand = op->regs->r[rm]; + if(rm == 15) + shifter_operand += 8; + if(shift_imm == 0) + { + shifter_operand >>= 1; + if((op->regs->cpsr) & (1 << 29)) + shifter_operand |= 0x80000000; + shift_imm = 32; + OP_PRINTF("R%d, RRX #%d [Operand2: %d]", (int)rm, (int) shift_imm, (int)shifter_operand) + } + else + { + shifter_operand >>= shift_imm; + OP_PRINTF("R%d, ROR #%d [Operand2: %d]", (int)rm, (int) shift_imm, (int)shifter_operand) + } + return shifter_operand; + } + if((inst & 0x0E0000F0) == 0x00000070) + { + /* Rotate right by register */ + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rs); + uint32_t shift_reg = op->regs->r[rs]; + uint32_t shifter_operand = op->regs->r[rm]; + + if(shift_reg != 0) + { + if(shift_reg < 32) + { + shifter_operand = (shifter_operand >> shift_reg) | (shifter_operand << (32 - shift_reg)); + } + else + { + shifter_operand = 0; + } + } + + OP_PRINTF("R%d, ROR R%d [Operand2: %d]", (int)rm, (int)rs, (int)shifter_operand) + return shifter_operand; + } + printf("Cannot determine Operand2!"); + return 0; +} + +/** + * @brief Parse addressing mode 2 - Load and Store Word or Unsigned Byte + */ +void decode_addressing_mode2(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* possible registers */ + uint32_t rn = (inst >> 16) & 0xF; + // uint32_t rd = (inst >> 12) & 0xF; + uint32_t rm = (inst) & 0xF; + + arm_op_add_reg_r(op, rn); + + char U = U_SET ? '+' : '-'; + + uint32_t index; + + if(!I_SET) + { + index = inst & 0xFFF; + if(!U_SET) + index *= -1; + + if(!P_SET) + { + /* post-indexed addressing */ + op->mem_addr = op->regs->r[rn]; + OP_PRINTF("[R%d], #%d", (int)rn, (int)index) + } + else if(W_SET) + { + /* pre-indexed addressing */ + op->mem_addr = op->regs->r[rn] + index; + OP_PRINTF("[R%d, #%d]!", (int)rn, (int)index) + + } + else + { + /* offset addressing */ + op->mem_addr = op->regs->r[rn] + index; + OP_PRINTF("[R%d, #%d]", (int)rn, (int)index) + } + OP_PRINTF(" [Address: %08x]", (unsigned int)op->mem_addr) + return; + } + else + { + arm_op_add_reg_r(op, rm); + + if((inst & 0x00000FF0) == 0) + { + index = op->regs->r[rm]; + if(!U_SET) + index *= -1; + if(!P_SET) + { + /* post-indexed addressing */ + op->mem_addr = op->regs->r[rn]; + OP_PRINTF("[R%d], #%cR%d", (int)rn, U, (int)rm) + } + else if(W_SET) + { + /* pre-indexed addressing */ + op->mem_addr = op->regs->r[rn] + index; + OP_PRINTF("[R%d, #%cR%d]!", (int)rn, U, (int)rm) + + } + else + { + /* offset addressing */ + op->mem_addr = op->regs->r[rn] + index; + OP_PRINTF("[R%d, #%cR%d]", (int)rn, U, (int)rm) + } + if(rn == 15) + op->mem_addr += 8; + OP_PRINTF(" [Address: %08x]", (unsigned int)op->mem_addr) + return; + } + else + { + uint32_t shift = (inst >> 7) & 0x1F; + uint32_t type = (inst >> 5) & 0x03; + uint32_t rm_val = op->regs->r[rm]; + + if(!P_SET) + { + /* post-indexed addressing */ + OP_PRINTF("[R%d], #%cR%d, ", (int)rn, U, (int)rm) + } + else + { + /* pre-indexed addressing, or + * offset addressing */ + OP_PRINTF("[R%d, #%cR%d, ", (int)rn, U, (int)rm) + + } + + switch(type) + { + case 0: /* LSL */ + index = rm_val << shift; + OP_PRINTF("LSL #%d", (int)shift) + break; + case 1: /* LSR */ + if(shift == 0) + index = 0; + else + index = rm_val >> shift; + OP_PRINTF("LSR #%d", (int)shift) + break; + case 2: /* ASR */ + if(shift == 0) + { + if(rm_val & 0x80000000) + index = 0xFFFFFFFF; + else + index = 0; + } + else + index = (uint32_t)(((int32_t)rm_val) >> (int32_t)shift); + OP_PRINTF("ASR #%d", (int)shift) + break; + case 3: /* ROR */ + default: + + if(shift == 0) /* RRX */ + { + index = ((op->regs->cpsr & (1 << 29)) << 31) | (rm_val > 1); + OP_PRINTF("RRX") + } + else + { + index = (rm_val >> shift) | (rm_val << (32 - shift)); + OP_PRINTF("ROR #%d", (int)shift) + } + break; + } + + if(!U_SET) + index *= -1; + + if(!P_SET) + { + /* post-indexed addressing */ + op->mem_addr = op->regs->r[rn]; + } + else if(W_SET) + { + /* pre-indexed addressing */ + op->mem_addr = op->regs->r[rn] + index; + OP_PRINTF("]!") + arm_op_add_reg_w(op, rn); + } + else + { + /* offset addressing */ + op->mem_addr = op->regs->r[rn] + index; + OP_PRINTF("]") + } + if(rn == 15) + op->mem_addr += 8; + OP_PRINTF(" [Address: %08x]", (unsigned int)op->mem_addr) + return; + } + } + + printf("Cannot determine Operand2!"); + return; +} + +/** + * @brief Parse addressing mode 3 - Miscellaneous Loads and Stores + */ +void decode_addressing_mode3(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* possible registers */ + uint32_t rn = (inst >> 16) & 0xF; + uint32_t rm = (inst) & 0xF; + + arm_op_add_reg_r(op, rn); + if(W_SET) + arm_op_add_reg_w(op, rm); + OP_PRINTF("[R%d", (int)rn) + + uint32_t index; + if(BIT_IS_SET(22)) + { + index = ((inst & 0xF00) >> 4) | (inst & 0xF); + } + else + { + arm_op_add_reg_r(op, rm); + index = op->regs->r[rm]; + } + char U; + if(U_SET) + { + U = '+'; + } + else + { + U = '-'; + index *= -1; + } + + if(!P_SET) + { + /* post-indexed addressing */ + op->mem_addr = op->regs->r[rn]; + if(BIT_IS_SET(22)) + { + OP_PRINTF("[R%d], #%d", (int)rn, (int)index) + } + else + { + OP_PRINTF("[R%d], %cR%d", (int)rn, U, (int)rm) + } + } + else if(W_SET) + { + /* pre-indexed addressing */ + op->mem_addr = op->regs->r[rn] + index; + if(BIT_IS_SET(22)) + { + OP_PRINTF("[R%d, #%d]!", (int)rn, (int)index) + } + else + { + OP_PRINTF("[R%d, %cR%d]!", (int)rn, U, (int)rm) + } + } + else + { + /* offset addressing */ + op->mem_addr = op->regs->r[rn] + index; + if(BIT_IS_SET(22)) + { + OP_PRINTF("[R%d, #%d]", (int)rn, (int)index) + } + else + { + OP_PRINTF("[R%d, %cR%d]", (int)rn, U, (int)rm) + } + } + OP_PRINTF(" [Address: %08x]", (unsigned int)op->mem_addr) +} + +/** + * @brief Parse addressing mode 5 - Load and Store Coprocessor + */ +void decode_addressing_mode5(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* possible registers */ + uint32_t rn = (inst >> 16) & 0xF; + uint32_t offset_8 = (inst & 0xF) * 4; + + if(!U_SET) + offset_8 *= -1; + + arm_op_add_reg_r(op, rn); + if(W_SET) + arm_op_add_reg_w(op, rn); + + OP_PRINTF("[R%d", (int)rn) + + if(P_SET && BIT_IS_CLEAR(21)) + { + /* Immediate offset */ + OP_PRINTF(", #%d]", (int)offset_8) + } + else if(P_SET && W_SET) + { + /* Immediate pre-indexed */ + OP_PRINTF(", #%d]!",(int) offset_8) + } + else if(BIT_IS_CLEAR(24) && W_SET) + { + /* Immediate post-indexed */ + OP_PRINTF("] , #%d", (int)offset_8) + } + else + { + /* Unindexed */ + OP_PRINTF("] , %d", (int)(inst & 0xF)) + } +} diff --git a/debuggers/openocd/opcode_parser/arm-condition.c b/debuggers/openocd/opcode_parser/arm-condition.c new file mode 100644 index 00000000..f7819ef7 --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-condition.c @@ -0,0 +1,82 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#include +#include "arm-opcode.h" + +typedef enum {C_EQ = 0x0, C_NE = 0x1, C_CS = 0x2, C_CC = 0x3, + C_MI = 0x4, C_PL = 0x5, C_VS = 0x6, C_VC = 0x7, + C_HI = 0x8, C_LS = 0x9, C_GE = 0xA, C_LT = 0xB, + C_GT = 0xC, C_LE = 0xD, C_AL = 0xE, C_NV = 0xF +}condition_t; + +#define V_FLAG 0x10000000 +#define C_FLAG 0x20000000 +#define Z_FLAG 0x40000000 +#define N_FLAG 0x80000000 + +#define CZ_FLAGS 0x60000000 +#define NV_FLAGS 0x90000000 + +uint32_t op_cond_test(uint32_t inst, uint32_t cpsr) +{ + condition_t cond = (condition_t) (inst >> 28); + switch (cond) + { + case C_EQ: + return ( (cpsr & Z_FLAG)); + case C_NE: + return (!(cpsr & Z_FLAG)); + case C_CS: + return ( (cpsr & C_FLAG)); + case C_CC: + return (!(cpsr & C_FLAG)); + case C_MI: + return ( (cpsr & N_FLAG)); + case C_PL: + return (!(cpsr & N_FLAG)); + case C_VS: + return ( (cpsr & V_FLAG)); + case C_VC: + return (!(cpsr & V_FLAG)); + + case C_HI: + return ((cpsr & CZ_FLAGS) == C_FLAG); + case C_LS: + return ((cpsr & C_FLAG) == 0) || + ((cpsr & Z_FLAG) == Z_FLAG); + case C_GE: + return (((cpsr & NV_FLAGS) == 0) || + ((cpsr & NV_FLAGS) == NV_FLAGS)); + case C_LT: + return (((cpsr & NV_FLAGS) == V_FLAG) || + ((cpsr & NV_FLAGS) == N_FLAG)); + case C_GT: + return (((cpsr & Z_FLAG) == 0) && + (((cpsr & NV_FLAGS) == NV_FLAGS) || + ((cpsr & NV_FLAGS) == 0))); + case C_LE: + return (((cpsr & Z_FLAG) == Z_FLAG) || + (((cpsr & NV_FLAGS) == V_FLAG) || + ((cpsr & NV_FLAGS) == N_FLAG))); + case C_AL: + return 1; + case C_NV: + default: + return 0xFFFFFFFF; + } + return 0; +} diff --git a/debuggers/openocd/opcode_parser/arm-opcode-coprocessor.c b/debuggers/openocd/opcode_parser/arm-opcode-coprocessor.c new file mode 100644 index 00000000..46e17aaa --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-opcode-coprocessor.c @@ -0,0 +1,142 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#include +#include "arm-opcode.h" + +#define SVC_INSTRUCTION_MASK 0x0F000000 +#define SVC_INSTRUCTION_SIG 0x0F000000 + +#define BKPT_INSTRUCTION_MASK 0x0FF000F0 +#define BKPT_INSTRUCTION_SIG 0x01200070 + +#define MRR_INSTRUCTIONS_MASK 0x0FE00000 +#define MRR_INSTRUCTIONS_SIG 0x0C400000 + +#define MR_INSTRUCTIONS_MASK 0x0F000010 +#define MR_INSTRUCTIONS_SIG 0x0E000010 + +#define CDP_INSTRUCTION_MASK 0x0F000010 +#define CDP_INSTRUCTION_SIG 0x0E000000 + +int decode_coprocessor(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* possible registers */ + uint32_t rn = (inst >> 16) & 0xF; + uint32_t rd = (inst >> 12) & 0xF; + uint32_t crm = (inst) & 0xF; + uint32_t cp_num = (inst >> 8) & 0xF; + + /* + * Software interrupt ? + */ + + if((inst & SVC_INSTRUCTION_MASK) == SVC_INSTRUCTION_SIG) + { + OP_PRINTF("SVC\t%d\n", (int)(inst & 0x00FFFFFF)) + return 0; + } + + /* + * Break point ? + */ + + if((inst & BKPT_INSTRUCTION_MASK) == BKPT_INSTRUCTION_SIG) + { + OP_PRINTF("BKPT\t%d\n", (int)(((inst & 0x000FFF00) >> 8) | (inst & 0xF))) + return 0; + } + + /* + * MCRR / MRRC ? + */ + + if((inst & MRR_INSTRUCTIONS_MASK) == MRR_INSTRUCTIONS_SIG) + { + if(_L_SET) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_w(op, rn); + OP_PRINTF("MRRC") + } + else + { + arm_op_add_reg_r(op, rd); + arm_op_add_reg_r(op, rn); + OP_PRINTF("MCRR") + } + + OP_PRINTF("\tp%d, %d, R%d, R%d, CR%d\n", (int)cp_num, (int)((inst >> 4) & 0xF), (int)rd, (int)rn, (int)crm) + return 0; + } + + + /* + * MCR / MRC ? + */ + + if((inst & MR_INSTRUCTIONS_MASK) == MR_INSTRUCTIONS_SIG) + { + + if(_L_SET) + { + arm_op_add_reg_w(op, rd); + OP_PRINTF("MRC") + } + else + { + arm_op_add_reg_r(op, rd); + OP_PRINTF("MCR") + } + + OP_PRINTF("\tp%d, %d, R%d, CR%d, CR%d, {%d}\n", (int)cp_num, (int)((inst >> 21) & 0x7), (int)rd, (int)rn, (int)crm, (int)((inst >> 5) & 0x7)) + return 0; + } + + /* + * CDP ? + */ + + if((inst & CDP_INSTRUCTION_MASK) == CDP_INSTRUCTION_SIG) + { + OP_PRINTF("CDP\tp%d, %d, CR%d, CR%d, CR%d, {%d}\n", (int)cp_num, (int)((inst >> 20) & 0xF), (int)rd, (int)rn, (int)crm, (int)((inst >> 5) & 0x7)) + return 0; + } + + /* + * LDC / STC ? + */ + + if(BIT_IS_CLEAR(25)) + { + if(_L_SET) + OP_PRINTF("LDC") + else + OP_PRINTF("STC") + + if(BIT_IS_SET(22)) + OP_PRINTF("L") + OP_PRINTF("\tp%d, CR%d, ", (int)cp_num, (int)rd) + decode_addressing_mode5(op); + OP_PRINTF("\n") + return 0; + } + + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; +} + diff --git a/debuggers/openocd/opcode_parser/arm-opcode-data.c b/debuggers/openocd/opcode_parser/arm-opcode-data.c new file mode 100644 index 00000000..dd967e78 --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-opcode-data.c @@ -0,0 +1,481 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#include +#include "arm-opcode.h" + +#define UNDEF_INSTRUCTION_MASK 0x0FB00000 +#define UNDEF_INSTRUCTION_SIG 0x03000000 + +#define MISC_INSTRUCTION_1_MASK 0x0F900010 +#define MISC_INSTRUCTION_1_SIG 0x01000000 + +#define MISC_INSTRUCTION_2_MASK 0x0F900090 +#define MISC_INSTRUCTION_2_SIG 0x01000010 + +#define MSR_IMM_INSTRUCTION_MASK 0x0FB00000 +#define MSR_IMM_INSTRUCTION_SIG 0x03200000 + +#define MUL_OR_EXTRA_LDSTR_INSTRUCTION_MASK 0x0E000090 +#define MUL_OR_EXTRA_LDSTR_INSTRUCTION_SIG 0x00000090 + +#define OP_AND 0 +#define OP_EOR 1 +#define OP_SUB 2 +#define OP_RSB 3 +#define OP_ADD 4 +#define OP_ADC 5 +#define OP_SBC 6 +#define OP_RSC 7 + +#define OP_TST 8 +#define OP_TEQ 9 +#define OP_CMP 10 +#define OP_CMN 11 +#define OP_ORR 12 +#define OP_MOV 13 +#define OP_BIC 14 +#define OP_MVN 15 + +static const char * alu_op_str[16] = { + "AND", + "EOR", + "SUB", + "RSB", + "ADD", + "ADC", + "SBC", + "RSC", + "TST", + "TEQ", + "CMP", + "CMN", + "ORR", + "MOV", + "BIC", + "MVN" +}; + +int decode_data_processing(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* possible registers */ + uint32_t rn = (inst >> 16) & 0xF; + uint32_t rd = (inst >> 12) & 0xF; + uint32_t rs = (inst >> 8) & 0xF; + uint32_t rm = (inst) & 0xF; + + /* + * Undefined instruction ? + */ + + if((inst & UNDEF_INSTRUCTION_MASK) == UNDEF_INSTRUCTION_SIG) + { + OP_PRINTF("Undefined Instruction\n") + return 0; + } + + /* + * Miscellaneous instructions ? + */ + + if((inst & MISC_INSTRUCTION_1_MASK) == MISC_INSTRUCTION_1_SIG || + (inst & MISC_INSTRUCTION_2_MASK) == MISC_INSTRUCTION_2_SIG) + { + uint32_t op1 = (inst >> 21) & 3; + uint32_t op2 = (inst >> 4) & 0xf; + + if(op2 == 0) + { + if(op1 & 1) + { + OP_PRINTF("MSR\t") + if(op1 & 2) + OP_PRINTF("SPSR, ") + else + OP_PRINTF("CPSR, ") + OP_PRINTF("R%d\n", (int)rm) + arm_op_add_reg_r(op, rm); + return 0; + } + else + { + OP_PRINTF("MRS\tR%d, ", (int)rd) + if(op1 & 2) + OP_PRINTF("SPSR\n") + else + OP_PRINTF("CPSR\n") + arm_op_add_reg_w(op, rd); + return 0; + } + } + if(op2 == 1) + { + if(op1 == 1) + { + OP_PRINTF("BX\tR%d\n", (int)rm) + arm_op_add_reg_r(op, rm); + return 0; + } + else if(op1 == 3) + { + OP_PRINTF("CLZ\tR%d, R%d\n", (int)rd, (int)rm) + arm_op_add_reg_r(op, rm); + arm_op_add_reg_w(op, rd); + return 0; + } + else + { + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + } + if(op2 == 2) + { + if(op1 == 1) + { + OP_PRINTF("BXJ\tR%d\n", (int)rm) + arm_op_add_reg_r(op, rm); + return 0; + } + else + { + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + } + if(op2 == 3) + { + if(op1 == 1) + { + OP_PRINTF("BLX\tR%d\n", (int)rm) + arm_op_add_reg_r(op, rm); + return 0; + } + else + { + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + } + if(op2 == 5) + { + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_w(op, rd); + + switch(op1) + { + case 0: + OP_PRINTF("QADD\tR%d, R%d, R%d\n", (int)rd, (int)rm, (int)rn) + return 0; + case 1: + OP_PRINTF("QSUB\tR%d, R%d, R%d\n", (int)rd, (int)rm, (int)rn) + return 0; + case 2: + OP_PRINTF("QDADD\tR%d, R%d, R%d\n", (int)rd, (int)rm, (int)rn) + return 0; + case 3: + default: + OP_PRINTF("QDSUB\tR%d, R%d, R%d\n", (int)rd, (int)rm, (int)rn) + return 0; + } + } + if(op2 == 7) + { + if(op1 == 1) + { + OP_PRINTF("BKPT\n") + return 0; + } + else + { + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + } + if((op2 & 9) == 8) + { + char x = BIT_IS_SET(5) ? 'T' : 'B'; + char y = BIT_IS_SET(6) ? 'T' : 'B'; + + arm_op_add_reg_w(op, rd); + switch(op1) + { + case 0: + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + OP_PRINTF("SMLA%c%c\tR%d, R%d, R%d, R%d\n", x, y, (int)rd, (int)rn, (int)rm, (int)rs) + return 0; + case 1: + if(x == 'B') + { + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + OP_PRINTF("SMLAW%c\tR%d, R%d, R%d, R%d\n", y, (int)rd, (int)rm, (int)rs, (int)rn) + return 0; + } + else + { + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rs); + OP_PRINTF("SMULW%c\tR%d, R%d, R%d\n", y, (int)rd, (int)rm, (int)rs) + return 0; + } + case 2: + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + OP_PRINTF("SMLAL%c%c\tR%d, R%d, R%d, R%d\n", x, y, (int)rd, (int)rn, (int)rm, (int)rs) + return 0; + case 3: + default: + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rs); + OP_PRINTF("SMLAL%c%c\tR%d, R%d, R%d\n", x, y, (int)rd, (int)rm, (int)rs) + return 0; + } + } + + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + + /* + * MSR with immediate ? + */ + + if((inst & MSR_IMM_INSTRUCTION_MASK) == MSR_IMM_INSTRUCTION_SIG) + { + OP_PRINTF("MSR\t") + if(BIT_IS_SET(22)) + OP_PRINTF("SPSR, immediate\n") + else + OP_PRINTF("CPSR, immediate\n") + return 0; + } + + /* + * Multiplies or extra stores ? + */ + if((inst & MUL_OR_EXTRA_LDSTR_INSTRUCTION_MASK) == MUL_OR_EXTRA_LDSTR_INSTRUCTION_SIG) + { + uint32_t op1 = (inst >> 20) & 0x1F; + uint32_t op2 = (inst >> 5) & 3; + + if(op2 == 0) + { + /* Multiply instructions */ + if((op1 & 0x1C) == 0) + { + arm_op_add_reg_w(op, rd); + if(op1 & 2) + { + OP_PRINTF("MLA") + if(op1 & 1) + OP_PRINTF("S") + OP_PRINTF("\tR%d, R%d, R%d, R%d\n", (int)rd, (int)rm, (int)rs, (int)rn) + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + return 0; + } + else + { + OP_PRINTF("MUL") + if(op1 & 1) + OP_PRINTF("S") + OP_PRINTF("\tR%d, R%d, R%d\n", (int)rd, (int)rm, (int)rs) + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rs); + return 0; + } + } + if((op1 & 0x1F) == 4) + { + OP_PRINTF("UMAAL\tR%d, R%d, R%d, R%d\n", (int)rd, (int)rn, (int)rm, (int)rs) + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + return 0; + + } + if((op1 & 0x18) == 8) + { + if(op1 & 4) + OP_PRINTF("S") + else + OP_PRINTF("U") + if(op1 & 2) + OP_PRINTF("MLAL") + else + OP_PRINTF("MULL") + if(op1 & 1) + OP_PRINTF("S") + + OP_PRINTF("\tR%d, R%d, R%d, R%d\n", (int)rd, (int)rn, (int)rm, (int)rs) + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + return 0; + } + + /* Load store */ + if((op1 & 0x1B) == 0x10) + { + OP_PRINTF("SWP") + if(op1 & 4) + { + OP_PRINTF("B") + op->mem_size = 1; + } + else + op->mem_size = 4; + op->mem_addr = op->regs->r[rn]; + op->flags = OP_FLAG_READ | OP_FLAG_WRITE; + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + arm_op_add_reg_r(op, rn); + OP_PRINTF("\tR%d, R%d, R%d [Addr: %08x]\n", (int)rd, (int)rm, (int)rn, (unsigned int)op->mem_addr) + return 0; + } + if((op1 & 0x1E) == 0x18) + { + op->mem_size = 4; + op->mem_addr = op->regs->r[rn]; + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rn); + if(op1 & 1) + { + OP_PRINTF("LDREX") + op->flags = OP_FLAG_READ; + } + else + { + OP_PRINTF("STREX") + op->flags = OP_FLAG_WRITE; + } + OP_PRINTF("\tR%d, R%d [Addr: %08x]\n", (int)rd, (int)rn, (unsigned int)op->mem_addr) + return 0; + } + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + if(op2 == 1) + { + if(op1 & 1) + { + OP_PRINTF("LDRH\tR%d, ", (int)rd) + op->flags = OP_FLAG_READ; + } + else + { + OP_PRINTF("STRH\tR%d, ", (int)rd) + op->flags = OP_FLAG_WRITE; + } + op->mem_size = 2; + arm_op_add_reg_w(op, rd); + decode_addressing_mode3(op); + OP_PRINTF("\n") + return 0; + + } + + if(op2 & 2) + { + if(op1 & 1) + { + if(op2 & 1) + { + op->mem_size = 2; + OP_PRINTF("LDRSH\tR%d, ", (int)rd) + } + else + { + op->mem_size = 1; + OP_PRINTF("LDRSB\tR%d, ", (int)rd) + } + op->flags = OP_FLAG_READ; + arm_op_add_reg_w(op, rd); + decode_addressing_mode3(op); + OP_PRINTF("\n") + return 0; + } + else + { + if(op2 & 1) + { + op->mem_size = 8; + op->flags = OP_FLAG_WRITE; + OP_PRINTF("STRD\tR%d:%d, ",(int) rd, (int)rd + 1) + } + else + { + op->mem_size = 8; + op->flags = OP_FLAG_READ; + OP_PRINTF("LDRD\tR%d:%d, ", (int)rd, (int)rd + 1) + } + arm_op_add_reg_w(op, rd); + arm_op_add_reg_w(op, rd + 1); + decode_addressing_mode3(op); + OP_PRINTF("\n") + return 0; + } + } + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + + /* + * The other possible instructions are ALU ? + */ + + /* ALU opcode */ + uint32_t opcode = (inst >> 21) & 0xF; + + + OP_PRINTF("%s", alu_op_str[opcode]) + if(ALU_S_SET) + OP_PRINTF("S") + + /* possibly normal ALU instructions */ + if(opcode == OP_MOV || opcode == OP_MVN) + { + OP_PRINTF("\tR%d, ", (int)rd) + arm_op_add_reg_w(op, rd); + } + else if(opcode == OP_CMP || opcode == OP_CMN || opcode == OP_TST || opcode == OP_TEQ) + { + OP_PRINTF("\tR%d, ", (int)rn) + arm_op_add_reg_r(op, rn); + } + else + { + OP_PRINTF("\tR%d, R%d, ", (int)rd, (int)rn) + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rn); + } + + decode_addressing_mode1(op); + OP_PRINTF("\n") + return 0; +} diff --git a/debuggers/openocd/opcode_parser/arm-opcode-ldmstm-branch.c b/debuggers/openocd/opcode_parser/arm-opcode-ldmstm-branch.c new file mode 100644 index 00000000..232aca53 --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-opcode-ldmstm-branch.c @@ -0,0 +1,135 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#include +#include "arm-opcode.h" + +int decode_load_store_multiple_and_branch(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* + * Branch ? + */ + + if(BIT_IS_SET(25)) + { + uint32_t target = (inst & 0x00FFFFFF) << 8; + target = ((int32_t)target) >> 6; + + target += op->regs->r[15] + 8; + if(BIT_IS_SET(24)) + { + OP_PRINTF("BL\t#0x%08x\n", (unsigned int)target) + arm_op_add_reg_r(op, 14); + arm_op_add_reg_w(op, 15); + return 0; + } + else + { + OP_PRINTF("B\t#0x%08x\n", (unsigned int)target) + arm_op_add_reg_w(op, 15); + return 0; + } + } + + /* LDM/STM */ + + uint32_t rn = (inst >> 16) & 0xF; + + op->mem_addr = op->regs->r[rn]; + arm_op_add_reg_r(op, rn); + + if(W_SET) + arm_op_add_reg_w(op, rn); + + if(_L_SET) + { + op->flags = OP_FLAG_READ; + op->regs_w |= (inst & 0x80FF); + if(IS_OP_FIQ(op) && !(BIT_IS_SET(22))) + op->regs_w_fiq |= (inst & 0x7F00); + else + op->regs_w |= (inst & 0x7F00); + OP_PRINTF("LDM") + } + else + { + op->flags = OP_FLAG_WRITE; + op->regs_r |= (inst & 0x80FF); + if(IS_OP_FIQ(op) && !(S_SET)) + op->regs_r_fiq |= (inst & 0x7F00); + else + op->regs_r |= (inst & 0x7F00); + OP_PRINTF("STM") + } + + /* determine memory range size */ + unsigned int i; + for(i = 0; i < 16; i++) + { + if(inst & (1 << i)) + op->mem_size += 4; + } + + if(!P_SET) + { + /* Word addressed by Rn is _included_ in range of memory */ + if(!U_SET) + { + /* Downward addressing */ + op->mem_addr -= op->mem_size; + OP_PRINTF("DA") + } + else + { + /* Upward addressing */ + // nothing to adjust in this case + OP_PRINTF("IA") + } + } + else + { + /* Word addressed by Rn is _excluded_ in range of memory */ + if(!U_SET) + { + /* Downward addressing */ + op->mem_addr -= op->mem_size; + op->mem_addr -= 4; + OP_PRINTF("DB") + } + else + { + /* Upward addressing */ + op->mem_addr += 4; + OP_PRINTF("IB") + } + } + OP_PRINTF("\tR%d", (int)rn) + if(W_SET) + OP_PRINTF("!") + OP_PRINTF(", {") + for(i = 0; i < 16; i++) + { + if(inst & (1 << i)) + OP_PRINTF("R%d, ", i) + } + OP_PRINTF("}") + if(S_SET) + OP_PRINTF("^") + + OP_PRINTF(" [Address: %08x]", (unsigned int)op->mem_addr) + return 0; +} diff --git a/debuggers/openocd/opcode_parser/arm-opcode-ldrstr.c b/debuggers/openocd/opcode_parser/arm-opcode-ldrstr.c new file mode 100644 index 00000000..9bc58d8c --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-opcode-ldrstr.c @@ -0,0 +1,373 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#include +#include "arm-opcode.h" + +#define ARCH_UNDEF_INSTRUCTION_MASK 0x0FF000F0 +#define ARCH_UNDEF_INSTRUCTION_SIG 0x07F000F0 + +#define MEDIA_INSTRUCTION_MASK 0x0E000010 +#define MEDIA_INSTRUCTION_SIG 0x06000010 + +int decode_load_store(arm_instruction_t * op) +{ + uint32_t inst = op->inst; + /* possible registers */ + uint32_t rn = (inst >> 16) & 0xF; + uint32_t rd = (inst >> 12) & 0xF; + uint32_t rs = (inst >> 8) & 0xF; + uint32_t rm = (inst) & 0xF; + + /* + * Architecturally undefined instruction ? + */ + + if((inst & ARCH_UNDEF_INSTRUCTION_MASK) == ARCH_UNDEF_INSTRUCTION_SIG) + { + OP_PRINTF("Architecturally Undefined Instruction\n") + return 0; + } + + /* + * Media instruction ? + */ + + if((inst & MEDIA_INSTRUCTION_MASK) == MEDIA_INSTRUCTION_SIG) + { + uint32_t opc = (inst >> 23) & 3; + uint32_t opc1 = (inst >> 20) & 7; + uint32_t opc2 = (inst >> 5) & 7; + + if(opc == 0) + { + /* Parallel add/subtract */ + switch(opc1) + { + case 1: + OP_PRINTF("S") + break; + case 2: + OP_PRINTF("Q") + break; + case 3: + OP_PRINTF("SH") + break; + case 5: + OP_PRINTF("U") + break; + case 6: + OP_PRINTF("UQ") + break; + case 7: + OP_PRINTF("UH") + break; + case 0: + case 4: + default: + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + switch(opc2 & 3) + { + case 0: + OP_PRINTF("ADD") + if(opc2 & 4) + OP_PRINTF("8") + else + OP_PRINTF("16") + break; + case 1: + OP_PRINTF("ADDSUBX") + break; + case 2: + OP_PRINTF("SUBADDX") + break; + case 3: + default: + OP_PRINTF("SUB") + if(opc2 & 4) + OP_PRINTF("8") + else + OP_PRINTF("16") + break; + } + OP_PRINTF("\tR%d, R%d, R%d\n", (int)rd, (int)rn, (int)rm) + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rm); + return 0; + } + if(opc == 1) + { + uint32_t shift_imm = (inst >> 7) & 0x1F; + if(opc1 == 0) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rm); + if(opc2 & 2) + { + if(shift_imm == 0) + shift_imm = 32; + OP_PRINTF("PKHTB\tR%d, R%d, R%d, ASR #%d\n", (int)rd, (int)rn, (int)rm, (int)shift_imm) + return 0; + } + else + { + OP_PRINTF("PKHBT\tR%d, R%d, R%d", (int)rd, (int)rn, (int)rm) + if(shift_imm) + OP_PRINTF(", LSL #%d\n", (int)shift_imm) + else + OP_PRINTF("\n") + return 0; + } + } + if((opc1 & 2) == 2 && (opc2 & 1) == 0) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + uint32_t sat_imm = (inst >> 16) & 0x1F; + uint32_t shift_imm = (inst >> 7) & 0x1F; + + if(opc1 & 4) + OP_PRINTF("U") + else + OP_PRINTF("S") + OP_PRINTF("SAT\tR%d, #%d, R%d", (int)rd, (int)sat_imm + 1, (int)rm) + if(BIT_IS_SET(6)) + { + if(shift_imm == 0) + OP_PRINTF(", ASR 32\n") + else + OP_PRINTF(", ASR #%d\n", (int)shift_imm) + } + else + { + if(shift_imm == 0) + { + OP_PRINTF("\n") + } + else + { + OP_PRINTF(", LSL #%d\n", (int)shift_imm) + } + } + return 0; + } + if((opc1 & 3) == 2 && opc2 == 1) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + uint32_t sat_imm = (inst >> 16) & 0xF; + if(opc1 & 4) + OP_PRINTF("U") + else + OP_PRINTF("S") + OP_PRINTF("SAT16\tR%d, #%d, R%d\n", (int)rd, (int)sat_imm, (int)rm) + return 0; + } + if(opc1 == 3 && opc2 == 1) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + OP_PRINTF("REV\tR%d, R%d\n", (int)rd, (int)rm) + return 0; + } + if(opc1 == 3 && opc2 == 5) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + OP_PRINTF("REV16\tR%d, R%d\n", (int)rd, (int)rm) + return 0; + } + if(opc1 == 7 && opc2 == 5) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + OP_PRINTF("REVSH\tR%d, R%d\n", (int)rd, (int)rm) + return 0; + } + if(opc1 == 0 && opc2 == 5) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rm); + OP_PRINTF("SEL\tR%d, R%d, R%d\n", (int)rd, (int)rn, (int)rm) + return 0; + } + if(opc2 == 3) + { + uint32_t rotate = (inst >> 10) & 3; + if(opc1 & 4) + OP_PRINTF("U") + else + OP_PRINTF("S") + if(rn != 15) + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rm); + switch(opc1 & 3) + { + case 0: + OP_PRINTF("XTAB16") + break; + case 2: + OP_PRINTF("XTAB") + break; + case 3: + OP_PRINTF("XTAH") + break; + case 1: + default: + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + OP_PRINTF("\tR%d, R%d, R%d", (int)rd, (int)rn, (int)rm) + } + else + { + arm_op_add_reg_w(op, rd); + arm_op_add_reg_r(op, rm); + switch(opc1 & 3) + { + case 0: + OP_PRINTF("XTB16") + break; + case 2: + OP_PRINTF("XTB") + break; + case 3: + OP_PRINTF("XTH") + break; + case 1: + default: + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + OP_PRINTF("\tR%d, R%d", (int)rd, (int)rm) + } + if(rotate == 0) + OP_PRINTF("\n") + else if(rotate == 1) + OP_PRINTF(", ROR #8\n") + else if(rotate == 2) + OP_PRINTF(", ROR #16\n") + else if(rotate == 3) + OP_PRINTF(", ROR #24\n") + return 0; + } + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + if(opc == 2) + { + /* RD and RN are switched!! */ + uint32_t temp = rd; + rd = rn; + rn = temp; + + arm_op_add_reg_w(op, rd); + if(rn != 15) + { + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + arm_op_add_reg_r(op, rm); + OP_PRINTF("SML") + } + else + { + arm_op_add_reg_r(op, rs); + arm_op_add_reg_r(op, rm); + OP_PRINTF("SMU") + } + if(opc2 & 2) + OP_PRINTF("S") + else + OP_PRINTF("A") + if(opc1 & 4) + OP_PRINTF("L") + if(opc2 & 1) + OP_PRINTF("X") + if(rn != 15) + OP_PRINTF("\tR%d, R%d, R%d, R%d", (int)rd, (int)rm, (int)rs, (int)rn) + else + OP_PRINTF("\tR%d, R%d, R%d", (int)rd, (int)rm, (int)rs) + return 0; + } + if(opc == 3 && opc1 == 0 && opc2 == 0) + { + /* RD and RN are switched!! */ + uint32_t temp = rd; + rd = rn; + rn = temp; + + arm_op_add_reg_w(op, rd); + if(rn != 15) + { + arm_op_add_reg_r(op, rn); + arm_op_add_reg_r(op, rs); + arm_op_add_reg_r(op, rm); + OP_PRINTF("USADA8\tR%d, R%d, R%d, R%d", (int)rd, (int)rm, (int)rs, (int)rn) + } + else + { + arm_op_add_reg_r(op, rs); + arm_op_add_reg_r(op, rm); + OP_PRINTF("USAD8\tR%d, R%d, R%d", (int)rd, (int)rm, (int)rs) + } + return 0; + } + printf("\n%d: CANNOT parse %08x\n", __LINE__, (unsigned int)inst); + return 1; + } + + /* + * ordinary load-store instruction + */ + + if(_L_SET) + { + op->flags |= OP_FLAG_READ; + arm_op_add_reg_w(op, rd); + OP_PRINTF("LDR") + } + else + { + op->flags |= OP_FLAG_WRITE; + arm_op_add_reg_r(op, rd); + OP_PRINTF("STR") + } + + if(B_SET) + { + op->mem_size = 1; + OP_PRINTF("B") + } + else + { + op->mem_size = 4; + } + + if(!P_SET && W_SET) + OP_PRINTF("T") + + OP_PRINTF("\tR%d, ", (int)rd) + decode_addressing_mode2(op); + OP_PRINTF("\n") + return 0; +} diff --git a/debuggers/openocd/opcode_parser/arm-opcode.c b/debuggers/openocd/opcode_parser/arm-opcode.c new file mode 100644 index 00000000..fd3bc872 --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-opcode.c @@ -0,0 +1,111 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#include +#include +#include "arm-opcode.h" + +int verbose_opcode = 0; +char opcode_string[128]; +char * opcode_string_tmp; + +int decode_instruction(uint32_t inst, arm_regs_t * regs, arm_instruction_t * op) +{ + memset(op, 0, sizeof(arm_instruction_t)); + op->inst = inst; + op->regs = regs; + + opcode_string_tmp = opcode_string; + + /* will the instruction be executed ?*/ + uint32_t condtest = op_cond_test(inst, regs->cpsr); + if(condtest == 0xFFFFFFFF) + { + //TODO: parse extension opcodes + printf("TODO: parse extension opcodes"); + return 1; + } + else if(condtest == 0) + { + op->flags = OP_FLAG_CONDITION_FALSE; + return 2; + } + + uint32_t type = (inst >> 26) & 3; + + switch(type) + { + case 0: + return decode_data_processing(op); + case 1: + return decode_load_store(op); + case 2: + return decode_load_store_multiple_and_branch(op); + case 3: + return decode_coprocessor(op); + } + return 1; +} + +void dump_instruction(const arm_instruction_t * op) +{ + printf("R0: %08x R1: %08x R2: %08x R3: %08x IP: %08x SP: %08x\n", + (unsigned int)op->regs->r[0], + (unsigned int)op->regs->r[1], + (unsigned int)op->regs->r[2], + (unsigned int)op->regs->r[3], + (unsigned int)op->regs->r[12], + (unsigned int)op->regs->r[13] + ); + printf("Instruction: %08x PC: %08x LR: %08x CPSR:%08x SPSR:%08x Mem:%08x(%c%c,%u) Flags:%08x\n\tRegisters: r:0x%04x r_fiq:0x%04x w:0x%04x w_fiq:0x%04x -- ", + (unsigned int)op->inst, + (unsigned int)op->regs->r[15], + (unsigned int)op->regs->r[14], + (unsigned int)op->regs->cpsr, + (unsigned int)op->regs->spsr, + (unsigned int)op->mem_addr, + op->flags & OP_FLAG_READ ? 'R' : ' ', + op->flags & OP_FLAG_WRITE ? 'W' : ' ', + (unsigned int)op->mem_size, + (unsigned int)op->flags, + (unsigned int)op->regs_r, + (unsigned int)op->regs_r_fiq, + (unsigned int)op->regs_w, + (unsigned int)op->regs_w_fiq + ); + int i; + for(i = 0; i < 16; i++) + { + if((op->regs_r & (1 << i)) || + (op->regs_r_fiq & (1 << i)) || + (op->regs_w & (1 << i)) || + (op->regs_w_fiq & (1 << i))) + { + printf("R%d(", i); + if(op->regs_r & (1 << i)) + printf("R"); + if(op->regs_r_fiq & (1 << i)) + printf("r"); + if(op->regs_w & (1 << i)) + printf("W"); + if(op->regs_w_fiq & (1 << i)) + printf("w"); + + printf("), "); + } + } + printf("\n"); +} diff --git a/debuggers/openocd/opcode_parser/arm-opcode.h b/debuggers/openocd/opcode_parser/arm-opcode.h new file mode 100644 index 00000000..540524b7 --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm-opcode.h @@ -0,0 +1,120 @@ +/* + * FAME - Fault Aware Micro-hypervisor Environment + * + * Author: Andreas Heinig + * + * Copyright (C) 2011,2012 Department of Computer Science, + * Design Automation of Embedded Systems Group + * Dortmund University of Technology + * + * This program is proprietary software: you must not redistribute it. + * Using this software is only allowed inside the DFG SPP1500 F.E.H.L.E.R project, + * ls12-www.cs.tu-dortmund.de/daes/forschung/dependable-embedded-real-time-systems + * + * The complete license is depicted in the LICENSE file in the top level folder. + */ + +#ifndef ARM_OPCODE_H__INCLUDED__ +#define ARM_OPCODE_H__INCLUDED__ + +#include + +typedef struct { + uint32_t r[16]; // registers of current mode only! + uint32_t cpsr; + uint32_t spsr; +} arm_regs_t; + + +extern int verbose_opcode; +extern char opcode_string[128]; +extern char * opcode_string_tmp; + +#define OP_PRINTF(fmt, arg...) { if(verbose_opcode) printf(fmt, ##arg); } +//#define OP_PRINTF(fmt, arg...) printf(fmt, ##arg) +//#define OP_PRINTF(fmt, arg...) opcode_string_tmp += sprintf(opcode_string_tmp, fmt, ##arg) + +#define BIT_IS_SET(bit) (inst & (1 << bit)) +#define BIT_IS_CLEAR(bit) (!(inst & (1 << bit))) + +#define ARM_MODE_MASK 0x1F + +#define ARM_MODE_SVC 0x13 +#define ARM_MODE_UND 0x1B +#define ARM_MODE_ABT 0x17 +#define ARM_MODE_IRQ 0x12 +#define ARM_MODE_FIQ 0x11 +#define ARM_MODE_USR 0x10 +#define ARM_MODE_SYS 0x1F + +#define IS_OP_FIQ(op) ((((op)->regs->cpsr) & ARM_MODE_MASK) == ARM_MODE_FIQ) + + +#define I_BIT (1 << 25) +#define P_BIT (1 << 24) +#define U_BIT (1 << 23) +#define B_BIT (1 << 22) +#define S_BIT (1 << 22) +#define ALU_S_BIT (1 << 20) +#define W_BIT (1 << 21) +#define L_BIT (1 << 20) + +#define I_SET (inst & I_BIT) +#define P_SET (inst & P_BIT) +#define U_SET (inst & U_BIT) +#define B_SET (inst & B_BIT) +#define S_SET (inst & S_BIT) +#define ALU_S_SET (inst & ALU_S_BIT) +#define W_SET (inst & W_BIT) +#define _L_SET (inst & L_BIT) + + +#define OP_FLAG_WRITE 0x00000001 +#define OP_FLAG_READ 0x00000002 + +#define OP_FLAG_CONDITION_FALSE 0x80000000 + +typedef struct { + uint32_t inst; + arm_regs_t * regs; + uint32_t flags; + uint32_t regs_r; + uint32_t regs_r_fiq; + uint32_t regs_w; + uint32_t regs_w_fiq; + uint32_t mem_addr; + uint32_t mem_size; +}arm_instruction_t; + +uint32_t op_cond_test(uint32_t inst, uint32_t cpsr); + +uint32_t decode_addressing_mode1(arm_instruction_t * op); +void decode_addressing_mode2(arm_instruction_t * op); +void decode_addressing_mode3(arm_instruction_t * op); +void decode_addressing_mode5(arm_instruction_t * op); + +int decode_data_processing(arm_instruction_t * op); +int decode_load_store(arm_instruction_t * op); +int decode_load_store_multiple_and_branch(arm_instruction_t * op); +int decode_coprocessor(arm_instruction_t * op); + +int decode_instruction(uint32_t inst, arm_regs_t * regs, arm_instruction_t * op); +void dump_instruction(const arm_instruction_t * op); + +static inline void arm_op_add_reg_r(arm_instruction_t * op, uint32_t r) +{ + if(r >= 8 && IS_OP_FIQ(op)) + op->regs_r_fiq |= (1 << r); + else + op->regs_r |= (1 << r); +} + +static inline void arm_op_add_reg_w(arm_instruction_t * op, uint32_t r) +{ + if(r >= 8 && r != 15 && IS_OP_FIQ(op)) + op->regs_w_fiq |= (1 << r); + else + op->regs_w |= (1 << r); +} + +#endif /* ARM_OPCODE_H__INCLUDED__ */ diff --git a/debuggers/openocd/opcode_parser/arm_opcodes.h b/debuggers/openocd/opcode_parser/arm_opcodes.h new file mode 100644 index 00000000..1b9e4fc0 --- /dev/null +++ b/debuggers/openocd/opcode_parser/arm_opcodes.h @@ -0,0 +1,274 @@ +// copied from OpenOCD + +/* + * Copyright (C) 2005 by Dominic Rath + * Dominic.Rath@gmx.de + * + * Copyright (C) 2006 by Magnus Lundin + * lundin@mlu.mine.nu + * + * Copyright (C) 2008 by Spencer Oliver + * spen@spen-soft.co.uk + * + * Copyright (C) 2009 by Øyvind Harboe + * oyvind.harboe@zylin.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef __ARM_OPCODES_H +#define __ARM_OPCODES_H + +/** + * @file + * Macros used to generate various ARM or Thumb opcodes. + */ + +/* ARM mode instructions */ + +/* Store multiple increment after + * Rn: base register + * List: for each bit in list: store register + * S: in priviledged mode: store user-mode registers + * W = 1: update the base register. W = 0: leave the base register untouched + */ +#define ARMV4_5_STMIA(Rn, List, S, W) \ + (0xe8800000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List)) + +/* Load multiple increment after + * Rn: base register + * List: for each bit in list: store register + * S: in priviledged mode: store user-mode registers + * W = 1: update the base register. W = 0: leave the base register untouched + */ +#define ARMV4_5_LDMIA(Rn, List, S, W) \ + (0xe8900000 | ((S) << 22) | ((W) << 21) | ((Rn) << 16) | (List)) + +/* MOV r8, r8 */ +#define ARMV4_5_NOP (0xe1a08008) + +/* Move PSR to general purpose register + * R = 1: SPSR R = 0: CPSR + * Rn: target register + */ +#define ARMV4_5_MRS(Rn, R) (0xe10f0000 | ((R) << 22) | ((Rn) << 12)) + +/* Store register + * Rd: register to store + * Rn: base register + */ +#define ARMV4_5_STR(Rd, Rn) (0xe5800000 | ((Rd) << 12) | ((Rn) << 16)) + +/* Load register + * Rd: register to load + * Rn: base register + */ +#define ARMV4_5_LDR(Rd, Rn) (0xe5900000 | ((Rd) << 12) | ((Rn) << 16)) + +/* Move general purpose register to PSR + * R = 1: SPSR R = 0: CPSR + * Field: Field mask + * 1: control field 2: extension field 4: status field 8: flags field + * Rm: source register + */ +#define ARMV4_5_MSR_GP(Rm, Field, R) \ + (0xe120f000 | (Rm) | ((Field) << 16) | ((R) << 22)) +#define ARMV4_5_MSR_IM(Im, Rotate, Field, R) \ + (0xe320f000 | (Im) | ((Rotate) << 8) | ((Field) << 16) | ((R) << 22)) + +/* Load Register Halfword Immediate Post-Index + * Rd: register to load + * Rn: base register + */ +#define ARMV4_5_LDRH_IP(Rd, Rn) (0xe0d000b2 | ((Rd) << 12) | ((Rn) << 16)) + +/* Load Register Byte Immediate Post-Index + * Rd: register to load + * Rn: base register + */ +#define ARMV4_5_LDRB_IP(Rd, Rn) (0xe4d00001 | ((Rd) << 12) | ((Rn) << 16)) + +/* Store register Halfword Immediate Post-Index + * Rd: register to store + * Rn: base register + */ +#define ARMV4_5_STRH_IP(Rd, Rn) (0xe0c000b2 | ((Rd) << 12) | ((Rn) << 16)) + +/* Store register Byte Immediate Post-Index + * Rd: register to store + * Rn: base register + */ +#define ARMV4_5_STRB_IP(Rd, Rn) (0xe4c00001 | ((Rd) << 12) | ((Rn) << 16)) + +/* Branch (and Link) + * Im: Branch target (left-shifted by 2 bits, added to PC) + * L: 1: branch and link 0: branch only + */ +#define ARMV4_5_B(Im, L) (0xea000000 | (Im) | ((L) << 24)) + +/* Branch and exchange (ARM state) + * Rm: register holding branch target address + */ +#define ARMV4_5_BX(Rm) (0xe12fff10 | (Rm)) + +/* Move to ARM register from coprocessor + * CP: Coprocessor number + * op1: Coprocessor opcode + * Rd: destination register + * CRn: first coprocessor operand + * CRm: second coprocessor operand + * op2: Second coprocessor opcode + */ +#define ARMV4_5_MRC(CP, op1, Rd, CRn, CRm, op2) \ + (0xee100010 | (CRm) | ((op2) << 5) | ((CP) << 8) \ + | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21)) + +/* Move to coprocessor from ARM register + * CP: Coprocessor number + * op1: Coprocessor opcode + * Rd: destination register + * CRn: first coprocessor operand + * CRm: second coprocessor operand + * op2: Second coprocessor opcode + */ +#define ARMV4_5_MCR(CP, op1, Rd, CRn, CRm, op2) \ + (0xee000010 | (CRm) | ((op2) << 5) | ((CP) << 8) \ + | ((Rd) << 12) | ((CRn) << 16) | ((op1) << 21)) + +/* Breakpoint instruction (ARMv5) + * Im: 16-bit immediate + */ +#define ARMV5_BKPT(Im) (0xe1200070 | ((Im & 0xfff0) << 8) | (Im & 0xf)) + + +/* Thumb mode instructions + * + * NOTE: these 16-bit opcodes fill both halves of a word with the same + * value. The reason for this is that when we need to execute Thumb + * opcodes on ARM7/ARM9 cores (to switch to ARM state on debug entry), + * we must shift 32 bits to the bus using scan chain 1 ... if we write + * both halves, we don't need to track which half matters. On ARMv6 and + * ARMv7 we don't execute Thumb instructions in debug mode; the ITR + * register does not accept Thumb (or Thumb2) opcodes. + */ + +/* Store register (Thumb mode) + * Rd: source register + * Rn: base register + */ +#define ARMV4_5_T_STR(Rd, Rn) \ + ((0x6000 | (Rd) | ((Rn) << 3)) | \ + ((0x6000 | (Rd) | ((Rn) << 3)) << 16)) + +/* Load register (Thumb state) + * Rd: destination register + * Rn: base register + */ +#define ARMV4_5_T_LDR(Rd, Rn) \ + ((0x6800 | ((Rn) << 3) | (Rd)) \ + | ((0x6800 | ((Rn) << 3) | (Rd)) << 16)) + +/* Load multiple (Thumb state) + * Rn: base register + * List: for each bit in list: store register + */ +#define ARMV4_5_T_LDMIA(Rn, List) \ + ((0xc800 | ((Rn) << 8) | (List)) \ + | ((0xc800 | ((Rn) << 8) | (List)) << 16)) + +/* Load register with PC relative addressing + * Rd: register to load + */ +#define ARMV4_5_T_LDR_PCREL(Rd) \ + ((0x4800 | ((Rd) << 8)) \ + | ((0x4800 | ((Rd) << 8)) << 16)) + +/* Move hi register (Thumb mode) + * Rd: destination register + * Rm: source register + */ +#define ARMV4_5_T_MOV(Rd, Rm) \ + ((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \ + (((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) \ + | ((0x4600 | ((Rd) & 0x7) | (((Rd) & 0x8) << 4) | \ + (((Rm) & 0x7) << 3) | (((Rm) & 0x8) << 3)) << 16)) + +/* No operation (Thumb mode) + * NOTE: this is "MOV r8, r8" ... Thumb2 adds two + * architected NOPs, 16-bit and 32-bit. + */ +#define ARMV4_5_T_NOP (0x46c0 | (0x46c0 << 16)) + +/* Move immediate to register (Thumb state) + * Rd: destination register + * Im: 8-bit immediate value + */ +#define ARMV4_5_T_MOV_IM(Rd, Im) \ + ((0x2000 | ((Rd) << 8) | (Im)) \ + | ((0x2000 | ((Rd) << 8) | (Im)) << 16)) + +/* Branch and Exchange + * Rm: register containing branch target + */ +#define ARMV4_5_T_BX(Rm) \ + ((0x4700 | ((Rm) << 3)) \ + | ((0x4700 | ((Rm) << 3)) << 16)) + +/* Branch (Thumb state) + * Imm: Branch target + */ +#define ARMV4_5_T_B(Imm) \ + ((0xe000 | (Imm)) \ + | ((0xe000 | (Imm)) << 16)) + +/* Breakpoint instruction (ARMv5) (Thumb state) + * Im: 8-bit immediate + */ +#define ARMV5_T_BKPT(Im) \ + ((0xbe00 | (Im)) \ + | ((0xbe00 | (Im)) << 16)) + +/* Move to Register from Special Register + * 32 bit Thumb2 instruction + * Rd: destination register + * SYSm: source special register + */ +#define ARM_T2_MRS(Rd, SYSm) \ + ((0xF3EF) | ((0x8000 | (Rd << 8) | SYSm) << 16)) + +/* Move from Register from Special Register + * 32 bit Thumb2 instruction + * Rd: source register + * SYSm: destination special register + */ +#define ARM_T2_MSR(SYSm, Rn) \ + ((0xF380 | (Rn << 8)) | ((0x8800 | SYSm) << 16)) + +/* Change Processor State. + * 16 bit Thumb2 instruction + * Rd: source register + * IF: A_FLAG and/or I_FLAG and/or F_FLAG + */ +#define A_FLAG 4 +#define I_FLAG 2 +#define F_FLAG 1 +#define ARM_T2_CPSID(IF) \ + ((0xB660 | (1 << 8) | ((IF)&0x3)) \ + | ((0xB660 | (1 << 8) | ((IF)&0x3)) << 16)) +#define ARM_T2_CPSIE(IF) \ + ((0xB660 | (0 << 8) | ((IF)&0x3)) \ + | ((0xB660 | (0 << 8) | ((IF)&0x3)) << 16)) + +#endif /* __ARM_OPCODES_H */ diff --git a/debuggers/openocd/openocd_wrapper.cc b/debuggers/openocd/openocd_wrapper.cc index bfb5791e..f59fb9f1 100644 --- a/debuggers/openocd/openocd_wrapper.cc +++ b/debuggers/openocd/openocd_wrapper.cc @@ -26,6 +26,8 @@ extern "C" { #include "jimtcl/jim.h" extern struct command_context *setup_command_handler(Jim_Interp *interp); + + #include "opcode_parser/arm-opcode.h" } #include @@ -36,8 +38,7 @@ extern "C" { #include "sal/SALInst.hpp" #include "sal/SALConfig.hpp" #include "sal/arm/ArmArchitecture.hpp" - -#include "sal/arm/ArmMemoryInstruction.hpp" +#include "util/ElfReader.hpp" #include "util/Logger.hpp" @@ -80,6 +81,8 @@ static bool horizontal_step = false; */ static bool single_step_requested = false; +static bool single_step_watch_memory = false; + /* * Variables for monitoring BP/WP resources * Reset at reboot @@ -87,11 +90,6 @@ static bool single_step_requested = false; static uint8_t free_watchpoints = 4; static uint8_t free_breakpoints = 6; -/* - * Analyzer for memory accesses on basis of elf file - */ -static fail::ArmMemoryInstructionAnalyzer inst_analyzer; - /* * Elf reader for reading symbols in startup-code */ @@ -158,7 +156,7 @@ static void update_timers(); static void freeze_timers(); static void unfreeze_timers(); static struct watchpoint *getHaltingWatchpoint(); -static void getCurrentMemAccesses(struct halt_condition *accesses); +static bool getCurrentMemAccess(struct halt_condition *accesses); static uint32_t getCurrentPC(); static struct reg *get_reg_by_number(unsigned int num); static void read_dpm_register(uint32_t reg_num, uint32_t *data); @@ -307,6 +305,22 @@ int main(int argc, char *argv[]) */ single_step_requested = false; + /* + * Get current memory access(es) + */ + if (single_step_watch_memory) { + struct halt_condition mem_access; + if (getCurrentMemAccess(&mem_access)) { + freeze_timers(); + fail::simulator.onMemoryAccess(NULL, + mem_access.address, + mem_access.addr_len, + mem_access.type == HALT_TYPE_WP_WRITE, + pc); + unfreeze_timers(); + } + } + freeze_timers(); fail::simulator.onBreakpoint(NULL, pc, fail::ANY_ADDR); unfreeze_timers(); @@ -386,12 +400,35 @@ int main(int argc, char *argv[]) uint32_t dfar; oocdw_read_reg(fail::RI_DFAR, &dfar); - // ToDo: Get potential additional memory accesses and access width (InstructionAnalyzer) - fail::MemoryInstruction mi; - if (!inst_analyzer.eval((fail::address_t)pc, mi)) { - LOG << "FATAL ERROR: Memory accessing instruction could not be analyzed" << endl; - exit(-1); + /* + * Analyze instruction to get access width. Also the base-address may differ from this in multiple + * data access instructions with decrement option. + * As some Register values have changed in the handler, we first must find the original values. + * This is easy for a static abort handler (pushed to stack), but must be adjusted, if handler + * is adjusted + */ + + uint32_t opcode; + oocdw_read_from_memory(lr_abt - 8, 4, 1, (uint8_t*)(&opcode)); + + uint32_t sp_abt; + oocdw_read_reg(fail::RI_SP_ABT, &sp_abt); + + arm_regs_t regs; + + oocdw_read_from_memory(sp_abt, 4, 4, (uint8_t*)(®s.r[2])); + + for (int i = 0; i < 16; i++) { + if (i >=2 && i <=5) { + continue; + } + oocdw_read_reg(i, &(regs.r[i])); } + oocdw_read_reg(fail::RI_CPSR, ®s.cpsr); + oocdw_read_reg(fail::RI_SPSR_ABT, ®s.spsr); + + arm_instruction_t op; + decode_instruction(opcode, ®s, &op); /* * set BP on the instruction, which caused the abort, singlestep and recover previous mmu state @@ -409,9 +446,12 @@ int main(int argc, char *argv[]) mmu_recovery_needed = true; - freeze_timers(); - fail::simulator.onMemoryAccess(NULL, dfar, mi.getWidth(), mi.isWriteAccess(), lr_abt - 8); - unfreeze_timers(); + if (op.flags & (OP_FLAG_READ | OP_FLAG_WRITE)) { + fail::simulator.onMemoryAccess(NULL, op.mem_addr, op.mem_size, op.flags & OP_FLAG_WRITE, lr_abt - 8); + } else { + LOG << "FATAL ERROR: Disassembling instruction in mmu handler failed" << endl; + exit(-1); + } } else if (pc == sym_GenericTrapHandler) { freeze_timers(); fail::simulator.onTrap(NULL, fail::ANY_TRAP); @@ -535,7 +575,9 @@ void oocdw_set_halt_condition(struct halt_condition *hc) } } else if (hc->type == HALT_TYPE_SINGLESTEP) { single_step_requested = true; - } else { + } else if ((hc->type == HALT_TYPE_WP_READ) || + (hc->type == HALT_TYPE_WP_WRITE) || + (hc->type == HALT_TYPE_WP_READWRITE)) { if ((hc->addr_len > 4) || !free_watchpoints) { // Use MMU for watching LOG << "Setting up MMU to watch memory range " << hex << hc->address << ":" << hc->addr_len << dec << endl; @@ -547,6 +589,12 @@ void oocdw_set_halt_condition(struct halt_condition *hc) mmu_watch_add_waiting_list.push_back(mr); return; } + + if (hc->address == fail::ANY_ADDR) { + single_step_watch_memory = true; + return; + } + LOG << "Adding WP " << hex << hc->address << dec << ":" << hc->addr_len << ":" << ((hc->type == HALT_TYPE_WP_READ)? "R" : (hc->type == HALT_TYPE_WP_WRITE)? "W" : "R/W")<< endl; @@ -569,26 +617,21 @@ void oocdw_set_halt_condition(struct halt_condition *hc) } free_watchpoints--; - // Compare current memory access events with set watchpoint + // Compare current memory access event with set watchpoint // (potential horizontal hop) - struct halt_condition mem_accesses [4]; - getCurrentMemAccesses(mem_accesses); - int i = 0; - while (mem_accesses[i].address) { - // Look for overlapping similar memory access - if (mem_accesses[i].type == hc->type) { - if (mem_accesses[i].address < hc->address) { - if (mem_accesses[i].address + mem_accesses[i].addr_len >= hc->address) { - horizontal_step = true; - } - } else { - if (hc->address + hc->addr_len >= mem_accesses[i].address) { - horizontal_step = true; - } + struct halt_condition mem_access; + if (getCurrentMemAccess(&mem_access)) { + if (mem_access.type == hc->type) { + if ((mem_access.address < hc->address) && (mem_access.address + mem_access.addr_len >= hc->address)) { + horizontal_step = true; + } else if ((mem_access.address >= hc->address) && (hc->address + hc->addr_len >= mem_access.address)) { + horizontal_step = true; } } - i++; } + } else { + LOG << "FATAL ERROR: Could not determine halt condition type" << endl; + exit(-1); } } @@ -620,6 +663,11 @@ void oocdw_delete_halt_condition(struct halt_condition *hc) return; } + if (hc->address == fail::ANY_ADDR) { + single_step_watch_memory = false; + return; + } + watchpoint_remove(target_a9, hc->address); free_watchpoints++; LOG << hex << "Removing WP " << hc->address << ":" << hc->addr_len << ":" << @@ -886,6 +934,18 @@ static void read_dpm_register(uint32_t reg_num, uint32_t *data) dpm->finish(dpm); } +static inline void read_processor_register(uint32_t reg_num, uint32_t *data) +{ + struct reg *reg; + reg = get_reg_by_number(reg_num); + + if (reg->valid == 0) { + reg->type->get(reg); + } + + *data = *((uint32_t*)(reg->value)); +} + void oocdw_read_reg(uint32_t reg_num, uint32_t *data) { assert((target_a9->state == TARGET_HALTED) && "Target not halted"); @@ -928,26 +988,79 @@ void oocdw_read_reg(uint32_t reg_num, uint32_t *data) case fail::RI_R14: /* fall through */ case fail::RI_R15: - { - struct reg *reg = get_reg_by_number(reg_num); - - if (reg->valid == 0) { - reg->type->get(reg); - } - - *data = *((uint32_t*)(reg->value)); - } + read_processor_register(reg_num, data); + break; + case fail::RI_R8_FIQ: + read_processor_register(16, data); + break; + case fail::RI_R9_FIQ: + read_processor_register(17, data); + break; + case fail::RI_R10_FIQ: + read_processor_register(18, data); + break; + case fail::RI_R11_FIQ: + read_processor_register(19, data); + break; + case fail::RI_R12_FIQ: + read_processor_register(20, data); + break; + case fail::RI_SP_FIQ: + read_processor_register(21, data); + break; + case fail::RI_LR_FIQ: + read_processor_register(22, data); + break; + case fail::RI_SP_IRQ: + read_processor_register(23, data); + break; + case fail::RI_LR_IRQ: + read_processor_register(24, data); + break; + case fail::RI_SP_SVC: + read_processor_register(25, data); + break; + case fail::RI_LR_SVC: + read_processor_register(26, data); + break; + case fail::RI_SP_ABT: + read_processor_register(27, data); break; case fail::RI_LR_ABT: - { - struct reg *reg = get_reg_by_number(28); - - if (reg->valid == 0) { - reg->type->get(reg); - } - - *data = *((uint32_t*)(reg->value)); - } + read_processor_register(28, data); + break; + case fail::RI_SP_UND: + read_processor_register(29, data); + break; + case fail::RI_LR_UND: + read_processor_register(30, data); + break; + case fail::RI_CPSR: + read_processor_register(31, data); + break; + case fail::RI_SPSR_FIQ: + read_processor_register(32, data); + break; + case fail::RI_SPSR_IRQ: + read_processor_register(33, data); + break; + case fail::RI_SPSR_SVC: + read_processor_register(34, data); + break; + case fail::RI_SPSR_ABT: + read_processor_register(35, data); + break; + case fail::RI_SPSR_UND: + read_processor_register(36, data); + break; + case fail::RI_SP_MON: + read_processor_register(37, data); + break; + case fail::RI_LR_MON: + read_processor_register(38, data); + break; + case fail::RI_SPSR_MON: + read_processor_register(39, data); break; default: LOG << "ERROR: Register with id " << reg_num << " unknown." << endl; @@ -1096,26 +1209,33 @@ static uint32_t getCurrentPC() * TODO implement analysis of current instruction in combination * with register contents */ -static void getCurrentMemAccesses(struct halt_condition *accesses) +static bool getCurrentMemAccess(struct halt_condition *access) { // ToDo: Get all memory access events of current // instruction. For now return empty array. uint32_t pc = getCurrentPC(); - int i = 0; + uint32_t opcode; + oocdw_read_from_memory(pc, 4 , 1, (uint8_t*)(&opcode)); - fail::MemoryInstruction mi; + arm_regs_t regs; - // TODO: Loop for multiple accesses? - if (inst_analyzer.eval(pc, mi)) { - accesses[i].address = mi.getAddress(); - accesses[i].addr_len = mi.getWidth(); - accesses[i].type = mi.isWriteAccess() ? HALT_TYPE_WP_WRITE : HALT_TYPE_WP_READ; - i++; + for (int i = 0; i < 16; i++) { + oocdw_read_reg(i, &(regs.r[i])); } + oocdw_read_reg(fail::RI_CPSR, ®s.cpsr); - accesses[i].address = 0; + arm_instruction_t op; + decode_instruction(opcode, ®s, &op); + + if (op.flags & (OP_FLAG_READ | OP_FLAG_WRITE)) { + access->address = op.mem_addr; + access->addr_len = op.mem_size; + access->type = (op.flags & OP_FLAG_READ) ? HALT_TYPE_WP_READ : HALT_TYPE_WP_WRITE; + return true; + } + return false; } /* @@ -1686,7 +1806,7 @@ static struct timeval freeze_begin; static void freeze_timers() { - LOG << "FREEZE TIMERS" << endl; + // LOG << "FREEZE TIMERS" << endl; gettimeofday(&freeze_begin, NULL); for (int i = 0; i < P_MAX_TIMERS; i++) { if (timers[i].inUse) { @@ -1697,7 +1817,7 @@ static void freeze_timers() static void unfreeze_timers() { - LOG << "UNFREEZE TIMERS" << endl; + // LOG << "UNFREEZE TIMERS" << endl; struct timeval freeze_end, freeze_delta; gettimeofday(&freeze_end, NULL); timersub(&freeze_end, &freeze_begin, &freeze_delta);