From b62ad6517e6a7d78462d5f18867cdd32bcbd3e00 Mon Sep 17 00:00:00 2001 From: Siggi Date: Sun, 12 Apr 2026 14:45:23 +0000 Subject: [PATCH] Fix r2 arch plugin for radare2 >= 5.8 RArchPlugin API - Rewrote plugin using RArchPlugin (decode callback) - Matches z80 reference plugin structure - Tested against r2 6.1.3 - Decodes: NOP, Type 1 (Compute|DM|PM), Type 6 (Imm16), Type 10 (Jump/Call), Type 11 (DO UNTIL), Type 20 (RTS/RTI) - Proper code alignment (3 bytes) via archinfo callback - Delayed branch flag support --- r2plugin/Makefile | 18 ++- r2plugin/asm_adsp219x.c | 255 +++++++++++++++++++++++++++++++-------- r2plugin/asm_adsp219x.so | Bin 0 -> 15960 bytes r2plugin/r2_adsp219x.py | 13 ++ 4 files changed, 230 insertions(+), 56 deletions(-) create mode 100755 r2plugin/asm_adsp219x.so create mode 100644 r2plugin/r2_adsp219x.py 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 0000000000000000000000000000000000000000..62df1df102b45b859eff0b3a1152f9ccc372effa GIT binary patch literal 15960 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 F{|&CYq|pEX literal 0 HcmV?d00001 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")