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:
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;
|
||||
}
|
||||
Reference in New Issue
Block a user