Skip to content

fix(ghidra): headless decompilation on modern Ghidra (Java scripts + JDK discovery)#13

Merged
AdamXweb merged 2 commits into
mainfrom
fix/ghidra-headless-modern
Jul 7, 2026
Merged

fix(ghidra): headless decompilation on modern Ghidra (Java scripts + JDK discovery)#13
AdamXweb merged 2 commits into
mainfrom
fix/ghidra-headless-modern

Conversation

@adamXbot

@adamXbot adamXbot commented Jul 7, 2026

Copy link
Copy Markdown
Collaborator

Re-lands two verified Ghidra fixes that missed the #12 merge

PR #12 was merged at its feature commit, but two follow-up fix commits were
pushed to that branch after it merged, so they never landed on main. Without
them the whole-app decompiler (and the pre-existing single-function decompile)
is broken on modern Ghidra. This re-lands them (cherry-picked, unchanged),
now verified against a real Ghidra 12.1.2 install.

Fixes

  1. .py post-scripts don't work on Ghidra 11.3+/12 — those versions route
    Python scripts through PyGhidra (CPython), which our headless invocation
    doesn't enable, so scripts fail with "Ghidra was not started with PyGhidra."
    PCDumpProgram and PCDecompileFunction are now Java GhidraScripts
    (Ghidra compiles them itself — no Python/pip dep, works on every version).
    This also fixes the existing single-function "Decompile" on network call sites.
  2. The install locator missed symlinked Ghidra (hasDirectoryPath is false
    for a symlink) — e.g. a Homebrew Ghidra linked into ~/Applications. Now
    follows symlinks.
  3. The GUI couldn't find a JDK — a Finder-launched app has no JAVA_HOME
    and no TTY, so Ghidra died with "Unable to locate a Java Runtime."
    GhidraDecompiler now discovers a JDK itself (/usr/libexec/java_home, then
    Homebrew's keg-only openjdk) and sets JAVA_HOME on the Ghidra process.

Testing

Adds an opt-in integration test (PC_GHIDRA_INTEGRATION=1) that runs real
headless Ghidra and asserts decompiled C for both the whole-app dump and the
single-function path. Verified green against Ghidra 12.1.2 / JDK 21 — including
with no JAVA_HOME set (the app self-discovers the JDK). Full suite 324
tests (3 integration skipped by default), 0 failures.

🤖 Generated with Claude Code

adamXbot and others added 2 commits July 7, 2026 23:44
…installs

Verified the whole-app decompiler against a real Ghidra 12 install and found
two problems, now fixed:

- Ghidra 11.3+/12 route `.py` scripts through PyGhidra (CPython), which our
  headless invocation doesn't enable, so both post-scripts failed with "Ghidra
  was not started with PyGhidra." Rewrote PCDumpProgram and PCDecompileFunction
  as Java GhidraScripts, which Ghidra compiles itself — no Python/pip
  dependency, works on every Ghidra version. This also fixes the pre-existing
  single-function "Decompile" action on network call sites.

- The install locator used the URL's `hasDirectoryPath`, which is false for a
  symlink, so it missed symlinked Ghidra installs (e.g. a Homebrew Ghidra
  linked into ~/Applications). It now follows symlinks via FileManager.

Adds an opt-in integration test (PC_GHIDRA_INTEGRATION=1 + JAVA_HOME) that
actually runs headless Ghidra and asserts real decompiled C for both the
whole-app dump and the single-function path. Verified green against Ghidra
12.1.2 / JDK 21. Full suite 276 tests (3 integration skipped by default); app
builds.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…I app

A Finder-launched .app has no JAVA_HOME and no TTY, so Ghidra's analyzeHeadless
couldn't find a JDK and couldn't prompt for one — it died with "Unable to
locate a Java Runtime", making the decompile features look broken in the app
even though the logic is correct.

GhidraDecompiler now locates a JDK itself (via /usr/libexec/java_home, then
Homebrew's keg-only openjdk under /opt/homebrew/opt and /usr/local/opt) and
sets JAVA_HOME on the Ghidra process when it isn't already set. Applies to both
the whole-app dump and the single-function decompile (shared runHeadless).

Verified: the Ghidra integration tests pass with NO JAVA_HOME in the
environment (i.e. the app self-discovers the JDK the way it must for a
Finder-launched app).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@AdamXweb AdamXweb merged commit 728f619 into main Jul 7, 2026
1 check passed
@AdamXweb AdamXweb deleted the fix/ghidra-headless-modern branch July 7, 2026 14:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants