From e13281829cb7c8bf29c2e822a43a6b2f8e8dc3d2 Mon Sep 17 00:00:00 2001 From: Kamil Lorenc Date: Fri, 29 Nov 2019 11:35:16 +0100 Subject: [PATCH] Add support for or1k (OpenRISC) disasm+analysis (#15515) ##arch --- libr/anal/meson.build | 2 + libr/anal/p/anal_or1k.c | 209 ++++++++++++++++++ libr/anal/p/or1k.mk | 12 ++ libr/asm/arch/or1k/or1k_disas.c | 361 ++++++++++++++++++++++++++++++++ libr/asm/arch/or1k/or1k_disas.h | 181 ++++++++++++++++ libr/asm/meson.build | 5 +- libr/asm/p/asm_or1k.c | 177 ++++++++++++++++ libr/asm/p/or1k.mk | 11 + libr/include/r_anal.h | 1 + libr/include/r_asm.h | 1 + libr/meson.build | 2 + plugins.def.cfg | 2 + 12 files changed, 963 insertions(+), 1 deletion(-) create mode 100644 libr/anal/p/anal_or1k.c create mode 100644 libr/anal/p/or1k.mk create mode 100644 libr/asm/arch/or1k/or1k_disas.c create mode 100644 libr/asm/arch/or1k/or1k_disas.h create mode 100644 libr/asm/p/asm_or1k.c create mode 100644 libr/asm/p/or1k.mk diff --git a/libr/anal/meson.build b/libr/anal/meson.build index 2296a6c2a9..fc858f9574 100644 --- a/libr/anal/meson.build +++ b/libr/anal/meson.build @@ -66,6 +66,7 @@ r_anal_sources = [ 'p/anal_msp430.c', 'p/anal_nios2.c', 'p/anal_null.c', + 'p/anal_or1k.c', 'p/anal_pic.c', 'p/anal_ppc_cs.c', 'p/anal_ppc_gnu.c', @@ -101,6 +102,7 @@ r_anal_sources = [ '../asm/arch/hexagon/hexagon_disas.c', '../asm/arch/mcore/mcore.c', '../asm/arch/msp430/msp430_disas.c', + '../asm/arch/or1k/or1k_disas.c', '../asm/arch/pic/pic_midrange.c', '../asm/arch/ppc/libvle/vle.c', '../asm/arch/propeller/propeller_disas.c', diff --git a/libr/anal/p/anal_or1k.c b/libr/anal/p/anal_or1k.c new file mode 100644 index 0000000000..0f9a48321b --- /dev/null +++ b/libr/anal/p/anal_or1k.c @@ -0,0 +1,209 @@ +/* radare2 - LGPL - Copyright 2019 - v3l0c1r4pt0r */ + +#include +#include +#include +#include + +struct operands { + ut32 rd; + ut32 ra; + ut32 rb; + ut32 n; + ut32 k1; + ut32 k2; + ut32 k; + ut32 i; + ut32 l; +}; + +static ut32 cpu[32] = {0}; /* register contents */ +static ut32 cpu_enable; /* allows to treat only registers with known value as + valid */ + +/** + * \brief Convert raw N operand to complete address + * + * \param n immediate, as appearing in instruction + * \param mask n operand mask + * \param addr address of current instruction + * + * \return 64-bit address + */ +static ut64 n_oper_to_addr(ut32 n, ut32 mask, ut64 addr) { + /* sign extension returns 32b unsigned N, then it is multiplied by 4, made + * signed to support negative offsets, added to address and made unsigned + * again */ + return (ut64) ((st64) ((st32) (sign_extend(n, mask) << 2)) + addr); +} + +static int insn_to_op(RAnal *a, RAnalOp *op, ut64 addr, insn_t *descr, insn_extra_t *extra, ut32 insn) { + struct operands o = {0}; + insn_type_t type = type_of_opcode(descr, extra); + insn_type_descr_t *type_descr = &types[INSN_X]; + + /* only use type descriptor if it has some useful data */ + if (has_type_descriptor(type) && is_type_descriptor_defined(type)) { + type_descr = &types[type]; + } + + if (extra == NULL) { + op->type = descr->insn_type; + } else { + op->type = extra->insn_type; + } + + switch ((insn & INSN_OPCODE_MASK) >> INSN_OPCODE_SHIFT) { + case 0x00: /* l.j */ + o.n = get_operand_value(insn, type_descr, INSN_OPER_N); + op->eob = true; + op->jump = n_oper_to_addr(o.n, get_operand_mask(type_descr, INSN_OPER_N), + addr); + op->delay = 1; + break; + case 0x01: /* l.jal */ + o.n = get_operand_value(insn, type_descr, INSN_OPER_N); + op->eob = true; + op->jump = n_oper_to_addr(o.n, get_operand_mask(type_descr, INSN_OPER_N), + addr); + op->delay = 1; + break; + case 0x03: /* l.bnf */ + o.n = get_operand_value(insn, type_descr, INSN_OPER_N); + op->cond = R_ANAL_COND_NE; + op->jump = n_oper_to_addr(o.n, get_operand_mask(type_descr, INSN_OPER_N), + addr); + op->fail = addr + 8; + op->delay = 1; + break; + case 0x04: /* l.bf */ + o.n = get_operand_value(insn, type_descr, INSN_OPER_N); + op->cond = R_ANAL_COND_EQ; + op->jump = n_oper_to_addr(o.n, get_operand_mask(type_descr, INSN_OPER_N), + addr); + op->fail = addr + 8; + op->delay = 1; + break; + case 0x11: /* l.jr */ + o.rb = get_operand_value(insn, type_descr, INSN_OPER_B); + op->eob = true; + if (cpu_enable & (1 << o.rb)) { + op->jump = cpu[o.rb]; + } + op->delay = 1; + break; + case 0x12: /* l.jalr */ + o.rb = get_operand_value(insn, type_descr, INSN_OPER_B); + op->eob = true; + if (cpu_enable & (1 << o.rb)) { + op->jump = cpu[o.rb]; + } + op->delay = 1; + break; + case 0x06: /* extended */ + switch (insn & (1 << 16)) { + case 0: /* l.movhi */ + o.rd = get_operand_value(insn, type_descr, INSN_OPER_D); + o.k = get_operand_value(insn, type_descr, INSN_OPER_K); + cpu[o.rd] = o.k << 16; + cpu_enable |= (1 << o.rd); + break; + case 1: /* l.macrc */ + break; + } + break; + case 0x27: /* l.addi */ + o.rd = get_operand_value(insn, type_descr, INSN_OPER_D); + o.ra = get_operand_value(insn, type_descr, INSN_OPER_A); + o.i = get_operand_value(insn, type_descr, INSN_OPER_I); + if (cpu_enable & (1 << o.ra) & cpu_enable & (1 << o.rd)) { + cpu[o.rd] = cpu[o.ra] | o.i; + cpu_enable |= (1 << o.rd); + op->ptr = cpu[o.rd]; + op->direction = 8; /* reference */ + } + break; + case 0x2a: /* l.ori */ + o.rd = get_operand_value(insn, type_descr, INSN_OPER_D); + o.ra = get_operand_value(insn, type_descr, INSN_OPER_A); + o.i = get_operand_value(insn, type_descr, INSN_OPER_I); + if (cpu_enable & (1 << o.ra)) { + cpu[o.rd] = cpu[o.ra] | o.i; + cpu_enable |= (1 << o.rd); + op->ptr = cpu[o.rd]; + op->direction = 8; /* reference */ + } + break; + default: + /* if unknown instruction encountered, better forget state */ + cpu_enable = 0; + } + + /* temporary solution to prevent using wrong register values */ + if ((op->type & R_ANAL_OP_TYPE_JMP) == R_ANAL_OP_TYPE_JMP) { + /* FIXME: handle delay slot after branches */ + cpu_enable = 0; + } + return 4; +} + +static int or1k_op(RAnal *a, RAnalOp *op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask) { + ut32 insn, opcode; + ut8 opcode_idx; + char *line = NULL; + insn_t *insn_descr; + insn_extra_t *extra_descr; + + op->size = -1; + r_strbuf_init (&op->esil); + + /* read instruction and basic opcode value */ + insn = r_read_be32(data); + op->size = 4; + opcode = (insn & INSN_OPCODE_MASK); + opcode_idx = opcode >> INSN_OPCODE_SHIFT; + + /* make sure instruction descriptor table is not overflowed */ + if (opcode_idx >= insns_count) { + return op->size; + } + + /* if instruction is marked as invalid finish processing now */ + insn_descr = &insns[opcode_idx]; + if (insn_descr->type == INSN_INVAL) { + return op->size; + } + + /* if name is null, but extra is present, it means 6 most significant bits + * are not enough to decode instruction */ + if ((insn_descr->name == NULL) && (insn_descr->extra != NULL)) { + extra_descr = find_extra_descriptor(insn_descr->extra, insn); + if (extra_descr != NULL) { + insn_to_op(a, op, addr, insn_descr, extra_descr, insn); + } + } + else { + /* otherwise basic descriptor is enough */ + insn_to_op(a, op, addr, insn_descr, NULL, insn); + } + + return op->size; +} + +RAnalPlugin r_anal_plugin_or1k = { + .name = "or1k", + .desc = "OpenRISC 1000", + .license = "LGPL3", + .bits = 32, + .arch = "or1k", + .esil = false, + .op = &or1k_op, +}; + +#ifndef R2_PLUGIN_INCORE +R_API RLibStruct radare_plugin = { + .type = R_LIB_TYPE_ANAL, + .data = &r_anal_plugin_or1k, + .version = R2_VERSION +}; +#endif diff --git a/libr/anal/p/or1k.mk b/libr/anal/p/or1k.mk new file mode 100644 index 0000000000..3f988a7f28 --- /dev/null +++ b/libr/anal/p/or1k.mk @@ -0,0 +1,12 @@ +OBJ_OR1K=anal_or1k.o +OBJ_OR1K+=../../asm/arch/or1k/or1k_disas.o +CFLAGS+=-I../asm/arch/or1k + +STATIC_OBJ+=${OBJ_OR1K} +TARGET_OR1K=anal_or1k.${EXT_SO} + +ALL_TARGETS+=${TARGET_OR1K} + +${TARGET_OR1K}: ${OBJ_OR1K} + ${CC} $(call libname,anal_nios2) ${LDFLAGS} ${CFLAGS} \ + -o anal_or1k.${EXT_SO} ${OBJ_OR1K} diff --git a/libr/asm/arch/or1k/or1k_disas.c b/libr/asm/arch/or1k/or1k_disas.c new file mode 100644 index 0000000000..0cceb2adcd --- /dev/null +++ b/libr/asm/arch/or1k/or1k_disas.c @@ -0,0 +1,361 @@ +/* radare2 - LGPL - Copyright 2019 - v3l0c1r4pt0r */ + +#include +#include "or1k_disas.h" + +insn_type_descr_t types[] = { + [INSN_X] = {INSN_X, "%s", + { + 0 + } + }, + /* ------KKKKKAAAAABBBBBKKKKKKKKKKK */ + [INSN_KABK] = {INSN_KABK, "%s r%d, r%d, 0x%x", + { + [INSN_OPER_K1] = {INSN_OPER_K1, INSN_K1_MASK, INSN_K1_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT}, + [INSN_OPER_B] = {INSN_OPER_B, INSN_B_MASK, INSN_B_SHIFT}, + [INSN_OPER_K2] = {INSN_OPER_K2, INSN_K2_MASK, INSN_EMPTY_SHIFT} + } + }, + /* ------IIIIIAAAAABBBBBIIIIIIIIIII */ + [INSN_IABI] = {INSN_IABI, "%s r%d, r%d, 0x%x", + { + [INSN_OPER_K1] = {INSN_OPER_K1, INSN_K1_MASK, INSN_K1_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT}, + [INSN_OPER_B] = {INSN_OPER_B, INSN_B_MASK, INSN_B_SHIFT}, + [INSN_OPER_K2] = {INSN_OPER_K2, INSN_K2_MASK, INSN_EMPTY_SHIFT} + } + }, + /* ------NNNNNNNNNNNNNNNNNNNNNNNNNN */ + [INSN_N] = {INSN_N, "%s 0x%x", + { + [INSN_OPER_N] = {INSN_OPER_N, INSN_N_MASK, INSN_EMPTY_SHIFT} + } + }, + /* ----------------KKKKKKKKKKKKKKKK */ + [INSN_K] = {INSN_K, "%s 0x%x", + { + [INSN_OPER_K] = {INSN_OPER_K, INSN_K_MASK, INSN_EMPTY_SHIFT} + } + }, + /* ------DDDDD-----KKKKKKKKKKKKKKKK */ + [INSN_DK] = {INSN_DK, "%s r%d, 0x%x", + { + [INSN_OPER_K] = {INSN_OPER_K, INSN_K_MASK, INSN_EMPTY_SHIFT}, + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT} + } + }, + /* ------DDDDDNNNNNNNNNNNNNNNNNNNNN */ + [INSN_DN] = {INSN_DN, "%s r%d, 0x%x", + { + [INSN_OPER_N] = {INSN_OPER_N, INSN_N_MASK, INSN_EMPTY_SHIFT}, + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT} + } + }, + /* ----------------BBBBB----------- */ + [INSN_B] = {INSN_B, "%s r%d", + { + [INSN_OPER_B] = {INSN_OPER_B, INSN_B_MASK, INSN_B_SHIFT} + } + }, + /* ------DDDDD--------------------- */ + [INSN_D] = {INSN_D, "%s r%d", + { + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT} + } + }, + /* -----------AAAAAIIIIIIIIIIIIIIII */ + [INSN_AI] = {INSN_AI, "%s r%d, 0x%x", + { + [INSN_OPER_I] = {INSN_OPER_I, INSN_I_MASK, INSN_EMPTY_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT} + } + }, + /* ------DDDDDAAAAAIIIIIIIIIIIIIIII */ + [INSN_DAI] = {INSN_DAI, "%s r%d, r%d, 0x%x", + { + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT}, + [INSN_OPER_I] = {INSN_OPER_I, INSN_I_MASK, INSN_EMPTY_SHIFT} + } + }, + /* ------DDDDDAAAAAKKKKKKKKKKKKKKKK */ + [INSN_DAK] = {INSN_DAK, "%s r%d, r%d, 0x%x", + { + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT}, + [INSN_OPER_I] = {INSN_OPER_I, INSN_I_MASK, INSN_EMPTY_SHIFT} + } + }, + /* ------DDDDDAAAAA----------LLLLLL */ + [INSN_DAL] = {INSN_DAL, "%s r%d, r%d, 0x%x", + { + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT}, + [INSN_OPER_L] = {INSN_OPER_L, INSN_L_MASK, INSN_EMPTY_SHIFT} + } + }, + /* ------DDDDDAAAAA---------------- */ + [INSN_DA] = {INSN_DA, "%s r%d, r%d", + { + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT} + } + }, + /* ------DDDDDAAAAABBBBB----------- */ + [INSN_DAB] = {INSN_DAB, "%s r%d, r%d, r%d", + { + [INSN_OPER_D] = {INSN_OPER_D, INSN_D_MASK, INSN_D_SHIFT}, + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT}, + [INSN_OPER_B] = {INSN_OPER_B, INSN_B_MASK, INSN_B_SHIFT} + } + }, + /* -----------AAAAABBBBB----------- */ + [INSN_AB] = {INSN_AB, "%s r%d, r%d", + { + [INSN_OPER_A] = {INSN_OPER_A, INSN_A_MASK, INSN_A_SHIFT}, + [INSN_OPER_B] = {INSN_OPER_B, INSN_B_MASK, INSN_B_SHIFT} + } + }, +}; + +size_t types_count = sizeof(types) / sizeof(insn_type_descr_t); + +insn_extra_t extra_0x5[] = { + {(0x05<<26)|(0b01<<24), "l.nop", INSN_K, INSN_OPCODE_MASK | (0b11 << 24), R_ANAL_OP_TYPE_NOP}, + {0} +}; + +insn_extra_t extra_0x6[] = { + {(0x06<<26)|(0<<16), "l.movhi", INSN_DK, INSN_OPCODE_MASK | (1 << 16)}, + {(0x06<<26)|(1<<16), "l.macrc", INSN_D, INSN_OPCODE_MASK | (1 << 16)}, + {0} +}; + +insn_extra_t extra_0x8[] = { + {(0x08<<26)|(0b0000000000), "l.sys", INSN_K, INSN_OPCODE_MASK | 0b1111111111 << 16}, + {(0x08<<26)|(0b0100000000), "l.trap", INSN_K, INSN_OPCODE_MASK | 0b1111111111 << 16}, + {(0x08<<26)|(0b10000000000000000000000000), "l.msync", INSN_X, INSN_OPCODE_MASK | 0x3ffffff}, + {(0x08<<26)|(0b10100000000000000000000000), "l.psync", INSN_X, INSN_OPCODE_MASK | 0x3ffffff}, + {(0x08<<26)|(0b11000000000000000000000000), "l.csync", INSN_X, INSN_OPCODE_MASK | 0x3ffffff}, + {0} +}; + +insn_extra_t extra_0x2e[] = { + {(0x2e<<26)|(0b00<<6), "l.slli", INSN_DAL, INSN_OPCODE_MASK | (0b11 << 6)}, + {(0x2e<<26)|(0b01<<6), "l.srli", INSN_DAL, INSN_OPCODE_MASK | (0b11 << 6)}, + {(0x2e<<26)|(0b10<<6), "l.srai", INSN_DAL, INSN_OPCODE_MASK | (0b11 << 6)}, + {(0x2e<<26)|(0b11<<6), "l.rori", INSN_DAL, INSN_OPCODE_MASK | (0b11 << 6)}, + {0} +}; + +insn_extra_t extra_0x2f[] = { + {(0x2f<<26)|(0b00000<<21), "l.sfeqi", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x2f<<26)|(0b00001<<21), "l.sfnei", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x2f<<26)|(0b00010<<21), "l.sfgtui", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x2f<<26)|(0b00011<<21), "l.sfgeui", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x2f<<26)|(0b00100<<21), "l.sfltui", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x2f<<26)|(0b00101<<21), "l.sfleui", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x2f<<26)|(0b01010<<21), "l.sfgtsi", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, /* FIXME: signed */ + {(0x2f<<26)|(0b01011<<21), "l.sfgesi", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, /* FIXME: signed */ + {(0x2f<<26)|(0b01100<<21), "l.sfltsi", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, /* FIXME: signed */ + {(0x2f<<26)|(0b01101<<21), "l.sflesi", INSN_AI, INSN_OPCODE_MASK | (0b11111 << 21)}, /* FIXME: signed */ + {0} +}; + +insn_extra_t extra_0x31[] = { + {(0x31<<26)|(0b0001), "l.mac", INSN_AB, INSN_OPCODE_MASK | (0b1111)}, + {(0x31<<26)|(0b0011), "l.macu", INSN_AB, INSN_OPCODE_MASK | (0b1111)}, + {(0x31<<26)|(0b0010), "l.msb", INSN_AB, INSN_OPCODE_MASK | (0b1111)}, + {(0x31<<26)|(0b0100), "l.msbu", INSN_AB, INSN_OPCODE_MASK | (0b1111)}, + {0} +}; + +insn_extra_t extra_0x32[] = { + {(0x32<<26)|(0b00001000), "lf.sfeq.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00001001), "lf.sfne.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00001010), "lf.sfgt.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00001011), "lf.sfge.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00001100), "lf.sflt.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00001101), "lf.sfle.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00011000), "lf.sfeq.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00011001), "lf.sfne.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00011010), "lf.sfgt.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00011011), "lf.sfge.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00011100), "lf.sflt.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00011101), "lf.sfle.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00101000), "lf.sfueq.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00101001), "lf.sfune.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00101010), "lf.sfugt.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00101011), "lf.sfuge.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00101100), "lf.sfult.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00101101), "lf.sfule.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00101110), "lf.sfun.s", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00110100), "lf.stod.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00110101), "lf.dtos.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00111000), "lf.sfueq.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00111001), "lf.sfune.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00111010), "lf.sfugt.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00111011), "lf.sfuge.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00111100), "lf.sfult.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00111101), "lf.sfule.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00111110), "lf.sfun.d", INSN_AB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b1101<<4), "lf.cust1.s", INSN_AB, INSN_OPCODE_MASK | (0b1111 << 4)}, + {(0x32<<26)|(0b1110<<4), "lf.cust1.d", INSN_AB, INSN_OPCODE_MASK | (0b1111 << 4)}, + {(0x32<<26)|(0b00000100), "lf.itof.s", INSN_DA, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00000101), "lf.ftoi.s", INSN_DA, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00010100), "lf.itof.d", INSN_DA, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00010101), "lf.ftoi.d", INSN_DA, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00000000), "lf.add.s", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00000001), "lf.sub.s", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00000010), "lf.mul.s", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00000011), "lf.div.s", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00000111), "lf.madd.s", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00010000), "lf.add.d", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00010001), "lf.sub.d", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00010010), "lf.mul.d", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00010011), "lf.div.d", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {(0x32<<26)|(0b00010111), "lf.madd.d", INSN_DAB, INSN_OPCODE_MASK | (0b11111111)}, + {0} +}; + +insn_extra_t extra_0x38[] = { + {(0x38<<26)|(0b0000<<6)|(0b1100), "l.exths", INSN_DA, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b1101), "l.extws", INSN_DA, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0001<<6)|(0b1100), "l.extbs", INSN_DA, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0001<<6)|(0b1101), "l.extwz", INSN_DA, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0010<<6)|(0b1100), "l.exthz", INSN_DA, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0011<<6)|(0b1100), "l.extbz", INSN_DA, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b0000), "l.add", INSN_DAB, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b0001), "l.addc", INSN_DAB, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b0010), "l.sub", INSN_DAB, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b0011), "l.and", INSN_DAB, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b0100), "l.or", INSN_DAB, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b0101), "l.xor", INSN_DAB, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b1110), "l.cmov", INSN_DAB, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b1111), "l.ff1", INSN_DA, INSN_OPCODE_MASK | (0xc << 6) | 0xf}, + {(0x38<<26)|(0b0000<<6)|(0b1000), "l.sll", INSN_DAB, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0001<<6)|(0b1000), "l.srl", INSN_DAB, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0010<<6)|(0b1000), "l.sra", INSN_DAB, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b0011<<6)|(0b1000), "l.ror", INSN_DAB, INSN_OPCODE_MASK | (0xf << 6) | 0xf}, + {(0x38<<26)|(0b01<<8)|(0b1111), "l.fl1", INSN_DA, INSN_OPCODE_MASK | (0x3 << 8) | 0xf}, + {(0x38<<26)|(0b11<<8)|(0b0110), "l.mul", INSN_DAB, INSN_OPCODE_MASK | (0x3 << 8) | 0xf}, + {(0x38<<26)|(0b11<<8)|(0b0111), "l.muld", INSN_AB, INSN_OPCODE_MASK | (0x3 << 8) | 0xf}, + {(0x38<<26)|(0b11<<8)|(0b1001), "l.div", INSN_DAB, INSN_OPCODE_MASK | (0x3 << 8) | 0xf}, + {(0x38<<26)|(0b11<<8)|(0b1010), "l.divu", INSN_DAB, INSN_OPCODE_MASK | (0x3 << 8) | 0xf}, + {(0x38<<26)|(0b11<<8)|(0b1011), "l.mulu", INSN_DAB, INSN_OPCODE_MASK | (0x3 << 8) | 0xf}, + {(0x38<<26)|(0b11<<8)|(0b1100), "l.muldu", INSN_AB, INSN_OPCODE_MASK | (0x3 << 8) | 0xf}, + {0} +}; + +insn_extra_t extra_0x39[] = { + {(0x39<<26)|(0b00000<<21), "l.sfeq", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b00001<<21), "l.sfne", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b00010<<21), "l.sfgtu", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b00011<<21), "l.sfgeu", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b00100<<21), "l.sfltu", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b00101<<21), "l.sfleu", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b01010<<21), "l.sfgts", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b01011<<21), "l.sfges", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b01100<<21), "l.sflts", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {(0x39<<26)|(0b01101<<21), "l.sfles", INSN_AB, INSN_OPCODE_MASK | (0b11111 << 21)}, + {0} +}; + +insn_t insns[] = { + [0x00] = {(0x00<<26), "l.j", INSN_N, R_ANAL_OP_TYPE_JMP}, + [0x01] = {(0x01<<26), "l.jal", INSN_N, R_ANAL_OP_TYPE_CALL}, + [0x02] = {(0x02<<26), "l.adrp", INSN_DN}, + [0x03] = {(0x03<<26), "l.bnf", INSN_N, R_ANAL_OP_TYPE_CJMP}, + [0x04] = {(0x04<<26), "l.bf", INSN_N, R_ANAL_OP_TYPE_CJMP}, + [0x05] = {(0x05<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x5}, + [0x06] = {(0x06<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x6}, + [0x07] = {(0x07<<26)}, + [0x08] = {(0x08<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x8}, + [0x09] = {(0x09<<26), "l.rfe", INSN_X}, + [0x0a] = {(0x0a<<26), "lv.ext0a", INSN_X}, /* TODO: implement */ + [0x0b] = {(0x0b<<26)}, + [0x0c] = {(0x0c<<26)}, + [0x0d] = {(0x0d<<26)}, + [0x0e] = {(0x0e<<26)}, + [0x0f] = {(0x0f<<26)}, + [0x10] = {(0x10<<26)}, + [0x11] = {(0x11<<26), "l.jr", INSN_B, R_ANAL_OP_TYPE_JMP}, + [0x12] = {(0x12<<26), "l.jalr", INSN_B, R_ANAL_OP_TYPE_CALL}, + [0x13] = {(0x13<<26), "l.maci", INSN_AI}, + [0x14] = {(0x14<<26)}, + [0x15] = {(0x15<<26)}, + [0x16] = {(0x16<<26)}, + [0x17] = {(0x17<<26)}, + [0x18] = {(0x18<<26)}, + [0x19] = {(0x19<<26)}, + [0x1a] = {(0x1a<<26), "l.lf", INSN_DAI}, + [0x1b] = {(0x1b<<26), "l.lwa", INSN_DAI}, + [0x1c] = {(0x1c<<26), "l.cust1", INSN_X}, + [0x1d] = {(0x1d<<26), "l.cust2", INSN_X}, + [0x1e] = {(0x1e<<26), "l.cust3", INSN_X}, + [0x1f] = {(0x1f<<26), "l.cust4", INSN_X}, + [0x20] = {(0x20<<26), "l.ld", INSN_DAI}, + [0x21] = {(0x21<<26), "l.lwz", INSN_DAI}, + [0x22] = {(0x22<<26), "l.lws", INSN_DAI}, + [0x23] = {(0x23<<26), "l.lbz", INSN_DAI}, + [0x24] = {(0x24<<26), "l.lbs", INSN_DAI}, + [0x25] = {(0x25<<26), "l.lhz", INSN_DAI}, + [0x26] = {(0x26<<26), "l.lhs", INSN_DAI}, + [0x27] = {(0x27<<26), "l.addi", INSN_DAI, R_ANAL_OP_TYPE_LOAD}, + [0x28] = {(0x28<<26), "l.addic", INSN_DAI}, + [0x29] = {(0x29<<26), "l.andi", INSN_DAK}, + [0x2a] = {(0x2a<<26), "l.ori", INSN_DAK, R_ANAL_OP_TYPE_LOAD}, + [0x2b] = {(0x2b<<26), "l.xori", INSN_DAI}, + [0x2c] = {(0x2c<<26), "l.muli", INSN_DAI}, + [0x2d] = {(0x2d<<26), "l.mfspr", INSN_DAK}, + [0x2e] = {(0x2e<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x2e}, + [0x2f] = {(0x2f<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x2f}, + [0x30] = {(0x30<<26), "l.mtspr", INSN_KABK}, + [0x31] = {(0x31<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x31}, + [0x32] = {(0x32<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x32}, + [0x33] = {(0x33<<26), "l.swa", INSN_IABI}, + [0x34] = {(0x34<<26)}, + [0x35] = {(0x35<<26), "l.sw", INSN_IABI}, + [0x36] = {(0x36<<26), "l.sb", INSN_IABI}, + [0x37] = {(0x37<<26), "l.sh", INSN_IABI}, + [0x38] = {(0x38<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x38}, + [0x39] = {(0x39<<26), NULL, INSN_X, R_ANAL_OP_TYPE_NULL, extra_0x39}, + [0x3a] = {(0x3a<<26)}, + [0x3b] = {(0x3b<<26)}, + [0x3c] = {(0x3c<<26), "l.cust5", INSN_X}, + [0x3d] = {(0x3d<<26), "l.cust6", INSN_X}, + [0x3e] = {(0x3e<<26), "l.cust7", INSN_X}, + [0x3f] = {(0x3f<<26), "l.cust8", INSN_X}, +}; + +size_t insns_count = sizeof(insns) / sizeof(insn_t); + +insn_extra_t *find_extra_descriptor(insn_extra_t *extra_descr, ut32 insn) { + ut32 opcode; + while (extra_descr->type != INSN_END) { + opcode = (insn & extra_descr->opcode_mask); + if (extra_descr->opcode == opcode) { + break; + } + extra_descr++; + } + if (extra_descr->type != INSN_END) { + return extra_descr; + } else { + return NULL; + } +} + +ut32 sign_extend(ut32 number, ut32 mask) { + /* xor of mask with itself shifted left detects msb of mask and msb of space + * on the right. And discards the latter */ + ut32 first_bit = (mask ^ (mask >> 1)) & mask; + /* if first bit is set */ + if (number & first_bit) { + /* set every bit outside mask */ + number |= ~mask; + } + return number; +} diff --git a/libr/asm/arch/or1k/or1k_disas.h b/libr/asm/arch/or1k/or1k_disas.h new file mode 100644 index 0000000000..b5c4ed4cdb --- /dev/null +++ b/libr/asm/arch/or1k/or1k_disas.h @@ -0,0 +1,181 @@ +/* radare2 - LGPL - Copyright 2019 - v3l0c1r4pt0r */ + +#include + +#ifndef OR1K_DISAS_H +#define OR1K_DISAS_H + +/** Default mask for opcode */ +#define INSN_OPCODE_MASK (0b111111 * 0x4000000) +#define INSN_OPCODE_SHIFT 26 + +/** Empty mask for unused operands */ +#define INSN_EMPTY_SHIFT 0 +#define INSN_EMPTY_MASK 0 + +/** Mask for N operand */ +#define INSN_N_MASK 0b11111111111111111111111111 + +/** Shift for D operand */ +#define INSN_D_SHIFT 21 +/** Mask for D operand */ +#define INSN_D_MASK (0b11111 * 0x200000) + +/** Mask for K operand */ +#define INSN_K_MASK 0b1111111111111111 + +/** Shift for B operand */ +#define INSN_B_SHIFT 11 +/** Mask for B operand */ +#define INSN_B_MASK (0b11111 * 0x800) + +/** Shift for A operand */ +#define INSN_A_SHIFT 16 +/** Mask for A operand */ +#define INSN_A_MASK (0b11111 * 0x10000) + +/** Mask for I operand */ +#define INSN_I_MASK 0b1111111111111111 + +/** Mask for L operand */ +#define INSN_L_MASK 0b111111 + +/** Shift for first K operand */ +#define INSN_K1_SHIFT 21 +/** Mask for first K operand */ +#define INSN_K1_MASK (0b11111 * 0x200000) + +/** Mask for second K operand */ +#define INSN_K2_MASK 0b11111111111 + +typedef enum insn_type { + INSN_END = 0, /**< end of array indicator */ + INSN_INVAL = 0, /**< invalid opcode */ + INSN_X, /**< no operands */ + INSN_N, /**< 26-bit immediate */ + INSN_DN, /**< 5-bit destination register, then 26-bit immediate */ + INSN_K, /**< 16-bit immediate */ + INSN_DK, /**< 5-bit destination register, then 16-bit immediate */ + INSN_D, /**< 5-bit destination register */ + INSN_B, /**< 5-bit source register */ + INSN_AI, /**< 5-bit source register, then 16-bit immediate */ + INSN_DAI, /**< 5-bit destination register, 5-bit source register, then 16-bit + immediate */ + INSN_DAK, /**< 5-bit destination register, 5-bit source register, then 16-bit + immediate */ + INSN_DAL, /**< 5-bit destination register, 5-bit source register, then 6-bit + immediate */ + INSN_KABK, /**< 5-bit MSB of immediate, 5-bit source register, 5-bit source + register, then 11-bit rest of immediate */ + INSN_AB, /**< 5-bit source register, then 5-bit source register */ + INSN_DA, /**< 5-bit destination register, then 5-bit source register */ + INSN_DAB, /**< 5-bit destination register, 5-bit source register, then 5-bit + source register */ + INSN_IABI, /**< 5-bit MSB of immediate, 5-bit source register, 5-bit source + register, then 11-bit rest of immediate */ + INSN_SIZE, /**< number of types */ +} insn_type_t; + +typedef enum { + INSN_OPER_K1, /**< 5-bit MSBs of immediate */ + INSN_OPER_K2, /**< 11-bit LSBs of immediate */ + INSN_OPER_A, /**< 5-bit source register */ + INSN_OPER_B, /**< 5-bit source register */ + INSN_OPER_N, /**< 26-bit immediate */ + INSN_OPER_K, /**< 16-bit immediate */ + INSN_OPER_D, /**< 5-bit destination register */ + INSN_OPER_I, /**< 16-bit immediate */ + INSN_OPER_L, /**< 6-bit immediate */ + INSN_OPER_SIZE /**< number of operand types */ +} insn_oper_t; + +typedef struct { + int oper; + ut32 mask; + ut32 shift; +} insn_oper_descr_t; + +typedef struct { + int type; + char *format; + insn_oper_descr_t operands[INSN_OPER_SIZE]; +} insn_type_descr_t; + +typedef struct { + ut32 opcode; + char *name; + int type; + int opcode_mask; + int insn_type; /**< One of \link _RAnalOpType \endlink */ +} insn_extra_t; + +typedef struct { + ut32 opcode; + char *name; + int type; + int insn_type; /**< One of \link _RAnalOpType \endlink */ + insn_extra_t *extra; +} insn_t; + +extern insn_type_descr_t types[]; +extern size_t types_count; + +extern insn_extra_t extra_0x5[]; +extern insn_extra_t extra_0x6[]; +extern insn_extra_t extra_0x8[]; +extern insn_extra_t extra_0x2e[]; +extern insn_extra_t extra_0x2f[]; +extern insn_extra_t extra_0x31[]; +extern insn_extra_t extra_0x32[]; +extern insn_extra_t extra_0x38[]; +extern insn_extra_t extra_0x39[]; + +extern insn_t insns[]; +extern size_t insns_count; + +insn_extra_t *find_extra_descriptor(insn_extra_t *extra_descr, ut32 insn); + +/** + * \brief Performs sign extension of number + * + * \param number number to extend + * \param mask mask under which number is placed + * + * \return sign-extended number + * + * If mask does not begin on the lsb, space on the right will also be filled with ones + * + */ +ut32 sign_extend(ut32 number, ut32 mask); + +static inline ut32 get_operand_mask(insn_type_descr_t *type_descr, insn_oper_t operand) { + return type_descr->operands[operand].mask; +} + +static inline ut32 get_operand_shift(insn_type_descr_t *type_descr, insn_oper_t operand) { + return type_descr->operands[operand].shift; +} + +static inline ut32 get_operand_value(ut32 insn, insn_type_descr_t *type_descr, insn_oper_t operand) { + return (insn & get_operand_mask(type_descr, operand)) >> get_operand_shift(type_descr, operand); +} + +static inline int has_type_descriptor(insn_type_t type) { + return types + types_count > &types[type]; +} + +static inline int is_type_descriptor_defined(insn_type_t type) { + return types[type].type == type; +} + +static inline insn_type_t type_of_opcode(insn_t *descr, insn_extra_t *extra_descr) { + r_return_val_if_fail (descr, INSN_END); + + if (extra_descr == NULL) { + return descr->type; + } else { + return extra_descr->type; + } +} + +#endif /* OR1K_DISAS_H */ diff --git a/libr/asm/meson.build b/libr/asm/meson.build index f55c91ae5c..f5caa3d7fe 100644 --- a/libr/asm/meson.build +++ b/libr/asm/meson.build @@ -39,6 +39,7 @@ r_asm_sources = [ 'p/asm_mips_gnu.c', 'p/asm_msp430.c', 'p/asm_nios2.c', + 'p/asm_or1k.c', 'p/asm_pic.c', 'p/asm_mcore.c', 'p/asm_ppc_cs.c', @@ -115,6 +116,7 @@ r_asm_sources = [ 'arch/msp430/msp430_disas.c', 'arch/nios/gnu/nios2-dis.c', 'arch/nios/gnu/nios2-opc.c', + 'arch/or1k/or1k_disas.c', 'arch/pic/pic_baseline.c', 'arch/pic/pic_midrange.c', 'arch/pic/pic_pic18.c', @@ -174,7 +176,8 @@ r_asm_inc = [ 'arch/ebc', 'arch/cr16', 'arch/8051', - 'arch/v810' + 'arch/v810', + 'arch/or1k' ) ] diff --git a/libr/asm/p/asm_or1k.c b/libr/asm/p/asm_or1k.c new file mode 100644 index 0000000000..dc51b32431 --- /dev/null +++ b/libr/asm/p/asm_or1k.c @@ -0,0 +1,177 @@ +/* radare2 - LGPL - Copyright 2019 - v3l0c1r4pt0r */ + +#include +#include +#include "../arch/or1k/or1k_disas.h" + +struct operands { + ut32 rd; + ut32 ra; + ut32 rb; + ut32 n; + ut32 k1; + ut32 k2; + ut32 k; + ut32 i; + ut32 l; +}; + +static int insn_to_str(RAsm *a, char **line, insn_t *descr, insn_extra_t *extra, ut32 insn) { + struct operands o = {0}; + char *name; + insn_type_t type = type_of_opcode(descr, extra); + insn_type_descr_t *type_descr = &types[INSN_X]; + + /* only use type descriptor if it has some useful data */ + if (has_type_descriptor(type) && is_type_descriptor_defined(type)) { + type_descr = &types[type]; + } + + o.rd = get_operand_value(insn, type_descr, INSN_OPER_D); + o.ra = get_operand_value(insn, type_descr, INSN_OPER_A); + o.rb = get_operand_value(insn, type_descr, INSN_OPER_B); + o.k1 = get_operand_value(insn, type_descr, INSN_OPER_K1); + o.k2 = get_operand_value(insn, type_descr, INSN_OPER_K2); + o.n = get_operand_value(insn, type_descr, INSN_OPER_N); + o.k = get_operand_value(insn, type_descr, INSN_OPER_K); + o.i = get_operand_value(insn, type_descr, INSN_OPER_I); + o.l = get_operand_value(insn, type_descr, INSN_OPER_L); + + name = (extra == NULL) ? descr->name : extra->name; + + if (name == NULL || type_descr->format == NULL) { + /* this should not happen, give up */ + *line = sdb_fmt("invalid"); + return 4; + } + + switch (type) { + case INSN_X: + *line = sdb_fmt(type_descr->format, name); + break; + case INSN_N: + *line = sdb_fmt(type_descr->format, name, + (sign_extend(o.n, get_operand_mask(type_descr, INSN_OPER_N)) << 2) + + a->pc); + break; + case INSN_K: + *line = sdb_fmt(type_descr->format, name, o.k); + break; + case INSN_DK: + *line = sdb_fmt(type_descr->format, name, o.rd, o.k); + break; + case INSN_DN: + *line = sdb_fmt(type_descr->format, name, o.rd, o.n << 13); + break; + case INSN_B: + *line = sdb_fmt(type_descr->format, name, o.rb); + break; + case INSN_D: + *line = sdb_fmt(type_descr->format, name, o.rd); + break; + case INSN_AI: + *line = sdb_fmt(type_descr->format, name, o.ra, o.i); + break; + case INSN_DAI: + *line = sdb_fmt(type_descr->format, name, o.rd, o.ra, o.i); + break; + case INSN_DAK: + *line = sdb_fmt(type_descr->format, name, o.rd, o.ra, o.i); + break; + case INSN_DAL: + *line = sdb_fmt(type_descr->format, name, o.rd, o.ra, o.l); + break; + case INSN_DA: + *line = sdb_fmt(type_descr->format, name, o.rd, o.ra); + break; + case INSN_DAB: + *line = sdb_fmt(type_descr->format, name, o.rd, o.ra, o.rb); + break; + case INSN_AB: + *line = sdb_fmt(type_descr->format, name, o.ra, o.rb); + break; + case INSN_IABI: + *line = sdb_fmt(type_descr->format, name, + o.ra, o.rb, (o.k1 << 11) | o.k2); + break; + case INSN_KABK: + *line = sdb_fmt(type_descr->format, name, + o.ra, o.rb, (o.k1 << 11) | o.k2); + break; + default: + *line = sdb_fmt("invalid"); + } + return 4; +} + +static int disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { + ut32 insn, opcode; + ut8 opcode_idx; + char *line = NULL; + insn_t *insn_descr; + insn_extra_t *extra_descr; + + op->size = -1; + + if (len < 4) { + line = sdb_fmt("invalid"); + r_strbuf_set (&op->buf_asm, line); + return op->size; + } + + /* read instruction and basic opcode value */ + insn = r_read_be32(buf); + op->size = 4; + opcode = (insn & INSN_OPCODE_MASK); + opcode_idx = opcode >> INSN_OPCODE_SHIFT; + + /* make sure instruction descriptor table is not overflowed */ + if (opcode_idx >= insns_count) { + line = sdb_fmt("invalid"); + r_strbuf_set (&op->buf_asm, line); + return op->size; + } + + /* if instruction is marked as invalid finish processing now */ + insn_descr = &insns[opcode_idx]; + if (insn_descr->type == INSN_INVAL) { + line = sdb_fmt("invalid"); + r_strbuf_set (&op->buf_asm, line); + return op->size; + } + + /* if name is null, but extra is present, it means 6 most significant bits + * are not enough to decode instruction */ + if ((insn_descr->name == NULL) && (insn_descr->extra != NULL)) { + if ((extra_descr = find_extra_descriptor(insn_descr->extra, insn)) != NULL) { + insn_to_str(a, &line, insn_descr, extra_descr, insn); + } + else { + line = sdb_fmt("invalid"); + } + r_strbuf_set (&op->buf_asm, line); + } + else { + /* otherwise basic descriptor is enough */ + insn_to_str(a, &line, insn_descr, NULL, insn); + r_strbuf_set (&op->buf_asm, line); + } + + return op->size; +} + +RAsmPlugin r_asm_plugin_or1k = { + .name = "or1k", + .desc = "OpenRISC 1000", + .license = "LGPL3", + .arch = "or1k", + .bits = 32, + .endian = R_SYS_ENDIAN_BIG, + .fini = NULL, + .disassemble = &disassemble, +}; + +#ifndef R2_PLUGIN_INCORE +R_API RLibStruct radare_plugin = { + .type = R_LIB_TYPE_ASM, .data = &r_asm_plugin_or1k, .version = R2_VERSION}; +#endif diff --git a/libr/asm/p/or1k.mk b/libr/asm/p/or1k.mk new file mode 100644 index 0000000000..b750de525e --- /dev/null +++ b/libr/asm/p/or1k.mk @@ -0,0 +1,11 @@ +OBJ_OR1K=asm_or1k.o +OBJ_OR1K+=../arch/or1k/or1k_disas.o +CFLAGS+=-I./arch/or1k/ + +STATIC_OBJ+=${OBJ_OR1K} +TARGET_OR1K=asm_or1k.${EXT_SO} + +ALL_TARGETS+=${TARGET_OR1K} + +${TARGET_OR1K}: ${OBJ_OR1K} + ${CC} $(call libname,asm_or1k) ${LDFLAGS} ${CFLAGS} -o asm_or1k.${EXT_SO} ${OBJ_OR1K} diff --git a/libr/include/r_anal.h b/libr/include/r_anal.h index 995201032c..381a2df3a4 100644 --- a/libr/include/r_anal.h +++ b/libr/include/r_anal.h @@ -2037,6 +2037,7 @@ extern RAnalPlugin r_anal_plugin_mips_cs; extern RAnalPlugin r_anal_plugin_mips_gnu; extern RAnalPlugin r_anal_plugin_msp430; extern RAnalPlugin r_anal_plugin_nios2; +extern RAnalPlugin r_anal_plugin_or1k; extern RAnalPlugin r_anal_plugin_pic; extern RAnalPlugin r_anal_plugin_ppc_cs; extern RAnalPlugin r_anal_plugin_ppc_gnu; diff --git a/libr/include/r_asm.h b/libr/include/r_asm.h index c4956bccce..57f6ba5281 100644 --- a/libr/include/r_asm.h +++ b/libr/include/r_asm.h @@ -237,6 +237,7 @@ extern RAsmPlugin r_asm_plugin_mips_cs; extern RAsmPlugin r_asm_plugin_mips_gnu; extern RAsmPlugin r_asm_plugin_msp430; extern RAsmPlugin r_asm_plugin_nios2; +extern RAsmPlugin r_asm_plugin_or1k; extern RAsmPlugin r_asm_plugin_pic; extern RAsmPlugin r_asm_plugin_ppc_cs; extern RAsmPlugin r_asm_plugin_ppc_gnu; diff --git a/libr/meson.build b/libr/meson.build index 9e6c03c6c6..9a870cc352 100644 --- a/libr/meson.build +++ b/libr/meson.build @@ -27,6 +27,7 @@ anal_plugins = [ 'msp430', 'nios2', 'null', + 'or1k', 'pic', 'ppc_cs', 'ppc_gnu', @@ -89,6 +90,7 @@ asm_plugins = [ 'mips_gnu', 'msp430', 'nios2', + 'or1k', 'pic', 'ppc_cs', 'ppc_gnu', diff --git a/plugins.def.cfg b/plugins.def.cfg index 35b1157069..c864b86d77 100644 --- a/plugins.def.cfg +++ b/plugins.def.cfg @@ -26,6 +26,7 @@ anal.mips_gnu anal.msp430 anal.nios2 anal.null +anal.or1k anal.ppc_cs anal.ppc_gnu anal.sh @@ -84,6 +85,7 @@ asm.mips_cs asm.mips_gnu asm.msp430 asm.nios2 +asm.or1k asm.ppc_cs asm.ppc_gnu asm.propeller