diff --git a/README.md b/README.md index 73c1e42c85..6e12bd638f 100644 --- a/README.md +++ b/README.md @@ -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, diff --git a/libr/anal/p/Makefile b/libr/anal/p/Makefile index 866cd79cb6..64dd295cc7 100644 --- a/libr/anal/p/Makefile +++ b/libr/anal/p/Makefile @@ -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: diff --git a/libr/anal/p/anal_riscv.c b/libr/anal/p/anal_riscv.c new file mode 100644 index 0000000000..68669a295e --- /dev/null +++ b/libr/anal/p/anal_riscv.c @@ -0,0 +1,169 @@ +/* radare - LGPL - Copyright 2015 - qnix */ + +#include +#include +#include +#include +#include +#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 diff --git a/libr/anal/p/riscv.mk b/libr/anal/p/riscv.mk new file mode 100644 index 0000000000..cca198e187 --- /dev/null +++ b/libr/anal/p/riscv.mk @@ -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} diff --git a/libr/include/r_anal.h b/libr/include/r_anal.h index 83c6f2a2f9..a551268564 100644 --- a/libr/include/r_anal.h +++ b/libr/include/r_anal.h @@ -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 diff --git a/plugins.def.cfg b/plugins.def.cfg index 8cb5a60419..db87d66150 100644 --- a/plugins.def.cfg +++ b/plugins.def.cfg @@ -37,6 +37,7 @@ anal.z80 anal.v810 anal.6502 anal.snes +anal.riscv asm.6502 asm.8051 asm.arc