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
This commit is contained in:
Lars Rademacher
2013-11-07 13:42:05 +01:00
parent 146984f2fc
commit c086800e58
11 changed files with 2422 additions and 64 deletions

View File

@ -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)

View File

@ -0,0 +1,509 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdio.h>
#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))
}
}

View File

@ -0,0 +1,82 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdio.h>
#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;
}

View File

@ -0,0 +1,142 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdio.h>
#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;
}

View File

@ -0,0 +1,481 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdio.h>
#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;
}

View File

@ -0,0 +1,135 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdio.h>
#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;
}

View File

@ -0,0 +1,373 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdio.h>
#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;
}

View File

@ -0,0 +1,111 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdio.h>
#include <string.h>
#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");
}

View File

@ -0,0 +1,120 @@
/*
* FAME - Fault Aware Micro-hypervisor Environment
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* 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 <stdint.h>
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__ */

View File

@ -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 */

View File

@ -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 <cassert>
@ -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*)(&regs.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, &regs.cpsr);
oocdw_read_reg(fail::RI_SPSR_ABT, &regs.spsr);
arm_instruction_t op;
decode_instruction(opcode, &regs, &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, &regs.cpsr);
accesses[i].address = 0;
arm_instruction_t op;
decode_instruction(opcode, &regs, &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);