[AUTOMATED] fix(ghidra): fetch p-code injects from the host instead of failing the function - #427
Merged
Merged
Conversation
…f failing the function In ghidra mode there is no local `.sla`, so no injection payload ever gets a compiled template and the first CALLOTHER carrying a cspec `<callotherfixup>` hard-errored the whole function. `ARM.cspec` and all nine vendored MIPS cspecs declare a `setISAMode` fixup that every interworking branch raises, so six of `fmt_arm`'s seven functions and `plt_mips32/main` produced nothing at all. The two template consumers in `decompile_drive.rs` now fall through to a new defaulted `EngineTranslate::fetch_inject_pcode`, which the ghidra translator answers with a `getPcodeInject` query carrying the live injection context. The response is p-code the host already lifted against that one call site, so it is streamed straight into the emitter and never cached. A host exception becomes a low-level error naming the payload rather than a passed Java exception, so an unsupplied payload costs one function and not the command. No option: this is a strict bug fix. The standalone path keeps the identical `Some(tpl)` arm and its CLI output is byte-for-byte unchanged. Closes #407 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzfafnkDMQiYoifXP5HSC8
…ect seam Dropping the Java-exception arm does not abort the command: the DecompileAt handler turns any Err into the incomplete-function shape, and pass_java_exception only sees the dispatcher's own error. The arm still matches upstream and still names the payload in the warning — that is all it buys. The integration table's call-fixup half is wired but unreachable: remote functions decode with func_inject_id -1 and the remote prototype has no inject arm. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TzfafnkDMQiYoifXP5HSC8
mahaloz
force-pushed
the
fix/ghidra-pcode-inject
branch
from
September 6, 2026 00:19
8c087a6 to
a34970d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
With kuna installed as Ghidra's decompiler core, most ARM and MIPS functions
produce nothing at all: six of
fmt_arm's seven functions andplt_mips32/maincome back with an empty payload, which Ghidra reports as a decode error.
kuna's own warning on that run names the cause:
could not decompile the function at r0x00000504 (inject_userop: callother-fixup template not compiled). Ghidra mode has no local.sla, so no<callotherfixup>body isever compiled, and
ARM.cspec'ssetISAMode— raised by every interworkingBX/BLX — fails the whole function. All nine vendored MIPS cspecs declare the
same fixup. The same functions decompile fine on the CLI, where the template
exists.
The fix
decompile_drive.rsfall through to a new defaultedEngineTranslate::fetch_inject_pcode, which the ghidra translator answerswith a
getPcodeInjectquery — the same seam shape asprobe_register_varnode.p-code the host has already lifted against one call site: two answers for the
same
setISAModediffer in both the fall-through offset and the<addr>stamped on every op, so keying a cache by payload id would silently
miscompile any body that uses
inst_start/inst_next/the call address.payload, as upstream does, so the warning says which injection failed instead
of repeating the host's bare text.
identical template arm and its C is byte-for-byte unchanged; ghidra mode goes
from failing the function to the CLI's answer. A flag would also be
unreachable from the GUI, which is where the affected user is.
The tests
tests/inject_e2e.rsdrives the six failing ARM functions plusframe_dummy,MIPS
main, and AArch64 (whose cspec declares no fixup) through the ghidra-simharness; without the fix six of seven ARM and the MIPS function come back with a
0-byte payload. Each drive also pins the
getCallOtherFixuptraffic, so adegrade that emitted a placeholder without touching the wire would fail. Two
more cover the host declining, by exception and by empty response. In
protocol_e2e.rs, a round trip over bytes captured from a live Ghidra 12.1.2:the request kuna builds is byte-identical to the one Ghidra received, and
Ghidra's own response decodes to the
r0 = r0fixup body.kuna decompile fmt_arm <fn>is unchanged on all seven functions.Closes #407.
🤖 Generated with Claude Code
https://claude.ai/code/session_01TzfafnkDMQiYoifXP5HSC8