Files
fail/debuggers/openocd/opcode_parser/arm-addressmode.c
Horst Schirmeier 85ef86b22c openocd: opcode parser relicensed
Relicensed version taken from: https://www.andreasheinig.de/project:inject

Change-Id: I740fd7b0c802e8fc6c1c54eb49830faf61dc8a25
2014-06-03 19:17:05 +02:00

530 lines
12 KiB
C

/*
* ARM JTAG Fault Injector
*
* Author: Andreas Heinig <andreas.heinig@gmx.de>
*
* Copyright (C) 2011-2014 Department of Computer Science,
* Design Automation of Embedded Systems Group,
* Dortmund University of Technology, all rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#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))
}
}