From 33607b853eecb5f0c5d3317dca86568432fb0444 Mon Sep 17 00:00:00 2001 From: pancake Date: Wed, 10 Jul 2024 19:03:46 +0200 Subject: [PATCH] Initial support for the UXN machine ##arch --- dist/plugins-cfg/plugins.def.cfg | 1 + libr/arch/p/uxn.mk | 10 +++ libr/arch/p/uxn/plugin.c | 43 +++++++++ libr/arch/p/uxn/uxndisass.inc.c | 150 +++++++++++++++++++++++++++++++ libr/include/r_arch.h | 5 +- 5 files changed, 207 insertions(+), 2 deletions(-) create mode 100644 libr/arch/p/uxn.mk create mode 100644 libr/arch/p/uxn/plugin.c create mode 100644 libr/arch/p/uxn/uxndisass.inc.c diff --git a/dist/plugins-cfg/plugins.def.cfg b/dist/plugins-cfg/plugins.def.cfg index 83624757c5f2e..071123c752d6f 100644 --- a/dist/plugins-cfg/plugins.def.cfg +++ b/dist/plugins-cfg/plugins.def.cfg @@ -72,6 +72,7 @@ arch.sparc_gnu arch.tms320 arch.tricore arch.tricore_cs +arch.uxn arch.v810 arch.v850 arch.vax diff --git a/libr/arch/p/uxn.mk b/libr/arch/p/uxn.mk new file mode 100644 index 0000000000000..85477b1c6fb30 --- /dev/null +++ b/libr/arch/p/uxn.mk @@ -0,0 +1,10 @@ +OBJ_UXN=p/uxn/plugin.o +# OBJ_UXN+=p/uxn/uxndisass.o + +STATIC_OBJ+=$(OBJ_UXN) +TARGET_UXN=p/arch_uxn.$(EXT_SO) + +ALL_TARGETS+=$(TARGET_UXN) + +${TARGET_UXN}: $(OBJ_UXN) + ${CC} $(call libname,arch_uxn) $(LDFLAGS) $(CFLAGS) -o arch_uxn.$(EXT_SO) $(OBJ_UXN) diff --git a/libr/arch/p/uxn/plugin.c b/libr/arch/p/uxn/plugin.c new file mode 100644 index 0000000000000..d8b660244f4d1 --- /dev/null +++ b/libr/arch/p/uxn/plugin.c @@ -0,0 +1,43 @@ +/* radare2 - PD - Copyright 2024 - pancake */ + +#include +#include "uxndisass.inc.c" + +static bool uxn_decode(RArchSession *a, RAnalOp *op, RArchDecodeMask mask) { + char text[32]; + + int len = uxn_disassemble (op->bytes, op->size, text, sizeof (text)); + if (len > 0) { + op->type = R_ANAL_OP_TYPE_MOV; + op->size = len; + op->mnemonic = strdup (text); + } else { + op->size = 1; + } + return true; +} + +static int archinfo(RArchSession *a, ut32 q) { + return 1; +} + +const RArchPlugin r_arch_plugin_uxn = { + .meta = { + .name = "uxn", + .desc = "UXN", + .license = "PD", + }, + .bits = 32, + .arch = "uxn", + .info = archinfo, + .decode = &uxn_decode, + // .encode = &uxn_encode, +}; + +#ifndef R2_PLUGIN_INCORE +R_API RLibStruct radare_plugin = { + .type = R_LIB_TYPE_ARCH, + .data = &r_arch_plugin_uxn, + .version = R2_VERSION +}; +#endif diff --git a/libr/arch/p/uxn/uxndisass.inc.c b/libr/arch/p/uxn/uxndisass.inc.c new file mode 100644 index 0000000000000..b4dc9df1b39a1 --- /dev/null +++ b/libr/arch/p/uxn/uxndisass.inc.c @@ -0,0 +1,150 @@ +/* radare2 - PD - Copyright 2024 - pancake */ + +#include + +#define MAX_INSTRUCTION_LEN 16 +#define NUM_INSTRUCTIONS 256 + +typedef struct { + uint8_t opcode; + int operand; +} Instruction; + +static const char* instruction_mnemonics[NUM_INSTRUCTIONS] = { + "brk", "inc", "pop", "nip", "swp", "rot", "dup", "ovr", + "equ", "neq", "gth", "lth", "jmp", "jcn", "jsr", "sth", + "ldz", "stz", "ldr", "str", "lda", "sta", "dei", "deo", + "add", "sub", "mul", "div", "and", "ora", "eor", "sft", + "jci", "inc2", "pop2", "nip2", "swp2", "rot2", "dup2", "ovr2", + "equ2", "neq2", "gth2", "lth2", "jmp2", "jcn2", "jsr2", "sth2", + "ldz2", "stz2", "ldr2", "str2", "lda2", "sta2", "dei2", "deo2", + "add2", "sub2", "mul2", "div2", "and2", "ora2", "eor2", "sft2", + "jmi", "incr", "popr", "nipr", "swpr", "rotr", "dupr", "ovrr", + "equr", "neqr", "gthr", "lthr", "jmpr", "jcnr", "jsrr", "sthr", + "ldzr", "stzr", "ldrr", "strr", "ldar", "star", "deir", "deor", + "addr", "subr", "mulr", "divr", "andr", "orar", "eorr", "sftr", + "jsi", "inc2r", "pop2r", "nip2r", "swp2r", "rot2r", "dup2r", "ovr2r", + "equ2r", "neq2r", "gth2r", "lth2r", "jmp2r", "jcn2r", "jsr2r", "sth2r", + "ldz2r", "stz2r", "ldr2r", "str2r", "lda2r", "sta2r", "dei2r", "deo2r", + "add2r", "sub2r", "mul2r", "div2r", "and2r", "ora2r", "eor2r", "sft2r", + "lit", "inck", "popk", "nipk", "swpk", "rotk", "dupk", "ovrk", + "equk", "neqk", "gthk", "lthk", "jmpk", "jcnk", "jsrk", "sthk", + "ldzk", "stzk", "ldrk", "strk", "ldak", "stak", "deik", "deok", + "addk", "subk", "mulk", "divk", "andk", "orak", "eork", "sftk", + "lit2", "inc2k", "pop2k", "nip2k", "swp2k", "rot2k", "dup2k", "ovr2k", + "equ2k", "neq2k", "gth2k", "lth2k", "jmp2k", "jcn2k", "jsr2k", "sth2k", + "ldz2k", "stz2k", "ldr2k", "str2k", "lda2k", "sta2k", "dei2k", "deo2k", + "add2k", "sub2k", "mul2k", "div2k", "and2k", "ora2k", "eor2k", "sft2k", + "litr", "inckr", "popkr", "nipkr", "swpkr", "rotkr", "dupkr", "ovrkr", + "equkr", "neqkr", "gthkr", "lthkr", "jmpkr", "jcnkr", "jsrkr", "sthkr", + "ldzkr", "stzkr", "ldrkr", "strkr", "ldakr", "stakr", "deikr", "deokr", + "addkr", "subkr", "mulkr", "divkr", "andkr", "orakr", "eorkr", "sftkr", + "lit2r", "inc2kr", "pop2kr", "nip2kr", "swp2kr", "rot2kr", "dup2kr", "ovr2kr", + "equ2kr", "neq2kr", "gth2kr", "lth2kr", "jmp2kr", "jcn2kr", "jsr2kr", "sth2kr", + "ldz2kr", "stz2kr", "ldr2kr", "str2kr", "lda2kr", "sta2kr", "dei2kr", "deo2kr", + "add2kr", "sub2kr", "mul2kr", "div2kr", "and2kr", "ora2kr", "eor2kr", "sft2kr" +}; + +static int find_opcode(const char* mnemonic) { + char upper_mnemonic[MAX_INSTRUCTION_LEN]; + r_str_ncpy (upper_mnemonic, mnemonic, sizeof (upper_mnemonic)); + r_str_case (upper_mnemonic, false); + int i; + + for (i = 0; i < NUM_INSTRUCTIONS; i++) { + if (!strcmp (instruction_mnemonics[i], upper_mnemonic)) { + return i; + } + } + return -1; +} + +int uxn_assemble(const char* mnemonic, uint8_t* code, size_t code_size) { + int code_len = 0; + if (code_size < 3) { + return -1; + } + Instruction instr = {0}; + char op[MAX_INSTRUCTION_LEN]; + r_str_ncpy (op, mnemonic, sizeof (op)); + char *arg = strchr (op, ' '); + int args = 0; + if (arg) { + *arg++ = 0; + instr.operand = atoi (arg); + args++; + } + + int opcode = find_opcode(op); + if (opcode == -1) { + return -1; + } + + instr.opcode = opcode; + + code[code_len++] = instr.opcode; + if (args > 1) { + if (instr.opcode == 0x80 || (instr.opcode >= 0xA0 && instr.opcode <= 0xBF) || + instr.opcode == 0x2C || instr.opcode == 0x2D || instr.opcode == 0x2E) { + // LIT2, JMP2, JCN2, JSR2, and their variations + code[code_len++] = (instr.operand >> 8) & 0xFF; + code[code_len++] = instr.operand & 0xFF; + } else if (instr.opcode == 0x60) { // JSI + code[code_len++] = instr.operand & 0xFF; + } else if (instr.opcode >= 0x80) { + code[code_len++] = instr.operand & 0xFF; + } + } + + return code_len; +} + +R_IPI int uxn_disassemble(const uint8_t* code, size_t code_size, char *text, size_t text_size) { + Instruction instr = {0}; + instr.opcode = code[0]; + + const char* op = instruction_mnemonics[instr.opcode]; + if (!op) { + op = "invalid"; + } + + size_t len = 1; + if (instr.opcode == 0x80 || (instr.opcode >= 0xA0 && instr.opcode <= 0xBF) || + instr.opcode == 0x2C || instr.opcode == 0x2D || instr.opcode == 0x2E) { + // LIT2, JMP2, JCN2, JSR2, and their variations + instr.operand = (code[1] << 8) | code[2]; + snprintf(text, text_size, "%s 0x%04x", op, instr.operand); + len = 3; + } else if (instr.opcode == 0x60) { // JSI + instr.operand = code[1]; + snprintf(text, text_size, "%s 0x%02x", op, instr.operand); + len = 2; + } else if (instr.opcode >= 0x80) { + instr.operand = code[1]; + snprintf(text, text_size, "%s 0x%02x", op, instr.operand); + len = 2; + } else { + snprintf(text, text_size, "%s", op); + } + + return len; +} + +#if 0 +const char* test_instructions[] = { + "BRK", "INC", "POP", "NIP", "SWP", "ROT", "DUP", "OVR", + "EQU", "NEQ", "GTH", "LTH", "JMP", "JCN", "JSR", "STH", + "LDZ", "STZ", "LDR", "STR", "LDA", "STA", "DEI", "DEO", + "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT", + "LIT 42", "LIT2 1234", "JMP2 0x1000", "JSI 0x20", + "inc2r", "pop2k", "jsr2kr 0x3000" + "BRK", "INC", "POP", "NIP", "SWP", "ROT", "DUP", "OVR", + "EQU", "NEQ", "GTH", "LTH", "JMP", "JCN", "JSR", "STH", + "LDZ", "STZ", "LDR", "STR", "LDA", "STA", "DEI", "DEO", + "ADD", "SUB", "MUL", "DIV", "AND", "ORA", "EOR", "SFT", + "LIT 42", "LIT2 1234", "JMP2 0x1000", "JSI 0x20", + "inc2r", "pop2k", "jsr2kr 0x3000", + "JCN2 0x2000", "JSR2 0x3000", + "LIT2r 0xABCD", "JMP2k 0x4000", "JCN2k 0x5000", "JSR2k 0x6000" +}; +#endif diff --git a/libr/include/r_arch.h b/libr/include/r_arch.h index 82076349ca032..d7cba057f8c7e 100644 --- a/libr/include/r_arch.h +++ b/libr/include/r_arch.h @@ -312,6 +312,7 @@ extern const RArchPlugin r_arch_plugin_mcs96; extern const RArchPlugin r_arch_plugin_mips_cs; extern const RArchPlugin r_arch_plugin_mips_gnu; extern const RArchPlugin r_arch_plugin_msp430; +extern const RArchPlugin r_arch_plugin_nds32; extern const RArchPlugin r_arch_plugin_nios2; extern const RArchPlugin r_arch_plugin_null; extern const RArchPlugin r_arch_plugin_or1k; @@ -333,9 +334,11 @@ extern const RArchPlugin r_arch_plugin_sm5xx; extern const RArchPlugin r_arch_plugin_snes; extern const RArchPlugin r_arch_plugin_sparc_cs; extern const RArchPlugin r_arch_plugin_sparc_gnu; +extern const RArchPlugin r_arch_plugin_stm8; extern const RArchPlugin r_arch_plugin_tms320; extern const RArchPlugin r_arch_plugin_tricore; extern const RArchPlugin r_arch_plugin_tricore_cs; +extern const RArchPlugin r_arch_plugin_uxn; extern const RArchPlugin r_arch_plugin_v810; extern const RArchPlugin r_arch_plugin_v850; extern const RArchPlugin r_arch_plugin_vax; @@ -345,11 +348,9 @@ extern const RArchPlugin r_arch_plugin_x86_cs; extern const RArchPlugin r_arch_plugin_x86_nasm; extern const RArchPlugin r_arch_plugin_x86_nz; extern const RArchPlugin r_arch_plugin_xap; -extern const RArchPlugin r_arch_plugin_stm8; extern const RArchPlugin r_arch_plugin_xcore_cs; extern const RArchPlugin r_arch_plugin_xtensa; extern const RArchPlugin r_arch_plugin_z80; -extern const RArchPlugin r_arch_plugin_nds32; #ifdef __cplusplus }