Files
adsp219x-re/docs/LARGE_ROM_ANALYSIS_WORKFLOW.md

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 adsp219x plugin 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:

  1. validate the entry region manually
  2. mark only plausible functions
  3. follow explicit control flow
  4. distinguish code from tables
  5. expand analysis gradually
  6. 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
  • JUMP or CALL
  • DO ... 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 address
  • pdf: print the current function linearly
  • agf: 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 function
  • VV: visual graph mode
  • afb: 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:

  • aa is less aggressive
  • aaa can 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.

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.