sanitizeCName() assumed every flag tail was `<lib>_<fn>`, which corrupted names in actual output: - ELF imports lost their prefix: sym.imp.pthread_mutex_lock became mutex_lock (and sym.imp.__libc_init lost a leading underscore). - Windows API-set DLL names stopped at the first underscore inside the library name, leaving a dot and naming the wrong symbol: sub.api_ms_win_crt_stdio_l1_1_0.dll__set_fmode became ms_win_crt_stdio_l1_1_0.dll__set_fmode. Only strip a real PE `.dll_` separator (case-insensitive); keep the whole tail for ELF imports, handle loc.imp. like sym.imp./imp., and use the same rule for sub. stubs. Normalize the result to a legal C identifier: keep leading underscores, map dots/@/other illegal characters to _, never return empty (a leading digit gets an underscore prefixed). Prefer import metadata when it actually improves the name: registerFunction() now uses a flag realname that differs from the raw flag name (rsym. flags carry their own namespaced name as realname). This matches what registerFunctionFlag and registerFlag already do for ccode output and also fixes those names for e asm.flags.real=true. Regressions in test/db/extras/r2ghidra_ccode: - radare2-testbins/pe/ConsoleApplication1.exe, the reviewer's sub.api_ms_win_crt_stdio_l1_1_0.dll__set_fmode fixture -> _set_fmode - a small ELF .so importing pthread_mutex_lock -> pthread_mutex_lock - hello-arm's sym.imp.__libc_init -> __libc_init
r2ghidra
This is an integration of the Ghidra decompiler for radare2. It is solely based on the decompiler part of Ghidra, which is written entirely in C++, so Ghidra itself is not required at all and the plugin can be built self-contained. This project was presented at r2con 2019 as part of the Cutter talk: https://youtu.be/eHtMiezr7l8?t=950
Installing
An r2pm package is available that can easily be installed like:
r2pm -U
r2pm -ci r2ghidra
By default r2pm will install stuff in your home, you can use -g to use the system wide installation.
Dependencies
To build and install r2ghidra you need the following software installed in your system:
- radare2 (preferably from git, for distro builds ensure the
-devpackage is also installed) - pkg-config - that's how build system find libraries and include files to compile stuff
- acr/make or meson/ninja - pick the build system you like! all of them are maintained and working
- msvc/g++/clang++ - basically a C++ compiler (and a C compiler)
- git/patch - needed to clone ghidra-native and build stuff
If the build fails, please carefully read the error message and act accordingly, r2pm should
handle the PKG_CONFIG_PATH automatically for you in any case.
Portability
r2ghidra is known to work on the following operating systems:
- Termux (Android-arm64)
- macOS / iOS
- GNU/Linux
- Windows
- FreeBSD/x86-64
Usage
To decompile a function, first type af to analize it and then pdg to invoke r2ghidra:
[0x100001060]> pdg?
Usage: pdg # Native Ghidra decompiler plugin
| pdg # Decompile current function with the Ghidra decompiler
| pdg* # Decompiled code is returned to r2 as comment
| pdga # Side by side two column disasm and decompilation
| pdgd # Dump the debug XML Dump
| pdgj # Dump the current decompiled function as JSON
| pdgo # Decompile current function side by side with offsets
| pdgp # Switch to RAsm and RAnal plugins driven by SLEIGH from Ghidra
| pdgs # Display loaded Sleigh Languages
| pdgsd N # Disassemble N instructions with Sleigh and print pcode
| pdgss # Display automatically matched Sleigh Language ID
| pdgw # Write recovered variable types, names and signatures to r2
| pdgx # Dump the XML of the current decompiled function
pdgw updates existing variables and the current function's signature. Unknown
1-, 2-, 4- and 8-byte scalar types are written as fixed-width unsigned integers;
this preserves their size without claiming that signedness was recovered. A
signature is written only when all exported types keep the recovered ABI storage;
individually safe argument types can still be written. Local arrays retain their
element types and dimensions without treating array bounds as proof that adjacent
stack writes are unobservable. Existing named composite types are preserved.
Unsupported types are skipped, and a second write reports no changes once the
recovered types have converged. Use
r2ghidra.write.vars and r2ghidra.write.sig to control the two kinds of writes.
With e asm.arch=r2ghidra, asm.cpu accepts r2 aliases such as arm, ppc,
java, msp430, and sh. Aliases and short Ghidra processor names are
case-insensitive: ArM still selects ARM or AArch64 according to asm.bits.
Full Sleigh IDs, such as AARCH64:LE:64:v8A, use the exact spelling listed by
pdgs and override automatic selection. pdgss prints the selected ID.
Aliases still require the corresponding Sleigh files to be installed; for
example, sh needs the optional SuperH4 processor, not the bundled SuperH.
The plugin leaves cpus unset because r2 treats a nonempty list as a strict
allowlist, which would reject languages added through r2ghidra.sleighhome.
Consequently, e asm.cpu=? and its CPU-name completion list are empty; use
pdgs to list installed languages. This does not remove the r2 aliases.
The following config vars (for the e command) can be used to adjust r2ghidra's behavior:
[0x000275a7]> e?r2ghidra.
r2ghidra.casts: Show type casts where needed
r2ghidra.ccode: Emit clean C identifiers (bare import names, no fcn./sub. prefixes)
r2ghidra.cmt.cpp: C++ comment style
r2ghidra.cmt.indent: Comment indent
r2ghidra.indent: Indent increment
r2ghidra.lang: Custom Sleigh ID to override auto-detection (e.g. x86:LE:32:default)
r2ghidra.linelen: Max line length
r2ghidra.maximplref: Maximum number of references to an expression before showing an explicit variable.
r2ghidra.rawptr: Show unknown globals as raw addresses instead of variables
r2ghidra.roprop: Propagate read-only constants (0,1,2,3,4)
r2ghidra.sleighhome: SLEIGHHOME
r2ghidra.timeout: Run decompilation in a separate process and kill it after a specific time
r2ghidra.verbose: Show verbose warning messages while decompiling
Here, r2ghidra.sleighhome must point to a directory containing the *.sla, *.lspec, ... files for
the architectures that should supported by the decompiler. This is however set up automatically when using
the r2pm package or installing as shown below.
Installation
Most users will just use r2pm -ci r2ghidra to build or update the plugin for the version of r2
Windows Binary installation
First, make sure you have the latest version of radare2 for Windows, which can be found as a binary package in the releases.
Then run the following command from the radare2/bin/ directory to find out the R2_USER_PLUGINS path:
$ r2 -H R2_USER_PLUGINS
Now, download the latest r2ghidra release for Windows and copy the dll file in the R2_USER_PLUGINS directory.
Also download the matching r2ghidra_sleigh-<version>.zip and extract its files into
R2_USER_PLUGINS\r2ghidra_sleigh (the .ldefs files must be directly inside that directory).
The plugin finds this directory automatically, then checks dir.plugins\r2ghidra_sleigh
for a system installation. SLEIGHHOME and e r2ghidra.sleighhome=... remain available
for custom locations.
You should now be able to do pdg while in radare2 to invoke the r2ghidra decompile command.
Building
r2ghidra can be built with meson/ninja and acr/make. Both build systems are maintained, feel free to pick the one you feel more comfortable with.
ACR/Make
The procedure is like the standard autoconf:
$ ./preconfigure # optional, but useful for offline-packagers, as its downloads the external repos
$ ./configure --prefix=$(r2 -H R2_PREFIX)
$ make
$ make install # or make user-install
At the moment there is no way to select which processors to support, so it builds them all and takes a lot of time to compile the sleighfiles.
Meson/Ninja
Also works with muon/samu and that's the preferred way to build r2ghidra on Windows.
meson setup b
meson compile -C b
meson install -C b
Windows
To compile r2ghidra on windows you need Visual Studio and git installed:
preconfigure # find VS installation, sets path and download external code
configure # prepare the build (run meson)
make # compile and zip the result (run ninja)
License
r2ghidra itself is LGPL-3.0-only. See LICENSE.md
for the full statement; the actual license texts live in
LESSER.md (LGPLv3) and COPYING (GPLv3,
referenced by the LGPLv3).
Third-party licenses
r2ghidra statically links / bundles a few third-party components, each under its own license:
- ghidra-native — Apache License 2.0 (statically linked; this is the native portion of the Ghidra decompiler that r2ghidra is built around).
- zlib — zlib License (vendored under
subprojects/zlib).