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:
@ -28,7 +28,18 @@ if(BUILD_PANDA)
|
|||||||
#include_directories(${PROJECT_SOURCE_DIR}/src/core ${CMAKE_BINARY_DIR}/src/core)
|
#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.
|
# 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})
|
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)
|
add_dependencies(fail-client libfailopenocd_external)
|
||||||
|
|
||||||
|
|||||||
509
debuggers/openocd/opcode_parser/arm-addressmode.c
Normal file
509
debuggers/openocd/opcode_parser/arm-addressmode.c
Normal 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))
|
||||||
|
}
|
||||||
|
}
|
||||||
82
debuggers/openocd/opcode_parser/arm-condition.c
Normal file
82
debuggers/openocd/opcode_parser/arm-condition.c
Normal 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;
|
||||||
|
}
|
||||||
142
debuggers/openocd/opcode_parser/arm-opcode-coprocessor.c
Normal file
142
debuggers/openocd/opcode_parser/arm-opcode-coprocessor.c
Normal 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;
|
||||||
|
}
|
||||||
|
|
||||||
481
debuggers/openocd/opcode_parser/arm-opcode-data.c
Normal file
481
debuggers/openocd/opcode_parser/arm-opcode-data.c
Normal 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;
|
||||||
|
}
|
||||||
135
debuggers/openocd/opcode_parser/arm-opcode-ldmstm-branch.c
Normal file
135
debuggers/openocd/opcode_parser/arm-opcode-ldmstm-branch.c
Normal 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;
|
||||||
|
}
|
||||||
373
debuggers/openocd/opcode_parser/arm-opcode-ldrstr.c
Normal file
373
debuggers/openocd/opcode_parser/arm-opcode-ldrstr.c
Normal 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;
|
||||||
|
}
|
||||||
111
debuggers/openocd/opcode_parser/arm-opcode.c
Normal file
111
debuggers/openocd/opcode_parser/arm-opcode.c
Normal 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");
|
||||||
|
}
|
||||||
120
debuggers/openocd/opcode_parser/arm-opcode.h
Normal file
120
debuggers/openocd/opcode_parser/arm-opcode.h
Normal 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__ */
|
||||||
274
debuggers/openocd/opcode_parser/arm_opcodes.h
Normal file
274
debuggers/openocd/opcode_parser/arm_opcodes.h
Normal 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 */
|
||||||
@ -26,6 +26,8 @@ extern "C" {
|
|||||||
#include "jimtcl/jim.h"
|
#include "jimtcl/jim.h"
|
||||||
|
|
||||||
extern struct command_context *setup_command_handler(Jim_Interp *interp);
|
extern struct command_context *setup_command_handler(Jim_Interp *interp);
|
||||||
|
|
||||||
|
#include "opcode_parser/arm-opcode.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
@ -36,8 +38,7 @@ extern "C" {
|
|||||||
#include "sal/SALInst.hpp"
|
#include "sal/SALInst.hpp"
|
||||||
#include "sal/SALConfig.hpp"
|
#include "sal/SALConfig.hpp"
|
||||||
#include "sal/arm/ArmArchitecture.hpp"
|
#include "sal/arm/ArmArchitecture.hpp"
|
||||||
|
#include "util/ElfReader.hpp"
|
||||||
#include "sal/arm/ArmMemoryInstruction.hpp"
|
|
||||||
|
|
||||||
#include "util/Logger.hpp"
|
#include "util/Logger.hpp"
|
||||||
|
|
||||||
@ -80,6 +81,8 @@ static bool horizontal_step = false;
|
|||||||
*/
|
*/
|
||||||
static bool single_step_requested = false;
|
static bool single_step_requested = false;
|
||||||
|
|
||||||
|
static bool single_step_watch_memory = false;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Variables for monitoring BP/WP resources
|
* Variables for monitoring BP/WP resources
|
||||||
* Reset at reboot
|
* Reset at reboot
|
||||||
@ -87,11 +90,6 @@ static bool single_step_requested = false;
|
|||||||
static uint8_t free_watchpoints = 4;
|
static uint8_t free_watchpoints = 4;
|
||||||
static uint8_t free_breakpoints = 6;
|
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
|
* Elf reader for reading symbols in startup-code
|
||||||
*/
|
*/
|
||||||
@ -158,7 +156,7 @@ static void update_timers();
|
|||||||
static void freeze_timers();
|
static void freeze_timers();
|
||||||
static void unfreeze_timers();
|
static void unfreeze_timers();
|
||||||
static struct watchpoint *getHaltingWatchpoint();
|
static struct watchpoint *getHaltingWatchpoint();
|
||||||
static void getCurrentMemAccesses(struct halt_condition *accesses);
|
static bool getCurrentMemAccess(struct halt_condition *accesses);
|
||||||
static uint32_t getCurrentPC();
|
static uint32_t getCurrentPC();
|
||||||
static struct reg *get_reg_by_number(unsigned int num);
|
static struct reg *get_reg_by_number(unsigned int num);
|
||||||
static void read_dpm_register(uint32_t reg_num, uint32_t *data);
|
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;
|
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();
|
freeze_timers();
|
||||||
fail::simulator.onBreakpoint(NULL, pc, fail::ANY_ADDR);
|
fail::simulator.onBreakpoint(NULL, pc, fail::ANY_ADDR);
|
||||||
unfreeze_timers();
|
unfreeze_timers();
|
||||||
@ -386,12 +400,35 @@ int main(int argc, char *argv[])
|
|||||||
uint32_t dfar;
|
uint32_t dfar;
|
||||||
oocdw_read_reg(fail::RI_DFAR, &dfar);
|
oocdw_read_reg(fail::RI_DFAR, &dfar);
|
||||||
|
|
||||||
// ToDo: Get potential additional memory accesses and access width (InstructionAnalyzer)
|
/*
|
||||||
fail::MemoryInstruction mi;
|
* Analyze instruction to get access width. Also the base-address may differ from this in multiple
|
||||||
if (!inst_analyzer.eval((fail::address_t)pc, mi)) {
|
* data access instructions with decrement option.
|
||||||
LOG << "FATAL ERROR: Memory accessing instruction could not be analyzed" << endl;
|
* As some Register values have changed in the handler, we first must find the original values.
|
||||||
exit(-1);
|
* 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
|
* 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;
|
mmu_recovery_needed = true;
|
||||||
|
|
||||||
freeze_timers();
|
if (op.flags & (OP_FLAG_READ | OP_FLAG_WRITE)) {
|
||||||
fail::simulator.onMemoryAccess(NULL, dfar, mi.getWidth(), mi.isWriteAccess(), lr_abt - 8);
|
fail::simulator.onMemoryAccess(NULL, op.mem_addr, op.mem_size, op.flags & OP_FLAG_WRITE, lr_abt - 8);
|
||||||
unfreeze_timers();
|
} else {
|
||||||
|
LOG << "FATAL ERROR: Disassembling instruction in mmu handler failed" << endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
} else if (pc == sym_GenericTrapHandler) {
|
} else if (pc == sym_GenericTrapHandler) {
|
||||||
freeze_timers();
|
freeze_timers();
|
||||||
fail::simulator.onTrap(NULL, fail::ANY_TRAP);
|
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) {
|
} else if (hc->type == HALT_TYPE_SINGLESTEP) {
|
||||||
single_step_requested = true;
|
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) {
|
if ((hc->addr_len > 4) || !free_watchpoints) {
|
||||||
// Use MMU for watching
|
// Use MMU for watching
|
||||||
LOG << "Setting up MMU to watch memory range " << hex << hc->address << ":" << hc->addr_len << dec << endl;
|
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);
|
mmu_watch_add_waiting_list.push_back(mr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hc->address == fail::ANY_ADDR) {
|
||||||
|
single_step_watch_memory = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
LOG << "Adding WP " << hex << hc->address << dec << ":" << hc->addr_len << ":" <<
|
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;
|
((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--;
|
free_watchpoints--;
|
||||||
|
|
||||||
// Compare current memory access events with set watchpoint
|
// Compare current memory access event with set watchpoint
|
||||||
// (potential horizontal hop)
|
// (potential horizontal hop)
|
||||||
struct halt_condition mem_accesses [4];
|
struct halt_condition mem_access;
|
||||||
getCurrentMemAccesses(mem_accesses);
|
if (getCurrentMemAccess(&mem_access)) {
|
||||||
int i = 0;
|
if (mem_access.type == hc->type) {
|
||||||
while (mem_accesses[i].address) {
|
if ((mem_access.address < hc->address) && (mem_access.address + mem_access.addr_len >= hc->address)) {
|
||||||
// Look for overlapping similar memory access
|
horizontal_step = true;
|
||||||
if (mem_accesses[i].type == hc->type) {
|
} else if ((mem_access.address >= hc->address) && (hc->address + hc->addr_len >= mem_access.address)) {
|
||||||
if (mem_accesses[i].address < hc->address) {
|
horizontal_step = true;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hc->address == fail::ANY_ADDR) {
|
||||||
|
single_step_watch_memory = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
watchpoint_remove(target_a9, hc->address);
|
watchpoint_remove(target_a9, hc->address);
|
||||||
free_watchpoints++;
|
free_watchpoints++;
|
||||||
LOG << hex << "Removing WP " << hc->address << ":" << hc->addr_len << ":" <<
|
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);
|
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)
|
void oocdw_read_reg(uint32_t reg_num, uint32_t *data)
|
||||||
{
|
{
|
||||||
assert((target_a9->state == TARGET_HALTED) && "Target not halted");
|
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:
|
case fail::RI_R14:
|
||||||
/* fall through */
|
/* fall through */
|
||||||
case fail::RI_R15:
|
case fail::RI_R15:
|
||||||
{
|
read_processor_register(reg_num, data);
|
||||||
struct reg *reg = get_reg_by_number(reg_num);
|
break;
|
||||||
|
case fail::RI_R8_FIQ:
|
||||||
if (reg->valid == 0) {
|
read_processor_register(16, data);
|
||||||
reg->type->get(reg);
|
break;
|
||||||
}
|
case fail::RI_R9_FIQ:
|
||||||
|
read_processor_register(17, data);
|
||||||
*data = *((uint32_t*)(reg->value));
|
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;
|
break;
|
||||||
case fail::RI_LR_ABT:
|
case fail::RI_LR_ABT:
|
||||||
{
|
read_processor_register(28, data);
|
||||||
struct reg *reg = get_reg_by_number(28);
|
break;
|
||||||
|
case fail::RI_SP_UND:
|
||||||
if (reg->valid == 0) {
|
read_processor_register(29, data);
|
||||||
reg->type->get(reg);
|
break;
|
||||||
}
|
case fail::RI_LR_UND:
|
||||||
|
read_processor_register(30, data);
|
||||||
*data = *((uint32_t*)(reg->value));
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG << "ERROR: Register with id " << reg_num << " unknown." << endl;
|
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
|
* TODO implement analysis of current instruction in combination
|
||||||
* with register contents
|
* 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
|
// ToDo: Get all memory access events of current
|
||||||
// instruction. For now return empty array.
|
// instruction. For now return empty array.
|
||||||
|
|
||||||
uint32_t pc = getCurrentPC();
|
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?
|
for (int i = 0; i < 16; i++) {
|
||||||
if (inst_analyzer.eval(pc, mi)) {
|
oocdw_read_reg(i, &(regs.r[i]));
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
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()
|
static void freeze_timers()
|
||||||
{
|
{
|
||||||
LOG << "FREEZE TIMERS" << endl;
|
// LOG << "FREEZE TIMERS" << endl;
|
||||||
gettimeofday(&freeze_begin, NULL);
|
gettimeofday(&freeze_begin, NULL);
|
||||||
for (int i = 0; i < P_MAX_TIMERS; i++) {
|
for (int i = 0; i < P_MAX_TIMERS; i++) {
|
||||||
if (timers[i].inUse) {
|
if (timers[i].inUse) {
|
||||||
@ -1697,7 +1817,7 @@ static void freeze_timers()
|
|||||||
|
|
||||||
static void unfreeze_timers()
|
static void unfreeze_timers()
|
||||||
{
|
{
|
||||||
LOG << "UNFREEZE TIMERS" << endl;
|
// LOG << "UNFREEZE TIMERS" << endl;
|
||||||
struct timeval freeze_end, freeze_delta;
|
struct timeval freeze_end, freeze_delta;
|
||||||
gettimeofday(&freeze_end, NULL);
|
gettimeofday(&freeze_end, NULL);
|
||||||
timersub(&freeze_end, &freeze_begin, &freeze_delta);
|
timersub(&freeze_end, &freeze_begin, &freeze_delta);
|
||||||
|
|||||||
Reference in New Issue
Block a user