Add analysis support: op->type for all instruction types

Every decode path now sets op->type for r2 analysis:
- R_ANAL_OP_TYPE_NOP/TRAP: NOP, IDLE
- R_ANAL_OP_TYPE_MUL: MAC operations (Type 1, 8, 9)
- R_ANAL_OP_TYPE_ADD: ALU operations (Type 1, 8, 9), MODIFY
- R_ANAL_OP_TYPE_MOV: register loads (Type 6, 7, 17, 18, 25, 33)
- R_ANAL_OP_TYPE_LOAD/STORE: memory access (Type 3, 4, 12, 29, 32)
- R_ANAL_OP_TYPE_JMP/CJMP/CALL: jumps and calls (Type 10, 10a, 19, 36)
- R_ANAL_OP_TYPE_RET: RTS/RTI (Type 20)
- R_ANAL_OP_TYPE_REP: DO UNTIL loops (Type 11)
- R_ANAL_OP_TYPE_SHR: shift operations (Type 14, 15, 16)
- R_ANAL_OP_TYPE_DIV: DIVQ/DIVS (Type 23, 24)
- R_ANAL_OP_TYPE_PUSH: Push/Pop/Cache (Type 26)
- R_ANAL_OP_TYPE_IO: IO/System register (Type 34, 35)
- R_ANAL_OP_TYPE_SWI: SETINT/CLRINT (Type 37)

op->jump set for all branch types.
op->fail set for conditional jumps (next instruction).

Enables: af (function analysis), pdf (function disassembly),
agf (control flow graph), VV (visual graph mode).
Tested: FIR and IIR functions recognized correctly.
This commit is contained in:
Dr. Christian Giessen
2026-04-27 09:06:34 +00:00
parent 82958cfe74
commit 26f01a5bdb

View File

@@ -1,11 +1,11 @@
/* asm_adsp219x.c -- Radare2 arch plugin for Analog Devices ADSP-219x /* asm_adsp219x.c -- Radare2 arch+anal plugin for Analog Devices ADSP-219x
Author: Dr. Christian Giessen Author: Dr. Christian Giessen
Date: 2026 Copyright (C) 2026 Dr. Christian Giessen
Decodes all documented ADSP-219x instruction types (Types 1-37). Decodes all documented ADSP-219x instruction types (Types 1-37)
Most types are verified against open21xx assembler output; see with op->type annotations for analysis, function detection, and
TESTING.md for the current verification matrix and any remaining control flow graphing. Most types verified against open21xx
structural-only cases. */ assembler output; see TESTING.md for the verification matrix. */
#include <r_arch.h> #include <r_arch.h>
@@ -101,6 +101,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("%s, %s=DM(I%d+=M%d), %s=PM(I%d+=M%d)", op->mnemonic = r_str_newf ("%s, %s=DM(I%d+=M%d), %s=PM(I%d+=M%d)",
f, reg0[dd], dmi, dmm, f, reg0[dd], dmi, dmm,
reg0[pd + 4], pmi + 4, pmm + 4); reg0[pd + 4], pmi + 4, pmm + 4);
op->type = (amf < 16) ? R_ANAL_OP_TYPE_MUL : R_ANAL_OP_TYPE_ADD;
return true; return true;
} }
@@ -115,11 +116,17 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
const char *rname = ((ins >> 21) & 1) const char *rname = ((ins >> 21) & 1)
? reg1[reg] : reg0[reg]; ? reg1[reg] : reg0[reg];
if (d) if (d)
op->mnemonic = r_str_newf ("DM(0x%04X) = %s", {
addr, rname); op->mnemonic = r_str_newf ("DM(0x%04X) = %s",
addr, rname);
op->type = R_ANAL_OP_TYPE_STORE;
}
else else
op->mnemonic = r_str_newf ("%s = DM(0x%04X)", {
rname, addr); op->mnemonic = r_str_newf ("%s = DM(0x%04X)",
rname, addr);
op->type = R_ANAL_OP_TYPE_LOAD;
}
return true; return true;
} }
@@ -138,13 +145,19 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 mreg = (ins & 3) | (g ? 4 : 0); ut32 mreg = (ins & 3) | (g ? 4 : 0);
char mem = g ? 'P' : 'D'; char mem = g ? 'P' : 'D';
if (d) if (d)
op->mnemonic = r_str_newf ("%s, %cM(I%d += M%d) = %s", {
f, mem, ireg, mreg, op->mnemonic = r_str_newf ("%s, %cM(I%d += M%d) = %s",
reg0[dreg]); f, mem, ireg, mreg,
reg0[dreg]);
op->type = R_ANAL_OP_TYPE_STORE;
}
else else
op->mnemonic = r_str_newf ("%s, %s = %cM(I%d += M%d)", {
f, reg0[dreg], mem, op->mnemonic = r_str_newf ("%s, %s = %cM(I%d += M%d)",
ireg, mreg); f, reg0[dreg], mem,
ireg, mreg);
op->type = R_ANAL_OP_TYPE_LOAD;
}
return true; return true;
} }
@@ -188,6 +201,8 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("%s = %s(%s, %s)", op->mnemonic = r_str_newf ("%s = %s(%s, %s)",
dst, f, reg0[xreg], dst, f, reg0[xreg],
reg0[yreg]); reg0[yreg]);
op->type = (amf < 16) ? R_ANAL_OP_TYPE_MUL
: R_ANAL_OP_TYPE_ADD;
return true; return true;
} }
@@ -202,6 +217,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
{ {
op->mnemonic = r_str_newf ("%s%s%s%s = %s(%s^2)", op->mnemonic = r_str_newf ("%s%s%s%s = %s(%s^2)",
cp, cs, sp, dst, f, x); cp, cs, sp, dst, f, x);
op->type = R_ANAL_OP_TYPE_MUL;
return true; return true;
} }
@@ -210,6 +226,8 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
{ {
op->mnemonic = r_str_newf ("%s%s%s%s = %s(%s, 0)", op->mnemonic = r_str_newf ("%s%s%s%s = %s(%s, 0)",
cp, cs, sp, dst, f, x); cp, cs, sp, dst, f, x);
op->type = (amf < 16) ? R_ANAL_OP_TYPE_MUL
: R_ANAL_OP_TYPE_ADD;
return true; return true;
} }
@@ -220,6 +238,8 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
: yop_alu[yop_i]; : yop_alu[yop_i];
op->mnemonic = r_str_newf ("%s%s%s%s = %s(%s, %s)", op->mnemonic = r_str_newf ("%s%s%s%s = %s(%s, %s)",
cp, cs, sp, dst, f, x, y); cp, cs, sp, dst, f, x, y);
op->type = (amf < 16) ? R_ANAL_OP_TYPE_MUL
: R_ANAL_OP_TYPE_ADD;
return true; return true;
} }
@@ -288,21 +308,23 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("%s(%s, %s), %s = %s", op->mnemonic = r_str_newf ("%s(%s, %s), %s = %s",
f, x, y, f, x, y,
reg0[ddreg], reg0[sdreg]); reg0[ddreg], reg0[sdreg]);
op->type = (amf < 16) ? R_ANAL_OP_TYPE_MUL
: R_ANAL_OP_TYPE_ADD;
return true; return true;
} }
/* Type 6/7/IO/System (010xxx / 011xxx) */ /* Type 6/7/IO/System (010xxx / 011xxx) */
if (b23_22 == 1) if (b23_22 == 1)
{ {
if (b21_20 == 0) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg0[ins&0xF], (ins>>4)&0xFFFF); return true; } /* Type 6 */ if (b21_20 == 0) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg0[ins&0xF], (ins>>4)&0xFFFF); op->type = R_ANAL_OP_TYPE_MOV; return true; } /* Type 6 */
if (b21_20 == 1) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg1[ins&0xF], (ins>>4)&0xFFFF); return true; } /* Type 7 */ if (b21_20 == 1) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg1[ins&0xF], (ins>>4)&0xFFFF); op->type = R_ANAL_OP_TYPE_MOV; return true; } /* Type 7 */
/* Type 34 and 35 are in the b23_22==0 block below */ /* Type 34 and 35 are in the b23_22==0 block below */
} }
/* Type 8/9/10/11/17... (00xxxx) */ /* Type 8/9/10/11/17... (00xxxx) */
if (b23_22 == 0) if (b23_22 == 0)
{ {
if (b21_20 == 3) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg2[ins&0xF], (ins>>4)&0xFFFF); return true; } /* Type 7 (Reg2) */ if (b21_20 == 3) { op->mnemonic = r_str_newf ("%s = 0x%04X", reg2[ins&0xF], (ins>>4)&0xFFFF); op->type = R_ANAL_OP_TYPE_MOV; return true; } /* Type 7 (Reg2) */
/* Type 36: Long Jump/Call (2-word, bits 23-16 = 00000101) */ /* Type 36: Long Jump/Call (2-word, bits 23-16 = 00000101) */
if ((ins >> 16) == 0x05) if ((ins >> 16) == 0x05)
@@ -416,6 +438,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
b_bit ? " (DB)" : ""); b_bit ? " (DB)" : "");
op->type = R_ANAL_OP_TYPE_CJMP; op->type = R_ANAL_OP_TYPE_CJMP;
op->jump = target; op->jump = target;
op->fail = op->addr + 3;
return true; return true;
} }
/* Type 17: Reg = Reg (bits 23-16 = 00001101) */ /* Type 17: Reg = Reg (bits 23-16 = 00001101) */
@@ -424,6 +447,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("%s = %s", op->mnemonic = r_str_newf ("%s = %s",
get_reg ((ins >> 10) & 3, (ins >> 4) & 0xF), get_reg ((ins >> 10) & 3, (ins >> 4) & 0xF),
get_reg ((ins >> 8) & 3, ins & 0xF)); get_reg ((ins >> 8) & 3, ins & 0xF));
op->type = R_ANAL_OP_TYPE_MOV;
return true; return true;
} }
@@ -469,6 +493,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
sf_names[sf], xop_shift[xop_i], sf_names[sf], xop_shift[xop_i],
reg0[dreg], reg0[dreg],
g ? 'P' : 'D', ireg + base, mreg + base); g ? 'P' : 'D', ireg + base, mreg + base);
op->type = d ? R_ANAL_OP_TYPE_STORE : R_ANAL_OP_TYPE_LOAD;
return true; return true;
} }
@@ -484,6 +509,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("%s %s, %s = %s", op->mnemonic = r_str_newf ("%s %s, %s = %s",
sf_names[sf], reg0[xreg], sf_names[sf], reg0[xreg],
reg0[ddreg], reg0[sdreg]); reg0[ddreg], reg0[sdreg]);
op->type = R_ANAL_OP_TYPE_SHR;
return true; return true;
} }
@@ -502,6 +528,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("IF %s SR = %s %s", op->mnemonic = r_str_newf ("IF %s SR = %s %s",
cond_str[cond], sf_names[sf], cond_str[cond], sf_names[sf],
reg0[xreg]); reg0[xreg]);
op->type = R_ANAL_OP_TYPE_SHR;
return true; return true;
} }
@@ -516,6 +543,8 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ( op->mnemonic = r_str_newf (
"DO 0x%06" PFMT64x " UNTIL %s", "DO 0x%06" PFMT64x " UNTIL %s",
target, cond_str[term]); target, cond_str[term]);
op->type = R_ANAL_OP_TYPE_REP;
op->jump = target;
return true; return true;
} }
@@ -528,6 +557,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("SR = %s %s BY %d", op->mnemonic = r_str_newf ("SR = %s %s BY %d",
sf_names[sf], reg0[xreg], sf_names[sf], reg0[xreg],
exp); exp);
op->type = R_ANAL_OP_TYPE_SHR;
return true; return true;
} }
@@ -552,6 +582,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
} }
op->mnemonic = pos ? strdup (buf) op->mnemonic = pos ? strdup (buf)
: strdup ("MODE NOP"); : strdup ("MODE NOP");
op->type = R_ANAL_OP_TYPE_MOV;
return true; return true;
} }
@@ -561,6 +592,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 r = (ins >> 13) & 1; ut32 r = (ins >> 13) & 1;
op->mnemonic = r_str_newf ("SAT %s", op->mnemonic = r_str_newf ("SAT %s",
r ? "SR" : "MR"); r ? "SR" : "MR");
op->type = R_ANAL_OP_TYPE_MOV;
return true; return true;
} }
@@ -571,6 +603,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 reg = ins & 0xF; ut32 reg = ins & 0xF;
op->mnemonic = r_str_newf ("%s = 0x%03X", op->mnemonic = r_str_newf ("%s = 0x%03X",
reg3[reg], data); reg3[reg], data);
op->type = R_ANAL_OP_TYPE_MOV;
return true; return true;
} }
@@ -608,6 +641,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
int base = g ? 4 : 0; int base = g ? 4 : 0;
op->mnemonic = r_str_newf ("MODIFY(I%d += M%d)", op->mnemonic = r_str_newf ("MODIFY(I%d += M%d)",
ireg + base, mreg + base); ireg + base, mreg + base);
op->type = R_ANAL_OP_TYPE_ADD;
return true; return true;
} }
@@ -617,6 +651,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 xop_i = (ins >> 8) & 0x7; ut32 xop_i = (ins >> 8) & 0x7;
op->mnemonic = r_str_newf ("DIVQ %s", op->mnemonic = r_str_newf ("DIVQ %s",
xop_alu[xop_i]); xop_alu[xop_i]);
op->type = R_ANAL_OP_TYPE_DIV;
return true; return true;
} }
@@ -628,6 +663,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
op->mnemonic = r_str_newf ("DIVS %s, %s", op->mnemonic = r_str_newf ("DIVS %s, %s",
yop_alu[yop_i], yop_alu[yop_i],
xop_alu[xop_i]); xop_alu[xop_i]);
op->type = R_ANAL_OP_TYPE_DIV;
return true; return true;
} }
@@ -669,6 +705,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
pos ? ", " : ""); pos ? ", " : "");
op->mnemonic = pos ? strdup (buf) op->mnemonic = pos ? strdup (buf)
: strdup ("STACK NOP"); : strdup ("STACK NOP");
op->type = R_ANAL_OP_TYPE_PUSH;
return true; return true;
} }
@@ -691,13 +728,19 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
int base = g ? 4 : 0; int base = g ? 4 : 0;
const char *op_str = u ? "+=" : "+"; const char *op_str = u ? "+=" : "+";
if (d) if (d)
op->mnemonic = r_str_newf ("DM(I%d %s %d) = %s", {
ireg + base, op_str, smod, op->mnemonic = r_str_newf ("DM(I%d %s %d) = %s",
reg0[dreg]); ireg + base, op_str, smod,
reg0[dreg]);
op->type = R_ANAL_OP_TYPE_STORE;
}
else else
op->mnemonic = r_str_newf ("%s = DM(I%d %s %d)", {
reg0[dreg], ireg + base, op_str, op->mnemonic = r_str_newf ("%s = DM(I%d %s %d)",
smod); reg0[dreg], ireg + base, op_str,
smod);
op->type = R_ANAL_OP_TYPE_LOAD;
}
return true; return true;
} }
@@ -719,13 +762,19 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
const char *mod = u_bit ? "+=" : "+"; const char *mod = u_bit ? "+=" : "+";
const char *rname = get_reg (rgp, reg); const char *rname = get_reg (rgp, reg);
if (d) if (d)
op->mnemonic = r_str_newf ("%s(I%d %s M%d) = %s", {
mem, ireg + base, mod, mreg + base, op->mnemonic = r_str_newf ("%s(I%d %s M%d) = %s",
rname); mem, ireg + base, mod, mreg + base,
rname);
op->type = R_ANAL_OP_TYPE_STORE;
}
else else
op->mnemonic = r_str_newf ("%s = %s(I%d %s M%d)", {
rname, mem, ireg + base, mod, op->mnemonic = r_str_newf ("%s = %s(I%d %s M%d)",
mreg + base); rname, mem, ireg + base, mod,
mreg + base);
op->type = R_ANAL_OP_TYPE_LOAD;
}
return true; return true;
} }
@@ -752,6 +801,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
"DM(I%d %s M%d) = %s, %s = I%d", "DM(I%d %s M%d) = %s, %s = I%d",
ireg + base, mod, mreg + base, ireg + base, mod, mreg + base,
rname, rname, ireg + base); rname, rname, ireg + base);
op->type = R_ANAL_OP_TYPE_STORE;
return true; return true;
} }
@@ -764,6 +814,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
int base = g ? 4 : 0; int base = g ? 4 : 0;
op->mnemonic = r_str_newf ("MODIFY(I%d += %d)", op->mnemonic = r_str_newf ("MODIFY(I%d += %d)",
ireg + base, mod); ireg + base, mod);
op->type = R_ANAL_OP_TYPE_ADD;
return true; return true;
} }
@@ -775,11 +826,17 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 addr = (addr_hi << 8) | ((ins >> 4) & 0xFF); ut32 addr = (addr_hi << 8) | ((ins >> 4) & 0xFF);
ut32 dreg = ins & 0xF; ut32 dreg = ins & 0xF;
if (d) if (d)
op->mnemonic = r_str_newf ("IO(0x%03X) = %s", {
addr, reg0[dreg]); op->mnemonic = r_str_newf ("IO(0x%03X) = %s",
addr, reg0[dreg]);
op->type = R_ANAL_OP_TYPE_IO;
}
else else
op->mnemonic = r_str_newf ("%s = IO(0x%03X)", {
reg0[dreg], addr); op->mnemonic = r_str_newf ("%s = IO(0x%03X)",
reg0[dreg], addr);
op->type = R_ANAL_OP_TYPE_IO;
}
return true; return true;
} }
/* Type 35: Sys ctrl reg (bits 23-16 = 00000110, bit15=0) */ /* Type 35: Sys ctrl reg (bits 23-16 = 00000110, bit15=0) */
@@ -789,11 +846,17 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 addr = (ins >> 4) & 0xFF; ut32 addr = (ins >> 4) & 0xFF;
ut32 dreg = ins & 0xF; ut32 dreg = ins & 0xF;
if (d) if (d)
op->mnemonic = r_str_newf ("REG(0x%02X) = %s", {
addr, reg0[dreg]); op->mnemonic = r_str_newf ("REG(0x%02X) = %s",
addr, reg0[dreg]);
op->type = R_ANAL_OP_TYPE_IO;
}
else else
op->mnemonic = r_str_newf ("%s = REG(0x%02X)", {
reg0[dreg], addr); op->mnemonic = r_str_newf ("%s = REG(0x%02X)",
reg0[dreg], addr);
op->type = R_ANAL_OP_TYPE_IO;
}
return true; return true;
} }
@@ -804,6 +867,7 @@ decode (RArchSession *as, RAnalOp *op, RAnalOpMask mask)
ut32 bit = ins & 0xF; ut32 bit = ins & 0xF;
op->mnemonic = r_str_newf ("%s %d", op->mnemonic = r_str_newf ("%s %d",
c ? "CLRINT" : "SETINT", bit); c ? "CLRINT" : "SETINT", bit);
op->type = R_ANAL_OP_TYPE_SWI;
return true; return true;
} }
} }