diff --git a/r2plugin/Makefile b/r2plugin/Makefile index 5a94c73..1449d1c 100644 --- a/r2plugin/Makefile +++ b/r2plugin/Makefile @@ -1,14 +1,24 @@ NAME=asm_adsp219x -R2_PLUGIN_PATH=$(shell r2 -H R2_USER_PLUGINS) +R2_PLUGINS=$(shell r2 -H R2_USER_PLUGINS) +R2_INCDIR=$(shell r2 -H R2_INCDIR) +R2_LIBDIR=$(shell r2 -H R2_LIBDIR) all: $(NAME).so $(NAME).so: $(NAME).c - gcc -shared -Wall -O2 -fPIC $(shell pkg-config --cflags --libs r_asm) $< -o $@ + gcc -shared -Wall -O2 -fPIC \ + -I$(R2_INCDIR) -I$(R2_INCDIR)/sdb \ + -L$(R2_LIBDIR) \ + $(NAME).c -o $@ -lr_arch -lr_util install: $(NAME).so - mkdir -p $(R2_PLUGIN_PATH) - cp $(NAME).so $(R2_PLUGIN_PATH) + mkdir -p $(R2_PLUGINS) + cp -f $(NAME).so $(R2_PLUGINS)/ + +uninstall: + rm -f $(R2_PLUGINS)/$(NAME).so clean: rm -f $(NAME).so + +.PHONY: all install uninstall clean diff --git a/r2plugin/asm_adsp219x.c b/r2plugin/asm_adsp219x.c index 69c1db8..0ac252e 100644 --- a/r2plugin/asm_adsp219x.c +++ b/r2plugin/asm_adsp219x.c @@ -1,61 +1,212 @@ -#include -#include +/* ADSP-219x radare2 arch plugin - LGPL - OpenClaw / adsp219x-re project */ +/* Targets radare2 >= 5.8 (RArchPlugin API) */ -/* ADSP-219x 24-bit Opcode Table (Basic definitions) */ -static const char *AXOP[] = {"AX0", "AX1", "AR", "MR0", "MR1", "MR2", "SR0", "SR1"}; -static const char *AYOP[] = {"AY0", "AY1", "AF", "0"}; -static const char *COND[] = {"EQ", "NE", "GT", "LE", "LT", "GE", "AV", "NAV", "AC", "NAC", "SWCOND", "NSWCOND", "MV", "NMV", "NCE", "TRUE"}; +#include -static int adsp219x_disassemble(RAsm *a, RAsmOp *op, const ut8 *buf, int len) { - if (len < 3) return -1; - ut32 ins = (buf[0] << 16) | (buf[1] << 8) | buf[2]; - op->size = 3; +/* ---- lookup tables ---- */ - /* Simplified decoding for the r2-Backend */ - // Type 1: Compute (11xxxxxx) - if ((ins >> 22) == 0b11) { - ut32 amf = (ins >> 13) & 0x1F; - ut32 xop = (ins >> 8) & 0x7; - ut32 yop = (ins >> 11) & 0x3; - if (amf == 0) r_strbuf_setf(&op->buf_asm, "NOP"); - else if (amf >= 0x10) r_strbuf_setf(&op->buf_asm, "COMPUTE (ALU:%d, %s, %s)", amf, AXOP[xop], AYOP[yop]); - else r_strbuf_setf(&op->buf_asm, "COMPUTE (MAC:%d, %s, %s)", amf, AXOP[xop], AYOP[yop]); - } - // Type 6: Dreg = Imm16 (0100xxxx) - else if ((ins >> 20) == 0b0100) { - ut32 dreg = ins & 0xF; - ut32 data = (ins >> 4) & 0xFFFF; - r_strbuf_setf(&op->buf_asm, "D%d = 0x%x", dreg, data); - } - // Type 10: Jump (000110B xxxxx COND) - else if ((ins >> 19) == 0b00011) { - ut32 addr = (ins >> 4) & 0x1FFF; - ut32 cond = ins & 0xF; - ut8 b = (ins >> 16) & 0x1; - const char *db = b ? " (DB)" : ""; - if (cond == 0xF) r_strbuf_setf(&op->buf_asm, "JUMP 0x%x%s", addr, db); - else r_strbuf_setf(&op->buf_asm, "IF %s JUMP 0x%x%s", COND[cond], addr, db); - } - // Type 30: NOP (00000000) - else if (ins == 0) { - r_strbuf_setf(&op->buf_asm, "NOP"); - } - else { - r_strbuf_setf(&op->buf_asm, "unknown (0x%06x)", ins); - } +static const char *amf_alu[] = { + "Y", "Y+1", "X+Y+C", "X+Y", + "NOT Y", "-Y", "X-Y+C-1", "X-Y", + "Y-1", "Y-X", "Y-X+C-1", "NOT X", + "X AND Y", "X OR Y", "X XOR Y", "ABS X" +}; +static const char *amf_mac[] = { + "NOP", "X*Y (RND)", "MR+X*Y (RND)", "MR-X*Y (RND)", + "X*Y (SS)", "X*Y (SU)", "X*Y (US)", "X*Y (UU)", + "MR+X*Y (SS)", "MR+X*Y (SU)", "MR+X*Y (US)", "MR+X*Y (UU)", + "MR-X*Y (SS)", "MR-X*Y (SU)", "MR-X*Y (US)", "MR-X*Y (UU)" +}; +static const char *cond_str[] = { + "EQ", "NE", "GT", "LE", "LT", "GE", "AV", "NOT AV", + "AC", "NOT AC", "SWCOND", "NOT SWCOND", "MV", "NOT MV", "NOT CE", "TRUE" +}; +static const char *reg0[] = { + "AX0", "AX1", "MX0", "MX1", "AY0", "AY1", "MY0", "MY1", + "MR2", "SR2", "AR", "SI", "MR1", "SR1", "MR0", "SR0" +}; +static const char *dd_str[] = { "AX0", "AX1", "MX0", "MX1" }; +static const char *pd_str[] = { "AY0", "AY1", "MY0", "MY1" }; - return op->size; +/* ---- helpers ---- */ + +static const char *ireg(int g, int idx) { + static const char *names[2][4] = { + {"I0", "I1", "I2", "I3"}, + {"I4", "I5", "I6", "I7"} + }; + return names[g & 1][idx & 3]; +} +static const char *mreg(int g, int idx) { + static const char *names[2][4] = { + {"M0", "M1", "M2", "M3"}, + {"M4", "M5", "M6", "M7"} + }; + return names[g & 1][idx & 3]; } -RAsmPlugin r_asm_plugin_adsp219x = { - .name = "adsp219x", - .desc = "Analog Devices ADSP-219x Disassembler (Air-Gapped RE)", - .arch = "adsp219x", - .bits = 24, - .endian = R_SYS_ENDIAN_BIG, - .disassemble = &adsp219x_disassemble +static const char *amf_str(int code) { + if (code < 16) { + return amf_mac[code]; + } + return amf_alu[code - 16]; +} + +/* ---- decode ---- */ + +static bool decode(RArchSession *as, RAnalOp *op, RArchDecodeMask mask) { + const int len = op->size; + if (len < 3) { + return false; + } + const ut8 *buf = op->bytes; + ut32 ins = ((ut32)buf[0] << 16) | ((ut32)buf[1] << 8) | (ut32)buf[2]; + op->size = 3; + op->type = R_ANAL_OP_TYPE_UNK; + + if (!(mask & R_ARCH_OP_MASK_DISASM)) { + /* lightweight decode: just set size + type */ + if (ins == 0) { + op->type = R_ANAL_OP_TYPE_NOP; + } + return true; + } + + /* ---- Type 30: NOP (0x000000) ---- */ + if (ins == 0) { + op->type = R_ANAL_OP_TYPE_NOP; + op->mnemonic = strdup ("NOP"); + return true; + } + + ut32 top2 = ins >> 22; + + /* ---- Type 1: Compute | DM | PM (top2 == 11) ---- */ + if (top2 == 3) { + ut32 amf = (ins >> 13) & 0x1F; + ut32 dmi = (ins >> 10) & 0x3; + ut32 dmm = (ins >> 8) & 0x3; + ut32 pmi = (ins >> 6) & 0x3; + ut32 pmm = (ins >> 4) & 0x3; + ut32 dd = (ins >> 2) & 0x3; + ut32 pd = (ins >> 0) & 0x3; + + if (amf == 0 && (ins & 0x3FFFFF) == 0) { + op->type = R_ANAL_OP_TYPE_NOP; + op->mnemonic = strdup ("NOP /* Type 1 */"); + } else { + op->type = R_ANAL_OP_TYPE_ADD; + op->mnemonic = r_str_newf ("%s, %s = DM(%s += %s), %s = PM(%s += %s)", + amf_str (amf), + dd_str[dd], ireg (0, dmi), mreg (0, dmm), + pd_str[pd], ireg (1, pmi), mreg (1, pmm)); + } + return true; + } + + /* ---- Type 6: Dreg = Imm16 (bits 23-20 == 0100) ---- */ + if ((ins >> 20) == 4) { + ut32 dreg = ins & 0xF; + ut32 data = (ins >> 4) & 0xFFFF; + op->type = R_ANAL_OP_TYPE_MOV; + op->val = data; + op->mnemonic = r_str_newf ("%s = 0x%04X", reg0[dreg], data); + return true; + } + + /* ---- Type 10: Direct Jump/Call (bits 23-19 == 00011) ---- */ + if ((ins >> 19) == 3) { + ut32 b = (ins >> 18) & 1; /* delayed branch */ + ut32 s = (ins >> 17) & 1; /* 0=jump, 1=call */ + ut32 addr = (ins >> 4) & 0x1FFF; + ut32 cond = ins & 0xF; + const char *db = b ? " (DB)" : ""; + const char *type = s ? "CALL" : "JUMP"; + op->jump = addr; + + if (s) { + op->type = (cond == 0xF) ? R_ANAL_OP_TYPE_CALL : R_ANAL_OP_TYPE_CCALL; + } else { + op->type = (cond == 0xF) ? R_ANAL_OP_TYPE_JMP : R_ANAL_OP_TYPE_CJMP; + } + if (cond != 0xF) { + op->fail = op->addr + 3; + } + + if (cond == 0xF) { + op->mnemonic = r_str_newf ("%s 0x%04X%s", type, addr, db); + } else { + op->mnemonic = r_str_newf ("IF %s %s 0x%04X%s", cond_str[cond], type, addr, db); + } + if (b) { + op->delay = 1; + } + return true; + } + + /* ---- Type 20: RTS / RTI (bits 23-19 == 00101) ---- */ + if ((ins >> 19) == 5) { + ut32 t = (ins >> 18) & 1; /* 0=RTS, 1=RTI */ + ut32 cond = ins & 0xF; + const char *type = t ? "RTI" : "RTS"; + op->type = (cond == 0xF) ? R_ANAL_OP_TYPE_RET : R_ANAL_OP_TYPE_CRET; + op->eob = true; + if (cond == 0xF) { + op->mnemonic = r_str_newf ("%s", type); + } else { + op->mnemonic = r_str_newf ("IF %s %s", cond_str[cond], type); + } + return true; + } + + /* ---- Type 11: DO UNTIL (bits 23-20 == 0010) ---- */ + if ((ins >> 20) == 2) { + ut32 addr = (ins >> 4) & 0x3FFF; + ut32 term = ins & 0xF; + op->type = R_ANAL_OP_TYPE_JMP; + op->jump = addr; + op->mnemonic = r_str_newf ("DO 0x%04X UNTIL %s", addr, cond_str[term]); + return true; + } + + /* ---- fallback ---- */ + op->mnemonic = r_str_newf ("unknown 0x%06X", ins); + return true; +} + +static int archinfo(RArchSession *s, ut32 q) { + switch (q) { + case R_ARCH_INFO_CODE_ALIGN: + return 3; + case R_ARCH_INFO_DATA_ALIGN: + return 1; + case R_ARCH_INFO_MINOP_SIZE: + return 3; + case R_ARCH_INFO_MAXOP_SIZE: + return 3; + default: + return -1; + } +} + +const RArchPlugin r_arch_plugin_adsp219x = { + .meta = { + .name = "adsp219x", + .author = "OpenClaw", + .desc = "Analog Devices ADSP-219x DSP", + .license = "LGPL-3.0-only", + }, + .arch = "adsp219x", + .bits = R_SYS_BITS_PACK (24), + .endian = R_SYS_ENDIAN_BIG, + .info = archinfo, + .decode = decode, }; -#ifndef R2_PLUGIN_INLINE -R_LIB_VERSION_SET(r_asm_plugin_adsp219x, r_asm); +#ifndef R2_PLUGIN_INCORE +R_API RLibStruct radare_plugin = { + .type = R_LIB_TYPE_ARCH, + .data = &r_arch_plugin_adsp219x, + .version = R2_VERSION +}; #endif diff --git a/r2plugin/asm_adsp219x.so b/r2plugin/asm_adsp219x.so new file mode 100755 index 0000000..62df1df Binary files /dev/null and b/r2plugin/asm_adsp219x.so differ diff --git a/r2plugin/r2_adsp219x.py b/r2plugin/r2_adsp219x.py new file mode 100644 index 0000000..8709622 --- /dev/null +++ b/r2plugin/r2_adsp219x.py @@ -0,0 +1,13 @@ +import r2pipe +import sys + +def adsp_disasm(hex_str): + """Simple bridge to our existing disasm logic""" + # For now, just return hex + architecture name as POC + return f"ADSP219x: {hex_str}" + +if __name__ == "__main__": + r2 = r2pipe.open() + # Register architecture via r2pipe hook + # Note: Modern r2 supports python-based asm plugins via 'L' (plugins) + print("ADSP219x Plugin loaded via r2pipe")