9.6 KiB
Large ADSP-219x ROM Analysis Workflow
This guide describes a practical workflow for reverse engineering a
large raw ADSP-219x ROM image in radare2 using the adsp219x
architecture plugin from this repository.
It is written for the common case where you have a large blob, for example a 1 MB ROM dump, and you do not yet know:
- where code starts and where data starts
- how many independent code regions exist
- where the main loops and dispatchers are
- which PM words are instructions and which are tables
The workflow below is intentionally conservative. For raw DSP ROMs, manual validation beats aggressive auto-analysis.
Assumptions
- The ROM is for an ADSP-219x family DSP.
- Instructions are 24-bit words.
- The dump is raw program memory, not a richly annotated executable.
- You already have a working radare2 installation and the
adsp219xplugin is installed or loadable with-L.
Load The ROM
For an installed plugin:
r2 -a adsp219x -b 24 firmware.bin
For a local plugin build that is not installed:
r2 -a adsp219x -L ./r2plugin/asm_adsp219x.so -b 24 firmware.bin
Why the flags matter:
-a adsp219x: forces the custom architecture plugin-b 24: tells radare2 to treat the code as 24-bit ADSP-219x words
ROM Format Sanity Check
Before analyzing flow, check whether the byte layout looks correct.
ADSP-219x code is usually stored either as:
- packed 24-bit words:
aa bb cc dd ee ff ... - padded 32-bit words with a leading zero byte
If your disassembly looks completely implausible, confirm the ROM format first.
Helpful first commands:
px 64
s 0
pd 16
If the first few decoded instructions look impossible but the hex dump
shows a repeating 00 xx xx xx structure, you may be looking at a
32-bit padded dump and need to strip padding before analysis.
High-Level Strategy
For a large ROM, do not start with aaa.
A better sequence is:
- validate the entry region manually
- mark only plausible functions
- follow explicit control flow
- distinguish code from tables
- expand analysis gradually
- use graph views only after local validation
aaa on a large raw DSP ROM often creates a false sense of structure
by treating valid-looking data words as code.
Workflow Diagram
flowchart TD
A[Load ROM in r2] --> B[Check raw bytes and first instructions]
B --> C{Plausible code at reset area?}
C -- no --> D[Verify ROM packing, offset, endianness, dump source]
D --> B
C -- yes --> E[Create first function manually]
E --> F[Inspect linear disassembly and graph]
F --> G{Looks like real control flow?}
G -- no --> H[Do not mark as function, treat as possible data]
G -- yes --> I[Follow jumps, calls, DO UNTIL loops]
I --> J[Name regions and comment findings]
J --> K[Search for more entry points and dispatchers]
K --> L[Only then expand with broader analysis]
L --> M[Separate code islands from PM data tables]
Step 1: Inspect The Reset Region Manually
Start at address zero unless you have evidence of a different boot mapping.
s 0
pd 20
pd 64
Look for signs of real code:
- immediate register loads
JUMPorCALLDO ... UNTIL- initialization of
I,M,L,CNTR, status registers - branches to other regions
Red flags that suggest you are not in code:
- long stretches of decodeable but nonsensical instructions
- no branches, no calls, no returns
- bizarre register moves with no purpose
- disassembly that looks random but hex bytes look regular
Step 2: Mark The First Function Manually
Once the entry region looks plausible:
s 0
af
pdf
agf
Meaning:
af: define a function at the current addresspdf: print the current function linearlyagf: show the control-flow graph of the current function
This is a better first move than aaa, because it forces you to
validate one region before scaling out.
Step 3: Use Graphs Locally, Not Globally
For a large ROM, graphs are most useful once you already believe the current region is code.
Useful commands:
agf
VV
afb
agf: static graph of current functionVV: visual graph modeafb: list/show basic blocks
If agf produces a clean graph with obvious branches and loop edges,
the region is probably code.
If agf is trivial, chaotic, or makes no semantic sense, you may be
looking at data or a bad function boundary.
Step 4: Expand By Following Explicit Flow
After validating the first function, expand manually through explicit targets:
pdf
axt
afl
Then jump to interesting destinations:
s <target>
af
pdf
agf
Prioritize:
- call targets
- jump targets
- loop bodies
- indirect branch setup code
For ADSP-219x specifically, also watch for:
DO ... UNTIL- tight MAC loops
- register setup for DAGs
- memory access kernels
Step 5: Search For ADSP-219x-Specific Patterns
Search directly for common control-flow patterns:
/a JUMP
/a CALL
/a DO
/a RTS
/a RTI
Also inspect likely DSP kernel patterns:
/a MR
/a MX0
/a MY0
/a IO(
These searches are not perfect, but they help locate:
- processing loops
- dispatch logic
- hardware initialization
- coefficient loads
Step 6: Distinguish Code From Data
In a large ADSP-219x ROM, many PM words are data, not instructions. You must actively separate them.
Heuristic: likely code
A region is likely code if it has:
- incoming xrefs from jumps or calls
- meaningful block structure
- function-like boundaries
- setup followed by control flow
- loops, branches, and exits
Check with:
axt @ <addr>
pdf
agf
Heuristic: likely data
A region is likely data if it has:
- regular numeric patterns in hex
- no meaningful control flow
- no incoming code xrefs
- no returns or loop structure
- many decodeable instructions that make no programmatic sense
Check with both disassembly and raw bytes:
pd 32
px 64
If the hex dump looks more plausible than the disassembly, it is often a table.
ADSP-219x-specific data patterns
Common PM data in DSP firmware:
- FIR coefficients
- IIR coefficients
- FFT sine/cosine tables
- lookup tables
- packed constants
- boot configuration words
These often decode into valid-looking instructions by accident.
Step 7: Delay Global Auto-Analysis
Only after you have mapped a few real code islands should you broaden analysis:
aa
afl
Prefer aa first.
Use aaa only when:
- the ROM format is confirmed
- the entry region is valid
- you already understand where major code regions are
- the plugin behaves consistently on this image
Why this matters:
aais less aggressiveaaacan create junk functions in large raw ROMs- false positives are expensive to clean up mentally
Step 8: Name What You Understand
As soon as a region is understood, name and annotate it.
Useful commands:
afn entry_init
afn main_loop
afn io_dispatch
CCu probable coefficient table
CCu hardware init and watchdog setup
Naming reduces rework and makes graph navigation much easier.
Step 9: Build A Region Map
For a 1 MB ROM, keep a rough map as you go:
- boot/reset code
- hardware init
- interrupt vector area
- main loop
- DSP kernels
- dispatch tables
- PM data tables
- obvious unused or padding regions
This can live in:
- r2 comments
- a notebook
- a separate markdown file
The important thing is to stop treating the ROM as one continuous thing. Large firmware becomes manageable once you divide it into regions.
Step 10: Revisit Ambiguous Areas Later
Do not force a conclusion too early.
When a region is ambiguous:
- leave it unnamed or mark it as tentative
- inspect surrounding xrefs first
- compare with neighboring validated code
- revisit it after understanding more of the firmware
Good reverse engineering on large DSP ROMs is iterative.
Recommended First 15 Minutes
If you want a concrete first-pass routine for a 1 MB ROM:
1. Open the ROM
r2 -a adsp219x -b 24 firmware.bin
2. Check the first bytes and first instructions
s 0
px 64
pd 32
3. If plausible, define the first function
af
pdf
agf
4. Enter visual graph mode
VV
5. Follow obvious branch targets manually
s <target>
af
pdf
agf
6. Search for loops and calls
/a DO
/a CALL
/a JUMP
7. Compare suspicious regions with hex
pd 32
px 64
8. Only then widen analysis
aa
afl
When To Suspect A Bad Decode
Pause and reassess if you see:
- no meaningful flow anywhere near the entry region
- every region looks equally nonsensical
- branch targets never lead to reasonable code
- graph mode shows nonsense everywhere
- the ROM appears to decode but nothing behaves like firmware
Then check:
- ROM packing
- dump alignment
- whether the image is compressed or encrypted
- whether the base offset is wrong
- whether the file contains headers before the actual code
Practical Command Cheat Sheet
Open:
r2 -a adsp219x -b 24 firmware.bin
Start region:
s 0
pd 20
pd 64
px 64
Define and inspect function:
af
pdf
agf
Visual graph:
VV
Search:
/a JUMP
/a CALL
/a DO
/a RTS
Cross-references:
axt
axt @ <addr>
Broader analysis:
aa
afl
Naming:
afn main_loop
CCu probable PM coefficient table
Summary
For a large ADSP-219x ROM:
- do not trust auto-analysis first
- validate the entry region manually
- graph only locally at first
- follow explicit flow edges
- use both disassembly and hex dumps
- treat PM as mixed code and data
- expand analysis gradually
The core rule is simple:
Local confidence first, global analysis later.