[GH-ISSUE #2735] Structured decompiler-completeness signal in function dossiers (+ optional instruction fallback for dropped blocks) #987

Open
opened 2026-10-15 18:30:08 +00:00 by bsakaguchi · 1 comment
Owner

Originally created by @scadastrangelove on GitHub (Oct 13, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/2735

Summary

Ghidra's decompiler silently drops "unreachable" blocks (jump tables, veneers,
literal-pool-heavy regions) and only reports it as an inline comment in the
pseudocode:

/* WARNING: Removing unreachable block (ram,0x00409e98) */

REA currently passes this comment through inside pseudocode (good — it is not
swallowed), but the rea function dossier carries no structured signal, and
agents routinely ignore inline comments. Concrete failure mode from a recent
audit: an auth-comparison lived entirely in blocks Ghidra classified as
unreachable; the reviewing agent read the pseudocode, saw no comparison after
the parse step, and concluded "fails closed" — a false security verdict. Only a
manual disassembly cross-check of the dropped ranges recovered the real control
flow.

Proposal

  1. In the function operation's dossier, add a structured field:
"decompiler_completeness": {
  "warning_count": 2,
  "dropped_blocks": [{"start": "0x409e98", "end": "0x409eb0", "reason": "unreachable"}],
  "disassembly_available": true
}

so agents can branch on completeness instead of regexing their own pseudocode.

  1. Optionally, when dropped_blocks is non-empty, include the raw disassembly
    of those ranges in the dossier (or accept a flag like
    --include-dropped-disassembly) — the fallback we perform manually today.

The same signal could be surfaced by analyze as a per-binary count, making it
cheap to identify which functions in a corpus need disassembly-level review.

Environment

  • rea-agents 6.4.0, Ghidra 12.1.3 provider, MIPS ELF32 corpus
  • Reproduction: any function whose Ghidra decompilation emits
    "Removing unreachable block" (e.g. jump-table dispatchers in busybox mips1);
    rea decompile <addr> shows the comment, rea function shows no structured flag.
Originally created by @scadastrangelove on GitHub (Oct 13, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/2735 ## Summary Ghidra's decompiler silently drops "unreachable" blocks (jump tables, veneers, literal-pool-heavy regions) and only reports it as an inline comment in the pseudocode: ``` /* WARNING: Removing unreachable block (ram,0x00409e98) */ ``` REA currently passes this comment through inside `pseudocode` (good — it is not swallowed), but the `rea function` dossier carries no structured signal, and agents routinely ignore inline comments. Concrete failure mode from a recent audit: an auth-comparison lived entirely in blocks Ghidra classified as unreachable; the reviewing agent read the pseudocode, saw no comparison after the parse step, and concluded "fails closed" — a false security verdict. Only a manual disassembly cross-check of the dropped ranges recovered the real control flow. ## Proposal 1. In the `function` operation's dossier, add a structured field: ```json "decompiler_completeness": { "warning_count": 2, "dropped_blocks": [{"start": "0x409e98", "end": "0x409eb0", "reason": "unreachable"}], "disassembly_available": true } ``` so agents can branch on completeness instead of regexing their own pseudocode. 2. Optionally, when `dropped_blocks` is non-empty, include the raw disassembly of those ranges in the dossier (or accept a flag like `--include-dropped-disassembly`) — the fallback we perform manually today. The same signal could be surfaced by `analyze` as a per-binary count, making it cheap to identify which functions in a corpus need disassembly-level review. ## Environment - rea-agents 6.4.0, Ghidra 12.1.3 provider, MIPS ELF32 corpus - Reproduction: any function whose Ghidra decompilation emits "Removing unreachable block" (e.g. jump-table dispatchers in busybox mips1); `rea decompile <addr>` shows the comment, `rea function` shows no structured flag.
Author
Owner

@RishTheFish21 commented on GitHub (Oct 15, 2026):

I'd like to take this. Proposed scope for a first PR:

  • analyze_function dossiers get an optional decompiler_completeness field listing each block Ghidra's decompiler removed. It's parsed from its exact Removing unreachable block (<space>,<address>) header warnings, with each block's full range taken from Ghidra's listing, so callers can go straight to that disassembly (already in assembly).
  • Absent means not inspected; an empty list means the decompiler removed nothing. Same convention as #2977.
  • A source-owned AArch64 fixture where the decompiler provably drops a block (a branch on a constant-zero register), checked in the aarch64-jump-table lane on ELF and Mach-O.
<!-- gh-comment-id:6201065412 --> @RishTheFish21 commented on GitHub (Oct 15, 2026): I'd like to take this. Proposed scope for a first PR: - `analyze_function` dossiers get an optional `decompiler_completeness` field listing each block Ghidra's decompiler removed. It's parsed from its exact `Removing unreachable block (<space>,<address>)` header warnings, with each block's full range taken from Ghidra's listing, so callers can go straight to that disassembly (already in `assembly`). - Absent means not inspected; an empty list means the decompiler removed nothing. Same convention as #2977. - A source-owned AArch64 fixture where the decompiler provably drops a block (a branch on a constant-zero register), checked in the `aarch64-jump-table` lane on ELF and Mach-O.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#987
No description provided.