Initial RISC-V 32/64 analysis

- Added risc-v to README
- Fixed ret detection, and branches
- Fix all the warns
This commit is contained in:
qnix 2015-10-30 22:31:57 -07:00 committed by pancake
parent 9092338930
commit 304cddfec3
6 changed files with 182 additions and 2 deletions

View File

@ -31,7 +31,7 @@ code, debugging programs, attaching to remote gdb servers, ..
* 6502, 8051, CRIS, H8/300, LH5801, T8200, arc, arm, avr, bf, blackfin, csr,
dalvik, dcpu16, gameboy, i386, i4004, i8080, m68k, malbolge, mips, mips, msil,
msp430, nios II, powerpc, rar, sh, snes, sparc, tms320 (c54x c55x c55+), V810,
x86-64, zimg.
x86-64, zimg, risc-v.
* **File Formats:**
* bios, CGC, dex, elf, elf64, filesystem, java, fatmach0, mach0,

View File

@ -12,7 +12,7 @@ all: ${ALL_TARGETS} ;
ALL_TARGETS=
# TODO: rename to enabled plugins
ARCHS=null.mk x86_udis.mk ppc_gnu.mk ppc_cs.mk arm_gnu.mk avr.mk csr.mk dalvik.mk sh.mk ebc.mk gb.mk malbolge.mk ws.mk h8300.mk cr16.mk v850.mk msp430.mk sparc_gnu.mk sparc_cs.mk x86_cs.mk cris.mk 6502.mk snes.mk
ARCHS=null.mk x86_udis.mk ppc_gnu.mk ppc_cs.mk arm_gnu.mk avr.mk csr.mk dalvik.mk sh.mk ebc.mk gb.mk malbolge.mk ws.mk h8300.mk cr16.mk v850.mk msp430.mk sparc_gnu.mk sparc_cs.mk x86_cs.mk cris.mk 6502.mk snes.mk riscv.mk
include $(ARCHS)
clean:

169
libr/anal/p/anal_riscv.c Normal file
View File

@ -0,0 +1,169 @@
/* radare - LGPL - Copyright 2015 - qnix */
#include <string.h>
#include <r_types.h>
#include <r_lib.h>
#include <r_asm.h>
#include <r_anal.h>
#include "../../asm/arch/riscv/riscv-opc.c"
#include "../../asm/arch/riscv/riscv.h"
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,\
_14,_15,_16,_17,_18,_19,_20, N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__,20,19,18,17,16,15,14,\
13,12,11,10,9,8,7,6,5,4,3,2,1)
static int init = 0;
static int _is_any(int n, const char *str, ...) {
char *cur;
va_list va;
va_start (va, str);
while (n-- > 0) {
cur = va_arg (va, char *);
if (!strcmp (str, cur)) return 1;
}
va_end (va);
return 0;
}
static struct riscv_opcode *get_opcode (insn_t word) {
struct riscv_opcode *op = NULL;
static const struct riscv_opcode *riscv_hash[OP_MASK_OP + 1] = {0};
#define OP_HASH_IDX(i) ((i) & (riscv_insn_length (i) == 2 ? 0x3 : OP_MASK_OP))
if (!init) {
for (op=riscv_opcodes; op < &riscv_opcodes[NUMOPCODES]; op++) {
if (!riscv_hash[OP_HASH_IDX (op->match)]) {
riscv_hash[OP_HASH_IDX (op->match)] = op;
}
}
init = 1;
}
return (struct riscv_opcode *)riscv_hash[OP_HASH_IDX (word)];
}
static int riscv_op(RAnal *anal, RAnalOp *op, ut64 addr, const ut8 *data, int len)
{
const int no_alias = 1;
struct riscv_opcode *o = NULL;
insn_t word = 0;
int xlen = anal->bits;
op->size = 4;
op->addr = addr;
op->type = R_ANAL_OP_TYPE_UNK;
memcpy (&word, data, 4);
o = get_opcode (word);
if (o == NULL) {
return op->size;
}
for(; o < &riscv_opcodes[NUMOPCODES]; o++) {
if ( !(o->match_func)(o, word) ) continue;
if ( no_alias && (o->pinfo & INSN_ALIAS) ) continue;
if ( isdigit (o->subset[0]) && atoi (o->subset) != xlen) continue;
if ( o == NULL) return op->size;
else break;
}
#define is_any(...) _is_any(NARGS(__VA_ARGS__), o->name, __VA_ARGS__)
// branch/jumps/calls/rets
if (is_any ("jal")) {
// decide wether it's ret or call
int rd = (word >> OP_SH_RD) & OP_MASK_RD;
op->type = (rd == 0) ? R_ANAL_OP_TYPE_RET : R_ANAL_OP_TYPE_CALL;
op->jump = EXTRACT_UJTYPE_IMM (word) + addr;
op->fail = addr + 4;
} else if(is_any ("jr")) {
op->type = R_ANAL_OP_TYPE_JMP;
} else if(is_any ("j", "jump")) {
op->type = R_ANAL_OP_TYPE_JMP;
} else if(is_any ("jalr", "ret")) { // ?
op->type = R_ANAL_OP_TYPE_UCALL;
} else if(is_any ("beqz", "beq", "blez", "bgez", "ble",
"bleu", "bge", "bgeu", "bltz", "bgtz", "blt", "bltu",
"bgt", "bgtu", "bnez", "bne")) {
op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = EXTRACT_SBTYPE_IMM (word) + addr;
op->fail = addr + 4;
// math
} else if(is_any ("addi", "addw", "addiw", "add")) {
op->type = R_ANAL_OP_TYPE_ADD;
} else if(is_any ("subi", "subw", "sub")) {
op->type = R_ANAL_OP_TYPE_SUB;
} else if(is_any ("xori", "xor")) {
op->type = R_ANAL_OP_TYPE_XOR;
} else if(is_any ("andi", "and")) {
op->type = R_ANAL_OP_TYPE_AND;
} else if(is_any ("ori", "or")) {
op->type = R_ANAL_OP_TYPE_OR;
} else if(is_any ("not")) {
op->type = R_ANAL_OP_TYPE_NOT;
} else if(is_any ("mul", "mulh", "mulhu", "mulhsu", "mulw")) {
op->type = R_ANAL_OP_TYPE_MUL;
} else if(is_any ("div", "divu", "divw", "divuw")) {
op->type = R_ANAL_OP_TYPE_DIV;
// memory
} else if (is_any ("sd", "sb", "sh", "sw")) {
op->type = R_ANAL_OP_TYPE_STORE;
} else if (is_any ("ld", "lw", "lwu", "lui", "li",
"lb", "lbu", "lh", "lhu", "la", "lla")) {
op->type = R_ANAL_OP_TYPE_LOAD;
}
return op->size;
}
#if 0
static int set_reg_profile(RAnal *anal) {
char *p =
"=pc pc\n"
"=sp sp\n"
"gpr a .8 0 0\n"
"gpr x .8 1 0\n"
"gpr y .8 2 0\n"
"gpr flags .8 3 0\n"
"gpr C .1 .24 0\n"
"gpr Z .1 .25 0\n"
"gpr I .1 .26 0\n"
"gpr D .1 .27 0\n"
// bit 4 (.28) is NOT a real flag.
// "gpr B .1 .28 0\n"
// bit 5 (.29) is not used
"gpr V .1 .30 0\n"
"gpr N .1 .31 0\n"
"gpr sp .8 4 0\n"
"gpr pc .16 5 0\n";
return r_reg_set_profile_string (anal->reg, p);
}
#endif
struct r_anal_plugin_t r_anal_plugin_riscv = {
.name = "riscv",
.desc = "RISC-V analysis plugin",
.license = "GPL",
.arch = "riscv",
.bits = 16|32,
.op = &riscv_op,
//.set_reg_profile = &set_reg_profile,
};
#ifndef CORELIB
struct r_lib_struct_t radare_plugin = {
.type = R_LIB_TYPE_ANAL,
.data = &r_anal_plugin_riscv,
.version = R2_VERSION
};
#endif

9
libr/anal/p/riscv.mk Normal file
View File

@ -0,0 +1,9 @@
OBJ_RISCV=anal_riscv.o
STATIC_OBJ+=${OBJ_RISCV}
TARGET_RISCV=anal_riscv.${EXT_SO}
ALL_TARGETS+=${TARGET_RISCV}
${TARGET_RISCV}: ${OBJ_RISCV}
${CC} $(call libname,anal_RISCV) ${LDFLAGS} ${CFLAGS} -o anal_riscv.${EXT_SO} ${OBJ_RISCV}

View File

@ -1517,6 +1517,7 @@ extern RAnalPlugin r_anal_plugin_cris;
extern RAnalPlugin r_anal_plugin_v810;
extern RAnalPlugin r_anal_plugin_6502;
extern RAnalPlugin r_anal_plugin_snes;
extern RAnalPlugin r_anal_plugin_riscv;
#ifdef __cplusplus
}
#endif

View File

@ -37,6 +37,7 @@ anal.z80
anal.v810
anal.6502
anal.snes
anal.riscv
asm.6502
asm.8051
asm.arc