mirror of
https://github.com/radareorg/radare2.git
synced 2024-12-11 06:55:01 +00:00
708 lines
20 KiB
C
708 lines
20 KiB
C
/* radare - LGPL - Copyright 2016-2017 - bobby.smiles32@gmail.com */
|
|
/*
|
|
* TODO: finish esil support of the non vector instructions
|
|
* TODO: implement vector instruction using custom esil commands
|
|
* (will be easier than pure esil approach)
|
|
* TODO: refactor code to simplify per opcode analysis
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <r_types.h>
|
|
#include <r_lib.h>
|
|
#include <r_asm.h>
|
|
#include <r_anal.h>
|
|
#include "rsp_idec.h"
|
|
|
|
static int rsp_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *b, int len) {
|
|
int i;
|
|
typedef struct {
|
|
RAnalValue* value;
|
|
char esil[32];
|
|
} ParsedOperands;
|
|
|
|
ParsedOperands parsed_operands[RSP_MAX_OPNDS];
|
|
memset (parsed_operands, 0, sizeof (ParsedOperands) * RSP_MAX_OPNDS);
|
|
ut32 iw;
|
|
rsp_instruction r_instr;
|
|
|
|
if (!op) {
|
|
return 4;
|
|
}
|
|
|
|
memset (op, 0, sizeof (RAnalOp));
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
op->size = 4;
|
|
op->jump = UT64_MAX;
|
|
op->fail = UT64_MAX;
|
|
op->addr = addr;
|
|
r_strbuf_init (&op->esil);
|
|
r_strbuf_set (&op->esil, "TODO");
|
|
|
|
iw = r_read_ble32 (b, anal->big_endian);
|
|
r_instr = rsp_instruction_decode (addr, iw);
|
|
|
|
/* parse operands */
|
|
for (i = 0; i < r_instr.noperands; ++i) {
|
|
parsed_operands[i].value = r_anal_value_new ();
|
|
parsed_operands[i].esil[0] = '\0';
|
|
|
|
switch (r_instr.operands[i].type) {
|
|
case RSP_OPND_GP_REG:
|
|
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%s", rsp_gp_reg_soft_names[r_instr.operands[i].u]);
|
|
parsed_operands[i].value->reg = r_reg_get (anal->reg, rsp_gp_reg_soft_names[r_instr.operands[i].u], R_REG_TYPE_GPR);
|
|
break;
|
|
case RSP_OPND_ZIMM:
|
|
case RSP_OPND_SHIFT_AMOUNT:
|
|
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%"PFMT64d, r_instr.operands[i].u);
|
|
parsed_operands[i].value->imm = op->val = r_instr.operands[i].u;
|
|
break;
|
|
case RSP_OPND_SIMM:
|
|
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%"PFMT64d, r_instr.operands[i].s);
|
|
parsed_operands[i].value->imm = op->val = r_instr.operands[i].s;
|
|
break;
|
|
case RSP_OPND_BASE_OFFSET:
|
|
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil),
|
|
"%"PFMT64d",%s,+", r_instr.operands[i].s, rsp_gp_reg_soft_names[r_instr.operands[i].u]);
|
|
parsed_operands[i].value->reg = r_reg_get (anal->reg, rsp_gp_reg_soft_names[r_instr.operands[i].u], R_REG_TYPE_GPR);
|
|
parsed_operands[i].value->imm = r_instr.operands[i].s;
|
|
break;
|
|
case RSP_OPND_OFFSET:
|
|
case RSP_OPND_TARGET:
|
|
op->delay = 1;
|
|
op->jump = r_instr.operands[i].u;
|
|
op->fail = rsp_mem_addr (addr + 8, RSP_IMEM_OFFSET);
|
|
op->eob = 1;
|
|
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%"PFMT64d, r_instr.operands[i].u);
|
|
parsed_operands[i].value->imm = r_instr.operands[i].u;
|
|
parsed_operands[i].value->memref = 4;
|
|
break;
|
|
case RSP_OPND_C0_REG:
|
|
snprintf (parsed_operands[i].esil, sizeof (parsed_operands[i].esil), "%s", rsp_c0_reg_names[r_instr.operands[i].u]);
|
|
parsed_operands[i].value->reg = r_reg_get (anal->reg, rsp_c0_reg_names[r_instr.operands[i].u], R_REG_TYPE_GPR);
|
|
break;
|
|
case RSP_OPND_C2_CREG:
|
|
case RSP_OPND_C2_ACCU:
|
|
case RSP_OPND_C2_VREG:
|
|
case RSP_OPND_C2_VREG_BYTE:
|
|
case RSP_OPND_C2_VREG_SCALAR:
|
|
case RSP_OPND_C2_VREG_ELEMENT:
|
|
/* TODO */
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (r_instr.opcode) {
|
|
case RSP_OP_INVALID:
|
|
op->type = R_ANAL_OP_TYPE_ILL;
|
|
break;
|
|
case RSP_OP_NOP:
|
|
op->type = R_ANAL_OP_TYPE_NOP;
|
|
r_strbuf_set (&op->esil, ",");
|
|
break;
|
|
case RSP_OP_BREAK:
|
|
op->type = R_ANAL_OP_TYPE_TRAP;
|
|
// TODO
|
|
break;
|
|
case RSP_OP_LUI:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_ADD:
|
|
case RSP_OP_ADDU:
|
|
case RSP_OP_ADDI:
|
|
case RSP_OP_ADDIU:
|
|
op->type = R_ANAL_OP_TYPE_ADD;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,+,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_SUB:
|
|
case RSP_OP_SUBU:
|
|
op->type = R_ANAL_OP_TYPE_SUB;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,-,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_AND:
|
|
case RSP_OP_ANDI:
|
|
op->type = R_ANAL_OP_TYPE_AND;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,&,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_OR:
|
|
case RSP_OP_ORI:
|
|
op->type = R_ANAL_OP_TYPE_OR;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,|,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_XOR:
|
|
case RSP_OP_XORI:
|
|
op->type = R_ANAL_OP_TYPE_XOR;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,^,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_NOR:
|
|
op->type = R_ANAL_OP_TYPE_NOR;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
// TODO
|
|
break;
|
|
case RSP_OP_SLL:
|
|
case RSP_OP_SLLV:
|
|
op->type = R_ANAL_OP_TYPE_SHL;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,<<,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_SRL:
|
|
case RSP_OP_SRLV:
|
|
op->type = R_ANAL_OP_TYPE_SHR;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,>>,%s,=", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_SRA:
|
|
case RSP_OP_SRAV:
|
|
op->type = R_ANAL_OP_TYPE_SAR;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
// TODO
|
|
break;
|
|
case RSP_OP_SLT:
|
|
case RSP_OP_SLTU:
|
|
case RSP_OP_SLTI:
|
|
case RSP_OP_SLTIU:
|
|
op->type = R_ANAL_OP_TYPE_CMOV;
|
|
op->cond = R_ANAL_COND_LT;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[1] = parsed_operands[2].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,<,$z,?{,1,%s,=,}{,0,%s,=,}", parsed_operands[2].esil, parsed_operands[1].esil, parsed_operands[0].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_J:
|
|
op->type = R_ANAL_OP_TYPE_JMP;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
r_strbuf_setf (&op->esil, "%s,PC,=", parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_JAL:
|
|
op->type = R_ANAL_OP_TYPE_CALL;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
r_strbuf_setf (&op->esil, "%s,PC,=,0x%08x,RA,=", parsed_operands[0].esil, op->fail);
|
|
break;
|
|
case RSP_OP_JR:
|
|
/* if register is RA, this is a return */
|
|
op->type = (r_instr.operands[0].u == 29)
|
|
? R_ANAL_OP_TYPE_RET
|
|
: R_ANAL_OP_TYPE_UJMP;
|
|
op->delay = 1;
|
|
op->eob = 1;
|
|
op->fail = rsp_mem_addr (addr + 8, RSP_IMEM_OFFSET);
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
r_strbuf_setf (&op->esil, "%s,PC,=", parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_BEQ:
|
|
op->type = R_ANAL_OP_TYPE_CJMP;
|
|
op->cond = R_ANAL_COND_EQ;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,==,$z,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil, parsed_operands[2].esil);
|
|
break;
|
|
case RSP_OP_BNE:
|
|
op->type = R_ANAL_OP_TYPE_CJMP;
|
|
op->cond = R_ANAL_COND_NE;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,==,$z,!,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil, parsed_operands[2].esil);
|
|
break;
|
|
case RSP_OP_BLEZ:
|
|
op->type = R_ANAL_OP_TYPE_CJMP;
|
|
op->cond = R_ANAL_COND_LE;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "0,%s,<=,$z,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_BGTZ:
|
|
op->type = R_ANAL_OP_TYPE_CJMP;
|
|
op->cond = R_ANAL_COND_GT;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "0,%s,>,$z,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_BLTZ:
|
|
op->type = R_ANAL_OP_TYPE_CJMP;
|
|
op->cond = R_ANAL_COND_LT;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "0,%s,<,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_BGEZ:
|
|
op->type = R_ANAL_OP_TYPE_CJMP;
|
|
op->cond = R_ANAL_COND_GE;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "0,%s,>=,?{,%s,PC,=,}", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_BLTZAL:
|
|
op->type = R_ANAL_OP_TYPE_CCALL;
|
|
op->cond = R_ANAL_COND_LT;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
// TODO
|
|
break;
|
|
case RSP_OP_BGEZAL:
|
|
op->type = R_ANAL_OP_TYPE_CCALL;
|
|
op->cond = R_ANAL_COND_GE;
|
|
op->dst = r_anal_value_new ();
|
|
op->dst->reg = r_reg_get (anal->reg, "PC", R_REG_TYPE_GPR);
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->src[1] = parsed_operands[1].value;
|
|
// TODO
|
|
break;
|
|
case RSP_OP_LB:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[0]->memref = op->refptr = 1;
|
|
// FIXME: sign extend
|
|
r_strbuf_setf (&op->esil, "%s,[1],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_LH:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[0]->memref = op->refptr = 2;
|
|
// FIXME: sign extend
|
|
r_strbuf_setf (&op->esil, "%s,[2],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_LW:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[0]->memref = op->refptr = 4;
|
|
r_strbuf_setf (&op->esil, "%s,[4],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_LBU:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[0]->memref = op->refptr = 1;
|
|
r_strbuf_setf (&op->esil, "%s,[1],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_LHU:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
op->src[0]->memref = op->refptr = 2;
|
|
r_strbuf_setf (&op->esil, "%s,[2],%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_SB:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->dst = parsed_operands[1].value;
|
|
op->dst->memref = op->refptr = 1;
|
|
r_strbuf_setf (&op->esil, "%s,%s,=[1]", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_SH:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->dst = parsed_operands[1].value;
|
|
op->dst->memref = op->refptr = 2;
|
|
r_strbuf_setf (&op->esil, "%s,%s,=[2]", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_SW:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->dst = parsed_operands[1].value;
|
|
op->dst->memref = op->refptr = 4;
|
|
r_strbuf_setf (&op->esil, "%s,%s,=[4]", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_MFC0:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
op->dst = parsed_operands[0].value;
|
|
op->src[0] = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,=", parsed_operands[1].esil, parsed_operands[0].esil);
|
|
break;
|
|
case RSP_OP_MTC0:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
op->src[0] = parsed_operands[0].value;
|
|
op->dst = parsed_operands[1].value;
|
|
r_strbuf_setf (&op->esil, "%s,%s,=", parsed_operands[0].esil, parsed_operands[1].esil);
|
|
break;
|
|
case RSP_OP_MFC2:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
op->dst = parsed_operands[0].value;
|
|
//op->src[0] = parsed_operands[1].value;
|
|
break;
|
|
case RSP_OP_MTC2:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
op->src[0] = parsed_operands[0].value;
|
|
//op->dst = parsed_operands[1].value;
|
|
break;
|
|
case RSP_OP_CFC2:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
break;
|
|
case RSP_OP_CTC2:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
break;
|
|
case RSP_OP_VMULF:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMULU:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMUDL:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMUDM:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMUDN:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMUDH:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMACF:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMACU:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMADL:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMADM:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMADN:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VMADH:
|
|
op->type = R_ANAL_OP_TYPE_MUL;
|
|
break;
|
|
case RSP_OP_VADD:
|
|
op->type = R_ANAL_OP_TYPE_ADD;
|
|
break;
|
|
case RSP_OP_VSUB:
|
|
op->type = R_ANAL_OP_TYPE_SUB;
|
|
break;
|
|
case RSP_OP_VABS:
|
|
op->type = R_ANAL_OP_TYPE_ABS;
|
|
break;
|
|
case RSP_OP_VADDC:
|
|
op->type = R_ANAL_OP_TYPE_ADD;
|
|
break;
|
|
case RSP_OP_VSUBC:
|
|
op->type = R_ANAL_OP_TYPE_SUB;
|
|
break;
|
|
case RSP_OP_VSAR:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
break;
|
|
case RSP_OP_VLT:
|
|
op->type = R_ANAL_OP_TYPE_CMP;
|
|
op->cond = R_ANAL_COND_LT;
|
|
break;
|
|
case RSP_OP_VEQ:
|
|
op->type = R_ANAL_OP_TYPE_CMP;
|
|
op->cond = R_ANAL_COND_EQ;
|
|
break;
|
|
case RSP_OP_VNE:
|
|
op->type = R_ANAL_OP_TYPE_CMP;
|
|
op->cond = R_ANAL_COND_NE;
|
|
break;
|
|
case RSP_OP_VGE:
|
|
op->type = R_ANAL_OP_TYPE_CMP;
|
|
op->cond = R_ANAL_COND_GE;
|
|
break;
|
|
case RSP_OP_VCL:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VCH:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VCR:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VMRG:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VAND:
|
|
op->type = R_ANAL_OP_TYPE_AND;
|
|
break;
|
|
case RSP_OP_VNAND:
|
|
op->type = R_ANAL_OP_TYPE_AND;
|
|
break;
|
|
case RSP_OP_VOR:
|
|
op->type = R_ANAL_OP_TYPE_OR;
|
|
break;
|
|
case RSP_OP_VNOR:
|
|
op->type = R_ANAL_OP_TYPE_NOR;
|
|
break;
|
|
case RSP_OP_VXOR:
|
|
op->type = R_ANAL_OP_TYPE_XOR;
|
|
break;
|
|
case RSP_OP_VNXOR:
|
|
op->type = R_ANAL_OP_TYPE_XOR;
|
|
break;
|
|
case RSP_OP_VRCP:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VRCPL:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VRCPH:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VMOV:
|
|
op->type = R_ANAL_OP_TYPE_MOV;
|
|
break;
|
|
case RSP_OP_VRSQ:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VRSQL:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VRSQH:
|
|
op->type = R_ANAL_OP_TYPE_UNK;
|
|
break;
|
|
case RSP_OP_VNOP:
|
|
op->type = R_ANAL_OP_TYPE_NOP;
|
|
break;
|
|
case RSP_OP_LBV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LSV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LLV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LDV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LQV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LRV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LPV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LUV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LHV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LFV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_LTV:
|
|
op->type = R_ANAL_OP_TYPE_LOAD;
|
|
break;
|
|
case RSP_OP_SBV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SSV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SLV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SDV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SQV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SRV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SPV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SUV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SHV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SFV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_SWV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
case RSP_OP_STV:
|
|
op->type = R_ANAL_OP_TYPE_STORE;
|
|
break;
|
|
default: break;
|
|
}
|
|
|
|
return op->size;
|
|
}
|
|
|
|
|
|
static char *get_reg_profile(RAnal *anal) {
|
|
static const char *p =
|
|
"=PC pc\n"
|
|
"=SP sp\n"
|
|
"=A0 a0\n"
|
|
"=A1 a1\n"
|
|
"=A2 a2\n"
|
|
"=A3 a3\n"
|
|
"=R0 v0\n"
|
|
"=R1 v1\n"
|
|
/* GP registers */
|
|
"gpr zero .32 0 0\n"
|
|
"gpr at .32 4 0\n"
|
|
"gpr v0 .32 8 0\n"
|
|
"gpr v1 .32 12 0\n"
|
|
"gpr a0 .32 16 0\n"
|
|
"gpr a1 .32 20 0\n"
|
|
"gpr a2 .32 24 0\n"
|
|
"gpr a3 .32 28 0\n"
|
|
"gpr t0 .32 32 0\n"
|
|
"gpr t1 .32 36 0\n"
|
|
"gpr t2 .32 40 0\n"
|
|
"gpr t3 .32 44 0\n"
|
|
"gpr t4 .32 48 0\n"
|
|
"gpr t5 .32 52 0\n"
|
|
"gpr t6 .32 56 0\n"
|
|
"gpr t7 .32 60 0\n"
|
|
"gpr s0 .32 64 0\n"
|
|
"gpr s1 .32 68 0\n"
|
|
"gpr s2 .32 72 0\n"
|
|
"gpr s3 .32 76 0\n"
|
|
"gpr s4 .32 80 0\n"
|
|
"gpr s5 .32 84 0\n"
|
|
"gpr s6 .32 88 0\n"
|
|
"gpr s7 .32 92 0\n"
|
|
"gpr t8 .32 96 0\n"
|
|
"gpr t9 .32 100 0\n"
|
|
"gpr k0 .32 104 0\n"
|
|
"gpr k1 .32 108 0\n"
|
|
"gpr gp .32 112 0\n"
|
|
"gpr sp .32 116 0\n"
|
|
"gpr s8 .32 120 0\n"
|
|
"gpr ra .32 124 0\n"
|
|
/* PC register */
|
|
"gpr pc .32 128 0\n"
|
|
/* C0 registers */
|
|
"gpr $c0 .32 132 0\n"
|
|
"gpr $c1 .32 136 0\n"
|
|
"gpr $c2 .32 140 0\n"
|
|
"gpr $c3 .32 144 0\n"
|
|
"gpr $c4 .32 148 0\n"
|
|
"gpr $c5 .32 152 0\n"
|
|
"gpr $c6 .32 156 0\n"
|
|
"gpr $c7 .32 160 0\n"
|
|
"gpr $c8 .32 164 0\n"
|
|
"gpr $c9 .32 168 0\n"
|
|
"gpr $c10 .32 172 0\n"
|
|
"gpr $c11 .32 176 0\n"
|
|
"gpr $c12 .32 180 0\n"
|
|
"gpr $c13 .32 184 0\n"
|
|
"gpr $c14 .32 188 0\n"
|
|
"gpr $c15 .32 192 0\n"
|
|
/* C2 vector registers - (32 x 128 bit) */
|
|
"gpr $v0 .128 196 0\n"
|
|
"gpr $v1 .128 212 0\n"
|
|
"gpr $v2 .128 228 0\n"
|
|
"gpr $v3 .128 244 0\n"
|
|
"gpr $v4 .128 260 0\n"
|
|
"gpr $v5 .128 276 0\n"
|
|
"gpr $v6 .128 292 0\n"
|
|
"gpr $v7 .128 308 0\n"
|
|
"gpr $v8 .128 324 0\n"
|
|
"gpr $v9 .128 340 0\n"
|
|
"gpr $v10 .128 356 0\n"
|
|
"gpr $v11 .128 372 0\n"
|
|
"gpr $v12 .128 388 0\n"
|
|
"gpr $v13 .128 404 0\n"
|
|
"gpr $v14 .128 420 0\n"
|
|
"gpr $v15 .128 436 0\n"
|
|
"gpr $v16 .128 452 0\n"
|
|
"gpr $v17 .128 468 0\n"
|
|
"gpr $v18 .128 484 0\n"
|
|
"gpr $v19 .128 500 0\n"
|
|
"gpr $v20 .128 516 0\n"
|
|
"gpr $v21 .128 532 0\n"
|
|
"gpr $v22 .128 548 0\n"
|
|
"gpr $v23 .128 564 0\n"
|
|
"gpr $v24 .128 580 0\n"
|
|
"gpr $v25 .128 596 0\n"
|
|
"gpr $v26 .128 612 0\n"
|
|
"gpr $v27 .128 628 0\n"
|
|
"gpr $v28 .128 644 0\n"
|
|
"gpr $v29 .128 660 0\n"
|
|
"gpr $v30 .128 676 0\n"
|
|
"gpr $v31 .128 692 0\n"
|
|
/* C2 control registers - (vco, vcc, vce) */
|
|
"gpr $vco .128 708 0\n"
|
|
"gpr $vcc .128 724 0\n"
|
|
"gpr $vce .128 740 0\n"
|
|
;
|
|
|
|
return strdup (p);
|
|
}
|
|
|
|
static int archinfo(RAnal *anal, int q) {
|
|
return 4;
|
|
}
|
|
|
|
RAnalPlugin r_anal_plugin_rsp = {
|
|
.name = "rsp",
|
|
.desc = "RSP code analysis plugin",
|
|
.license = "LGPL3",
|
|
.arch = "rsp",
|
|
.esil = true,
|
|
.bits = 32,
|
|
.op = &rsp_op,
|
|
.archinfo = &archinfo,
|
|
.get_reg_profile = &get_reg_profile,
|
|
};
|
|
|
|
#ifndef CORELIB
|
|
RLibStruct radare_plugin = {
|
|
.type = R_LIB_TYPE_ANAL,
|
|
.data = &r_anal_plugin_rsp,
|
|
.version = R2_VERSION
|
|
};
|
|
#endif
|