├── ghidra-processors.txt.x86arm ├── dist ├── windows │ ├── build.bat │ └── r2pm │ │ ├── install.bat │ │ ├── uninstall.bat │ │ ├── r2pm-u.ps1 │ │ └── r2pm-i.ps1 ├── images │ ├── logo.png │ ├── ghidra_logo_round_white.png │ └── logo.svg ├── debian │ ├── DESCR │ ├── CONFIG │ ├── Makefile │ ├── build.sh │ └── deb.mk ├── docker │ ├── Dockerfile.jessie │ ├── Dockerfile.buster │ └── dockcross ├── macos │ └── Makefile └── tarball │ └── Makefile ├── test ├── .gitignore ├── bins │ ├── rec │ ├── strings │ ├── dectest32 │ ├── dectest64 │ ├── hello-arm │ ├── mach0 │ │ └── arg │ ├── prg │ │ └── t01.prg │ ├── mz │ │ └── unzip.exe │ ├── objc-employee │ ├── elf │ │ ├── crackme0x05 │ │ └── hello_world │ ├── types_rec.h │ ├── Makefile │ ├── types.h │ ├── rec.c │ ├── strings.c │ └── dectest.c ├── Makefile └── db │ └── extras │ └── anal_ghidra ├── configure.bat ├── assert.h ├── config.h.acr ├── subprojects ├── pugixml.wrap ├── zlib.wrap ├── autogen.sh ├── Makefile ├── packagefiles │ ├── pugixml │ │ └── meson.build │ ├── ghidra-native │ │ ├── patches │ │ │ ├── 0091-decompiler-xml-packer.patch │ │ │ ├── 0056-nullderef-workaround.patch │ │ │ ├── 0010-null-subflow.patch │ │ │ ├── 0080-getparent-flow.patch │ │ │ ├── 0090-nocasts-warnings.patch │ │ │ ├── 0024-ignore-symbol-beyond-space.patch │ │ │ ├── 0023-Undef-LoadImage-for-windows.patch │ │ │ ├── 0006-readonly-warning.patch │ │ │ ├── 0044-bad-unicode-codepoint.patch │ │ │ ├── Attic │ │ │ │ ├── 0011-Clean-Sleigh-Descriptions-on-Shutdown.patch │ │ │ │ ├── done │ │ │ │ │ ├── 0017-Make-getBaseState-return-a-pointer-5.patch │ │ │ │ │ ├── 0008-Make-Commas-less-ugly.patch │ │ │ │ │ └── 0012-Make-SleighArchitecture-Langs-public.patch │ │ │ │ ├── 0014-Fix-std-vector-oob-access-in-StringManager-saveXml.patch │ │ │ │ ├── 0021-Fail-gently-in-PrintC-when-a-Basic-Block-gives-an-in.patch │ │ │ │ ├── 0018-Add-FreeBSD-and-OpenBSD-support-6.patch │ │ │ │ ├── 0013-Fix-Build-with-G-4.9.2.patch │ │ │ │ ├── 0009-Make-some-PrintC-methods-virtual.patch │ │ │ │ ├── 0016-Export-two-private-field-to-SLEIGH-plugin.-4.patch │ │ │ │ ├── 0010-Add-Setter-for-NL-before-else.patch │ │ │ │ └── 0007-Add-some-Formatting-Options.patch │ │ │ ├── 0004-public-fields.patch │ │ │ ├── 0093-no-virtual-destructor.patch │ │ │ ├── 0001-space-after-comma.patch │ │ │ ├── 0055-datatype-clone.patch │ │ │ ├── 0100-CHAR-windows.patch │ │ │ ├── 0092-badvar-segfault.patch │ │ │ ├── 0002-make-sleigharch-public.patch │ │ │ ├── 0020-Fix-double-free-crash-when-deinitializing-multiple-X.patch │ │ │ └── 0022-Show-noreturn-information-in-function-signature-2.patch.disabled │ │ └── meson.build │ └── zlib │ │ └── meson.build ├── pugixml.mk ├── zlib.mk ├── ghidra-native.wrap └── ghidra-native.mk ├── .github └── dependabot.yml ├── ghidra-processors.txt.default ├── src ├── r2ghidra.h ├── CodeXMLParse.h ├── PcodeFixupPreprocessor.h ├── PrettyXmlEncode.h ├── R2PrintC.h ├── PrettyXmlEncode.cpp ├── R2LoadImage.h ├── ArchMap.h ├── RCoreMutex.cpp ├── R2Utils.h ├── RCoreMutex.h ├── SleighAnalValue.h ├── R2CommentDatabase.h ├── core_ghidra_plugin.c ├── R2TypeFactory.h ├── R2Architecture.h ├── R2CommentDatabase.cpp ├── PcodeFixupPreprocessor.cpp ├── anal_ghidra_plugin.c ├── R2PrintC.cpp ├── R2LoadImage.cpp ├── Makefile ├── R2Scope.h ├── R2Architecture.cpp ├── SleighAsm.h ├── SleighAnalValue.cpp ├── R2TypeFactory.cpp └── ArchMap.cpp ├── config.mk.acr ├── .gitignore ├── ghidra-processors.txt.all ├── iaito-plugin ├── R2GhidraPlugin.cpp ├── R2GhidraDecompiler.h ├── R2GhidraDecompiler.cpp └── R2GhidraPlugin.h ├── preconfigure ├── ghidra ├── Makefile └── deps.mk ├── make.bat ├── configure.acr ├── autogen.sh ├── sys └── download-artifacts.sh ├── Makefile.acr ├── preconfigure.bat ├── meson.build ├── README.md └── COPYING /ghidra-processors.txt.x86arm: -------------------------------------------------------------------------------- 1 | AARCH64 2 | ARM 3 | x86 4 | -------------------------------------------------------------------------------- /dist/windows/build.bat: -------------------------------------------------------------------------------- 1 | cd ..\.. 2 | preconfigure 3 | configure 4 | make 5 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | /r2r 2 | /r2-testbins 3 | /node_modules 4 | package-lock.json 5 | -------------------------------------------------------------------------------- /test/bins/rec: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/rec -------------------------------------------------------------------------------- /configure.bat: -------------------------------------------------------------------------------- 1 | @echo OFF 2 | echo "Configuring the build directory with cmake" 3 | meson w 4 | -------------------------------------------------------------------------------- /test/bins/strings: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/strings -------------------------------------------------------------------------------- /dist/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/dist/images/logo.png -------------------------------------------------------------------------------- /dist/windows/r2pm/install.bat: -------------------------------------------------------------------------------- 1 | powershell -executionpolicy unrestricted -command .\r2pm-i.ps1 2 | -------------------------------------------------------------------------------- /test/bins/dectest32: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/dectest32 -------------------------------------------------------------------------------- /test/bins/dectest64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/dectest64 -------------------------------------------------------------------------------- /test/bins/hello-arm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/hello-arm -------------------------------------------------------------------------------- /test/bins/mach0/arg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/mach0/arg -------------------------------------------------------------------------------- /test/bins/prg/t01.prg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/prg/t01.prg -------------------------------------------------------------------------------- /dist/windows/r2pm/uninstall.bat: -------------------------------------------------------------------------------- 1 | powershell -executionpolicy unrestricted -command .\r2pm-u.ps1 2 | -------------------------------------------------------------------------------- /test/bins/mz/unzip.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/mz/unzip.exe -------------------------------------------------------------------------------- /test/bins/objc-employee: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/objc-employee -------------------------------------------------------------------------------- /test/bins/elf/crackme0x05: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/elf/crackme0x05 -------------------------------------------------------------------------------- /test/bins/elf/hello_world: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/test/bins/elf/hello_world -------------------------------------------------------------------------------- /assert.h: -------------------------------------------------------------------------------- 1 | #ifndef CUSTOM_ASSERT_H 2 | #define CUSTOM_ASSERT_H 1 3 | 4 | #define assert(x) if ((x)) {} 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /dist/images/ghidra_logo_round_white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/radareorg/r2ghidra/master/dist/images/ghidra_logo_round_white.png -------------------------------------------------------------------------------- /config.h.acr: -------------------------------------------------------------------------------- 1 | #ifndef R2GHIDRA_CONFIG_H 2 | #define R2GHIDRA_CONFIG_H 1 3 | 4 | #define R2GHIDRA_VERSION "@R2GHIDRA_VERSION@" 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /test/bins/types_rec.h: -------------------------------------------------------------------------------- 1 | 2 | typedef struct LinkedList *LL; 3 | 4 | struct LinkedList { 5 | uint32_t data; 6 | uint32_t padding; 7 | LL next; 8 | }; 9 | -------------------------------------------------------------------------------- /subprojects/pugixml.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/zeux/pugixml.git 3 | revision = v1.15 4 | directory = pugixml 5 | patch_directory = pugixml 6 | depth = 1 7 | -------------------------------------------------------------------------------- /subprojects/zlib.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/madler/zlib.git 3 | revision = 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf 4 | directory = zlib 5 | patch_directory = zlib 6 | depth = 1 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | labels: 8 | - buildsystem 9 | -------------------------------------------------------------------------------- /dist/windows/r2pm/r2pm-u.ps1: -------------------------------------------------------------------------------- 1 | $R2_USER_PLUGINS=(radare2 -H R2_USER_PLUGINS) 2 | Remove-Item -Confirm "${R2_USER_PLUGINS}\core_r2ghidra.dll" 3 | Remove-Item -Confirm "${R2_USER_PLUGINS}\r2ghidra_sleigh" 4 | -------------------------------------------------------------------------------- /subprojects/autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | ACR_WRAP=acr-wrap 3 | 4 | for i in *.wrap ; do 5 | o=`echo $i | sed -e 's,.wrap,.mk,'` 6 | echo "[ACR] Wrapping $i" 7 | ${ACR_WRAP} $i > $o 8 | done 9 | 10 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | all: run 2 | 3 | run: 4 | r2r -L db/extras 5 | 6 | attic: r2-testbins 7 | r2r -L db/extras 8 | 9 | r2-testbins: 10 | git clone https://github.com/radareorg/radare2-testbins --depth 1 r2-testbins 11 | 12 | .PHONY: all run attic 13 | -------------------------------------------------------------------------------- /ghidra-processors.txt.default: -------------------------------------------------------------------------------- 1 | 6502 2 | 8051 3 | BPF 4 | eBPF 5 | sBPF 6 | Atmel 7 | AARCH64 8 | ARM 9 | MIPS 10 | MCS96 11 | PowerPC 12 | hexagon 13 | tricore 14 | SuperH 15 | TI_MSP430 16 | RISCV 17 | JVM 18 | Sparc 19 | STM8 20 | V850 21 | Z80 22 | x86 23 | Xtensa 24 | -------------------------------------------------------------------------------- /src/r2ghidra.h: -------------------------------------------------------------------------------- 1 | #ifndef R2GHIDRA_H 2 | #define R2GHIDRA_H 3 | 4 | #undef R_LOG_ORIGIN 5 | #define R_LOG_ORIGIN "r2ghidra" 6 | 7 | #include 8 | 9 | R_API RCodeMeta *r2ghidra_decompile_annotated_code(RCore *core, ut64 addr); 10 | 11 | #endif //R2GHIDRA_H 12 | -------------------------------------------------------------------------------- /dist/debian/DESCR: -------------------------------------------------------------------------------- 1 | Native Ghidra Decompiler plugin for radare2 2 | This plugin adds the ability to use the Ghidra decompiler from r2, without having the need to use Java or Ghidra at all. The plugin ships all the Sleigh arch descriptions and syncs the names and types information with radare2. 3 | -------------------------------------------------------------------------------- /subprojects/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: default all clean 2 | 3 | DEPS=ghidra-native pugixml 4 | ifeq ($(NEED_ZLIB),1) 5 | DEPS += zlib 6 | endif 7 | 8 | ALL=$(basename $(wildcard *.mk)) 9 | 10 | default: $(DEPS) 11 | 12 | all: $(ALL) 13 | 14 | clean: 15 | rm -rf $(ALL) 16 | 17 | include *.mk 18 | -------------------------------------------------------------------------------- /dist/docker/Dockerfile.jessie: -------------------------------------------------------------------------------- 1 | 2 | FROM debian:jessie 3 | 4 | RUN apt-get update 5 | RUN apt-get -y install git g++ pkg-config flex bison 6 | 7 | RUN cd /root && git clone --depth 1 https://github.com/radareorg/radare2 && cd radare2 && ./configure --prefix=/usr && make -j4 && make install 8 | 9 | CMD [] 10 | 11 | -------------------------------------------------------------------------------- /dist/debian/CONFIG: -------------------------------------------------------------------------------- 1 | PACKAGE=r2ghidra 2 | VERSION=$(shell ../../configure -qV) 3 | DEPENDS=radare2 4 | REPLACES=r2ghidra-dec 5 | SECTION=user/shell 6 | PRIORITY=optional 7 | MAINTAINER=pancake 8 | # arch 9 | UNAMEM=$(shell uname -m) 10 | ifeq ($(UNAMEM),x86_64) 11 | ARCH=amd64 12 | else 13 | ARCH=arm64 14 | endif 15 | -------------------------------------------------------------------------------- /dist/docker/Dockerfile.buster: -------------------------------------------------------------------------------- 1 | 2 | FROM debian:buster 3 | 4 | RUN apt-get update 5 | RUN apt-get -y install git g++ pkg-config flex bison unzip patch 6 | 7 | RUN export CFLAGS=-O2 && cd /root && git clone --depth 1 https://github.com/radareorg/radare2 && cd radare2 && ./configure --prefix=/usr && make -j4 && make install 8 | 9 | CMD [] 10 | 11 | -------------------------------------------------------------------------------- /config.mk.acr: -------------------------------------------------------------------------------- 1 | # processed by ./configure 2 | 3 | CXX=@CXX@ 4 | 5 | PKGCONFIG=@PKGCONFIG@ 6 | PREFIX=@PREFIX@ 7 | DATADIR=@DATADIR@ 8 | BINDIR=$(PREFIX)/bin 9 | BISON=@BISON@ 10 | FLEX=@FLEX@ 11 | 12 | R2_CFLAGS=@R2_CFLAGS@ 13 | R2_LDFLAGS=@R2_LDFLAGS@ 14 | VERSION=@VERSION@ 15 | 16 | R2_USER_PLUGINS=@R2_USER_PLUGINS@ 17 | R2_LIBR_PLUGINS=@R2_LIBR_PLUGINS@ 18 | -------------------------------------------------------------------------------- /subprojects/packagefiles/pugixml/meson.build: -------------------------------------------------------------------------------- 1 | project('pugixml', 'cpp', meson_version : '>=0.60.0', version : '1.15') 2 | 3 | pugixml_sources = [ 4 | 'src/pugixml.cpp', 5 | ] 6 | 7 | incdirs = [ 8 | 'src', 9 | ] 10 | 11 | pugixml_dep = declare_dependency( 12 | sources: pugixml_sources, 13 | include_directories: include_directories(incdirs), 14 | ) 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | cmake-build-* 3 | src/sleighc 4 | build 5 | *.swp 6 | *.o 7 | *.so 8 | compile_commands.json 9 | ghidra/flex/ 10 | .vscode 11 | .ccls-cache 12 | .gdb_history 13 | dist/artifacts 14 | dist/tarball/r2ghidra-* 15 | 16 | ghidra-processors.txt 17 | ghidra/sleighc 18 | 19 | subprojects/.wraplock 20 | subprojects/ghidra-native 21 | subprojects/pugixml 22 | subprojects/zlib 23 | -------------------------------------------------------------------------------- /src/CodeXMLParse.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2023 - thestr4ng3r, pancake */ 2 | 3 | #ifndef R2GHIDRA_CODEXMLPARSE_H 4 | #define R2GHIDRA_CODEXMLPARSE_H 5 | 6 | #include 7 | #include 8 | 9 | //using namespace ghidra; 10 | 11 | //class Funcdata; 12 | 13 | R_API RCodeMeta *ParseCodeXML(ghidra::Funcdata *func, const char *xml); 14 | 15 | #endif //R2GHIDRA_CODEXMLPARSE_H 16 | -------------------------------------------------------------------------------- /ghidra-processors.txt.all: -------------------------------------------------------------------------------- 1 | 6502 2 | 68000 3 | 6805 4 | 8048 5 | 8051 6 | 8085 7 | BPF 8 | eBPF 9 | sBPF 10 | AARCH64 11 | ARM 12 | Atmel 13 | CP1600 14 | CR16 15 | DATA 16 | Dalvik 17 | HCS08 18 | HCS12 19 | JVM 20 | MCS96 21 | MIPS 22 | PA-RISC 23 | PIC 24 | PowerPC 25 | RISCV 26 | Sparc 27 | STM8 28 | SuperH 29 | SuperH4 30 | TI_MSP430 31 | Toy 32 | V850 33 | Z80 34 | hexagon 35 | tricore 36 | x86 37 | Xtensa 38 | -------------------------------------------------------------------------------- /iaito-plugin/R2GhidraPlugin.cpp: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2019 - thestr4ng3r */ 2 | 3 | #include "R2GhidraDecompiler.h" 4 | #include "R2GhidraPlugin.h" 5 | 6 | void R2GhidraPlugin::setupPlugin() 7 | { 8 | } 9 | 10 | void R2GhidraPlugin::setupInterface(MainWindow *) 11 | { 12 | } 13 | 14 | void R2GhidraPlugin::registerDecompilers() 15 | { 16 | Core()->registerDecompiler(new R2GhidraDecompiler(Core())); 17 | } -------------------------------------------------------------------------------- /preconfigure: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | git submodule update --init 3 | MAKE=make 4 | ./configure 5 | gmake --version > /dev/null 2>&1 6 | [ $? = 0 ] && MAKE=gmake 7 | 8 | export NEED_ZLIB=1 9 | pkg-config --cflags zlib > /dev/null 2>&1 10 | if [ $? = 0 ]; then 11 | NEED_ZLIB=0 12 | else 13 | echo "Warning: Cannot find system wide zlib" 14 | fi 15 | echo "[*] Checking subprojects... " 16 | ${MAKE} -C subprojects # > /dev/null 17 | # ${MAKE} ghidra-native 18 | -------------------------------------------------------------------------------- /dist/macos/Makefile: -------------------------------------------------------------------------------- 1 | ARCH ?= $(shell uname -m) 2 | V=$(shell ../../configure -qV) 3 | P=r2ghidra_sleigh-$(V)-$(ARCH) 4 | D=$(shell pwd)/$(P) 5 | 6 | all: 7 | rm -rf r2ghidra* 8 | mkdir -p $(P) 9 | make -C ../../src sleigh-install D=$(D) 10 | zip -r $(P).zip $(P) 11 | # package plugin for specific architecture 12 | mkdir r2ghidra-$(V)-macos-$(ARCH) 13 | cp ../../src/*.dylib r2ghidra-$(V)-macos-$(ARCH) 14 | zip -r r2ghidra-$(V)-macos-$(ARCH).zip r2ghidra-$(V)-macos-$(ARCH) 15 | -------------------------------------------------------------------------------- /src/PcodeFixupPreprocessor.h: -------------------------------------------------------------------------------- 1 | #ifndef PCODE_PREPROCESSOR_H 2 | #define PCODE_PREPROCESSOR_H 3 | 4 | #include "R2Architecture.h" 5 | 6 | #include 7 | 8 | class PcodeFixupPreprocessor 9 | { 10 | public: 11 | static void fixupSharedReturnJumpToRelocs(RAnalFunction *function, ghidra::Funcdata *func, RCore *core, R2Architecture &arch); 12 | static bool applyFunctionSignature(const char *funcName, const ghidra::Address &addr, R2Architecture &arch); 13 | }; 14 | 15 | #endif 16 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0091-decompiler-xml-packer.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/prettyprint.cc b/src/decompiler/prettyprint.cc 2 | index 3e8d18a..4d48bf8 100644 3 | --- a/src/decompiler/prettyprint.cc 4 | +++ b/src/decompiler/prettyprint.cc 5 | @@ -279,7 +279,7 @@ void EmitMarkup::setOutputStream(ostream *t) 6 | if (encoder != (Encoder *)0) 7 | delete encoder; 8 | s = t; 9 | - encoder = new PackedEncode(*s); 10 | + encoder = new XmlEncode(*s); 11 | } 12 | 13 | int4 TokenSplit::countbase = 0; 14 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0056-nullderef-workaround.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/merge.hh b/src/decompiler/merge.hh 2 | index bcce463..c965f86 100644 3 | --- a/src/decompiler/merge.hh 4 | +++ b/src/decompiler/merge.hh 5 | @@ -137,6 +137,7 @@ public: 6 | inline bool Merge::compareHighByBlock(const HighVariable *a,const HighVariable *b) 7 | 8 | { 9 | + if (!a || !b) return false; 10 | int4 result = a->getCover().compareTo(b->getCover()); 11 | if ( result == 0 ) { 12 | Varnode *v1 = a->getInstance( 0 ); 13 | -------------------------------------------------------------------------------- /test/bins/Makefile: -------------------------------------------------------------------------------- 1 | 2 | all: 3 | 4 | .PHONY: clean 5 | clean: 6 | rm -fv dectest32 dectest64 rec 7 | 8 | dectest32: dectest.c types.h 9 | gcc -m32 -fno-pic -no-pie -fno-omit-frame-pointer -o dectest32 -O0 dectest.c 10 | 11 | dectest64: dectest.c types.h 12 | gcc -m64 -fno-pic -no-pie -fno-omit-frame-pointer -o dectest64 -O0 dectest.c 13 | 14 | rec: rec.c types_rec.h 15 | gcc -m64 -fno-pic -no-pie -fno-omit-frame-pointer -o rec -O0 rec.c 16 | 17 | strings: strings.c 18 | gcc -m64 -fno-pic -no-pie -fno-omit-frame-pointer -o strings -O0 strings.c 19 | -------------------------------------------------------------------------------- /ghidra/Makefile: -------------------------------------------------------------------------------- 1 | all: sleigh-build 2 | 3 | -include ../config.mk 4 | include deps.mk 5 | 6 | DD=$(DESTDIR)/$(R2_LIBR_PLUGINS)/r2ghidra_sleigh 7 | DH=$(DESTDIR)/$(R2_USER_PLUGINS)/r2ghidra_sleigh 8 | D?=$(DH) 9 | 10 | install: 11 | $(MAKE) sleigh-install D="$(DD)" 12 | 13 | user-install: 14 | $(MAKE) sleigh-install D="$(DH)" 15 | 16 | user-uninstall: 17 | $(MAKE) sleigh-uninstall D="$(DH)" 18 | 19 | clean: 20 | @echo clean 21 | 22 | uninstall: 23 | $(MAKE) sleigh-uninstall D="$(DD)" 24 | 25 | .PHONY: install uninstall user-install user-uninstall all 26 | -------------------------------------------------------------------------------- /src/PrettyXmlEncode.h: -------------------------------------------------------------------------------- 1 | 2 | // SPDX-FileCopyrightText: 2023 Florian Märkl 3 | // SPDX-License-Identifier: LGPL-3.0-or-later 4 | 5 | #ifndef PRETTY_XML_ENCODE_H 6 | #define PRETTY_XML_ENCODE_H 7 | 8 | #include 9 | 10 | class PrettyXmlEncode: public XmlEncode 11 | { 12 | private: 13 | int depth = 0; 14 | void indent(); 15 | 16 | public: 17 | PrettyXmlEncode(std::ostream &s) : XmlEncode(s) {} 18 | void openElement(const ElementId &elemId) override; 19 | void closeElement(const ElementId &elemId) override; 20 | }; 21 | 22 | #endif 23 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0010-null-subflow.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/subflow.cc b/src/decompiler/subflow.cc 2 | index 0c42b50..522c435 100644 3 | --- a/src/decompiler/subflow.cc 4 | +++ b/src/decompiler/subflow.cc 5 | @@ -66,6 +66,9 @@ SubvariableFlow::ReplaceVarnode *SubvariableFlow::setReplacement(Varnode *vn,uin 6 | 7 | { 8 | ReplaceVarnode *res; 9 | + if (vn == nullptr) { 10 | + return nullptr; 11 | + } 12 | if (vn->isMark()) { // Already seen before 13 | map::iterator iter; 14 | iter = varmap.find(vn); 15 | -------------------------------------------------------------------------------- /make.bat: -------------------------------------------------------------------------------- 1 | if EXIST w ( 2 | echo Building R2Ghidra Plugin 3 | ) else ( 4 | configure.bat 5 | ) 6 | 7 | call ninja -C w -j 2 && ( 8 | echo Copying Plugin 9 | mkdir destdir 10 | copy w\*.dll destdir 11 | 12 | REM echo Copying Sleigh Files 13 | REM mkdir destdir\r2ghidra_sleigh 14 | REM copy ghidra-native\src\Processors\*.* destdir\r2ghidra_sleigh 15 | 16 | echo Ziping it Up 17 | cd destdir 18 | python -m zipfile -c r2ghidra-w64.zip core_r2ghidra.dll 19 | dir 20 | cd .. 21 | exit /b 0 22 | ) || ( 23 | echo Ninja compilation has failed 24 | exit /b 1 25 | ) 26 | 27 | 28 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0080-getparent-flow.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/flow.cc b/src/decompiler/flow.cc 2 | index 178047f..78565eb 100644 3 | --- a/src/decompiler/flow.cc 4 | +++ b/src/decompiler/flow.cc 5 | @@ -1006,8 +1006,10 @@ void FlowInfo::connectBasic(void) 6 | op = *iter++; 7 | targ_op = *iter2++; 8 | bs = op->getParent(); 9 | - targ_bs = targ_op->getParent(); 10 | - bblocks.addEdge(bs,targ_bs); 11 | + if (targ_op != nullptr) { 12 | + targ_bs = targ_op->getParent(); 13 | + bblocks.addEdge(bs,targ_bs); 14 | + } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /iaito-plugin/R2GhidraDecompiler.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2019 - thestr4ng3r */ 2 | 3 | #ifndef R2GHIDRA_R2GHIDRADECOMPILER_H 4 | #define R2GHIDRA_R2GHIDRADECOMPILER_H 5 | 6 | #include "Decompiler.h" 7 | #include "R2Task.h" 8 | 9 | class R2GhidraDecompiler: public Decompiler 10 | { 11 | enum DecompilerState {DecompilerRunning, DecompilerFinished}; 12 | private: 13 | DecompilerState task; 14 | 15 | public: 16 | R2GhidraDecompiler(QObject *parent = nullptr); 17 | void decompileAt(RVA addr) override; 18 | bool isRunning() override { return task == DecompilerRunning; } 19 | }; 20 | 21 | #endif //R2GHIDRA_R2GHIDRADECOMPILER_H 22 | -------------------------------------------------------------------------------- /configure.acr: -------------------------------------------------------------------------------- 1 | PKGNAME r2ghidra 2 | VERSION 6.0.7 3 | CONTACT pancake ; pancake@nopcode.org 4 | 5 | LANG_CXX! 6 | CHKPRG! GIT git 7 | USE_PKGCONFIG! 8 | 9 | PKGCFG! R2_CFLAGS R2_LDFLAGS r_core 10 | PKGCFG! R2ASM_CFLAGS R2ASM_LDFLAGS r_asm 11 | PKGCFG! R2ANAL_CFLAGS R2ANAL_LDFLAGS r_anal 12 | CHKPRG! R2 r2 13 | (( 14 | CHKPRG BISON bison 15 | CHKPRG FLEX flex 16 | )) 17 | 18 | EXEC! R2_PREFIX r2 -H R2_PREFIX ; 19 | EXEC! R2_USER_PLUGINS r2 -H R2_USER_PLUGINS ; 20 | EXEC! R2_LIBR_PLUGINS r2 -H R2_LIBR_PLUGINS ; 21 | 22 | R2GHIDRA_VERSION = $VERSION ; 23 | 24 | SUBDIRS config.mk config.h Makefile ; 25 | 26 | REPORT VERSION R2_PREFIX PREFIX PKGCONFIG ; 27 | -------------------------------------------------------------------------------- /test/bins/types.h: -------------------------------------------------------------------------------- 1 | 2 | enum Ambassador 3 | { 4 | AMBASSADOR_PURE = 0, 5 | AMBASSADOR_REASON = 1, 6 | AMBASSADOR_REVOLUTION = 2, 7 | AMBASSADOR_ECHOES = 3, 8 | AMBASSADOR_WALL = 4, 9 | AMBASSADOR_MILLION = 1000000 10 | }; 11 | 12 | struct Window 13 | { 14 | const char *sunlight; 15 | }; 16 | 17 | struct Morning 18 | { 19 | uint32_t saved_argc; 20 | char **saved_argv; 21 | }; 22 | 23 | struct Bright 24 | { 25 | struct Morning *morning; 26 | struct Window window; 27 | enum Ambassador ambassador; 28 | }; 29 | 30 | typedef struct Bright *BrightPtr; 31 | typedef struct Bright BrightTypedefd; 32 | typedef struct BrightTypedefd *BrightTypedefdPtr; 33 | -------------------------------------------------------------------------------- /test/bins/rec.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "types_rec.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | struct LinkedList *BuildList() 12 | { 13 | struct LinkedList *l = NULL; 14 | for(uint32_t i=0; i<50; i++) 15 | { 16 | struct LinkedList *p = l; 17 | l = malloc(sizeof(struct LinkedList)); 18 | l->data = i; 19 | l->next = p; 20 | } 21 | } 22 | 23 | void KillList(struct LinkedList *l) 24 | { 25 | while(l) 26 | { 27 | struct LinkedList *n = l->next; 28 | free(l); 29 | l = n; 30 | } 31 | } 32 | 33 | int main(int argc, char **argv) 34 | { 35 | KillList(BuildList()); 36 | return 0; 37 | } 38 | 39 | -------------------------------------------------------------------------------- /test/bins/strings.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | 6 | const uint16_t utf16_str[] = { 7 | 0x0048, 0x0065, 0x006e, 0x006c, 0x006f, 0x0020, 0x0063, 0x006f, 0x006d, 8 | 0x0070, 0x006c, 0x0065, 0x0074, 0x0065, 0x006c, 0x0079, 0x0020, 0x006f, 9 | 0x0062, 0x0073, 0x006f, 0x006c, 0x0065, 0x0074, 0x0065, 0x0020, 0x0065, 10 | 0x006e, 0x0063, 0x006f, 0x0064, 0x0069, 0x006e, 0x0067, 0x000a, 0x0000 11 | }; 12 | 13 | void use_utf16(const uint16_t *str) 14 | { 15 | (void)str; 16 | } 17 | 18 | int main() 19 | { 20 | puts("Hello this is a regular string\n"); 21 | use_utf16(utf16_str); 22 | fputws(L"This is a wiiiiiiiiiiiide string\n", stdout); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /iaito-plugin/R2GhidraDecompiler.cpp: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2019 - thestr4ng3r */ 2 | 3 | #include "R2GhidraDecompiler.h" 4 | #include "../src/r2ghidra.h" 5 | 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | R2GhidraDecompiler::R2GhidraDecompiler(QObject *parent) 13 | : Decompiler("r2ghidra", "Ghidra", parent) 14 | { 15 | task = DecompilerFinished; 16 | } 17 | 18 | void R2GhidraDecompiler::decompileAt(ut64 addr) 19 | { 20 | task = DecompilerRunning; 21 | RCodeMeta *code = r2ghidra_decompile_annotated_code(Core()->core(), addr); 22 | emit finished(code); //Here, we emit RAnnotatedCode *code or by value 23 | task = DecompilerFinished; 24 | } 25 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0090-nocasts-warnings.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/printc.cc b/src/decompiler/printc.cc 2 | index 64ecda1..a02ca74 100644 3 | --- a/src/decompiler/printc.cc 4 | +++ b/src/decompiler/printc.cc 5 | @@ -3095,6 +3097,7 @@ void PrintC::emitCommentFuncHeader(const Funcdata *fd) 6 | emitLineComment(1,comm); 7 | } 8 | } 9 | +/* 10 | if (option_nocasts) { 11 | if (extralinebreak) 12 | emit->tagLine(); 13 | @@ -3103,6 +3106,7 @@ void PrintC::emitCommentFuncHeader(const Funcdata *fd) 14 | emitLineComment(0,&comm); 15 | extralinebreak = true; 16 | } 17 | +*/ 18 | if (extralinebreak) 19 | emit->tagLine(); // Extra linebreak if comment exists 20 | } 21 | -------------------------------------------------------------------------------- /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # 3 | # Check out the 'acr' tool in: https://github.com/radareorg/acr 4 | # 5 | # -- pancake 6 | 7 | r2pm -h >/dev/null 2>&1 8 | if [ $? = 0 ]; then 9 | echo "Installing the last version of 'acr'..." 10 | r2pm -i acr > /dev/null 11 | r2pm -r acr -h > /dev/null 2>&1 12 | if [ $? = 0 ]; then 13 | echo "Running 'acr -p'..." 14 | r2pm -r acr -p 15 | else 16 | echo "Cannot find 'acr' in PATH" 17 | fi 18 | else 19 | echo "Running acr..." 20 | acr -p 21 | fi 22 | V=`./configure -qV | cut -d - -f -1` 23 | meson rewrite kwargs set project / version "$V" 24 | if [ -n "$1" ]; then 25 | echo "./configure $*" 26 | ./configure $* 27 | fi 28 | vim .github/workflows/ci.yml 29 | # sed -i -e "s,^R2V:.*,R2V: $V" .github/workflows/ci.yml 30 | -------------------------------------------------------------------------------- /subprojects/pugixml.mk: -------------------------------------------------------------------------------- 1 | # This file is autogenerated by acr-wrap 2 | 3 | WRAP_wrap_git_url:=https://github.com/zeux/pugixml.git 4 | WRAP_wrap_git_revision:=v1.15 5 | WRAP_wrap_git_directory:=pugixml 6 | WRAP_wrap_git_patch_directory:=pugixml 7 | WRAP_wrap_git_depth:=1 8 | 9 | .PHONY: pugixml_clean pugixml_all 10 | 11 | pugixml: 12 | if [ ! -d "pugixml" -o "v1.15" != "$(shell cd pugixml 2>/dev/null && git rev-parse HEAD)" ]; then rm -rf "pugixml"; ${MAKE} pugixml_all; fi 13 | 14 | pugixml_all: 15 | git clone --no-checkout --depth=1 https://github.com/zeux/pugixml.git pugixml 16 | cd pugixml && git fetch --depth=1 origin v1.15 17 | cd pugixml && git checkout FETCH_HEAD 18 | cp -rf packagefiles/pugixml/* pugixml 19 | 20 | pugixml_clean: 21 | rm -rf pugixml 22 | -------------------------------------------------------------------------------- /dist/debian/Makefile: -------------------------------------------------------------------------------- 1 | include ./CONFIG 2 | 3 | DEPENDS= 4 | CROSSARCH=x64 5 | PWD=$(shell pwd) 6 | PACKAGE_DIR?=${PWD} 7 | 8 | DOCKCROSS=$(PWD)/../docker/dockcross 9 | R2PLUGDIR=$(shell r2 -H R2_LIBR_PLUGINS) 10 | 11 | all: root 12 | $(MAKE) build 13 | 14 | local: data 15 | $(MAKE) -C ../.. install DESTDIR=$(PWD)/root 16 | $(MAKE) build 17 | 18 | data $(shell pwd)/data: 19 | sudo rm -rf control data 20 | ${MAKE} clean 21 | rm -f data 22 | mkdir -p data 23 | cp -rf root/* data 24 | 25 | build: data 26 | ${MAKE} control 27 | ${MAKE} deb 28 | 29 | root: 30 | cd ../.. && $(DOCKCROSS) --image dockcross/linux-$(CROSSARCH) \ 31 | bash -c 'DESTDIR=/work/dist/debian/root sh dist/debian/build.sh' 32 | 33 | purge: clean 34 | rm -rf root 35 | 36 | summary: 37 | echo $(VERSION) 38 | 39 | include deb.mk 40 | -------------------------------------------------------------------------------- /subprojects/zlib.mk: -------------------------------------------------------------------------------- 1 | # This file is autogenerated by acr-wrap 2 | 3 | WRAP_wrap_git_url:=https://github.com/madler/zlib.git 4 | WRAP_wrap_git_revision:=51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf 5 | WRAP_wrap_git_directory:=zlib 6 | WRAP_wrap_git_patch_directory:=zlib 7 | WRAP_wrap_git_depth:=1 8 | 9 | .PHONY: zlib_clean zlib_all 10 | 11 | zlib: 12 | if [ ! -d "zlib" -o "51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf" != "$(shell cd zlib 2>/dev/null && git rev-parse HEAD)" ]; then rm -rf "zlib"; ${MAKE} zlib_all; fi 13 | 14 | zlib_all: 15 | git clone --no-checkout --depth=1 https://github.com/madler/zlib.git zlib 16 | cd zlib && git fetch --depth=1 origin 51b7f2abdade71cd9bb0e7a373ef2610ec6f9daf 17 | cd zlib && git checkout FETCH_HEAD 18 | cp -rf packagefiles/zlib/* zlib 19 | 20 | zlib_clean: 21 | rm -rf zlib 22 | -------------------------------------------------------------------------------- /src/R2PrintC.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2024 - pancake */ 2 | 3 | #ifndef R2GHIDRA_R2PRINTC_H 4 | #define R2GHIDRA_R2PRINTC_H 5 | 6 | #include 7 | 8 | using namespace ghidra; 9 | 10 | class R2PrintC : public PrintC { 11 | protected: 12 | void pushUnnamedLocation(const Address &addr, const Varnode *vn,const PcodeOp *op) override; 13 | // void opCast(const PcodeOp *op) override; 14 | 15 | public: 16 | explicit R2PrintC(Architecture *g, const string &nm = "c-language"); 17 | void setOptionNoCasts(bool nc); 18 | 19 | }; 20 | 21 | class R2PrintCCapability : public PrintLanguageCapability { 22 | private: 23 | static R2PrintCCapability inst; 24 | R2PrintCCapability(); 25 | 26 | public: 27 | PrintLanguage *buildLanguage(Architecture *glb) override; 28 | }; 29 | 30 | #endif //R2GHIDRA_R2PRINTC_H 31 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0024-ignore-symbol-beyond-space.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/database.cc b/src/decompiler/database.cc 2 | index 6eab457..8d17f38 100644 3 | --- a/src/decompiler/database.cc 4 | +++ b/src/decompiler/database.cc 5 | @@ -1805,9 +1805,10 @@ SymbolEntry *ScopeInternal::addMapInternal(Symbol *sym,uint4 exfl,const Address 6 | string msg = "Symbol "; 7 | msg += sym->getName(); 8 | msg += " extends beyond the end of the address space"; 9 | - throw LowlevelError(msg); 10 | + fprintf (stderr, "%s\n", msg.c_str()); 11 | + //throw LowlevelError(msg); 12 | } 13 | - 14 | + 15 | list::iterator iter = rangemap->insert(initdata,addr.getOffset(),lastaddress.getOffset()); 16 | // Store reference to map in symbol 17 | sym->mapentry.push_back(iter); 18 | -------------------------------------------------------------------------------- /src/PrettyXmlEncode.cpp: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2023 Florian Märkl 2 | // SPDX-License-Identifier: LGPL-3.0-or-later 3 | 4 | #include "PrettyXmlEncode.h" 5 | 6 | void PrettyXmlEncode::indent() { 7 | for (int i = 0; i < depth; i++) { 8 | outStream << " "; 9 | } 10 | } 11 | 12 | void PrettyXmlEncode::openElement(const ElementId &elemId) { 13 | if (elementTagIsOpen) { 14 | outStream << ">\n"; 15 | } else { 16 | elementTagIsOpen = true; 17 | } 18 | indent (); 19 | depth++; 20 | outStream << '<' << elemId.getName(); 21 | } 22 | 23 | void PrettyXmlEncode::closeElement(const ElementId &elemId) { 24 | depth--; 25 | if (elementTagIsOpen) { 26 | outStream << "/>\n"; 27 | elementTagIsOpen = false; 28 | } else { 29 | indent(); 30 | outStream << "\n"; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0023-Undef-LoadImage-for-windows.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/loadimage.hh b/src/decompiler/loadimage.hh 2 | index 76dce9b..2df840a 100644 3 | --- a/src/decompiler/loadimage.hh 4 | +++ b/src/decompiler/loadimage.hh 5 | @@ -21,6 +21,10 @@ 6 | 7 | #include "address.hh" 8 | 9 | +#ifdef LoadImage 10 | +#undef LoadImage 11 | +#endif 12 | + 13 | namespace ghidra { 14 | 15 | /// \brief Exception indicating data was not available 16 | diff --git a/src/decompiler/sleigh.hh b/src/decompiler/sleigh.hh 17 | index 32ef856..f0a7461 100644 18 | --- a/src/decompiler/sleigh.hh 19 | +++ b/src/decompiler/sleigh.hh 20 | @@ -21,6 +21,10 @@ 21 | 22 | #include "sleighbase.hh" 23 | 24 | +#ifdef LoadImage 25 | +#undef LoadImage 26 | +#endif 27 | + 28 | namespace ghidra { 29 | 30 | class LoadImage; 31 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0006-readonly-warning.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/funcdata_varnode.cc b/src/decompiler/funcdata_varnode.cc 2 | index dad2994..5a43b1d 100644 3 | --- a/src/decompiler/funcdata_varnode.cc 4 | +++ b/src/decompiler/funcdata_varnode.cc 5 | @@ -516,6 +516,7 @@ void Funcdata::transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffs 6 | bool Funcdata::fillinReadOnly(Varnode *vn) 7 | 8 | { 9 | +/* 10 | if (vn->isWritten()) { // Can't replace output with constant 11 | PcodeOp *defop = vn->getDef(); 12 | if (defop->isMarker()) 13 | @@ -534,6 +535,7 @@ bool Funcdata::fillinReadOnly(Varnode *vn) 14 | } 15 | return false; // No change was made 16 | } 17 | +*/ 18 | 19 | if (vn->getSize() > sizeof(uintb)) 20 | return false; // Constant will exceed precision 21 | -------------------------------------------------------------------------------- /src/R2LoadImage.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2021 - thestr4ng3r */ 2 | 3 | #ifndef R2GHIDRA_R2LOADIMAGE_H 4 | #define R2GHIDRA_R2LOADIMAGE_H 5 | 6 | #include "loadimage.hh" 7 | 8 | #include 9 | 10 | // Windows defines LoadImage to LoadImageA 11 | #ifdef LoadImage 12 | #undef LoadImage 13 | #endif 14 | 15 | using namespace ghidra; 16 | class RCoreMutex; 17 | 18 | class R2LoadImage : public LoadImage { 19 | private: 20 | RCoreMutex *const coreMutex; 21 | AddrSpaceManager *addr_space_manager; 22 | 23 | public: 24 | explicit R2LoadImage(RCoreMutex *coreMutex, AddrSpaceManager *addr_space_manager); 25 | 26 | void loadFill(uint1 *ptr, int4 size, const Address &addr) override; 27 | string getArchType() const override; 28 | void adjustVma(long adjust) override; 29 | void getReadonly(RangeList &list) const override; 30 | }; 31 | 32 | #endif //R2GHIDRA_R2LOADIMAGE_H 33 | -------------------------------------------------------------------------------- /src/ArchMap.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2023 - thestr4ng3r */ 2 | 3 | #ifndef R2GHIDRA_ARCHMAP_H 4 | #define R2GHIDRA_ARCHMAP_H 5 | 6 | #include 7 | 8 | #include 9 | 10 | #include 11 | 12 | using namespace ghidra; 13 | 14 | /** 15 | * Match sleigh id from whatever is currently configured. 16 | * For regular r2 plugins, guess the matching sleigh id, 17 | * for the specific sleigh plugin, same as SleighIdFromSleighAsmConfig() 18 | */ 19 | std::string SleighIdFromCore(RCore *core); 20 | 21 | /** 22 | * Match sleigh id from sleigh-plugin specific settings (asm.cpu) 23 | */ 24 | std::string SleighIdFromSleighAsmConfig(RCore *core, const char *cpu, int bits, bool bigendian, const vector &langs); 25 | // XXX find a better name, this is used from SleigAsm/asm plugin 26 | int ai(RCore *core, std::string cpu, int query); 27 | 28 | #endif 29 | -------------------------------------------------------------------------------- /iaito-plugin/R2GhidraPlugin.h: -------------------------------------------------------------------------------- 1 | /* radare - LGPL - Copyright 2019 - thestr4ng3r */ 2 | 3 | #ifndef R2GHIDRAPLUGIN_H 4 | #define R2GHIDRAPLUGIN_H 5 | 6 | #include 7 | #include 8 | #include 9 | 10 | class R2GhidraPlugin : public QObject, IaitoPlugin 11 | { 12 | Q_OBJECT 13 | Q_PLUGIN_METADATA(IID "org.radare.iaito.plugins.r2ghidra") 14 | Q_INTERFACES(IaitoPlugin) 15 | 16 | public: 17 | void setupPlugin() override; 18 | void setupInterface(MainWindow *main) override; 19 | void registerDecompilers() override; 20 | 21 | QString getName() const { return "Ghidra Decompiler (r2ghidra)"; } 22 | QString getAuthor() const { return "thestr4ng3r"; } 23 | QString getDescription() const { return "GUI Integration of r2ghidra."; } 24 | QString getVersion() const { return "1.0"; } 25 | }; 26 | 27 | 28 | #endif // IAITOSAMPLEPLUGIN_H 29 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0044-bad-unicode-codepoint.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/stringmanage.cc b/src/decompiler/stringmanage.cc 2 | index 6e60b4f..fb7e2eb 100644 3 | --- a/src/decompiler/stringmanage.cc 4 | +++ b/src/decompiler/stringmanage.cc 5 | @@ -40,14 +40,14 @@ void StringManager::writeUtf8(ostream &s,int4 codepoint) 6 | int4 size; 7 | 8 | if (codepoint < 0) 9 | - throw LowlevelError("Negative unicode codepoint"); 10 | + return; // throw LowlevelError("Negative unicode codepoint"); 11 | if (codepoint < 128) { 12 | s.put((uint1)codepoint); 13 | return; 14 | } 15 | int4 bits = mostsigbit_set(codepoint) + 1; 16 | if (bits > 21) 17 | - throw LowlevelError("Bad unicode codepoint"); 18 | + return; // throw LowlevelError("Bad unicode codepoint"); 19 | if (bits < 12) { // Encode with two bytes 20 | bytes[0] = 0xc0 ^ ((codepoint >> 6)&0x1f); 21 | bytes[1] = 0x80 ^ (codepoint & 0x3f); 22 | -------------------------------------------------------------------------------- /src/RCoreMutex.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2025 - thestr4ng3r, pancake */ 2 | 3 | #include "RCoreMutex.h" 4 | #include 5 | 6 | RCoreMutex::RCoreMutex(RCore *core) : caffeine_level(1), bed(nullptr), _core(core) { 7 | } 8 | 9 | void RCoreMutex::sleepEnd() { 10 | if (caffeine_level < 0) { 11 | return; 12 | } 13 | caffeine_level++; 14 | if (caffeine_level == 1) { 15 | #if R2_VERSION_NUMBER >= 50909 16 | r_cons_sleep_end (_core->cons, bed); 17 | #else 18 | r_cons_sleep_end (bed); 19 | #endif 20 | bed = nullptr; 21 | } 22 | } 23 | 24 | void RCoreMutex::sleepEndForce() { 25 | if (caffeine_level) { 26 | return; 27 | } 28 | sleepEnd (); 29 | } 30 | 31 | void RCoreMutex::sleepBegin() { 32 | if (caffeine_level <= 0) { 33 | return; 34 | } 35 | caffeine_level--; 36 | if (caffeine_level == 0) { 37 | #if R2_VERSION_NUMBER >= 50909 38 | bed = r_cons_sleep_begin (_core->cons); 39 | #else 40 | bed = r_cons_sleep_begin (); 41 | #endif 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/R2Utils.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2023 - thestr4ng3r, pancake */ 2 | 3 | #ifndef R2GHIDRA_R2UTILS_H 4 | #define R2GHIDRA_R2UTILS_H 5 | 6 | typedef struct r_list_t RList; 7 | typedef struct r_list_iter_t RListIter; 8 | 9 | template void r_list_foreach_cpp(RList *list, const F &cb) { 10 | for (RListIter *it = list->head; it; it = it->n) { 11 | cb (reinterpret_cast(it->data)); 12 | } 13 | } 14 | 15 | template void r_interval_tree_foreach_cpp(RIntervalTree *tree, const F &cb) { 16 | RIntervalTreeIter it; 17 | for (it = r_rbtree_first (&(tree)->root->node); r_rbtree_iter_has (&it); r_rbtree_iter_next (&(it))) { 18 | RIntervalNode *node = r_interval_tree_iter_get (&it); 19 | cb (node, reinterpret_cast(node->data)); 20 | } 21 | } 22 | 23 | static inline std::string tolower(std::string str) { 24 | std::transform (str.begin (), str.end (), str.begin (), [](int c) { 25 | return tolower (c); 26 | }); 27 | return str; 28 | } 29 | 30 | #endif 31 | -------------------------------------------------------------------------------- /src/RCoreMutex.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2020-2025 - thestr4ng3r */ 2 | 3 | #ifndef R2GHIDRA_RCOREMUTEX_H 4 | #define R2GHIDRA_RCOREMUTEX_H 5 | 6 | #include 7 | 8 | /** 9 | * Maintains sleep/awake state of the current r2 task like a recursive mutex 10 | * Use with RCoreLock for RAII behavior 11 | */ 12 | class RCoreMutex { 13 | friend class RCoreLock; 14 | 15 | private: 16 | /** 17 | * > 0 => awake 18 | * == 0 => sleeping 19 | */ 20 | int caffeine_level; 21 | void *bed; 22 | RCore *_core; 23 | 24 | public: 25 | RCoreMutex(RCore *core); 26 | 27 | void sleepEnd(); 28 | void sleepEndForce(); 29 | void sleepBegin(); 30 | }; 31 | 32 | class RCoreLock { 33 | private: 34 | RCoreMutex * const mutex; 35 | 36 | public: 37 | explicit RCoreLock(RCoreMutex *mutex) : mutex(mutex) { mutex->sleepEnd(); } 38 | ~RCoreLock() { mutex->sleepBegin(); } 39 | operator RCore *() const { return mutex->_core; } 40 | RCore *operator->() const { return mutex->_core; } 41 | 42 | }; 43 | 44 | #endif //R2GHIDRA_RCOREMUTEX_H 45 | -------------------------------------------------------------------------------- /dist/tarball/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean 2 | VERSION=$(shell ../../configure -qV) 3 | DSTDIR=r2ghidra-${VERSION} 4 | GIT_TIP=HEAD 5 | 6 | ifneq ($(shell xz --help 2>/dev/null | grep improve),) 7 | TAR=tar -cvf 8 | TAREXT=tar.xz 9 | CZ=xz -f 10 | else 11 | TAR=bsdtar cvf 12 | TAREXT=tar.gz 13 | CZ=gzip -f 14 | endif 15 | 16 | all: 17 | rm -rf $(DSTDIR) 18 | mkdir $(DSTDIR) 19 | git -C ../.. archive $(GIT_TIP) | tar -x -C $(DSTDIR) 20 | # git log --decorate=short $(GIT_TIP) > $(DSTDIR)/ChangeLog 21 | 22 | # Subprojects 23 | make -C $(DSTDIR)/subprojects all 24 | rm -rf $(DSTDIR)/subprojects/*/.git 25 | mv $(DSTDIR)/subprojects/Makefile $(DSTDIR)/subprojects/Makefile.orig 26 | echo "default:" > $(DSTDIR)/subprojects/Makefile 27 | 28 | # Cleanup 29 | rm -rf $(DSTDIR)/preconfigure* $(DSTDIR)/.github 30 | 31 | # Archive 32 | ${TAR} "r2ghidra-${VERSION}.tar" $(DSTDIR) ; \ 33 | ${CZ} "r2ghidra-${VERSION}.tar" 34 | zip -r r2ghidra-$(VERSION).zip $(DSTDIR) 35 | 36 | clean: 37 | rm -rf r2ghidra-$(VERSION).zip r2ghidra-$(VERSION).tar* r2ghidra-$(VERSION) 38 | -------------------------------------------------------------------------------- /dist/debian/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | type fakeroot > /dev/null 2>&1 4 | if [ $? = 0 ]; then 5 | FAKEROOT=fakeroot 6 | else 7 | FAKEROOT=sudo 8 | fi 9 | 10 | r2 -qv 11 | 12 | if [ $? != 0 ]; then 13 | # git clone --depth=1 git@github.com:radareorg/radare2 r2 || exit 1 14 | wget -c https://github.com/radareorg/radare2/archive/master.zip 15 | sudo apt-get update 16 | sudo apt-get -y install git g++ make pkg-config flex bison unzip patch 17 | unzip master.zip 18 | mv radare2-master r2 19 | ( cd r2 && sys/debian.sh ) # make -C r2/dist/debian 20 | sudo dpkg -i r2/dist/debian/*/*.deb 21 | fi 22 | [ -z "${DESTDIR}" ] && DESTDIR="/work/dist/debian/root" 23 | 24 | RV=`r2 -qv` 25 | [ -z "${RV}" ] && RV=`r2/configure -qV` 26 | 27 | R2_LIBR_PLUGINS=`r2 -H R2_LIBR_PLUGINS` 28 | [ -z "${R2_LIBR_PLUGINS}" ] && R2_LIBR_PLUGINS=/usr/lib/radare2 29 | 30 | export CFLAGS=-O2 31 | make R2_PLUGDIR=${R2_LIBR_PLUGINS} DESTDIR=${DESTDIR} 32 | 33 | ./configure --prefix=/usr 34 | make -j4 35 | strip --strip-unneeded src/core_ghidra.so 36 | ${FAKEROOT} make install DESTDIR="${DESTDIR}" 37 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0011-Clean-Sleigh-Descriptions-on-Shutdown.patch: -------------------------------------------------------------------------------- 1 | From 8ae5683e2342ec67c0b4efd2cf2d6913b56e62b8 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Sun, 25 Aug 2019 18:23:23 +0200 4 | Subject: [PATCH 11/23] Clean Sleigh Descriptions on Shutdown 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc 11 | index 038bc379e..7cd004b4b 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.cc 14 | @@ -467,5 +467,5 @@ void SleighArchitecture::shutdown(void) 15 | delete last_sleigh; 16 | last_sleigh = (Sleigh *)0; 17 | } 18 | - // description.clear(); // static vector is destroyed by the normal exit handler 19 | + description.clear(); 20 | } 21 | -- 22 | 2.24.3 (Apple Git-128) 23 | 24 | -------------------------------------------------------------------------------- /subprojects/ghidra-native.wrap: -------------------------------------------------------------------------------- 1 | [wrap-git] 2 | url = https://github.com/radareorg/ghidra-native 3 | revision = 0.6.4 4 | directory = ghidra-native 5 | patch_directory = ghidra-native 6 | diff_files = ghidra-native/patches/0001-space-after-comma.patch, ghidra-native/patches/0002-make-sleigharch-public.patch, ghidra-native/patches/0004-public-fields.patch, ghidra-native/patches/0006-readonly-warning.patch, ghidra-native/patches/0010-null-subflow.patch, ghidra-native/patches/0020-Fix-double-free-crash-when-deinitializing-multiple-X.patch, ghidra-native/patches/0023-Undef-LoadImage-for-windows.patch, ghidra-native/patches/0024-ignore-symbol-beyond-space.patch, ghidra-native/patches/0044-bad-unicode-codepoint.patch, ghidra-native/patches/0055-datatype-clone.patch, ghidra-native/patches/0056-nullderef-workaround.patch, ghidra-native/patches/0080-getparent-flow.patch, ghidra-native/patches/0090-nocasts-warnings.patch, ghidra-native/patches/0091-decompiler-xml-packer.patch, ghidra-native/patches/0092-badvar-segfault.patch, ghidra-native/patches/0093-no-virtual-destructor.patch, ghidra-native/patches/0100-CHAR-windows.patch 7 | depth = 1 8 | -------------------------------------------------------------------------------- /dist/windows/r2pm/r2pm-i.ps1: -------------------------------------------------------------------------------- 1 | # powershell -executionpolicy unrestricted -command r2pm.ps1 2 | $R2_USER_PLUGINS=(radare2 -H R2_USER_PLUGINS) 3 | $V="5.8.2" 4 | Remove-Item r2ghidra-${V}-w64.zip 5 | Remove-Item r2ghidra_sleigh-${V}.zip 6 | echo "Downloading blobs" 7 | iwr -OutFile r2ghidra-${V}-w64.zip https://github.com/radareorg/r2ghidra/releases/download/${V}/r2ghidra-${V}-w64.zip 8 | iwr -OutFile r2ghidra_sleigh-${V}.zip https://github.com/radareorg/r2ghidra/releases/download/${V}/r2ghidra_sleigh-${V}.zip 9 | # python -m wget https://github.com/radareorg/r2ghidra/releases/download/${V}/r2ghidra-${V}-w64.zip 10 | # python -m wget https://github.com/radareorg/r2ghidra/releases/download/${V}/r2ghidra_sleigh-${V}.zip 11 | echo "Expanding blobs" 12 | Expand-Archive -Force -Path r2ghidra-${V}-w64.zip 13 | Expand-Archive -Force -Path r2ghidra_sleigh-${V}.zip 14 | echo "Installing plugin" 15 | Remove-Item "${R2_USER_PLUGINS}\core_r2ghidra.dll" 16 | Move-Item -Path r2ghidra-${V}-w64\core_r2ghidra.dll -Force -Destination "${R2_USER_PLUGINS}\core_r2ghidra.dll" 17 | Remove-Item "${R2_USER_PLUGINS}\r2ghidra_sleigh" 18 | Move-Item -Path r2ghidra_sleigh-${V} -Force -Destination "${R2_USER_PLUGINS}\r2ghidra_sleigh" 19 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/done/0017-Make-getBaseState-return-a-pointer-5.patch: -------------------------------------------------------------------------------- 1 | From 815e71870e67c29187a20ee2563a11c09acb5a93 Mon Sep 17 00:00:00 2001 2 | From: FXTi 3 | Date: Wed, 26 Aug 2020 22:37:55 +0800 4 | Subject: [PATCH 17/23] Make getBaseState return a pointer (#5) 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/context.hh | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh 11 | index 5920bceb4..5d2e108f7 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh 14 | @@ -90,7 +90,7 @@ private: 15 | int4 alloc; // Number of ConstructState's allocated 16 | int4 delayslot; // delayslot depth 17 | protected: 18 | - ConstructState *getBaseState(void) { return base_state; } 19 | + ConstructState **getBaseState(void) { return &base_state; } 20 | public: 21 | ParserContext(ContextCache *ccache); 22 | ~ParserContext(void) { if (context != (uintm *)0) delete [] context; } 23 | -- 24 | 2.24.3 (Apple Git-128) 25 | 26 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0014-Fix-std-vector-oob-access-in-StringManager-saveXml.patch: -------------------------------------------------------------------------------- 1 | From 49accbd25688976dc665b8bc7abd8775de2b26ed Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Thu, 11 Jun 2020 21:39:54 +0200 4 | Subject: [PATCH 14/23] Fix std::vector oob access in StringManager::saveXml() 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc 11 | index 6e60b4f66..60b6d6852 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/stringmanage.cc 14 | @@ -98,7 +98,7 @@ void StringManager::saveXml(ostream &s) const 15 | s << " \n" << setfill('0'); 18 | - for(int4 i=0;stringData.byteData.size();++i) { 19 | + for(uintp i=0;i 3 | Date: Sun, 14 Mar 2021 22:20:31 +0100 4 | Subject: [PATCH 21/23] Fail gently in PrintC when a Basic Block gives an 5 | invalid Address 6 | 7 | --- 8 | Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc | 4 ++++ 9 | 1 file changed, 4 insertions(+) 10 | 11 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 12 | index 56c37e783..07461326a 100644 13 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 14 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 15 | @@ -2904,6 +2904,10 @@ void PrintC::emitLabel(const FlowBlock *bl) 16 | if (bl == (FlowBlock *)0) return; 17 | BlockBasic *bb = (BlockBasic *)bl->subBlock(0); 18 | Address addr = bb->getEntryAddr(); 19 | + if (addr.isInvalid()) { 20 | + emit->print("INVALID_ADDRESS"); 21 | + return; 22 | + } 23 | const AddrSpace *spc = addr.getSpace(); 24 | uintb off = addr.getOffset(); 25 | if (!bb->hasSpecialLabel()) { 26 | -- 27 | 2.24.3 (Apple Git-128) 28 | 29 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0004-public-fields.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/context.hh b/src/decompiler/context.hh 2 | index 3372e5a..5d2e108 100644 3 | --- a/src/decompiler/context.hh 4 | +++ b/src/decompiler/context.hh 5 | @@ -89,6 +89,8 @@ private: 6 | ConstructState *base_state; 7 | int4 alloc; // Number of ConstructState's allocated 8 | int4 delayslot; // delayslot depth 9 | +protected: 10 | + ConstructState **getBaseState(void) { return &base_state; } 11 | public: 12 | ParserContext(ContextCache *ccache); 13 | ~ParserContext(void) { if (context != (uintm *)0) delete [] context; } 14 | diff --git a/src/decompiler/sleigh.hh b/src/decompiler/sleigh.hh 15 | index 1a758a4..1e96c2c 100644 16 | --- a/src/decompiler/sleigh.hh 17 | +++ b/src/decompiler/sleigh.hh 18 | @@ -166,6 +166,7 @@ protected: 19 | ParserContext *obtainContext(const Address &addr,int4 state) const; 20 | void resolve(ParserContext &pos) const; ///< Generate a parse tree suitable for disassembly 21 | void resolveHandles(ParserContext &pos) const; ///< Prepare the parse tree for p-code generation 22 | + ContextCache *getContextCache(void) { return cache; } 23 | public: 24 | Sleigh(LoadImage *ld,ContextDatabase *c_db); ///< Constructor 25 | virtual ~Sleigh(void); ///< Destructor 26 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0093-no-virtual-destructor.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/constseq.hh b/src/decompiler/constseq.hh 2 | index dbfc3c5..0036c53 100644 3 | --- a/src/decompiler/constseq.hh 4 | +++ b/src/decompiler/constseq.hh 5 | @@ -112,6 +112,7 @@ public: 6 | if (!grouplist.contains(getGroup())) return (Rule *)0; 7 | return new RuleStringCopy(getGroup()); 8 | } 9 | + virtual ~RuleStringCopy(); 10 | virtual void getOpList(vector &oplist) const; 11 | virtual int4 applyOp(PcodeOp *op,Funcdata &data); 12 | }; 13 | @@ -123,6 +124,7 @@ public: 14 | if (!grouplist.contains(getGroup())) return (Rule *)0; 15 | return new RuleStringStore(getGroup()); 16 | } 17 | + virtual ~RuleStringStore(); 18 | virtual void getOpList(vector &oplist) const; 19 | virtual int4 applyOp(PcodeOp *op,Funcdata &data); 20 | }; 21 | diff --git a/src/decompiler/coreaction.cc b/src/decompiler/coreaction.cc 22 | index bed14fc..8a808d5 100644 23 | --- a/src/decompiler/coreaction.cc 24 | +++ b/src/decompiler/coreaction.cc 25 | @@ -21,6 +21,10 @@ 26 | 27 | namespace ghidra { 28 | 29 | +RuleStringCopy::~RuleStringCopy() {} 30 | + 31 | +RuleStringStore::~RuleStringStore() {} 32 | + 33 | /// \brief A stack equation 34 | struct StackEqn { 35 | int4 var1; ///< Variable with 1 coefficient 36 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0001-space-after-comma.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/printc.cc b/src/decompiler/printc.cc 2 | index b2637c1..eac56f7 100644 3 | --- a/src/decompiler/printc.cc 4 | +++ b/src/decompiler/printc.cc 5 | @@ -54,7 +54,7 @@ OpToken PrintC::boolean_and = { "&&", "", 2, 22, false, OpToken::binary, 1, 0, ( 6 | OpToken PrintC::boolean_xor = { "^^", "", 2, 20, false, OpToken::binary, 1, 0, (OpToken *)0 }; 7 | OpToken PrintC::boolean_or = { "||", "", 2, 18, false, OpToken::binary, 1, 0, (OpToken *)0 }; 8 | OpToken PrintC::assignment = { "=", "", 2, 14, false, OpToken::binary, 1, 5, (OpToken *)0 }; 9 | -OpToken PrintC::comma = { ",", "", 2, 2, true, OpToken::binary, 0, 0, (OpToken *)0 }; 10 | +OpToken PrintC::comma = { ", ", "", 2, 2, true, OpToken::binary, 0, 0, (OpToken *)0 }; 11 | OpToken PrintC::new_op = { "", "", 2, 62, false, OpToken::space, 1, 0, (OpToken *)0 }; 12 | 13 | // Inplace assignment operators 14 | @@ -82,7 +82,7 @@ const string PrintC::CLOSE_CURLY = "}"; 15 | const string PrintC::SEMICOLON = ";"; 16 | const string PrintC::COLON = ":"; 17 | const string PrintC::EQUALSIGN = "="; 18 | -const string PrintC::COMMA = ","; 19 | +const string PrintC::COMMA = ", "; 20 | const string PrintC::DOTDOTDOT = "..."; 21 | const string PrintC::KEYWORD_VOID = "void"; 22 | const string PrintC::KEYWORD_TRUE = "true"; -------------------------------------------------------------------------------- /src/SleighAnalValue.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2020-2021 - FXTi, pancake */ 2 | 3 | #ifndef R2GHIDRA_SLEIGHANALVALUE_H 4 | #define R2GHIDRA_SLEIGHANALVALUE_H 5 | 6 | #include "SleighAsm.h" 7 | 8 | struct SleighAnalValue: public RAnalValue { 9 | public: 10 | SleighAnalValue() { 11 | // access = RAnalValueAccess(0); 12 | memref = base = delta = imm = mul = 0; 13 | absolute = false; 14 | seg = reg = regdelta = nullptr; 15 | } 16 | 17 | static SleighAnalValue resolve_arg(RAnal *anal, const PcodeOperand *arg); 18 | 19 | static std::vector resolve_out(RAnal *anal, 20 | std::vector::const_iterator curr_op, 21 | std::vector::const_iterator end_op, 22 | const PcodeOperand *arg); 23 | 24 | bool is_valid() const { return absolute; } 25 | bool is_imm() const { return type == R_ANAL_VAL_IMM; } 26 | bool is_reg() const { return type == R_ANAL_VAL_REG; } 27 | bool is_mem() const { return type == R_ANAL_VAL_MEM; } 28 | 29 | void invalid() { absolute = false; } 30 | void mem(uint4 size); 31 | RAnalValue *dup() const; 32 | 33 | private: 34 | static RAnalValueType type_from_values(const SleighAnalValue &in0, const SleighAnalValue &in1); 35 | 36 | template 37 | static inline T inner_max(T foo, T bar) { 38 | return foo > bar? foo: bar; 39 | } 40 | }; 41 | 42 | #endif // R2GHIDRA_SLEIGHANALVALUE_H 43 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0055-datatype-clone.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/type.hh b/src/decompiler/type.hh 2 | index 92d4882..26bfa3e 100644 3 | --- a/src/decompiler/type.hh 4 | +++ b/src/decompiler/type.hh 5 | @@ -201,12 +201,12 @@ protected: 6 | void encodeTypedef(Encoder &encoder) const; ///< Encode \b this as a \e typedef element to a stream 7 | void markComplete(void) { flags &= ~(uint4)type_incomplete; } ///< Mark \b this data-type as completely defined 8 | void setDisplayFormat(uint4 format); ///< Set a specific display format 9 | - virtual Datatype *clone(void) const=0; ///< Clone the data-type 10 | static uint8 hashName(const string &nm); ///< Produce a data-type id by hashing the type name 11 | static uint8 hashSize(uint8 id,int4 size); ///< Reversibly hash size into id 12 | protected: 13 | static int4 calcAlignSize(int4 sz,int4 align); ///< Calculate aligned size, given size and alignment of data-type 14 | public: 15 | + virtual Datatype *clone(void) const=0; ///< Clone the data-type 16 | /// Construct the base data-type copying low-level properties of another 17 | Datatype(const Datatype &op) { size = op.size; name=op.name; displayName=op.displayName; metatype=op.metatype; 18 | submeta=op.submeta; flags=op.flags; id=op.id; typedefImm=op.typedefImm; alignment=op.alignment; alignSize=op.alignSize; } 19 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0100-CHAR-windows.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/slghparse.cc b/src/decompiler/slghparse.cc 2 | index ec1f76a..01abe32 100644 3 | --- a/src/decompiler/slghparse.cc 4 | +++ b/src/decompiler/slghparse.cc 5 | @@ -246,7 +246,7 @@ extern int sleighdebug; 6 | ELLIPSIS_KEY = 344, 7 | GLOBALSET_KEY = 345, 8 | BITRANGE_KEY = 346, 9 | - CHAR = 347, 10 | + CHARVALUE = 347, 11 | INTEGER = 348, 12 | INTB = 349, 13 | STRING = 350, 14 | diff --git a/src/decompiler/slghparse.hh b/src/decompiler/slghparse.hh 15 | index 3d615cc..065e1e9 100644 16 | --- a/src/decompiler/slghparse.hh 17 | +++ b/src/decompiler/slghparse.hh 18 | @@ -161,7 +161,7 @@ extern int sleighdebug; 19 | ELLIPSIS_KEY = 344, 20 | GLOBALSET_KEY = 345, 21 | BITRANGE_KEY = 346, 22 | - CHAR = 347, 23 | + CHARVALUE = 347, 24 | INTEGER = 348, 25 | INTB = 349, 26 | STRING = 350, 27 | diff --git a/src/decompiler/slghscan.cc b/src/decompiler/slghscan.cc 28 | index 82f7e82..4e21247 100644 29 | --- a/src/decompiler/slghscan.cc 30 | +++ b/src/decompiler/slghscan.cc 31 | @@ -2138,7 +2138,7 @@ YY_RULE_SETUP 32 | YY_BREAK 33 | case 61: 34 | YY_RULE_SETUP 35 | -{ sleighlval.ch = sleightext[0]; return CHAR; } 36 | +{ sleighlval.ch = sleightext[0]; return CHARVALUE; } 37 | YY_BREAK 38 | case 62: 39 | YY_RULE_SETUP 40 | -------------------------------------------------------------------------------- /src/R2CommentDatabase.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2023 - thestr4ng3r, pancake */ 2 | 3 | #ifndef R2GHIDRA_R2COMMENTDATABASE_H 4 | #define R2GHIDRA_R2COMMENTDATABASE_H 5 | 6 | #include 7 | 8 | using namespace ghidra; 9 | 10 | class R2Architecture; 11 | 12 | class R2CommentDatabase : public CommentDatabase { 13 | R2Architecture *arch; 14 | mutable CommentDatabaseInternal cache; 15 | mutable bool cache_filled; 16 | void fillCache(const Address &fad) const; 17 | 18 | public: 19 | R2CommentDatabase(R2Architecture *arch); 20 | 21 | void clear() override; 22 | void clearType(const Address &fad, uint4 tp) override; 23 | 24 | void addComment(uint4 tp, const Address &fad, const Address &ad, const string &txt) override; 25 | bool addCommentNoDuplicate(uint4 tp, const Address &fad, const Address &ad, const string &txt) override; 26 | 27 | void deleteComment(Comment *com) override { 28 | throw LowlevelError("deleteComment unimplemented"); 29 | } 30 | 31 | CommentSet::const_iterator beginComment(const Address &fad) const override; 32 | CommentSet::const_iterator endComment(const Address &fad) const override; 33 | 34 | void encode(Encoder &encoder) const override { cache.encode(encoder); } 35 | void decode(Decoder &decoder) override { throw LowlevelError("CommentDatabaseGhidra::decode unimplemented"); } 36 | }; 37 | 38 | #endif //R2GHIDRA_R2COMMENTDATABASE_H 39 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0092-badvar-segfault.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/varmap.cc b/src/decompiler/varmap.cc 2 | index ce1660b..4928ad0 100644 3 | --- a/src/decompiler/varmap.cc 4 | +++ b/src/decompiler/varmap.cc 5 | @@ -1198,7 +1198,7 @@ void ScopeLocal::markUnaliased(const vector &alias) 6 | // NOTE: this is primarily to reset aliasing between 7 | // stack parameters and stack locals 8 | if (aliason && (curoff - curalias > 0xffff)) aliason = false; 9 | - if (!aliason) symbol->getScope()->setAttribute(symbol,Varnode::nolocalalias); 10 | + if (!aliason && symbol->getName().length () > 0) symbol->getScope()->setAttribute(symbol,Varnode::nolocalalias); 11 | if (symbol->isTypeLocked() && alias_block_level != 0) { 12 | if (alias_block_level == 3) 13 | aliason = false; // For this level, all locked data-types block aliases 14 | diff --git a/src/decompiler/database.cc b/src/decompiler/database.cc 15 | index 5544616..ec1a036 100644 16 | --- a/src/decompiler/database.cc 17 | +++ b/src/decompiler/database.cc 18 | @@ -158,6 +158,8 @@ Datatype *SymbolEntry::getSizedType(const Address &inaddr,int4 sz) const 19 | else 20 | off = (int4)(inaddr.getOffset() - addr.getOffset()) + offset; 21 | Datatype *cur = symbol->getType(); 22 | + if (symbol->getName().length() == 0) 23 | + return nullptr; 24 | return symbol->getScope()->getArch()->types->getExactPiece(cur, off, sz); 25 | } 26 | 27 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0002-make-sleigharch-public.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/sleigh_arch.hh b/src/decompiler/sleigh_arch.hh 2 | index 695622e..1bccbef 100644 3 | --- a/src/decompiler/sleigh_arch.hh 4 | +++ b/src/decompiler/sleigh_arch.hh 5 | @@ -116,7 +116,6 @@ class SleighArchitecture : public Architecture { 6 | protected: 7 | ostream *errorstream; ///< Error stream associated with \b this SleighArchitecture 8 | // buildLoader must be filled in by derived class 9 | - static void collectSpecFiles(ostream &errs); ///< Gather specification files in normal locations 10 | virtual Translate *buildTranslator(DocumentStorage &store); 11 | virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void); 12 | virtual void buildTypegrp(DocumentStorage &store); 13 | @@ -138,6 +137,8 @@ public: 14 | virtual ~SleighArchitecture(void); 15 | virtual string getDescription(void) const; 16 | 17 | + static void collectSpecFiles(ostream &errs); ///< Gather specification files in normal locations 18 | + static const vector &getLanguageDescriptions() { return description; } 19 | static string normalizeProcessor(const string &nm); ///< Try to recover a \e language \e id processor field 20 | static string normalizeEndian(const string &nm); ///< Try to recover a \e language \e id endianess field 21 | static string normalizeSize(const string &nm); ///< Try to recover a \e language \e id size field 22 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/done/0008-Make-Commas-less-ugly.patch: -------------------------------------------------------------------------------- 1 | From bfa4d25c3154306fe03b853efec84bbc9d19c518 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Thu, 25 Jul 2019 19:00:44 +0200 4 | Subject: [PATCH 08/23] Make Commas less ugly 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc | 2 +- 8 | 1 file changed, 1 insertion(+), 1 deletion(-) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 11 | index c7e290fe8..19acbfaf0 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 14 | @@ -52,7 +52,7 @@ OpToken PrintC::boolean_and = { "&&", 2, 22, false, OpToken::binary, 1, 0, (OpTo 15 | OpToken PrintC::boolean_xor = { "^^", 2, 20, false, OpToken::binary, 1, 0, (OpToken *)0 }; 16 | OpToken PrintC::boolean_or = { "||", 2, 18, false, OpToken::binary, 1, 0, (OpToken *)0 }; 17 | OpToken PrintC::assignment = { "=", 2, 14, false, OpToken::binary, 1, 5, (OpToken *)0 }; 18 | -OpToken PrintC::comma = { ",", 2, 2, true, OpToken::binary, 0, 0, (OpToken *)0 }; 19 | +OpToken PrintC::comma = { ", ", 2, 2, true, OpToken::binary, 0, 0, (OpToken *)0 }; 20 | OpToken PrintC::new_op = { "", 2, 62, false, OpToken::space, 1, 0, (OpToken *)0 }; 21 | 22 | // Inplace assignment operators 23 | -- 24 | 2.24.3 (Apple Git-128) 25 | 26 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0020-Fix-double-free-crash-when-deinitializing-multiple-X.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/xml.cc b/src/decompiler/xml.cc 2 | index 51fb587..3a064d4 100644 3 | --- a/src/decompiler/xml.cc 4 | +++ b/src/decompiler/xml.cc 5 | @@ -98,8 +98,6 @@ 6 | #include 7 | #include 8 | 9 | -string Attributes::bogus_uri("http://unused.uri"); 10 | - 11 | /// \brief The XML character scanner 12 | /// 13 | /// Tokenize a byte stream suitably for the main XML parser. The scanner expects an ASCII or UTF-8 14 | diff --git a/src/decompiler/xml.hh b/src/decompiler/xml.hh 15 | index 75e7dd9..93f6278 100644 16 | --- a/src/decompiler/xml.hh 17 | +++ b/src/decompiler/xml.hh 18 | @@ -27,6 +27,7 @@ 19 | 20 | using namespace std; 21 | 22 | +#define bogus_uri "http://unused.uri" 23 | /// \brief The \e attributes for a single XML element 24 | /// 25 | /// A container for name/value pairs (of strings) for the formal attributes, as collected during parsing. 26 | @@ -34,7 +35,6 @@ using namespace std; 27 | /// This also holds other properties of the element that are unused in this implementation, 28 | /// including the \e namespace URI. 29 | class Attributes { 30 | - static string bogus_uri; ///< A placeholder for the namespace URI that should be attached to the element 31 | // static string prefix; 32 | string *elementname; ///< The name of the XML element 33 | vector name; ///< List of names for each formal XML attribute 34 | -------------------------------------------------------------------------------- /sys/download-artifacts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | WORKFLOWS="ci.yml" 6 | DESTDIR="dist/artifacts" 7 | LIMIT=100 8 | 9 | if ! command -v gh &> /dev/null; then 10 | echo "GitHub CLI (gh command) could not be found" 11 | exit 1 12 | fi 13 | 14 | cd `dirname $PWD/$0`/.. 15 | 16 | COMMIT="$1" # Optional 17 | if [ -z "${COMMIT}" ]; then 18 | COMMIT=`git rev-parse HEAD` 19 | echo "Detected commit: ${COMMIT}" 20 | fi 21 | 22 | echo "Removing old dist artifacts..." 23 | rm -Rf "${DESTDIR}" 24 | 25 | for WORKFLOW in $WORKFLOWS; do 26 | echo "Looking for ${COMMIT} in ${WORKFLOW} last ${LIMIT} executions..." 27 | RUN_ID=`gh run list --workflow "${WORKFLOW}" --limit "${LIMIT}" --json "databaseId,headSha" --jq '.[] | select(.headSha=="'"${COMMIT}"'") | .databaseId'` 28 | if [ -n "${RUN_ID}" ]; then 29 | echo "Found run id ${RUN_ID} for ${WORKFLOW} workflow." 30 | echo "Downloading all artifacts..." 31 | gh run download "${RUN_ID}" --dir "${DESTDIR}" 32 | else 33 | echo "No execution found for ${COMMIT} in the last ${LIMIT} executions of ${WORKFLOW} workflow." 34 | exit 1 35 | fi 36 | done 37 | 38 | echo "Artifacts downloaded:" 39 | find "${DESTDIR}" -type f 40 | 41 | # Move plugin ZIPs up from nested dist/macos subdirs into the artifact root 42 | for d in "${DESTDIR}"/macos-pkg-*; do 43 | if [ -d "$d/dist/macos" ]; then 44 | mv "$d/dist/macos/"*.zip "$d/" 2>/dev/null || true 45 | rm -rf "$d/dist" 46 | fi 47 | done 48 | 49 | echo "Flattened plugin ZIPs:" 50 | find "${DESTDIR}" -type f -name '*.zip' 51 | -------------------------------------------------------------------------------- /src/core_ghidra_plugin.c: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2025 - thestr4ng3r, pancake */ 2 | 3 | #include 4 | #include "../config.h" 5 | 6 | #if R2_VERSION_NUMBER >= 50909 7 | extern bool r2ghidra_core_fini(RCorePluginSession *cps); 8 | extern bool r2ghidra_core_init(RCorePluginSession *cps); 9 | extern bool r2ghidra_core_cmd(RCorePluginSession *cps, const char *cmd); 10 | #else 11 | extern int r2ghidra_core_fini(void *user, const char *cmd); 12 | extern int r2ghidra_core_init(void *user, const char *cmd); 13 | extern int r2ghidra_core_cmd(void *user, const char *input); 14 | #endif 15 | 16 | RCorePlugin r_core_plugin_ghidra = { 17 | #if R2_VERSION_NUMBER > 50808 18 | .meta = { 19 | .name = "r2ghidra", 20 | .desc = "Ghidra decompiler with pdg command", 21 | .license = "GPL3", 22 | .author = "thestr4ng3r, pancake", 23 | .version = R2GHIDRA_VERSION, 24 | }, 25 | #else 26 | .name = "r2ghidra", 27 | .desc = "Ghidra decompiler with pdg command", 28 | .license = "GPL3", 29 | .author = "thestr4ng3r, pancake", 30 | #endif 31 | .call = r2ghidra_core_cmd, 32 | .init = r2ghidra_core_init, 33 | .fini = r2ghidra_core_fini 34 | }; 35 | 36 | #ifndef CORELIB 37 | #ifdef __cplusplus 38 | extern "C" 39 | #endif 40 | R_API RLibStruct radare_plugin = { 41 | .type = R_LIB_TYPE_CORE, 42 | .data = &r_core_plugin_ghidra, 43 | .version = R2_VERSION, 44 | .free = NULL, 45 | #if R2_VERSION_NUMBER >= 50909 46 | .abiversion = R2_ABIVERSION, 47 | #endif 48 | #if R2_VERSION_NUMBER >= 40200 49 | .pkgname = "r2ghidra" 50 | #endif 51 | }; 52 | #endif 53 | -------------------------------------------------------------------------------- /src/R2TypeFactory.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2021 - thestr4ng3r, pancake */ 2 | 3 | #ifndef R2GHIDRA_R2TYPEFACTORY_H 4 | #define R2GHIDRA_R2TYPEFACTORY_H 5 | 6 | #include 7 | 8 | /* 9 | typedef struct r_parse_ctype_t RParseCType; 10 | typedef struct r_parse_ctype_type_t RParseCTypeType; 11 | */ 12 | 13 | using namespace ghidra; 14 | class R2Architecture; 15 | 16 | class R2TypeFactory : public TypeFactory { 17 | private: 18 | R2Architecture *arch; 19 | // RParseCType *ctype; 20 | 21 | Datatype *queryR2Struct(const string &n, std::set &stackTypes); 22 | Datatype *queryR2Enum(const string &n); 23 | Datatype *queryR2Typedef(const string &n, std::set &stackTypes); 24 | Datatype *queryR2(const string &n, std::set &stackTypes); 25 | 26 | protected: 27 | Datatype *findById(const string &n, uint8 id, int4 sz, std::set &stackTypes); 28 | Datatype *findById(const string &n, uint8 id, int4 sz) override; 29 | using TypeFactory::findByName; 30 | Datatype *findByName(const string &n, std::set &stackTypes) { return findById(n, 0, 0, stackTypes); } 31 | 32 | public: 33 | using StackTypes = std::set; 34 | R2TypeFactory(R2Architecture *arch); 35 | ~R2TypeFactory() override; 36 | 37 | Datatype *fromCString(const string &str, string *error = nullptr, std::set *stackTypes = nullptr); 38 | // Datatype *fromCType(const RParseCTypeType *ctype, string *error = nullptr, std::set *stackTypes = nullptr); 39 | }; 40 | 41 | #endif //R2GHIDRA_R2TYPEFACTORY_H 42 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0018-Add-FreeBSD-and-OpenBSD-support-6.patch: -------------------------------------------------------------------------------- 1 | From 20caeaccb5e2b85e7c0f519b5f23cddea24b8801 Mon Sep 17 00:00:00 2001 2 | From: Anton Kochkov 3 | Date: Tue, 22 Dec 2020 17:28:02 +0800 4 | Subject: [PATCH 18/23] Add FreeBSD and OpenBSD support (#6) 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/types.h | 4 ++-- 8 | 1 file changed, 2 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/types.h b/Ghidra/Features/Decompiler/src/decompile/cpp/types.h 11 | index ff6f423ab..6d5b6acb2 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/types.h 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/types.h 14 | @@ -71,7 +71,7 @@ typedef char int1; 15 | typedef uint8 uintp; 16 | #endif 17 | 18 | -#if defined (__linux__) && (defined (__i386__) || defined (__arm__)) 19 | +#if (defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__)) && (defined (__i386__) || defined (__arm__)) 20 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 21 | #define HOST_ENDIAN 1 22 | #else 23 | @@ -90,7 +90,7 @@ typedef char int1; 24 | typedef uint4 uintp; 25 | #endif 26 | 27 | -#if defined (__linux__) && (defined (__x86_64__) || defined (__aarch64__)) 28 | +#if (defined (__linux__) || defined (__FreeBSD__) || defined (__OpenBSD__)) && (defined (__x86_64__) || defined (__aarch64__)) 29 | #if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 30 | #define HOST_ENDIAN 1 31 | #else 32 | -- 33 | 2.24.3 (Apple Git-128) 34 | 35 | -------------------------------------------------------------------------------- /Makefile.acr: -------------------------------------------------------------------------------- 1 | include config.mk 2 | DESTDIR?= 3 | 4 | GHIDRA_NATIVE_COMMIT=0.5.0 5 | 6 | all: ghidra-processors.txt 7 | $(MAKE) -C src 8 | $(MAKE) -C ghidra 9 | 10 | c: 11 | make -C src -j4 12 | 13 | purge: clean 14 | $(MAKE) uninstall 15 | $(MAKE) user-uninstall 16 | 17 | ghidra-processors.txt: 18 | cp -f ghidra-processors.txt.default ghidra-processors.txt 19 | 20 | asan: ghidra-processors.txt 21 | CFLAGS=-g CXXFLAGS=-g $(MAKE) -C src asan 22 | 23 | asan-run: 24 | DYLD_INSERT_LIBRARIES=/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/lib/clang/12.0.0/lib/darwin/libclang_rt.asan_osx_dynamic.dylib r2 -s 9664 /Users/pancake/Downloads/usr-4/bin/bc 25 | 26 | help: 27 | @echo 28 | @echo "./configure # first you need to run configure" 29 | @echo "make # build r2ghidra plugins" 30 | @echo "make install # install plugin and sleighs into prefix" 31 | @echo "make uninstall # uninstall r2ghidra from prefix (see user-uninstall)" 32 | @echo "make user-install # install in your home" 33 | @echo "make user-uninstall # uninstall r2ghidra from prefix (see user-uninstall)" 34 | @echo 35 | 36 | clean: 37 | $(MAKE) -C src clean 38 | $(MAKE) -C ghidra clean 39 | rm -f ghidra-processors.txt 40 | rm -f config.mk 41 | 42 | install uninstall user-install user-uninstall: 43 | $(MAKE) -C src $@ 44 | $(MAKE) -C ghidra $@ 45 | 46 | mrproper: clean 47 | rm -rf subprojects/ghidra-native 48 | rm -rf subprojects/pugixml 49 | 50 | r2ghidra_sleigh.zip dist: 51 | rm -rf tmp && mkdir -p tmp 52 | $(MAKE) -C ghidra user-install DH=$(shell pwd)/tmp/r2ghidra_sleigh-$(VERSION) 53 | cd tmp && zip -r ../r2ghidra_sleigh-$(VERSION).zip * 54 | rm -rf tmp 55 | 56 | 57 | .PHONY: mrproper clean install uninstall all dist 58 | -------------------------------------------------------------------------------- /src/R2Architecture.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2023 - thestr4ng3r */ 2 | 3 | #ifndef R2GHIDRA_R2ARCHITECTURE_H 4 | #define R2GHIDRA_R2ARCHITECTURE_H 5 | 6 | #include "sleigh_arch.hh" 7 | #include "architecture.hh" 8 | 9 | #include "RCoreMutex.h" 10 | 11 | using namespace ghidra; 12 | 13 | class R2TypeFactory; 14 | typedef struct r_core_t RCore; 15 | 16 | class R2Architecture : public SleighArchitecture { 17 | private: 18 | RCoreMutex coreMutex; 19 | 20 | R2TypeFactory *r2TypeFactory_ = nullptr; 21 | std::map registers; 22 | std::vector warnings; 23 | 24 | bool rawptr = false; 25 | 26 | void loadRegisters(const Translate *translate); 27 | 28 | public: 29 | explicit R2Architecture(RCore *core, const std::string &sleigh_id); 30 | 31 | RCoreMutex *getCore() { return &coreMutex; } 32 | 33 | R2TypeFactory *getTypeFactory() const { return r2TypeFactory_; } 34 | 35 | ProtoModel *protoModelFromR2CC(const char *cc); 36 | Address registerAddressFromR2Reg(const char *regname); 37 | 38 | void addWarning(const std::string &warning) { warnings.push_back(warning); } 39 | const std::vector getWarnings() const { return warnings; } 40 | ContextDatabase *getContextDatabase(); 41 | 42 | void setRawPtr(bool rawptr) { this->rawptr = rawptr; } 43 | 44 | protected: 45 | Translate *buildTranslator(DocumentStorage &store) override; 46 | void buildLoader(DocumentStorage &store) override; 47 | Scope *buildDatabase(DocumentStorage &store) override; 48 | void buildTypegrp(DocumentStorage &store) override; 49 | void buildCoreTypes(DocumentStorage &store) override; 50 | void buildCommentDB(DocumentStorage &store) override; 51 | void postSpecFile() override; 52 | void buildAction(DocumentStorage &store) override; 53 | }; 54 | 55 | #endif //R2GHIDRA_R2ARCHITECTURE_H 56 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0013-Fix-Build-with-G-4.9.2.patch: -------------------------------------------------------------------------------- 1 | From ca94da1513658a208f32ccff11ed28ff9a9fafb3 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Tue, 12 May 2020 21:17:00 +0200 4 | Subject: [PATCH 13/23] Fix Build with G++ 4.9.2 5 | 6 | --- 7 | .../Decompiler/src/decompile/cpp/float.cc | 32 +++++++++++++++++++ 8 | 1 file changed, 32 insertions(+) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc 11 | index 1af9b5d79..9b044d0c1 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/float.cc 14 | @@ -19,6 +19,38 @@ 15 | #include 16 | #include "address.hh" 17 | 18 | +#if defined(_WINDOWS) && !defined(INFINITY) 19 | + 20 | +// Some definitions for Windows floating point stuff 21 | +#include 22 | + 23 | +inline int4 signbit(double x) { 24 | + return (((_fpclass(x)& (_FPCLASS_NINF | _FPCLASS_NN 25 | + | _FPCLASS_ND | _FPCLASS_NZ))!=0) ? 1 : 0); 26 | +} 27 | + 28 | +inline int4 isnan(double x) { 29 | + return (((_fpclass(x)& (_FPCLASS_SNAN | _FPCLASS_QNAN))!=0) ? 1 : 0); 30 | +} 31 | + 32 | +inline int4 isinf(double x) { 33 | + int4 classify = _fpclass(x); 34 | + if (classify == _FPCLASS_NINF) return -1; 35 | + if (classify == _FPCLASS_PINF) return 1; 36 | + return 0; 37 | +} 38 | + 39 | +#define INFINITY HUGE_VAL 40 | +#define NAN (INFINITY/INFINITY) 41 | + 42 | +#else 43 | + 44 | +// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=48891 45 | +#define isnan std::isnan 46 | +#define isinf std::isinf 47 | + 48 | +#endif 49 | + 50 | /// Set format for a given encoding size according to IEEE 754 standards 51 | /// \param sz is the size of the encoding in bytes 52 | FloatFormat::FloatFormat(int4 sz) 53 | -- 54 | 2.24.3 (Apple Git-128) 55 | 56 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0009-Make-some-PrintC-methods-virtual.patch: -------------------------------------------------------------------------------- 1 | From 30eade046424dc86966d09d4ec6b26e43640ce89 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Sat, 3 Aug 2019 15:21:59 +0200 4 | Subject: [PATCH 09/23] Make some PrintC methods virtual 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh | 4 ++-- 8 | 1 file changed, 2 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 11 | index f315d7023..9301678ee 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 14 | @@ -152,9 +152,9 @@ protected: 15 | void emitPrototypeInputs(const FuncProto *proto); ///< Emit the input data-types of a function prototype 16 | void emitGlobalVarDeclsRecursive(Scope *scope); ///< Emit variable declarations for all global symbols under given scope 17 | void emitLocalVarDecls(const Funcdata *fd); ///< Emit variable declarations for a function 18 | - void emitStatement(const PcodeOp *inst); ///< Emit a statement in the body of a function 19 | + virtual void emitStatement(const PcodeOp *inst); ///< Emit a statement in the body of a function 20 | bool emitInplaceOp(const PcodeOp *op); ///< Attempt to emit an expression rooted at an \e in-place operator 21 | - void emitGotoStatement(const FlowBlock *bl,const FlowBlock *exp_bl,uint4 type); 22 | + virtual void emitGotoStatement(const FlowBlock *bl,const FlowBlock *exp_bl,uint4 type); 23 | void emitSwitchCase(int4 casenum,const BlockSwitch *switchbl); ///< Emit labels for a \e case block 24 | void emitLabel(const FlowBlock *bl); ///< Emit a formal label for a given control-flow block 25 | void emitLabelStatement(const FlowBlock *bl); ///< Emit any required label statement for a given basic block 26 | -- 27 | 2.24.3 (Apple Git-128) 28 | 29 | -------------------------------------------------------------------------------- /subprojects/packagefiles/zlib/meson.build: -------------------------------------------------------------------------------- 1 | # Copied from Rizin 2 | project('zlib', 'c', 3 | version : '1.3.1', 4 | license : 'zlib', 5 | meson_version: '>=0.55.0', 6 | ) 7 | 8 | cc = meson.get_compiler('c') 9 | 10 | if cc.has_argument('--std=c99') 11 | add_project_arguments('--std=c99', language: ['c']) 12 | endif 13 | 14 | link_args = [] 15 | compile_args = [] 16 | if cc.get_argument_syntax() == 'msvc' 17 | add_project_arguments( 18 | '-D_CRT_SECURE_NO_DEPRECATE', 19 | '-D_CRT_NONSTDC_NO_DEPRECATE', 20 | language : 'c') 21 | elif cc.get_argument_syntax() == 'gcc' 22 | # Don't spam consumers of this wrap with these warnings 23 | compile_args += cc.get_supported_arguments('-Wno-implicit-fallthrough') 24 | if host_machine.system() not in ['windows', 'darwin'] 25 | link_args += '-Wl,--version-script,@0@/zlib.map'.format(meson.current_source_dir()) 26 | endif 27 | endif 28 | 29 | if cc.has_header('unistd.h') 30 | compile_args += '-DHAVE_UNISTD_H' 31 | endif 32 | 33 | if cc.has_header('stdarg.h') 34 | compile_args += '-DHAVE_STDARG_H' 35 | endif 36 | 37 | src = files([ 38 | 'adler32.c', 39 | 'crc32.c', 40 | 'deflate.c', 41 | 'infback.c', 42 | 'inffast.c', 43 | 'inflate.c', 44 | 'inftrees.c', 45 | 'trees.c', 46 | 'zutil.c', 47 | 'compress.c', 48 | 'uncompr.c', 49 | 'gzclose.c', 50 | 'gzlib.c', 51 | 'gzread.c', 52 | 'gzwrite.c']) 53 | 54 | headers = files(['zconf.h', 'zlib.h']) 55 | 56 | if host_machine.system() == 'windows' 57 | win = import('windows') 58 | win_args = [] 59 | if cc.get_id() != 'msvc' 60 | win_args += '-DGCC_WINDRES' 61 | endif 62 | src += win.compile_resources('win32/zlib1.rc', args : win_args) 63 | endif 64 | 65 | zlib = library('z', src, 66 | c_args : compile_args, 67 | link_args : link_args, 68 | vs_module_defs : 'win32/zlib.def', 69 | install : false) 70 | 71 | incdir = include_directories('.') 72 | 73 | zlib_dep = declare_dependency( 74 | link_with : zlib, 75 | include_directories : incdir) 76 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0016-Export-two-private-field-to-SLEIGH-plugin.-4.patch: -------------------------------------------------------------------------------- 1 | From 7849991ccefe012792f1fc8cfc56f36772db32c6 Mon Sep 17 00:00:00 2001 2 | From: FXTi 3 | Date: Wed, 26 Aug 2020 15:10:30 +0800 4 | Subject: [PATCH 16/23] Export two private field to SLEIGH plugin. (#4) 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/context.hh | 2 ++ 8 | Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.hh | 1 + 9 | 2 files changed, 3 insertions(+) 10 | 11 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh 12 | index 3372e5ac5..5920bceb4 100644 13 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh 14 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/context.hh 15 | @@ -89,6 +89,8 @@ private: 16 | ConstructState *base_state; 17 | int4 alloc; // Number of ConstructState's allocated 18 | int4 delayslot; // delayslot depth 19 | +protected: 20 | + ConstructState *getBaseState(void) { return base_state; } 21 | public: 22 | ParserContext(ContextCache *ccache); 23 | ~ParserContext(void) { if (context != (uintm *)0) delete [] context; } 24 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.hh 25 | index 1a758a488..1e96c2c30 100644 26 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.hh 27 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh.hh 28 | @@ -166,6 +166,7 @@ protected: 29 | ParserContext *obtainContext(const Address &addr,int4 state) const; 30 | void resolve(ParserContext &pos) const; ///< Generate a parse tree suitable for disassembly 31 | void resolveHandles(ParserContext &pos) const; ///< Prepare the parse tree for p-code generation 32 | + ContextCache *getContextCache(void) { return cache; } 33 | public: 34 | Sleigh(LoadImage *ld,ContextDatabase *c_db); ///< Constructor 35 | virtual ~Sleigh(void); ///< Destructor 36 | -- 37 | 2.24.3 (Apple Git-128) 38 | 39 | -------------------------------------------------------------------------------- /preconfigure.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | set PKG_CONFIG_PATH=%CD%\radare2\lib\pkgconfig 4 | set PATH=%CD%\radare2\bin;%PATH% 5 | set VSARCH=x64 6 | 7 | git submodule update --init 8 | 9 | REM call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64 10 | echo === Finding Visual Studio... 11 | cl > NUL 2> NUL 12 | if %ERRORLEVEL% == 0 ( 13 | echo FOUND 14 | ) else ( 15 | if EXIST "C:\Program Files\Microsoft Visual Studio\2022\Enterprise" ( 16 | echo "Found 2022 Enterprise edition" 17 | call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %VSARCH% 18 | ) else if EXIST "C:\Program Files\Microsoft Visual Studio\2022\Community" ( 19 | echo "Found 2022 Community edition" 20 | call "C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsall.bat" %VSARCH% 21 | ) else if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community" ( 22 | echo "Found 2019 community edition" 23 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvarsall.bat" %VSARCH% 24 | ) else if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" ( 25 | echo "Found 2019 Enterprise edition" 26 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" %VSARCH% 27 | ) else if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" ( 28 | echo "Found 2019 Professional edition" 29 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvarsall.bat" %VSARCH% 30 | ) else if EXIST "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" ( 31 | echo "Found 2019 BuildTools" 32 | call "C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\VC\Auxiliary\Build\vcvarsall.bat" %VSARCH% 33 | ) else ( 34 | echo Error: Could not find Visual Studio. Run the script with VS Developer Console. 35 | exit /b 1 36 | ) 37 | ) 38 | 39 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/done/0012-Make-SleighArchitecture-Langs-public.patch: -------------------------------------------------------------------------------- 1 | From c16edaf929f9087bb457a3e76e067cac9772d67b Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Sun, 25 Aug 2019 21:20:48 +0200 4 | Subject: [PATCH 12/23] Make SleighArchitecture Langs public 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh | 5 +++-- 8 | 1 file changed, 3 insertions(+), 2 deletions(-) 9 | 10 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh 11 | index 01d41fe07..7a902c5b0 100644 12 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh 13 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/sleigh_arch.hh 14 | @@ -98,7 +98,6 @@ class SleighArchitecture : public Architecture { 15 | protected: 16 | ostream *errorstream; ///< Error stream associated with \b this SleighArchitecture 17 | // buildLoader must be filled in by derived class 18 | - static void collectSpecFiles(ostream &errs); ///< Gather specification files in normal locations 19 | virtual Translate *buildTranslator(DocumentStorage &store); 20 | virtual PcodeInjectLibrary *buildPcodeInjectLibrary(void); 21 | virtual void buildSpecFile(DocumentStorage &store); 22 | @@ -113,7 +112,9 @@ public: 23 | virtual void printMessage(const string &message) const { *errorstream << message << endl; } 24 | virtual ~SleighArchitecture(void); 25 | virtual string getDescription(void) const; 26 | - 27 | + 28 | + static void collectSpecFiles(ostream &errs); ///< Gather specification files in normal locations 29 | + static const vector &getLanguageDescriptions() { return description; } 30 | static string normalizeProcessor(const string &nm); ///< Try to recover a \e language \e id processor field 31 | static string normalizeEndian(const string &nm); ///< Try to recover a \e language \e id endianess field 32 | static string normalizeSize(const string &nm); ///< Try to recover a \e language \e id size field 33 | -- 34 | 2.24.3 (Apple Git-128) 35 | 36 | -------------------------------------------------------------------------------- /src/R2CommentDatabase.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2021 - thestr4ng3r, pancake */ 2 | 3 | #include "R2CommentDatabase.h" 4 | #include "R2Architecture.h" 5 | 6 | #include 7 | 8 | #include "R2Utils.h" 9 | 10 | R2CommentDatabase::R2CommentDatabase(R2Architecture *arch) : arch (arch), cache_filled (false) { 11 | } 12 | 13 | void R2CommentDatabase::fillCache(const Address &fad) const { 14 | RCoreLock core(arch->getCore()); 15 | 16 | RAnalFunction *fcn = r_anal_get_function_at(core->anal, fad.getOffset()); 17 | if (fcn == nullptr) { 18 | RList *fcns = r_anal_get_functions_in (core->anal, fad.getOffset()); 19 | if (!r_list_empty (fcns)) { 20 | fcn = reinterpret_cast(r_list_first (fcns)); 21 | } 22 | r_list_free (fcns); 23 | if (fcn == nullptr) { 24 | return; 25 | } 26 | } 27 | r_interval_tree_foreach_cpp(&core->anal->meta, [fad, fcn, this](RIntervalNode *node, RAnalMetaItem *meta) { 28 | if (!meta || meta->type != R_META_TYPE_COMMENT || !meta->str) { 29 | return; 30 | } 31 | if (!r_anal_function_contains (fcn, node->start)) { 32 | return; 33 | } 34 | cache.addComment (Comment::user2, fad, Address(arch->getDefaultCodeSpace(), node->start), meta->str); 35 | // cache.addComment (Comment::header, fad, Address(arch->getDefaultCodeSpace(), node->start), meta->str); 36 | }); 37 | cache_filled = true; 38 | } 39 | 40 | void R2CommentDatabase::clear() { 41 | cache.clear (); 42 | cache_filled = false; 43 | } 44 | 45 | void R2CommentDatabase::clearType(const Address &fad, uint4 tp) { 46 | cache.clearType (fad, tp); 47 | } 48 | 49 | void R2CommentDatabase::addComment(uint4 tp, const Address &fad, const Address &ad, const string &txt) { 50 | cache.addComment (tp, fad, ad, txt); 51 | } 52 | 53 | bool R2CommentDatabase::addCommentNoDuplicate(uint4 tp, const Address &fad, const Address &ad, const string &txt) { 54 | return cache.addCommentNoDuplicate (tp, fad, ad, txt); 55 | } 56 | 57 | CommentSet::const_iterator R2CommentDatabase::beginComment(const Address &fad) const { 58 | fillCache (fad); 59 | return cache.beginComment (fad); 60 | } 61 | 62 | CommentSet::const_iterator R2CommentDatabase::endComment(const Address &fad) const { 63 | return cache.endComment (fad); 64 | } 65 | -------------------------------------------------------------------------------- /src/PcodeFixupPreprocessor.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2025 - pancake */ 2 | 3 | #include "PcodeFixupPreprocessor.h" 4 | #include "R2LoadImage.h" 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace ghidra; 21 | 22 | static bool is_import_name(const char * R_NONNULL name) { 23 | return r_str_startswith (name, "imp.") 24 | || r_str_startswith (name, "sym.imp.") 25 | || r_str_startswith (name, "plt.") 26 | || r_str_startswith (name, "reloc."); 27 | } 28 | 29 | // Helper to extract base function name from an import 30 | static const char* extractLibcFuncName(const char *importName) { 31 | const char *last_dot = r_str_lchr (importName, '.'); 32 | if (last_dot) { 33 | return last_dot + 1; 34 | } 35 | return nullptr; 36 | } 37 | 38 | R_VEC_TYPE (RVecAnalRef, RAnalRef); 39 | 40 | void PcodeFixupPreprocessor::fixupSharedReturnJumpToRelocs(RAnalFunction *r2Func, Funcdata *ghFunc, RCore *core, R2Architecture &arch) { 41 | RVecAnalRef *refs = r_anal_function_get_refs (r2Func); 42 | RAnalRef *refi; 43 | auto space = arch.getDefaultCodeSpace(); 44 | #if 0 45 | auto ops = ghFunc->getBasicBlocks(); 46 | #endif 47 | if (r2Func->is_noreturn) { 48 | ghFunc->getFuncProto().setNoReturn(true); 49 | } 50 | R_VEC_FOREACH (refs, refi) { 51 | // R_LOG_INFO ("refi 0x%"PFMT64x"", refi->addr); 52 | RFlagItem *f = r_flag_get_at (core->flags, refi->addr, true); 53 | if (f) { 54 | if (is_import_name (f->name)) { 55 | RAnalOp *op = r_core_anal_op (core, refi->at, 0); 56 | bool isCallRet = (op->type == R_ANAL_OP_TYPE_JMP); 57 | // isCallRet = true; 58 | if (isCallRet) { 59 | // apply only if its a jump ref? 60 | // Address callAddr (space, refi->addr); // address of FUNCTION 61 | Address callAddr (space, refi->at); // address of CALL 62 | R_LOG_INFO ("OverridingCallReturn %s", extractLibcFuncName (f->name)); 63 | ghFunc->getOverride().insertFlowOverride(callAddr, Override::CALL_RETURN); 64 | } 65 | r_anal_op_free (op); 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0010-Add-Setter-for-NL-before-else.patch: -------------------------------------------------------------------------------- 1 | From 87d83f509ba66f1b41bb5306da19d3f04f455d78 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Fri, 23 Aug 2019 18:45:22 +0200 4 | Subject: [PATCH 10/23] Add Setter for NL before else 5 | 6 | --- 7 | Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc | 8 +++++--- 8 | Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh | 1 + 9 | 2 files changed, 6 insertions(+), 3 deletions(-) 10 | 11 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 12 | index 19acbfaf0..56c37e783 100644 13 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 14 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 15 | @@ -2638,11 +2638,13 @@ void PrintC::emitBlockIf(const BlockIf *bl) 16 | emit->tagLine(); 17 | emit->print("}"); 18 | if (bl->getSize()==3) { 19 | - if (option_newline_before_else) { 20 | - emit->tagLine(); 21 | + if (option_newline_before_else) { 22 | + emit->tagLine(); 23 | + } else { 24 | + emit->spaces(1); 25 | } 26 | emit->print("else",EmitXml::keyword_color); 27 | - if (option_newline_before_else) { 28 | + if (option_newline_before_opening_brace) { 29 | emit->tagLine(); 30 | } else { 31 | emit->spaces(1); 32 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 33 | index 9301678ee..86d4e47d2 100644 34 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 35 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 36 | @@ -211,6 +211,7 @@ public: 37 | void setHideImpliedExts(bool val) { option_hide_exts = val; } ///< Toggle whether implied extensions are hidden 38 | void setSpaceAfterComma(bool val) { option_space_after_comma = val; } 39 | void setNewlineBeforeOpeningBrace(bool val) { option_newline_before_opening_brace = val; } 40 | + void setNewlineBeforeElse(bool val) { option_newline_before_else = val; } 41 | void setNewlineAfterPrototype(bool val) { option_newline_after_prototype = val; } 42 | virtual ~PrintC(void) {} 43 | virtual void resetDefaults(void); 44 | -- 45 | 2.24.3 (Apple Git-128) 46 | 47 | -------------------------------------------------------------------------------- /test/bins/dectest.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | 5 | #include "types.h" 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | uint32_t global_var = 42; 12 | 13 | uint32_t get_global_var() { 14 | return global_var; 15 | } 16 | 17 | uint32_t global_array[2] = { 1337, 123 }; 18 | 19 | uint32_t get_global_array_entry() { 20 | return global_array[1]; 21 | } 22 | 23 | 24 | void Aeropause(struct Bright *bright, int argc, char **argv); 25 | 26 | int main(int argc, char **argv) 27 | { 28 | struct Bright bright; 29 | Aeropause(&bright, argc, argv); 30 | return 0; 31 | } 32 | 33 | static inline void PrintAmbassador(enum Ambassador ambassador) 34 | { 35 | printf("Ambassador value: "); 36 | switch(ambassador) 37 | { 38 | case AMBASSADOR_PURE: 39 | printf("pure"); 40 | break; 41 | case AMBASSADOR_REASON: 42 | printf("reason"); 43 | break; 44 | case AMBASSADOR_REVOLUTION: 45 | printf("revolution"); 46 | break; 47 | case AMBASSADOR_ECHOES: 48 | printf("echoes"); 49 | break; 50 | case AMBASSADOR_WALL: 51 | printf("wall"); 52 | break; 53 | case AMBASSADOR_MILLION: 54 | printf("million"); 55 | break; 56 | default: 57 | break; 58 | } 59 | printf("\n"); 60 | } 61 | 62 | void Aeropause(struct Bright *bright, int argc, char **argv) 63 | { 64 | bright->morning = malloc(sizeof(struct Morning)); 65 | bright->morning->saved_argc = argc; 66 | bright->morning->saved_argv = argv; 67 | if(bright->morning->saved_argc < 2) 68 | { 69 | bright->ambassador = AMBASSADOR_PURE; 70 | } 71 | else 72 | { 73 | bright->window.sunlight = bright->morning->saved_argv[1]; 74 | if(strcmp(bright->window.sunlight, "the ") == 0) 75 | bright->ambassador = AMBASSADOR_REASON; 76 | else if(strcmp(bright->window.sunlight, "dark") == 0) 77 | bright->ambassador = AMBASSADOR_REVOLUTION; 78 | else if(strcmp(bright->window.sunlight, "third") == 0) 79 | bright->ambassador = AMBASSADOR_ECHOES; 80 | else 81 | bright->ambassador = AMBASSADOR_MILLION; 82 | } 83 | switch(bright->ambassador) 84 | { 85 | case AMBASSADOR_PURE: 86 | printf("pure"); 87 | break; 88 | case AMBASSADOR_REASON: 89 | printf("reason"); 90 | break; 91 | case AMBASSADOR_REVOLUTION: 92 | printf("revolution"); 93 | break; 94 | case AMBASSADOR_ECHOES: 95 | printf("echoes"); 96 | break; 97 | case AMBASSADOR_WALL: 98 | printf("wall"); 99 | break; 100 | case AMBASSADOR_MILLION: 101 | printf("million"); 102 | break; 103 | default: 104 | break; 105 | } 106 | PrintAmbassador(bright->ambassador); 107 | } 108 | 109 | -------------------------------------------------------------------------------- /subprojects/ghidra-native.mk: -------------------------------------------------------------------------------- 1 | # This file is autogenerated by acr-wrap 2 | 3 | WRAP_wrap_git_url:=https://github.com/radareorg/ghidra-native 4 | WRAP_wrap_git_revision:=0.6.4 5 | WRAP_wrap_git_directory:=ghidra-native 6 | WRAP_wrap_git_patch_directory:=ghidra-native 7 | WRAP_wrap_git_diff_files:=ghidra-native/patches/0001-space-after-comma.patch,ghidra-native/patches/0002-make-sleigharch-public.patch,ghidra-native/patches/0004-public-fields.patch,ghidra-native/patches/0006-readonly-warning.patch,ghidra-native/patches/0010-null-subflow.patch,ghidra-native/patches/0020-Fix-double-free-crash-when-deinitializing-multiple-X.patch,ghidra-native/patches/0023-Undef-LoadImage-for-windows.patch,ghidra-native/patches/0024-ignore-symbol-beyond-space.patch,ghidra-native/patches/0044-bad-unicode-codepoint.patch,ghidra-native/patches/0055-datatype-clone.patch,ghidra-native/patches/0056-nullderef-workaround.patch,ghidra-native/patches/0080-getparent-flow.patch,ghidra-native/patches/0090-nocasts-warnings.patch,ghidra-native/patches/0091-decompiler-xml-packer.patch,ghidra-native/patches/0092-badvar-segfault.patch,ghidra-native/patches/0093-no-virtual-destructor.patch,ghidra-native/patches/0100-CHAR-windows.patch 8 | WRAP_wrap_git_depth:=1 9 | 10 | .PHONY: ghidra-native_clean ghidra-native_all 11 | 12 | ghidra-native: 13 | if [ ! -d "ghidra-native" -o "0.6.4" != "$(shell cd ghidra-native 2>/dev/null && git rev-parse HEAD)" ]; then rm -rf "ghidra-native"; ${MAKE} ghidra-native_all; fi 14 | 15 | ghidra-native_all: 16 | git clone --no-checkout --depth=1 https://github.com/radareorg/ghidra-native ghidra-native 17 | cd ghidra-native && git fetch --depth=1 origin 0.6.4 18 | cd ghidra-native && git checkout FETCH_HEAD 19 | cp -rf packagefiles/ghidra-native/* ghidra-native 20 | for a in ghidra-native/patches/0001-space-after-comma.patch ghidra-native/patches/0002-make-sleigharch-public.patch ghidra-native/patches/0004-public-fields.patch ghidra-native/patches/0006-readonly-warning.patch ghidra-native/patches/0010-null-subflow.patch ghidra-native/patches/0020-Fix-double-free-crash-when-deinitializing-multiple-X.patch ghidra-native/patches/0023-Undef-LoadImage-for-windows.patch ghidra-native/patches/0024-ignore-symbol-beyond-space.patch ghidra-native/patches/0044-bad-unicode-codepoint.patch ghidra-native/patches/0055-datatype-clone.patch ghidra-native/patches/0056-nullderef-workaround.patch ghidra-native/patches/0080-getparent-flow.patch ghidra-native/patches/0090-nocasts-warnings.patch ghidra-native/patches/0091-decompiler-xml-packer.patch ghidra-native/patches/0092-badvar-segfault.patch ghidra-native/patches/0093-no-virtual-destructor.patch ghidra-native/patches/0100-CHAR-windows.patch ; do echo "patch -d ghidra-native -p1 < $$a" ; patch -d ghidra-native -p1 < $$a ; done 21 | 22 | ghidra-native_clean: 23 | rm -rf ghidra-native 24 | -------------------------------------------------------------------------------- /src/anal_ghidra_plugin.c: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2020-2024 - pancake */ 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #if R2_VERSION_NUMBER >= 50709 8 | #define RAnalEsil REsil 9 | #endif 10 | 11 | #if R2_VERSION_NUMBER >= 50809 12 | extern int archinfo(RArchSession *as, ut32 query); 13 | extern bool sanal_init(RArchSession *as); 14 | extern bool sanal_fini(RArchSession *as); 15 | extern RList *r2ghidra_preludes(RArchSession *as); 16 | extern int archinfo(RArchSession *as, ut32 query); 17 | extern char *r2ghidra_regs(RArchSession *as); 18 | extern bool r2ghidra_esilcb(RArchSession *as, RArchEsilAction action); 19 | extern char *get_reg_profile(RAnal *anal); 20 | bool sleigh_decode(RArchSession *as, RAnalOp *op, RArchDecodeMask mask); 21 | 22 | RArchPlugin r_arch_plugin_ghidra = { 23 | .meta = { 24 | .name = "r2ghidra", 25 | .desc = "SLEIGH Disassembler from Ghidra", 26 | .license = "GPL3", 27 | .author = "FXTi, pancake", 28 | .version = R2_VERSION, 29 | }, 30 | .arch = "sleigh", 31 | .endian = R_SYS_ENDIAN_LITTLE | R_SYS_ENDIAN_BIG, 32 | .cpus = "6502,6805,8051,arm,avr,cr16,dalvik,hppa,java,m68k,m8c,mips,mcs96,msp430,pic24,ppc,sh,sparc,stm8,tricore,toy,v850,wasm,x86,z80,xtensa", 33 | .bits = 0, 34 | .init = &sanal_init, 35 | .fini = &sanal_fini, 36 | .info = &archinfo, 37 | .preludes = r2ghidra_preludes, 38 | .decode = &sleigh_decode, 39 | .regs = &r2ghidra_regs, 40 | .esilcb = r2ghidra_esilcb, 41 | .mnemonics = NULL, 42 | }; 43 | #else 44 | 45 | extern RList *anal_preludes(RAnal *anal); 46 | extern int sanal_init(void *p); 47 | extern int sanal_fini(void *p); 48 | extern RList *r2ghidra_preludes(RAnal *anal); 49 | extern int archinfo(RAnal *a, int query); 50 | extern char *get_reg_profile(RAnal *anal); 51 | extern int sleigh_op(RAnal *a, RAnalOp *anal_op, ut64 addr, const ut8 *data, int len, RAnalOpMask mask); 52 | extern int esil_sleigh_fini(RAnalEsil *esil); 53 | extern int esil_sleigh_init(RAnalEsil *esil); 54 | RAnalPlugin r_anal_plugin_ghidra = { 55 | .name = "r2ghidra", 56 | .desc = "SLEIGH Disassembler from Ghidra", 57 | .license = "GPL3", 58 | .arch = "sleigh", 59 | .author = "FXTi, pancake", 60 | .version = R2_VERSION, 61 | #if R2_VERSION_NUMBER >= 50609 62 | .endian = R_SYS_ENDIAN_LITTLE | R_SYS_ENDIAN_BIG, 63 | #endif 64 | .cpus = "6502,6805,8051,arm,avr,cr16,dalvik,hppa,java,m68k,m8c,mips,mcs96,msp430,pic24,ppc,sh,sparc,stm8,tricore,toy,v850,wasm,x86,z80,xtensa", 65 | .bits = 0, 66 | .esil = true, 67 | .fileformat_type = 0, 68 | .init = &sanal_init, 69 | .fini = &sanal_fini, 70 | .archinfo = &archinfo, 71 | .preludes = anal_preludes, 72 | .op = &sleigh_op, 73 | .get_reg_profile = &get_reg_profile, 74 | .esil_init = esil_sleigh_init, 75 | .esil_fini = esil_sleigh_fini, 76 | #if R2_VERSION_NUMBER >= 50609 77 | .mnemonics = NULL, 78 | #endif 79 | }; 80 | #endif 81 | -------------------------------------------------------------------------------- /src/R2PrintC.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2025 - thestr4ng3r, pancake */ 2 | 3 | #include 4 | #include 5 | 6 | #include "R2PrintC.h" 7 | #include "RCoreMutex.h" 8 | 9 | 10 | using namespace ghidra; 11 | 12 | // Constructing this registers the capability 13 | R2PrintCCapability R2PrintCCapability::inst; 14 | 15 | R2PrintCCapability::R2PrintCCapability(void) { 16 | name = "r2-c-language"; 17 | isdefault = false; 18 | } 19 | 20 | PrintLanguage *R2PrintCCapability::buildLanguage(Architecture *glb) { 21 | return new R2PrintC (glb, name); 22 | } 23 | 24 | R2PrintC::R2PrintC(Architecture *g, const string &nm) : PrintC(g, nm) { 25 | option_NULL = true; 26 | // unplaced option is necessary to show the inline ::user2 comments defined from radare2 27 | option_unplaced = false; 28 | // option_space_after_comma = true; 29 | // option_nocasts = true; 30 | /// option_convention = true; 31 | /// option_hide_exts = true; 32 | /// option_inplace_ops = false; 33 | /// option_nocasts = false; 34 | /// option_NULL = false; 35 | /// option_space_after_comma = false; 36 | /// option_newline_before_else = true; 37 | /// option_newline_before_opening_brace = false; 38 | /// option_newline_after_prototype = true; 39 | // Default r2ghidra C printer options: 40 | #if 0 41 | setNULLPrinting(true); // print NULL keyword for null pointers 42 | setNoCastPrinting(false); // show C casts by default 43 | setInplaceOps(false); // disable in-place operators (+=, *=, etc.) 44 | setConvention(true); // include calling convention in function prototypes 45 | setHideImpliedExts(true); // hide implied zero/sign extensions (ZEXT/SEXT) 46 | setCStyleComments(); // use C-style /* */ comments 47 | setMaxLineSize(80); // wrap lines at 80 characters 48 | setIndentIncrement(2); // indent 2 spaces per nested block 49 | setLineCommentIndent(0); // align line comments with code 50 | setCommentStyle("c"); // use traditional C comment style 51 | setBraceFormatFunction(Emit::skip_line); // function opening brace on a separate line 52 | setBraceFormatIfElse(Emit::same_line); // if/else opening brace on same line 53 | setBraceFormatLoop(Emit::same_line); // loop opening brace on same line 54 | setBraceFormatSwitch(Emit::same_line); // switch opening brace on same line 55 | setNamespaceStrategy(PrintLanguage::MINIMAL_NAMESPACES); // minimal namespace qualifiers 56 | #endif 57 | } 58 | 59 | void R2PrintC::setOptionNoCasts(bool nc) { 60 | option_nocasts = nc; 61 | } 62 | 63 | #if 0 64 | void R2PrintC::opCast(const PcodeOp *op) 65 | { 66 | // do nothing 67 | fprintf (stderr, "opCast%c", 10); 68 | } 69 | #endif 70 | 71 | void R2PrintC::pushUnnamedLocation(const Address &addr, const Varnode *vn, const PcodeOp *op) { 72 | // option_nocasts = true; 73 | // print (*(type *)0x0000...) instead of ram00000... 74 | AddrSpace *space = addr.getSpace (); 75 | if (space->getType() == IPTR_PROCESSOR) { 76 | pushOp (&dereference, op); 77 | auto type = glb->types->getTypePointer (space->getAddrSize (), vn->getType (), space->getWordSize ()); 78 | // pushConstant (addr.getOffset (), type, vn, op); 79 | pushConstant(addr.getOffset(),type,vartoken,vn, op); 80 | } else { 81 | PrintC::pushUnnamedLocation (addr,vn, op); 82 | } 83 | } 84 | 85 | /* 86 | void R2PrintC::push_integer(uintb val,int4 sz,bool sign,tagtype tag, const Varnode *vn,const PcodeOp *op) { 87 | } 88 | 89 | void R2PrintC::pushConstant(uintb val,const Datatype *ct,tagtype tag, const Varnode *vn, const PcodeOp *op) { 90 | } 91 | */ 92 | -------------------------------------------------------------------------------- /src/R2LoadImage.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2022 - pancake, thestr4ng3r */ 2 | 3 | #include "R2Architecture.h" 4 | #include "R2LoadImage.h" 5 | 6 | #include "R2Utils.h" 7 | 8 | R2LoadImage::R2LoadImage(RCoreMutex *coreMutex, AddrSpaceManager *addr_space_manager) : LoadImage("radare2_program"), 9 | coreMutex(coreMutex), 10 | addr_space_manager(addr_space_manager) 11 | { 12 | // nothing to do 13 | } 14 | 15 | void R2LoadImage::loadFill(uint1 *ptr, int4 size, const Address &addr) { 16 | RCoreLock core (coreMutex); 17 | r_io_read_at (core->io, addr.getOffset(), ptr, size); 18 | } 19 | 20 | string R2LoadImage::getArchType() const { 21 | return "radare2"; 22 | } 23 | 24 | void R2LoadImage::adjustVma(long adjust) { 25 | throw LowlevelError("Cannot adjust radare2 virtual memory"); 26 | } 27 | static bool isptr(ut64 *p) { 28 | //if (!*p) return false; 29 | if (*p < 0x1000) { return false; } 30 | return (*p != UT64_MAX); 31 | } 32 | 33 | void R2LoadImage::getReadonly(RangeList &list) const { 34 | RCoreLock core(coreMutex); 35 | int roprop = r_config_get_i (core->config, "r2ghidra.roprop"); 36 | if (roprop > 0) { 37 | auto space = addr_space_manager->getDefaultCodeSpace (); 38 | switch (roprop) { 39 | case 1: 40 | break; 41 | case 2: 42 | { 43 | // find ranges with pointers 44 | RIOMapRef *mapref; 45 | RListIter *iter; 46 | RIO *io = core->io; 47 | RIOBank *bank = r_io_bank_get (io, io->bank); 48 | r_list_foreach_cpp(bank->maprefs, [&](RIOMapRef *mapref) { 49 | RIOMap *map = r_io_map_get (io, mapref->id); 50 | ut64 begin = r_io_map_begin (map); 51 | ut64 end = r_io_map_end (map); 52 | if (map->perm & R_PERM_W) { 53 | return; 54 | } 55 | ut64 fin = end - begin; 56 | if (fin > 0xffffff) { 57 | list.insertRange(space, begin, end); 58 | return; 59 | } 60 | ut8 *buf = (ut8 *)malloc (fin); 61 | if (!buf) { 62 | list.insertRange(space, begin, end); 63 | return; 64 | } 65 | r_io_read_at (io, begin, buf, fin); 66 | ut64 base = begin; 67 | ut64 basefin = begin; 68 | ut8 *data = buf; 69 | bool hasdata = false; 70 | #if R2_VERSION_NUMBER >= 50609 71 | int inc = (core->rasm->config->bits == 64)? 8: 4; 72 | #else 73 | int inc = (core->rasm->bits == 64)? 8: 4; 74 | #endif 75 | for (int i = 0; i < fin; i += inc) { 76 | basefin = begin + i; 77 | if (isptr ((ut64 *)(data + i))) { 78 | // eprintf ("valid %llx\n", data[i]); 79 | hasdata = true; 80 | } else { 81 | if (hasdata) { 82 | // eprintf ("0 append %llx %llx because of 0x%llx\n", base, basefin, *((ut64*)(data +i))); 83 | if (base > 0) { 84 | list.insertRange(space, base, basefin); // begin, end); 85 | } 86 | hasdata = false; 87 | base = basefin; 88 | } 89 | } 90 | } 91 | free (buf); 92 | if (hasdata) { 93 | // eprintf ("1 append %llx %llx\n", base, basefin); 94 | list.insertRange(space, base, basefin); 95 | } 96 | }); 97 | } 98 | break; 99 | case 3: 100 | { 101 | RIOMapRef *mapref; 102 | RListIter *iter; 103 | RIO *io = core->io; 104 | RIOBank *bank = r_io_bank_get (io, io->bank); 105 | r_list_foreach_cpp(bank->maprefs, [&](RIOMapRef *mapref) { 106 | RIOMap *map = r_io_map_get (io, mapref->id); 107 | ut64 begin = r_io_map_begin (map); 108 | ut64 end = r_io_map_end (map); 109 | if (map->perm & R_PERM_W) { 110 | return; 111 | } 112 | list.insertRange(space, begin, end); 113 | }); 114 | } 115 | break; 116 | case 4: 117 | list.insertRange(space, 0x1000, ST64_MAX - 1); 118 | break; 119 | default: 120 | list.insertRange(space, 0, UT64_MAX - 1); 121 | break; 122 | } 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /meson.build: -------------------------------------------------------------------------------- 1 | project( 2 | 'r2ghidra', 3 | ['c', 'cpp'], 4 | license : 'LGPL3', 5 | meson_version : '>=0.50.1', 6 | version : '6.0.7', 7 | default_options : ['c_std=c11', 'cpp_std=c++14'] 8 | ) 9 | 10 | 11 | r2ghidra_sources = [ 12 | 'src/R2Architecture.cpp', 13 | 'src/R2LoadImage.cpp', 14 | 'src/R2Scope.cpp', 15 | 'src/R2TypeFactory.cpp', 16 | 'src/R2CommentDatabase.cpp', 17 | 'src/CodeXMLParse.cpp', 18 | 'src/ArchMap.cpp', 19 | 'src/R2PrintC.cpp', 20 | 'src/RCoreMutex.cpp', 21 | 'src/SleighAnalValue.cpp', 22 | 'src/SleighAsm.cpp', 23 | 'src/SleighInstruction.cpp', 24 | 'src/PcodeFixupPreprocessor.cpp', 25 | ] 26 | 27 | incdirs = [ 28 | 'src', 29 | ] 30 | 31 | res = run_command(['radare2','-HR2_LIBR_PLUGINS'], capture:true, check:false) 32 | if res.returncode() == 0 33 | r2_plugdir = res.stdout().strip() 34 | else 35 | prefix = get_option('prefix') 36 | r2_plugdir = prefix + '/lib/radare2/plugins' 37 | endif 38 | 39 | cpp = meson.get_compiler('cpp') 40 | if cpp.get_id() == 'msvc' 41 | incdirs += [ 42 | 'radare2/include/libr', 43 | 'radare2/include/libr/sdb', 44 | ] 45 | add_global_arguments('-D_WINDOWS', language:'cpp') 46 | add_global_arguments('-D_WIN32', language:'cpp') 47 | add_global_arguments('-DZLIB_WINAPI', language:'cpp') 48 | add_global_arguments('/wd4200', language:'cpp') # Suppress C4200: zero-sized array in struct 49 | r2libdir = [ 50 | meson.current_source_dir() + '\\radare2\\lib', 51 | 'C:\\radare2\\lib' 52 | ] 53 | r_core = [ 54 | cpp.find_library('r_core', dirs: r2libdir), 55 | cpp.find_library('r_io', dirs: r2libdir), 56 | cpp.find_library('r_bin', dirs: r2libdir), 57 | cpp.find_library('r_cons', dirs: r2libdir), 58 | cpp.find_library('r_asm', dirs: r2libdir), 59 | cpp.find_library('r_esil', dirs: r2libdir), 60 | cpp.find_library('r_arch', dirs: r2libdir), 61 | cpp.find_library('r_flag', dirs: r2libdir), 62 | cpp.find_library('r_reg', dirs: r2libdir), 63 | cpp.find_library('r_util', dirs: r2libdir), 64 | cpp.find_library('r_anal', dirs: r2libdir), 65 | cpp.find_library('r_config', dirs: r2libdir), 66 | ] 67 | else 68 | r_core = dependency('r_core') 69 | endif 70 | 71 | r2ghidra_version = meson.project_version() 72 | versionconf = configuration_data() 73 | versionconf.set('R2GHIDRA_VERSION', r2ghidra_version) 74 | r_version_h = configure_file( 75 | input: 'config.h.acr', 76 | output: 'config.h', 77 | configuration: versionconf 78 | ) 79 | 80 | add_global_arguments('-DNDEBUG', language: ['c', 'cpp']) 81 | 82 | r2ghidra_incdirs = include_directories(incdirs) 83 | 84 | zlib = dependency('zlib', version : '>=1.2.8', required: false) 85 | if not zlib.found() 86 | zlib_proj = subproject('zlib', default_options: ['default_library=static', 'werror=false']) 87 | zlib = zlib_proj.get_variable('zlib_dep') 88 | meson.override_dependency('zlib', zlib) 89 | endif 90 | 91 | 92 | ghidra = subproject('ghidra-native', default_options: ['default_library=static', 'werror=false']) 93 | # ghidra_decompiler_sources = ghidra.get_variable('sources') 94 | # ghidra_slgh_sources = ghidra.get_variable('slgh_sources') 95 | ghidra_incs = ghidra.get_variable('incs') 96 | libdecomp_static = ghidra.get_variable('libdecomp_static') 97 | slgh_static = ghidra.get_variable('slgh_static') 98 | 99 | pugixml = subproject('pugixml').get_variable('pugixml_dep') 100 | 101 | r2ghidra_core_sources = [ 102 | r2ghidra_sources, 103 | # ghidra_decompiler_sources, 104 | 'src/anal_ghidra_plugin.c', 105 | 'src/anal_ghidra.cpp', 106 | 'src/core_ghidra_plugin.c', 107 | 'src/core_ghidra.cpp', 108 | ] 109 | 110 | sleighc_sources = [ 111 | r2ghidra_sources, 112 | # ghidra_slgh_sources, 113 | # ghidra_decompiler_sources, 114 | ] 115 | 116 | r2ghidra_core_plugin = shared_library('core_r2ghidra', 117 | r2ghidra_core_sources, 118 | link_with: libdecomp_static, 119 | dependencies: [r_core, zlib, pugixml], 120 | override_options : ['c_std=c11', 'cpp_std=c++14'], 121 | include_directories: [ghidra_incs, r2ghidra_incdirs], 122 | install: true, 123 | install_dir: r2_plugdir 124 | ) 125 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | all: plugins 2 | 3 | -include ../config.mk 4 | include ../ghidra/deps.mk 5 | 6 | R2GHIDRA_SRCS= R2Architecture.cpp 7 | R2GHIDRA_SRCS+=PcodeFixupPreprocessor.cpp 8 | R2GHIDRA_SRCS+=R2LoadImage.cpp 9 | R2GHIDRA_SRCS+=R2Scope.cpp 10 | R2GHIDRA_SRCS+=R2TypeFactory.cpp 11 | R2GHIDRA_SRCS+=R2CommentDatabase.cpp 12 | R2GHIDRA_SRCS+=CodeXMLParse.cpp 13 | R2GHIDRA_SRCS+=ArchMap.cpp 14 | R2GHIDRA_SRCS+=R2PrintC.cpp 15 | R2GHIDRA_SRCS+=RCoreMutex.cpp 16 | 17 | R2GHIDRA_SRCS+=SleighAnalValue.cpp 18 | R2GHIDRA_SRCS+=SleighAsm.cpp 19 | R2GHIDRA_SRCS+=SleighInstruction.cpp 20 | 21 | # R2GHIDRA_SRCS= ArchMap.cpp CodeXMLParse.cpp R2Architecture.cpp R2CommentDatabase.cpp R2LoadImage.cpp 22 | # R2GHIDRA_SRCS+= R2PrintC.cpp R2Scope.cpp R2TypeFactory.cpp RCoreMutex.cpp SleighAnalValue.cpp SleighAsm.cpp 23 | # R2GHIDRA_SRCS+= SleighInstruction.cpp 24 | 25 | R2G_PLUG_SRCS= anal_ghidra.cpp core_ghidra.cpp 26 | R2G_PLUG_SRCS+= anal_ghidra_plugin.o core_ghidra_plugin.o 27 | 28 | PUGIXML_HOME=../subprojects/pugixml/src/ 29 | PUGIXML_CFLAGS=-I$(PUGIXML_HOME) 30 | PUGIXML_SRCS= $(PUGIXML_HOME)/pugixml.cpp 31 | PUGIXML_OBJS= $(PUGIXML_HOME)/pugixml.o 32 | #PUGIXML_OBJS= pugixml.o 33 | 34 | $(PUGIXML_OBJS): $(PUGIXML_SRCS) 35 | $(CXX) -c $(R2_LDFLAGS) $(CXXFLAGS) -o $@ $< 36 | 37 | CXXFLAGS+=$(PUGIXML_CFLAGS) 38 | # CXXFLAGS+=-DR2GHIDRA_SLEIGHHOME_DEFAULT=\"$(GHIDRA_HOME)\" 39 | 40 | R2GHIDRA_OBJS=$(subst .cpp,.o,$(R2GHIDRA_SRCS)) 41 | R2G_PLUGIN_OBJS=$(subst .cpp,.o,$(R2G_PLUG_SRCS)) 42 | 43 | CFLAGS+=-DR2GHIDRA_SLEIGHHOME_DEFAULT=\"$(R2_USER_PLUGINS)/r2ghidra_sleigh\" 44 | CFLAGS+=-w 45 | CFLAGS+=-fPIC 46 | CFLAGS+=-Wshadow 47 | CFLAGS+=-I$(GHIDRA_DECOMPILER) 48 | CFLAGS+=-I. 49 | 50 | #CFLAGS+=-g -ggdb 51 | #LDFLAGS+=-g -ggdb 52 | #CXXFLAGS+=-g -ggdb 53 | 54 | CXXFLAGS+=-std=c++11 55 | CFLAGS+=$(R2_CFLAGS) 56 | 57 | CXXFLAGS+=$(CFLAGS) 58 | 59 | R2_LIBEXT=$(shell r2 -H R2_LIBEXT) 60 | # TODO: rename to r2ghidra.$(R2_LIBEXT) 61 | R2G_CORE_PLUGIN=core_ghidra.$(R2_LIBEXT) 62 | R2G_ASM_PLUGIN=asm_ghidra.$(R2_LIBEXT) 63 | R2G_ANAL_PLUGIN=anal_ghidra.$(R2_LIBEXT) 64 | 65 | ifeq ($(R2_LIBEXT),) 66 | Cannot run r2 67 | endif 68 | 69 | clean: 70 | rm -f *.o $(PUGIXML_HOME)/*.o 71 | rm -f *.o $(GHIDRA_DECOMPILER)/*.o 72 | rm -f $(R2G_CORE_PLUGIN) $(R2G_ASM_PLUGIN) $(R2G_ANAL_PLUGIN) sleighc 73 | 74 | plugins: $(R2G_CORE_PLUGIN) sleighc 75 | $(MAKE) sign 76 | 77 | deps=$(R2GHIDRA_OBJS) $(GHIDRA_OBJS) $(R2G_PLUGIN_OBJS) $(PUGIXML_OBJS) 78 | 79 | asan: 80 | LDFLAGS="-fsanitize=address" CFLAGS="-fsanitize=address -g" $(MAKE) -j 81 | $(MAKE) user-install 82 | 83 | $(R2G_CORE_PLUGIN): $(deps) 84 | $(CXX) -shared -o $@ $(R2GHIDRA_OBJS) $(GHIDRA_OBJS) $(PUGIXML_OBJS) core_ghidra.o \ 85 | anal_ghidra.o core_ghidra_plugin.o anal_ghidra_plugin.o $(R2_LDFLAGS) $(LDFLAGS) $(CXXFLAGS) 86 | 87 | $(R2G_ANAL_PLUGIN): $(deps) 88 | $(CXX) -shared $(GHIDRA_OBJS) $(PUGIXML_OBJS) anal_ghidra.o anal_ghidra_plugin.o \ 89 | $(R2GHIDRA_OBJS) $(R2_LDFLAGS) $(LDFLAGS) $(CXXFLAGS) -o $@ 90 | 91 | ifneq (,$(wildcard /usr/bin/codesign)) 92 | sign macsign: 93 | -codesign -f -s - *.dylib 94 | else 95 | sign macsign: 96 | endif 97 | 98 | %.o: %.cpp 99 | $(CXX) -fPIC $(CXXFLAGS) $(R2_CFLAGS) -c $< 100 | 101 | PLUGDIR?=$(R2_LIBR_PLUGINS) 102 | 103 | install: 104 | mkdir -p $(DESTDIR)$(BINDIR) 105 | cp -f sleighc $(DESTDIR)$(BINDIR) 106 | mkdir -p $(DESTDIR)$(PLUGDIR) 107 | for a in *.$(R2_LIBEXT) ; do rm -f "$(DESTDIR)/$(PLUGDIR)/$$a" ; done 108 | cp -f *.$(R2_LIBEXT) $(DESTDIR)$(PLUGDIR) 109 | rm -f $(DESTDIR)$(PLUGDIR)/asm*ghidra*.$(R2_LIBEXT) 110 | rm -f $(DESTDIR)$(PLUGDIR)/anal*ghidra*.$(R2_LIBEXT) 111 | ifneq (,$(wildcard /usr/bin/codesign)) 112 | -codesign -f -s - $(DESTDIR)$(PLUGDIR)/*.$(R2_LIBEXT) 113 | endif 114 | 115 | uninstall: 116 | rm -f $(PLUGDIR)/*ghidra*.$(R2_LIBEXT) 117 | rm -f $(DESTDIR)/$(BINDIR)/sleighc 118 | 119 | user-install: 120 | rm -f $(PLUGDIR)/asm*ghidra*.$(R2_LIBEXT) 121 | rm -f $(PLUGDIR)/anal*ghidra*.$(R2_LIBEXT) 122 | $(MAKE) install PLUGDIR=$(R2_USER_PLUGINS) BINDIR=$(shell r2pm -H R2PM_BINDIR) 123 | 124 | user-uninstall: 125 | $(MAKE) uninstall PLUGDIR=$(R2_USER_PLUGINS) BINDIR=$(shell r2pm -H R2PM_BINDIR) 126 | -------------------------------------------------------------------------------- /dist/debian/deb.mk: -------------------------------------------------------------------------------- 1 | # Create .deb without using dpkg tools. 2 | # 3 | # Author: Tim Wegener 4 | # 5 | # Use 'include deb_hand.mak' after defining the user variables in a local 6 | # makefile. 7 | # 8 | # The 'data' rule must be customised in the local make file. 9 | # This rule should make a 'data' directory containing the full file 10 | # layout of the installed package. 11 | # 12 | # This makefile will create a debian-binary file a control directory and a 13 | # a build directory in the current directory. 14 | # Do 'make clobber' to remove these generated files. 15 | # 16 | # Destination: 17 | # PACKAGE_DIR - directory where package (and support files) will be built 18 | # defaults to the current directory 19 | # 20 | # Sources: 21 | # SOURCE_DIR - directory containing files to be packaged 22 | # ICON_SOURCE - 26x26 icon file for maemo 23 | # DESCR - description with summary on first line 24 | # preinst, postinst, prerm, postrm - optional control shell scripts 25 | 26 | # These fields are used to build the control file: 27 | # PACKAGE = 28 | # VERSION = 29 | # ARCH = 30 | # SECTION = 31 | # PRIORITY = 32 | # MAINTAINER = 33 | # DEPENDS = 34 | # 35 | # SOURCE_DIR = 36 | # ICON_SOURCE = 37 | # (ICON_SOURCE is optional) 38 | 39 | # *** NO USER CHANGES REQUIRED BEYOND THIS POINT *** 40 | ifeq ($(shell uname),Darwin) 41 | MD5SUM=md5 42 | else 43 | MD5SUM=md5sum 44 | endif 45 | 46 | GAWK=awk 47 | PACKAGE_DIR=$(shell pwd) 48 | CONTROL_EXTRAS ?= ${wildcard preinst postinst prerm postrm} 49 | 50 | ${PACKAGE_DIR}/control: ${PACKAGE_DIR}/data ${CONTROL_EXTRAS} DESCR \ 51 | ${ICON_SOURCE} 52 | #rm -rf $@ 53 | mkdir -p $@ 54 | ifneq (${CONTROL_EXTRAS},) 55 | cp ${CONTROL_EXTRAS} $@ 56 | endif 57 | # Make control file. 58 | echo "Package: ${PACKAGE}" > $@/control 59 | echo "Version: ${VERSION}" >> $@/control 60 | echo "Section: ${SECTION}" >> $@/control 61 | echo "Priority: ${PRIORITY}" >> $@/control 62 | echo "Architecture: ${ARCH}" >> $@/control 63 | ifneq (${REPLACES},) 64 | echo "Replaces: ${REPLACES}" >> $@/control 65 | endif 66 | ifneq (${DEPENDS},) 67 | echo "Depends: ${DEPENDS}" >> $@/control 68 | endif 69 | echo "Installed-Size: ${shell du -s ${PACKAGE_DIR}/data|cut -f1}" \ 70 | >> $@/control 71 | echo "Maintainer: ${MAINTAINER}" >> $@/control 72 | printf "Description:" >> $@/control 73 | cat DESCR | ${GAWK} '{print " "$$0;}' >> $@/control 74 | #ifneq (${ICON_SOURCE},) 75 | # echo "Maemo-Icon-26:" >> $@/control 76 | # base64 ${ICON_SOURCE} | ${GAWK} '{print " "$$0;}' >> $@/control 77 | #endif 78 | # Make md5sums. 79 | cd ${PACKAGE_DIR}/data && find . -type f -exec ${MD5SUM} {} \; \ 80 | | sed -e 's| \./||' \ 81 | > $@/md5sums 82 | 83 | ${PACKAGE_DIR}/debian-binary: 84 | echo "2.0" > $@ 85 | 86 | ${PACKAGE_DIR}/clean: 87 | rm -rf ${PACKAGE_DIR}/data ${PACKAGE_DIR}/control ${PACKAGE_DIR}/build *.deb 88 | 89 | ${PACKAGE_DIR}/build: ${PACKAGE_DIR}/debian-binary ${PACKAGE_DIR}/control \ 90 | ${PACKAGE_DIR}/data 91 | rm -rf $@ 92 | mkdir $@ 93 | cp ${PACKAGE_DIR}/debian-binary $@/ 94 | cd ${PACKAGE_DIR}/control && tar cJvf $@/control.tar.xz * 95 | cd ${PACKAGE_DIR}/data && \ 96 | COPY_EXTENDED_ATTRIBUTES_DISABLE=true \ 97 | COPYFILE_DISABLE=true \ 98 | tar cpJvf $@/data.tar.xz * 99 | 100 | # Convert GNU ar to BSD ar that debian requires. 101 | # Note: Order of files within ar archive is important! 102 | ${PACKAGE_DIR}/${PACKAGE}_${VERSION}_${ARCH}.deb: ${PACKAGE_DIR}/build 103 | ar -rc $@ $ $@fail 105 | #rm -f $@tmp 106 | #mv $@fail $@ 107 | 108 | .PHONY: data 109 | data: ${PACKAGE_DIR}/data 110 | 111 | .PHONY: control 112 | control: ${PACKAGE_DIR}/control 113 | 114 | .PHONY: build 115 | build: ${PACKAGE_DIR}/build 116 | 117 | .PHONY: clean 118 | clean: ${PACKAGE_DIR}/clean $(EXTRA_CLEAN) 119 | rm -f debian-binary 120 | 121 | .PHONY: deb 122 | deb: ${PACKAGE_DIR}/${PACKAGE}_${VERSION}_${ARCH}.deb 123 | 124 | 125 | clobber:: 126 | rm -rf ${PACKAGE_DIR}/debian_binary ${PACKAGE_DIR}/control \ 127 | ${PACKAGE_DIR}/data ${PACKAGE_DIR}/build 128 | 129 | push: 130 | scp *.deb radare.org:/srv/http/radareorg/cydia/debs 131 | 132 | mrproper: clean 133 | rm -rf root 134 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/0022-Show-noreturn-information-in-function-signature-2.patch.disabled: -------------------------------------------------------------------------------- 1 | diff --git a/src/decompiler/prettyprint.cc b/src/decompiler/prettyprint.cc 2 | index 3e8d18a..6b98d02 100644 3 | --- a/src/decompiler/prettyprint.cc 4 | +++ b/src/decompiler/prettyprint.cc 5 | @@ -174,6 +174,14 @@ void EmitMarkup::tagOp(const string &name,syntax_highlight hl,const PcodeOp *op) 6 | encoder->closeElement(ELEM_OP); 7 | } 8 | 9 | +/// \brief Emit a function noreturn identifier 10 | +/// 11 | +/// An identifier string representing noreturn information of the function is emitted 12 | +void EmitMarkup::tagNoreturn(void) 13 | +{ 14 | + *s << "' << " noreturn "; 15 | +} 16 | + 17 | void EmitMarkup::tagFuncName(const string &name,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op) 18 | 19 | { 20 | @@ -343,6 +351,9 @@ void TokenSplit::print(Emit *emit) const 21 | case fnam_t: // tagFuncName 22 | emit->tagFuncName(tok,hl,ptr_second.fd,op); 23 | break; 24 | + case noret_t: 25 | + emit->tagNoreturn(); 26 | + break; 27 | case type_t: // tagType 28 | emit->tagType(tok,hl,ptr_second.ct); 29 | break; 30 | @@ -973,6 +984,14 @@ void EmitPrettyPrint::tagFuncName(const string &name,syntax_highlight hl,const F 31 | scan(); 32 | } 33 | 34 | +void EmitPrettyPrint::tagNoreturn(void) 35 | +{ 36 | + checkstring(); 37 | + TokenSplit &tok( tokqueue.push() ); 38 | + tok.tagNoreturn(); 39 | + scan(); 40 | +} 41 | + 42 | void EmitPrettyPrint::tagType(const string &name,syntax_highlight hl,const Datatype *ct) 43 | 44 | { 45 | diff --git a/src/decompiler/prettyprint.hh b/src/decompiler/prettyprint.hh 46 | index 6e7124c..21f2fdf 100644 47 | --- a/src/decompiler/prettyprint.hh 48 | +++ b/src/decompiler/prettyprint.hh 49 | @@ -469,6 +469,7 @@ public: 50 | virtual void tagVariable(const string &name,syntax_highlight hl,const Varnode *vn,const PcodeOp *op); 51 | virtual void tagOp(const string &name,syntax_highlight hl,const PcodeOp *op); 52 | virtual void tagFuncName(const string &name,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op); 53 | + virtual void tagNoreturn(void); 54 | virtual void tagType(const string &name,syntax_highlight hl,const Datatype *ct); 55 | virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op); 56 | virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off); 57 | @@ -514,6 +515,8 @@ public: 58 | *s << name; } 59 | virtual void tagFuncName(const string &name,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op) { 60 | *s << name; } 61 | + virtual void tagNoreturn(void) { 62 | + *s << " noreturn ";} 63 | virtual void tagType(const string &name,syntax_highlight hl,const Datatype *ct) { 64 | *s << name; } 65 | virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op) { 66 | @@ -580,6 +583,7 @@ public: 67 | vari_t, ///< A variable identifier 68 | op_t, ///< An operator 69 | fnam_t, ///< A function identifier 70 | + noret_t, ///< A function noreturn identifier 71 | type_t, ///< A data-type identifier 72 | field_t, ///< A field name for a structured data-type 73 | comm_t, ///< Part of a comment block 74 | @@ -734,6 +738,10 @@ public: 75 | tok = name; size = tok.size(); 76 | tagtype=fnam_t; delimtype=tokenstring; hl=h; ptr_second.fd=f; op=o; } 77 | 78 | + /// \brief Create a function noreturn identifiertoken 79 | + void tagNoreturn(void) { 80 | + tagtype=noret_t; delimtype=tokenstring; } 81 | + 82 | /// \brief Create a data-type identifier token 83 | /// 84 | /// \param name is the character data for the identifier 85 | @@ -1015,6 +1023,7 @@ public: 86 | virtual void tagVariable(const string &name,syntax_highlight hl,const Varnode *vn,const PcodeOp *op); 87 | virtual void tagOp(const string &name,syntax_highlight hl,const PcodeOp *op); 88 | virtual void tagFuncName(const string &name,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op); 89 | + virtual void tagNoreturn(void); 90 | virtual void tagType(const string &name,syntax_highlight hl,const Datatype *ct); 91 | virtual void tagField(const string &name,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op); 92 | virtual void tagComment(const string &name,syntax_highlight hl,const AddrSpace *spc,uintb off); 93 | diff --git a/src/decompiler/printc.cc b/src/decompiler/printc.cc 94 | index b2637c1..d7a680c 100644 95 | --- a/src/decompiler/printc.cc 96 | +++ b/src/decompiler/printc.cc 97 | @@ -2512,6 +2512,9 @@ void PrintC::emitFunctionDeclaration(const Funcdata *fd) 98 | emitSymbolScope(fd->getSymbol()); 99 | emit->tagFuncName(fd->getDisplayName(),EmitMarkup::funcname_color,fd,(PcodeOp *)0); 100 | 101 | + if (proto->isNoReturn()) { 102 | + emit->tagNoreturn(); 103 | + } 104 | emit->spaces(function_call.spacing,function_call.bump); 105 | int4 id2 = emit->openParen(OPEN_PAREN); 106 | emit->spaces(0,function_call.bump); 107 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/meson.build: -------------------------------------------------------------------------------- 1 | project('ghidra-native', 'cpp', meson_version : '>=0.60.0', version : 'd2242691bf45a12e3ea483a4789f825af4651506') 2 | 3 | base_sources = [ 4 | 'src/decompiler/marshal.cc', 5 | 'src/decompiler/space.cc', 6 | 'src/decompiler/float.cc', 7 | 'src/decompiler/address.cc', 8 | 'src/decompiler/pcoderaw.cc', 9 | 'src/decompiler/translate.cc', 10 | 'src/decompiler/opcodes.cc', 11 | 'src/decompiler/globalcontext.cc', 12 | 'src/decompiler/xml.cc', 13 | ] 14 | 15 | decompiler_sources = [ 16 | 'src/decompiler/capability.cc', 17 | 'src/decompiler/architecture.cc', 18 | 'src/decompiler/options.cc', 19 | 'src/decompiler/graph.cc', 20 | 'src/decompiler/cover.cc', 21 | 'src/decompiler/block.cc', 22 | 'src/decompiler/cast.cc', 23 | 'src/decompiler/typeop.cc', 24 | 'src/decompiler/database.cc', 25 | 'src/decompiler/cpool.cc', 26 | 'src/decompiler/comment.cc', 27 | 'src/decompiler/stringmanage.cc', 28 | 'src/decompiler/modelrules.cc', 29 | 'src/decompiler/fspec.cc', 30 | 'src/decompiler/action.cc', 31 | 'src/decompiler/loadimage.cc', 32 | 'src/decompiler/varnode.cc', 33 | 'src/decompiler/op.cc', 34 | 'src/decompiler/type.cc', 35 | 'src/decompiler/variable.cc', 36 | 'src/decompiler/varmap.cc', 37 | 'src/decompiler/jumptable.cc', 38 | 'src/decompiler/emulate.cc', 39 | 'src/decompiler/emulateutil.cc', 40 | 'src/decompiler/flow.cc', 41 | 'src/decompiler/userop.cc', 42 | 'src/decompiler/expression.cc', 43 | 'src/decompiler/multiprecision.cc', 44 | 'src/decompiler/funcdata.cc', 45 | 'src/decompiler/funcdata_block.cc', 46 | 'src/decompiler/funcdata_varnode.cc', 47 | 'src/decompiler/unionresolve.cc', 48 | 'src/decompiler/funcdata_op.cc', 49 | 'src/decompiler/pcodeinject.cc', 50 | 'src/decompiler/heritage.cc', 51 | 'src/decompiler/prefersplit.cc', 52 | 'src/decompiler/rangeutil.cc', 53 | 'src/decompiler/ruleaction.cc', 54 | 'src/decompiler/subflow.cc', 55 | 'src/decompiler/transform.cc', 56 | 'src/decompiler/blockaction.cc', 57 | 'src/decompiler/merge.cc', 58 | 'src/decompiler/double.cc', 59 | 'src/decompiler/coreaction.cc', 60 | 'src/decompiler/condexe.cc', 61 | 'src/decompiler/override.cc', 62 | 'src/decompiler/dynamic.cc', 63 | 'src/decompiler/crc32.cc', 64 | 'src/decompiler/prettyprint.cc', 65 | 'src/decompiler/printlanguage.cc', 66 | 'src/decompiler/printc.cc', 67 | 'src/decompiler/printjava.cc', 68 | 'src/decompiler/memstate.cc', 69 | 'src/decompiler/opbehavior.cc', 70 | 'src/decompiler/paramid.cc', 71 | 'src/decompiler/string_ghidra.cc', 72 | 'src/decompiler/constseq.cc', 73 | ] 74 | 75 | libdecomp_sources = [ 76 | 'src/decompiler/libdecomp.cc', 77 | ] 78 | 79 | ghidra_sources = [ 80 | 'src/decompiler/ghidra_process.cc', 81 | 'src/decompiler/ghidra_arch.cc', 82 | 'src/decompiler/loadimage_ghidra.cc', 83 | 'src/decompiler/typegrp_ghidra.cc', 84 | 'src/decompiler/database_ghidra.cc', 85 | 'src/decompiler/ghidra_context.cc', 86 | 'src/decompiler/cpool_ghidra.cc', 87 | 'src/decompiler/comment_ghidra.cc', 88 | 'src/decompiler/inject_ghidra.cc', 89 | 'src/decompiler/ghidra_translate.cc', 90 | ] 91 | 92 | slgh_sources = [ 93 | 'src/decompiler/sleigh.cc', 94 | 'src/decompiler/sleigh_arch.cc', 95 | 'src/decompiler/inject_sleigh.cc', 96 | 'src/decompiler/pcodecompile.cc', 97 | 'src/decompiler/sleighbase.cc', 98 | 'src/decompiler/slghsymbol.cc', 99 | 'src/decompiler/slghpatexpress.cc', 100 | 'src/decompiler/slghpattern.cc', 101 | 'src/decompiler/semantics.cc', 102 | 'src/decompiler/context.cc', 103 | 'src/decompiler/slaformat.cc', 104 | 'src/decompiler/compression.cc', 105 | 'src/decompiler/filemanage.cc', 106 | 107 | 'src/decompiler/pcodeparse.cc', 108 | 'src/decompiler/grammar.cc', 109 | ] 110 | 111 | sleigh_compiler_sources = [ 112 | 'src/decompiler/slgh_compile.cc', 113 | 'src/decompiler/slgh_compile.hh', 114 | 'src/decompiler/slghparse.hh', 115 | 'src/decompiler/slghparse.cc', 116 | 'src/decompiler/slghscan.cc', 117 | ] 118 | 119 | zlib = dependency('zlib', version : '>=1.2.8', required: false) 120 | if not zlib.found() 121 | zlib_proj = subproject('zlib', default_options: ['default_library=static', 'werror=false']) 122 | zlib = zlib_proj.get_variable('zlib_dep') 123 | meson.override_dependency('zlib', zlib) 124 | endif 125 | 126 | incs = include_directories('src/decompiler') 127 | 128 | ghidra_base_static = static_library('base', 129 | base_sources, 130 | include_directories: incs 131 | ) 132 | 133 | ghidra_decompiler_static = static_library('ghidra', 134 | decompiler_sources, 135 | dependencies: zlib, 136 | link_with: ghidra_base_static, 137 | include_directories: incs 138 | ) 139 | 140 | slgh_static = static_library('slgh', 141 | slgh_sources, # + sleigh_compiler_sources, 142 | dependencies: zlib, 143 | link_with: ghidra_base_static, 144 | include_directories: incs 145 | ) 146 | 147 | libdecomp_static = static_library('libdecomp', 148 | libdecomp_sources, 149 | dependencies: zlib, 150 | link_with: [ghidra_decompiler_static, slgh_static], 151 | include_directories: incs 152 | ) 153 | 154 | sleighc_exe = executable('sleighc', 155 | sleigh_compiler_sources, 156 | dependencies: zlib, 157 | link_with: slgh_static, 158 | include_directories: incs, 159 | override_options : ['c_std=c11', 'cpp_std=c++14'], 160 | install: true 161 | ) 162 | -------------------------------------------------------------------------------- /dist/images/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 20 | 22 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 73 | 76 | 79 | 86 | 87 | 89 | 92 | 99 | 106 | 107 | 110 | 116 | 117 | 118 | 119 | 120 | 121 | -------------------------------------------------------------------------------- /ghidra/deps.mk: -------------------------------------------------------------------------------- 1 | # hardcoded for now 2 | USE_BISON=0 3 | 4 | 5 | LDFLAGS+=-lz 6 | 7 | # GHIDRA_HOME=../ghidra/ghidra/ 8 | # GHIDRA_DECOMPILER=$(GHIDRA_HOME)/Ghidra/Features/Decompiler/src/decompile/cpp 9 | # GHIDRA_HOME=../ghidra-native 10 | GHIDRA_HOME=../subprojects/ghidra-native 11 | GHIDRA_DECOMPILER=$(GHIDRA_HOME)/src/decompiler 12 | 13 | G_DECOMPILER=marshal.cc space.cc float.cc address.cc pcoderaw.cc 14 | G_DECOMPILER+=translate.cc opcodes.cc globalcontext.cc 15 | G_DECOMPILER+=capability.cc architecture.cc options.cc graph.cc 16 | G_DECOMPILER+=cover.cc block.cc cast.cc typeop.cc database.cc 17 | G_DECOMPILER+=cpool.cc comment.cc stringmanage.cc modelrules.cc fspec.cc action.cc loadimage.cc 18 | G_DECOMPILER+=varnode.cc op.cc type.cc variable.cc varmap.cc 19 | G_DECOMPILER+=jumptable.cc emulate.cc emulateutil.cc flow.cc userop.cc expression.cc 20 | G_DECOMPILER+=multiprecision.cc funcdata.cc funcdata_block.cc funcdata_varnode.cc 21 | G_DECOMPILER+=funcdata_op.cc unionresolve.cc pcodeinject.cc heritage.cc prefersplit.cc 22 | G_DECOMPILER+=rangeutil.cc ruleaction.cc subflow.cc blockaction.cc 23 | G_DECOMPILER+=merge.cc double.cc coreaction.cc condexe.cc override.cc 24 | G_DECOMPILER+=dynamic.cc crc32.cc prettyprint.cc printlanguage.cc 25 | G_DECOMPILER+=printc.cc printjava.cc memstate.cc opbehavior.cc 26 | G_DECOMPILER+=paramid.cc transform.cc string_ghidra.cc constseq.cc 27 | 28 | G_DECOMPILER+=ghidra_arch.cc inject_ghidra.cc ghidra_translate.cc 29 | G_DECOMPILER+=loadimage_ghidra.cc typegrp_ghidra.cc database_ghidra.cc 30 | G_DECOMPILER+=ghidra_context.cc cpool_ghidra.cc comment_ghidra.cc 31 | # G_DECOMPILER+=ghidra_process.cc 32 | 33 | G_DECOMPILER+= $(GHIDRA_LIBDECOMP_SRCS) 34 | 35 | G_DECOMPILER+=sleigh_arch.cc 36 | G_DECOMPILER+=sleigh.cc 37 | G_DECOMPILER+=inject_sleigh.cc 38 | G_DECOMPILER+=pcodecompile.cc 39 | G_DECOMPILER+=sleighbase.cc 40 | G_DECOMPILER+=slghsymbol.cc 41 | G_DECOMPILER+=slghpatexpress.cc 42 | G_DECOMPILER+=slghpattern.cc 43 | G_DECOMPILER+=semantics.cc 44 | G_DECOMPILER+=context.cc 45 | G_DECOMPILER+=slaformat.cc 46 | G_DECOMPILER+=compression.cc 47 | G_DECOMPILER+=filemanage.cc 48 | 49 | 50 | # set(DECOMPILER_SOURCE_CONSOLE_CXX 51 | ## G_DECOMPILER+=consolemain.cc 52 | ## G_DECOMPILER+=interface.cc 53 | ## G_DECOMPILER+=ifacedecomp.cc 54 | ## G_DECOMPILER+=ifaceterm.cc 55 | ## G_DECOMPILER+=callgraph.cc 56 | ## G_DECOMPILER+=raw_arch.cc 57 | 58 | ifeq ($(USE_BISON),1) 59 | $(GHIDRA_DECOMPILER)/grammar.cc: $(GHIDRA_DECOMPILER)/grammar.y 60 | $(BISON) -p grammar -o $(GHIDRA_DECOMPILER)/grammar.cc $(GHIDRA_DECOMPILER)/grammar.y 61 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(GHIDRA_DECOMPILER)/grammar.o -c $(GHIDRA_DECOMPILER)/grammar.cc 62 | 63 | $(GHIDRA_DECOMPILER)/ruleparser.cc: $(GHIDRA_DECOMPILER)/grammar.y 64 | $(BISON) -p ruleparser -o $(GHIDRA_DECOMPILER)/ruleparser.cc $(GHIDRA_DECOMPILER)/ruleparser.y 65 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(GHIDRA_DECOMPILER)/ruleparser.o -c $(GHIDRA_DECOMPILER)/ruleparser.cc 66 | 67 | $(GHIDRA_DECOMPILER)/xml.cc: $(GHIDRA_DECOMPILER)/xml.y 68 | $(BISON) -p xml -o $(GHIDRA_DECOMPILER)/xml.cc $(GHIDRA_DECOMPILER)/xml.y 69 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(GHIDRA_DECOMPILER)/xml.o -c $(GHIDRA_DECOMPILER)/xml.cc 70 | 71 | $(GHIDRA_DECOMPILER)/pcodeparse.cc: $(GHIDRA_DECOMPILER)/pcodeparse.y 72 | $(BISON) -p pcodeparser -o $(GHIDRA_DECOMPILER)/pcodeparse.cc $(GHIDRA_DECOMPILER)/pcodeparse.y 73 | $(CXX) $(CXXFLAGS) $(LDFLAGS) -o $(GHIDRA_DECOMPILER)/pcodeparse.o -c $(GHIDRA_DECOMPILER)/pcodeparse.cc 74 | 75 | $(GHIDRA_DECOMPILER)/slghparse.cc: $(GHIDRA_DECOMPILER)/slghparse.y 76 | echo '#include \"slghparse.hpp\"' > $(GHIDRA_DECOMPILER)/slghparse.tab.hpp 77 | $(BISON) -d -o $(GHIDRA_DECOMPILER)/slghparse.tab.hh $(GHIDRA_DECOMPILER)/slghparse.y 78 | $(BISON) -o $(GHIDRA_DECOMPILER)/slghparse.cc $(GHIDRA_DECOMPILER)/slghparse.y 79 | 80 | .PHONY: $(GHIDRA_DECOMPILER)/slghparse.cc 81 | .PHONY: $(GHIDRA_DECOMPILER)/slghscan.cc 82 | 83 | $(GHIDRA_DECOMPILER)/slghscan.cc: $(GHIDRA_DECOMPILER)/slghscan.l $(GHIDRA_DECOMPILER)/slghparse.cc 84 | $(FLEX) --header-file=$(GHIDRA_DECOMPILER)/slghscan.tab.hh -o $(GHIDRA_DECOMPILER)/slghscan.cc $(GHIDRA_DECOMPILER)/slghscan.l 85 | else 86 | G_DECOMPILER+= grammar.cc 87 | # no .cc? G_DECOMPILER+= ruleparser.cc 88 | G_DECOMPILER+= xml.cc 89 | G_DECOMPILER+= pcodeparse.cc 90 | # G_DECOMPILER+= slghparse.cc ## bison 91 | # G_DECOMPILER+= pcodeparse.cc ## bison 92 | endif 93 | 94 | GHIDRA_SRCS=$(addprefix $(GHIDRA_DECOMPILER)/,$(G_DECOMPILER)) 95 | GHIDRA_OBJS+=$(subst .cc,.o,$(GHIDRA_SRCS)) 96 | 97 | GHIDRA_LIBDECOMP_SRCS=libdecomp.cc 98 | GHIDRA_LIBDECOMP_OBJS+=$(subst .cc,.o,$(GHIDRA_LIBDECOMP_SRCS)) 99 | 100 | GHIDRA_SLEIGH_COMPILER_SRCS=slgh_compile.cc 101 | GHIDRA_SLEIGH_COMPILER_OBJS=$(subst .cc,.o,$(GHIDRA_SLEIGH_COMPILER_SRCS)) 102 | 103 | sleigh: sleighc 104 | $(SLEIGHC) $(SPECFILE) $(SLAFILE) 105 | 106 | SLEIGHTC_OBJS=$(GHIDRA_DECOMPILER)/slgh_compile.o $(GHIDRA_DECOMPILER)/slghscan.o $(GHIDRA_DECOMPILER)/slghparse.o 107 | 108 | sleighc: $(SLEIGHTC_OBJS) $(GHIDRA_OBJS) 109 | $(CXX) $(CXXFLAGS) -o sleighc $(SLEIGHTC_OBJS) $(GHIDRA_OBJS) $(LDFLAGS) 110 | 111 | GHIDRA_SLEIGH_HOME=$(GHIDRA_HOME)/src/Processors 112 | GHIDRA_SLEIGH_SLASPECS=$(GHIDRA_SLEIGH_HOME)/*.slaspec 113 | GHIDRA_SLEIGH_FILES=$(GHIDRA_SLEIGH_HOME)/*.cspec 114 | GHIDRA_SLEIGH_FILES+=$(GHIDRA_SLEIGH_HOME)/*.ldefs 115 | GHIDRA_SLEIGH_FILES+=$(GHIDRA_SLEIGH_HOME)/*.pspec 116 | 117 | ../ghidra-processors.txt: 118 | cp -f ../ghidra-processors.txt.default ../ghidra-processors.txt 119 | 120 | sleigh-build: sleighc ../ghidra-processors.txt 121 | for a in DATA $(shell cat ../ghidra-processors.txt) ; do ./sleighc -a $(GHIDRA_SLEIGH_HOME)/$$a ; done 122 | 123 | GHIDRA_PROCS=$(GHIDRA_SLEIGH_HOME)/*/*/* 124 | 125 | sleigh-install: 126 | mkdir -p "$(D)" 127 | for a in DATA $(shell cat ../ghidra-processors.txt) ; do \ 128 | for b in cspec ldefs sla pspec ; do \ 129 | cp -f $(GHIDRA_SLEIGH_HOME)/$$a/*/*/*.$$b "$(D)"; \ 130 | done ;\ 131 | done 132 | 133 | sleigh-uninstall: 134 | rm -rf "$(D)" 135 | -------------------------------------------------------------------------------- /src/R2Scope.h: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2021 - thestr4ng3r, pancake */ 2 | 3 | #ifndef R2GHIDRA_R2SCOPE_H 4 | #define R2GHIDRA_R2SCOPE_H 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | // Windows defines LoadImage to LoadImageA 12 | #ifdef LoadImage 13 | #undef LoadImage 14 | #endif 15 | 16 | using namespace ghidra; 17 | 18 | class R2Architecture; 19 | typedef struct r_anal_function_t RAnalFunction; 20 | typedef struct r_flag_item_t RFlagItem; 21 | 22 | class R2Scope : public Scope { 23 | private: 24 | R2Architecture *arch; 25 | ScopeInternal *cache; 26 | std::unique_ptr next_id; 27 | 28 | uint8 makeId() const { return (*next_id)++; } 29 | 30 | FunctionSymbol *registerFunction(RAnalFunction *fcn) const; 31 | Symbol *registerFlag(RFlagItem *flag) const; 32 | Symbol *queryR2Absolute(ut64 addr, bool contain) const; 33 | Symbol *queryR2(const Address &addr, bool contain) const; 34 | LabSymbol *queryR2FunctionLabel(const Address &addr) const; 35 | 36 | protected: 37 | // TODO? void addRange(AddrSpace *spc,uintb first,uintb last) override; 38 | void removeRange(AddrSpace *spc,uintb first,uintb last) override { throw LowlevelError("remove_range should not be performed on radare2 scope"); } 39 | void addSymbolInternal(Symbol *sym) override { throw LowlevelError("addSymbolInternal unimplemented"); } 40 | SymbolEntry *addMapInternal(Symbol *sym, uint4 exfl, const Address &addr, int4 off, int4 sz, const RangeList &uselim) override { throw LowlevelError("addMapInternal unimplemented"); } 41 | SymbolEntry *addDynamicMapInternal(Symbol *sym, uint4 exfl, uint8 hash, int4 off, int4 sz, const RangeList &uselim) override { throw LowlevelError("addMap unimplemented"); } 42 | 43 | public: 44 | explicit R2Scope(R2Architecture *arch); 45 | ~R2Scope() override; 46 | 47 | Scope *buildSubScope(uint8 id, const string &nm) override; 48 | void clear(void) override { cache->clear(); } 49 | SymbolEntry *addSymbol(const string &name, Datatype *ct, const Address &addr, const Address &usepoint) override { return cache->addSymbol(name, ct, addr, usepoint); } 50 | string buildVariableName(const Address &addr, const Address &pc, Datatype *ct,int4 &index,uint4 flags) const override { return cache->buildVariableName(addr,pc,ct,index,flags); } 51 | string buildUndefinedName(void) const override { return cache->buildUndefinedName(); } 52 | void setAttribute(Symbol *sym,uint4 attr) override { cache->setAttribute(sym,attr); } 53 | void clearAttribute(Symbol *sym,uint4 attr) override { cache->clearAttribute(sym,attr); } 54 | void setDisplayFormat(Symbol *sym,uint4 attr) override { cache->setDisplayFormat(sym,attr); } 55 | void adjustCaches(void) override { cache->adjustCaches(); } 56 | 57 | SymbolEntry *findAddr(const Address &addr,const Address &usepoint) const override; 58 | SymbolEntry *findContainer(const Address &addr,int4 size, const Address &usepoint) const override; 59 | SymbolEntry *findClosestFit(const Address &addr,int4 size, const Address &usepoint) const override { throw LowlevelError("findClosestFit unimplemented"); } 60 | Funcdata *findFunction(const Address &addr) const override; 61 | ExternRefSymbol *findExternalRef(const Address &addr) const override; 62 | LabSymbol *findCodeLabel(const Address &addr) const override; 63 | bool isNameUsed(const string &name, const Scope *op2) const override { throw LowlevelError("isNameUsed unimplemented"); } 64 | Funcdata *resolveExternalRefFunction(ExternRefSymbol *sym) const override; 65 | 66 | SymbolEntry *findOverlap(const Address &addr,int4 size) const override { throw LowlevelError("findOverlap unimplemented"); } 67 | SymbolEntry *findBefore(const Address &addr) const { throw LowlevelError("findBefore unimplemented"); } 68 | SymbolEntry *findAfter(const Address &addr) const { throw LowlevelError("findAfter unimplemented"); } 69 | void findByName(const string &name,vector &res) const override { throw LowlevelError("findByName unimplemented"); } 70 | MapIterator begin() const override { throw LowlevelError("begin unimplemented"); } 71 | MapIterator end() const override { throw LowlevelError("end unimplemented"); } 72 | list::const_iterator beginDynamic() const override { throw LowlevelError("beginDynamic unimplemented"); } 73 | list::const_iterator endDynamic() const override { throw LowlevelError("endDynamic unimplemented"); } 74 | list::iterator beginDynamic() override { throw LowlevelError("beginDynamic unimplemented"); } 75 | list::iterator endDynamic() override { throw LowlevelError("endDynamic unimplemented"); } 76 | void clearCategory(int4 cat) override { throw LowlevelError("clearCategory unimplemented"); } 77 | void clearUnlockedCategory(int4 cat) override { throw LowlevelError("clearUnlockedCategory unimplemented"); } 78 | void clearUnlocked() override { throw LowlevelError("clearUnlocked unimplemented"); } 79 | void restrictScope(Funcdata *f) override { throw LowlevelError("restrictScope unimplemented"); } 80 | void removeSymbolMappings(Symbol *symbol) override { throw LowlevelError("removeSymbolMappings unimplemented"); } 81 | void removeSymbol(Symbol *symbol) override { throw LowlevelError("removeSymbol unimplemented"); } 82 | void renameSymbol(Symbol *sym,const string &newname) override { throw LowlevelError("renameSymbol unimplemented"); } 83 | void retypeSymbol(Symbol *sym,Datatype *ct) override { throw LowlevelError("retypeSymbol unimplemented"); } 84 | string makeNameUnique(const string &nm) const override { throw LowlevelError("makeNameUnique unimplemented"); } 85 | void encode(Encoder &encoder) const override { cache->encode(encoder); } 86 | void decode(Decoder &decoder) override { throw LowlevelError("not implemented"); } 87 | void printEntries(ostream &s) const override { throw LowlevelError("printEntries unimplemented"); } 88 | int4 getCategorySize(int4 cat) const override { throw LowlevelError("getCategorySize unimplemented"); } 89 | Symbol *getCategorySymbol(int4 cat,int4 ind) const override { throw LowlevelError("getCategorySymbol unimplemented"); } 90 | void setCategory(Symbol *sym,int4 cat,int4 ind) override { throw LowlevelError("setCategory unimplemented"); } 91 | }; 92 | 93 | #endif //R2GHIDRA_R2SCOPE_H 94 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | r2ghidra logo 2 | 3 | # r2ghidra 4 | 5 | [![ci](https://github.com/radareorg/r2ghidra/actions/workflows/ci.yml/badge.svg)](https://github.com/radareorg/r2ghidra/actions/workflows/ci.yml) 6 | 7 | This is an integration of the Ghidra decompiler for [radare2](https://github.com/radareorg/radare2). 8 | It is solely based on the decompiler part of Ghidra, which is written entirely in 9 | C++, so Ghidra itself is not required at all and the plugin can be built self-contained. 10 | This project was presented at r2con 2019 as part of the Cutter talk: [https://youtu.be/eHtMiezr7l8?t=950](https://youtu.be/eHtMiezr7l8?t=950) 11 | 12 | ## Installing 13 | 14 | An r2pm package is available that can easily be installed like: 15 | 16 | ``` 17 | r2pm -U 18 | r2pm -ci r2ghidra 19 | ``` 20 | 21 | By default r2pm will install stuff in your home, you can use `-g` to use the system wide installation. 22 | 23 | ## Dependencies 24 | 25 | To build and install r2ghidra you need the following software installed in your system: 26 | 27 | * radare2 (preferibly from git, for distro builds ensure the `-dev` package is also installed) 28 | * pkg-config - that's how build system find libraries and include files to compile stuff 29 | * acr/make or meson/ninja - pick the build system you like! all of them are maintained and working 30 | * msvc/g++/clang++ - basically a C++ compiler (and a C compiler) 31 | * git/patch - needed to clone ghidra-native and build stuff 32 | 33 | If the build fails, please carefully read the error message and act accordingly, r2pm should 34 | handle the `PKG_CONFIG_PATH` automatically for you in any case. 35 | 36 | ## Portability 37 | 38 | r2ghidra is known to work on the following operating systems: 39 | 40 | * Termux (Android-arm64) 41 | * macOS / iOS 42 | * GNU/Linux 43 | * Windows 44 | * FreeBSD/x86-64 45 | 46 | ## Usage 47 | 48 | To decompile a function, first type `af` to analize it and then `pdg` to invoke r2ghidra: 49 | 50 | ``` 51 | [0x100001060]> pdg? 52 | Usage: pdg # Native Ghidra decompiler plugin 53 | | pdg # Decompile current function with the Ghidra decompiler 54 | | pdg* # Decompiled code is returned to r2 as comment 55 | | pdga # Side by side two column disasm and decompilation 56 | | pdgd # Dump the debug XML Dump 57 | | pdgj # Dump the current decompiled function as JSON 58 | | pdgo # Decompile current function side by side with offsets 59 | | pdgp # Switch to RAsm and RAnal plugins driven by SLEIGH from Ghidra 60 | | pdgs # Display loaded Sleigh Languages 61 | | pdgsd N # Disassemble N instructions with Sleigh and print pcode 62 | | pdgss # Display automatically matched Sleigh Language ID 63 | | pdgx # Dump the XML of the current decompiled function 64 | ``` 65 | 66 | The following config vars (for the `e` command) can be used to adjust r2ghidra's behavior: 67 | 68 | ``` 69 | [0x000275a7]> e?r2ghidra. 70 | r2ghidra.casts: Show type casts where needed 71 | r2ghidra.cmt.cpp: C++ comment style 72 | r2ghidra.cmt.indent: Comment indent 73 | r2ghidra.indent: Indent increment 74 | r2ghidra.lang: Custom Sleigh ID to override auto-detection (e.g. x86:LE:32:default) 75 | r2ghidra.linelen: Max line length 76 | r2ghidra.maximplref: Maximum number of references to an expression before showing an explicit variable. 77 | r2ghidra.rawptr: Show unknown globals as raw addresses instead of variables 78 | r2ghidra.roprop: Propagate read-only constants (0,1,2,3,4) 79 | r2ghidra.sleighhome: SLEIGHHOME 80 | r2ghidra.timeout: Run decompilation in a separate process and kill it after a specific time 81 | r2ghidra.verbose: Show verbose warning messages while decompiling 82 | ``` 83 | 84 | Here, `r2ghidra.sleighhome` must point to a directory containing the `*.sla`, `*.lspec`, ... files for 85 | the architectures that should supported by the decompiler. This is however set up automatically when using 86 | the r2pm package or installing as shown below. 87 | 88 | ## Installation 89 | 90 | Most users will just use `r2pm -ci r2ghidra` to build or update the plugin for the version of r2 91 | 92 | ### Windows Binary installation 93 | 94 | First, make sure you have the latest version of radare2 for Windows, which can be found as a binary package [in the releases](https://github.com/radareorg/radare2/releases). 95 | 96 | Then run the following command from the radare2/bin/ directory to find out the `R2_USER_PLUGINS` path: 97 | 98 | ``` 99 | $ r2 -hh 100 | ``` 101 | 102 | Now, download the [latest r2ghidra release](https://github.com/radareorg/r2ghidra/releases) for Windows and copy the `dll file in the `R2_USER_PLUGINS` directory. 103 | 104 | You should now be able to do `pdg` while in radare2 to invoke the r2ghidra decompile command. 105 | 106 | ## Building 107 | 108 | 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. 109 | 110 | ### ACR/Make 111 | 112 | The procedure is like the standard autoconf: 113 | 114 | ``` 115 | $ ./preconfigure # optional, but useful for offline-packagers, as its downloads the external repos 116 | $ ./configure --prefix=$(r2 -H R2_PREFIX) 117 | $ make 118 | $ make install # or make user-install 119 | ``` 120 | 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. 121 | 122 | ### Meson/Ninja 123 | 124 | Also works with `muon/samu` and that's the preferred way to build r2ghidra on Windows. 125 | 126 | ``` 127 | meson setup b 128 | meson compile -C b 129 | meson install -C b 130 | ``` 131 | 132 | ### Windows 133 | 134 | To compile r2ghidra on windows you need Visual Studio and git installed: 135 | 136 | ```cmd 137 | preconfigure # find VS installation, sets path and download external code 138 | configure # prepare the build (run meson) 139 | make # compile and zip the result (run ninja) 140 | ``` 141 | 142 | ## License 143 | 144 | See `LICENSE.md` for more details. but it's basically **LGPLv3**. 145 | -------------------------------------------------------------------------------- /dist/docker/dockcross: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | DEFAULT_DOCKCROSS_IMAGE=dockcross/linux-armv5 4 | 5 | #------------------------------------------------------------------------------ 6 | # Helpers 7 | # 8 | err() { 9 | echo >&2 ERROR: $@\\n 10 | } 11 | 12 | die() { 13 | err $@ 14 | exit 1 15 | } 16 | 17 | has() { 18 | # eg. has command update 19 | local kind=$1 20 | local name=$2 21 | 22 | type -t $kind:$name | grep -q function 23 | } 24 | 25 | #------------------------------------------------------------------------------ 26 | # Command handlers 27 | # 28 | command_update_image() { 29 | docker pull $FINAL_IMAGE 30 | } 31 | 32 | help_update_image() { 33 | echo "Pull the latest $FINAL_IMAGE ." 34 | } 35 | 36 | command_update_script() { 37 | if [ docker run $FINAL_IMAGE | cmp -s $0 ]; then 38 | echo "$0 is up to date" 39 | else 40 | printf "Updating $0 '... '" 41 | docker run $FINAL_IMAGE > $0 && echo ok 42 | fi 43 | } 44 | 45 | command_update() { 46 | command_update_image 47 | command_update_script 48 | } 49 | 50 | help_update() { 51 | echo "Pull the latest $FINAL_IMAGE, and then update $0 from that." 52 | } 53 | 54 | command_help() { 55 | if [ $# != 0 ]; then 56 | if ! has command $1; then 57 | err \"$1\" is not an dockcross command 58 | command:help 59 | elif ! has help $1; then 60 | err No help found for \"$1\" 61 | else 62 | help:$1 63 | fi 64 | else 65 | cat >&2 < 84 | ENDHELP 85 | exit 1 86 | fi 87 | } 88 | 89 | #------------------------------------------------------------------------------ 90 | # Option processing 91 | # 92 | special_update_command='' 93 | while [ $# != 0 ]; do 94 | case $1 in 95 | 96 | --) 97 | break 98 | ;; 99 | 100 | --args|-a) 101 | ARG_ARGS="$2" 102 | shift 2 103 | ;; 104 | 105 | --config|-c) 106 | ARG_CONFIG="$2" 107 | shift 2 108 | ;; 109 | 110 | --image|-i) 111 | ARG_IMAGE="$2" 112 | shift 2 113 | ;; 114 | update|update-image|update-script) 115 | special_update_command=$1 116 | break 117 | ;; 118 | -*) 119 | err Unknown option \"$1\" 120 | command:help 121 | exit 122 | ;; 123 | 124 | *) 125 | break 126 | ;; 127 | 128 | esac 129 | done 130 | 131 | # The precedence for options is: 132 | # 1. command-line arguments 133 | # 2. environment variables 134 | # 3. defaults 135 | 136 | # Source the config file if it exists 137 | DEFAULT_DOCKCROSS_CONFIG=~/.dockcross 138 | FINAL_CONFIG=${ARG_CONFIG-${DOCKCROSS_CONFIG-$DEFAULT_DOCKCROSS_CONFIG}} 139 | 140 | [ -f "$FINAL_CONFIG" ] && source "$FINAL_CONFIG" 141 | 142 | # Set the docker image 143 | FINAL_IMAGE=${ARG_IMAGE-${DOCKCROSS_IMAGE-$DEFAULT_DOCKCROSS_IMAGE}} 144 | 145 | # Handle special update command 146 | if [ "$special_update_command" != "" ]; then 147 | case $special_update_command in 148 | 149 | update) 150 | command:update 151 | exit $? 152 | ;; 153 | 154 | update-image) 155 | command:update-image 156 | exit $? 157 | ;; 158 | 159 | update-script) 160 | command:update-script 161 | exit $? 162 | ;; 163 | 164 | esac 165 | fi 166 | 167 | # Set the docker run extra args (if any) 168 | FINAL_ARGS=${ARG_ARGS-${DOCKCROSS_ARGS}} 169 | 170 | # Bash on Ubuntu on Windows 171 | UBUNTU_ON_WINDOWS=$([ -e /proc/version ] && grep -l Microsoft /proc/version || echo "") 172 | # MSYS, Git Bash, etc. 173 | MSYS=$([ -e /proc/version ] && grep -l MINGW /proc/version || echo "") 174 | 175 | if [ -z "$UBUNTU_ON_WINDOWS" -a -z "$MSYS" ]; then 176 | USER_IDS="-e BUILDER_UID=$( id -u ) -e BUILDER_GID=$( id -g ) -e BUILDER_USER=$( id -un ) -e BUILDER_GROUP=$( id -gn )" 177 | fi 178 | 179 | # Change the PWD when working in Docker on Windows 180 | if [ -n "$UBUNTU_ON_WINDOWS" ]; then 181 | HOST_PWD=$PWD 182 | HOST_PWD=${HOST_PWD/\/mnt\//} 183 | HOST_PWD=${HOST_PWD/\//:\/} 184 | elif [ -n "$MSYS" ]; then 185 | HOST_PWD=$PWD 186 | HOST_PWD=${HOST_PWD/\//} 187 | HOST_PWD=${HOST_PWD/\//:\/} 188 | else 189 | HOST_PWD=$PWD 190 | fi 191 | 192 | #------------------------------------------------------------------------------ 193 | # Now, finally, run the command in a container 194 | # 195 | tty -s && TTY_ARGS=-ti || TTY_ARGS= 196 | CONTAINER_NAME=dockcross_$RANDOM 197 | docker run $TTY_ARGS --name $CONTAINER_NAME \ 198 | -v "$HOST_PWD":/work \ 199 | $USER_IDS \ 200 | $FINAL_ARGS \ 201 | $FINAL_IMAGE "$@" 202 | run_exit_code=$? 203 | 204 | # Attempt to delete container 205 | rm_output=$(docker rm -f $CONTAINER_NAME 2>&1) 206 | rm_exit_code=$? 207 | if [ $rm_exit_code != 0 ]; then 208 | if [ "$CIRCLECI" == "true" ] && [ $rm_output == *"Driver btrfs failed to remove"* ]; then 209 | : # Ignore error because of https://circleci.com/docs/docker-btrfs-error/ 210 | else 211 | echo "$rm_output" 212 | exit $rm_exit_code 213 | fi 214 | fi 215 | 216 | exit $run_exit_code 217 | 218 | ################################################################################ 219 | # 220 | # This image is not intended to be run manually. 221 | # 222 | # To create a dockcross helper script for the 223 | # dockcross/linux-armv7 image, run: 224 | # 225 | # docker run --rm dockcross/linux-armv7 > dockcross-linux-armv7 226 | # chmod +x dockcross-linux-armv7 227 | # 228 | # You may then wish to move the dockcross script to your PATH. 229 | # 230 | ################################################################################ 231 | -------------------------------------------------------------------------------- /src/R2Architecture.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2022 - thestr4ng3r, pancake */ 2 | 3 | #include "R2Architecture.h" 4 | #include "R2LoadImage.h" 5 | #include "R2Scope.h" 6 | #include "R2TypeFactory.h" 7 | #include "R2CommentDatabase.h" 8 | #include "R2Utils.h" 9 | #include "ArchMap.h" 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | using namespace ghidra; 17 | 18 | // maps radare2 calling conventions to decompiler proto models 19 | static const std::map cc_map = { 20 | { "cdecl", "__cdecl" }, 21 | { "fastcall", "__fastcall" }, 22 | { "ms", "__fastcall" }, 23 | { "stdcall", "__stdcall" }, 24 | { "cdecl-thiscall-ms", "__thiscall" }, 25 | { "sh32", "__stdcall" }, 26 | { "amd64", "__stdcall" }, 27 | { "arm64", "__cdecl" }, 28 | { "arm32", "__stdcall" }, 29 | { "arm16", "__stdcall" } /* not actually __stdcall */ 30 | }; 31 | 32 | std::string FilenameFromCore(RCore *core) { 33 | if (core && core->bin && core->bin->file) { 34 | return core->bin->file; 35 | } 36 | return std::string(); 37 | } 38 | 39 | R2Architecture::R2Architecture(RCore *core, const std::string &sleigh_id) 40 | : SleighArchitecture (FilenameFromCore (core), sleigh_id.empty () ? SleighIdFromCore (core) : sleigh_id, &std::cout), 41 | coreMutex (core) { 42 | #if 1 43 | collectSpecFiles(std::cerr); ///< Gather specification files in normal locations 44 | auto langs = getLanguageDescriptions (); 45 | #endif 46 | } 47 | 48 | ProtoModel *R2Architecture::protoModelFromR2CC(const char *cc) { 49 | auto it = cc_map.find (cc); 50 | if (it == cc_map.end ()) { 51 | return nullptr; 52 | } 53 | auto protoIt = protoModels.find (it->second); 54 | if (protoIt == protoModels.end ()) { 55 | return nullptr; 56 | } 57 | return protoIt->second; 58 | } 59 | 60 | void R2Architecture::loadRegisters(const Translate *translate) { 61 | registers = {}; 62 | if (!translate) { 63 | return; 64 | } 65 | std::map regs; 66 | translate->getAllRegisters (regs); 67 | for (const auto ® : regs) { 68 | registers[reg.second] = reg.first; 69 | auto lower = tolower (reg.second); 70 | if (registers.find(lower) == registers.end()) { 71 | registers[lower] = reg.first; 72 | } 73 | } 74 | } 75 | 76 | Address R2Architecture::registerAddressFromR2Reg(const char *regname) { 77 | loadRegisters (translate); 78 | auto it = registers.find (regname); 79 | if (it == registers.end ()) { 80 | it = registers.find (tolower (regname)); 81 | } 82 | if (it == registers.end ()) { 83 | return Address (); // not found, invalid addr 84 | } 85 | return it->second.getAddr (); 86 | } 87 | 88 | Translate *R2Architecture::buildTranslator(DocumentStorage &store) { 89 | Translate *ret = SleighArchitecture::buildTranslator (store); 90 | loadRegisters(ret); 91 | return ret; 92 | } 93 | 94 | ContextDatabase *R2Architecture::getContextDatabase() { 95 | return context; 96 | } 97 | 98 | void R2Architecture::postSpecFile() { 99 | RCoreLock core(getCore()); 100 | r_list_foreach_cpp(core->anal->fcns, [&](RAnalFunction *func) { 101 | if (func->is_noreturn) { 102 | // Configure noreturn functions 103 | Funcdata *infd = symboltab->getGlobalScope()->queryFunction(Address(getDefaultCodeSpace(), func->addr)); 104 | if (!infd) { 105 | return; 106 | } 107 | infd->getFuncProto ().setNoReturn(true); 108 | } 109 | }); 110 | } 111 | 112 | void R2Architecture::buildAction(DocumentStorage &store) { 113 | parseExtraRules (store); // Look for any additional rules 114 | allacts.universalAction (this); 115 | allacts.resetDefaults (); 116 | if (rawptr) { 117 | allacts.cloneGroup ("decompile", "decompile-deuglified"); 118 | allacts.removeFromGroup ("decompile-deuglified", "fixateglobals"); // this action (ActionMapGlobals) will create these ugly uRam0x12345s 119 | allacts.setCurrent ("decompile-deuglified"); 120 | } 121 | } 122 | 123 | void R2Architecture::buildLoader(DocumentStorage &store) { 124 | RCoreLock core (getCore ()); 125 | collectSpecFiles (*errorstream); 126 | loader = new R2LoadImage (getCore (), this); 127 | } 128 | 129 | Scope *R2Architecture::buildDatabase(DocumentStorage &store) { 130 | symboltab = new Database (this, false); 131 | Scope *globalscope = new R2Scope (this); 132 | symboltab->attachScope (globalscope, nullptr); 133 | return globalscope; 134 | } 135 | void R2Architecture::buildCoreTypes(DocumentStorage &store) { 136 | // TODO: load from r2? 137 | types->setCoreType ("void", 1, TYPE_VOID, false); 138 | 139 | types->setCoreType ("bool", 1, TYPE_BOOL, false); 140 | types->setCoreType ("bool4", 4, TYPE_BOOL, false); 141 | types->setCoreType ("bool8", 8, TYPE_BOOL, false); 142 | 143 | types->setCoreType ("uint8_t", 1, TYPE_UINT, false); 144 | types->setCoreType ("uint16_t", 2, TYPE_UINT, false); 145 | types->setCoreType ("uint32_t", 4, TYPE_UINT, false); 146 | types->setCoreType ("uint64_t", 8, TYPE_UINT, false); 147 | types->setCoreType ("int8_t", 1, TYPE_INT, false); 148 | types->setCoreType ("int16_t", 2, TYPE_INT, false); 149 | types->setCoreType ("int32_t", 4, TYPE_INT, false); 150 | types->setCoreType ("int64_t", 8, TYPE_INT, false); 151 | types->setCoreType ("int", sizeof (int), TYPE_INT, false); 152 | 153 | types->setCoreType ("double", 8, TYPE_FLOAT, false); 154 | types->setCoreType ("float", 4, TYPE_FLOAT, false); 155 | types->setCoreType ("float8", 8, TYPE_FLOAT, false); 156 | types->setCoreType ("float10", 10, TYPE_FLOAT, false); 157 | types->setCoreType ("float16", 16 ,TYPE_FLOAT, false); 158 | 159 | types->setCoreType ("uchar", 1, TYPE_UNKNOWN, false); 160 | types->setCoreType ("ushort", 2, TYPE_UNKNOWN, false); 161 | types->setCoreType ("uint", 4, TYPE_UNKNOWN, false); 162 | types->setCoreType ("ulong", 8, TYPE_UNKNOWN, false); 163 | 164 | types->setCoreType ("code", 1, TYPE_CODE, false); 165 | 166 | types->setCoreType ("char", 1, TYPE_INT, true); 167 | types->setCoreType ("wchar", 2, TYPE_INT, true); 168 | // types->setCoreType ("char8_t", 1, TYPE_INT, true); // last type defined overrides the previous 169 | types->setCoreType ("char16_t", 2, TYPE_INT, true); 170 | types->setCoreType ("char32_t", 4, TYPE_INT, true); 171 | 172 | types->cacheCoreTypes (); 173 | } 174 | 175 | void R2Architecture::buildTypegrp(DocumentStorage &store) { 176 | r2TypeFactory_ = new R2TypeFactory (this); 177 | types = r2TypeFactory_; 178 | } 179 | 180 | void R2Architecture::buildCommentDB(DocumentStorage &store) { 181 | commentdb = new R2CommentDatabase (this); 182 | } 183 | -------------------------------------------------------------------------------- /test/db/extras/anal_ghidra: -------------------------------------------------------------------------------- 1 | NAME=x86:LE:32:default:gcc 2 | ARGS=-a x86 3 | FILE=malloc://2048 4 | EXPECT=<>,1,32,1,<<,-,&,DUP,0,SWAP,>>,1,8,1,<<,-,&,31,5,PICK,>>,1,32,1,<<,-,&,DUP,0,SWAP,>>,1,8,1,<<,-,&,31,6,PICK,>>,1,32,1,<<,-,&,DUP,0,SWAP,>>,1,8,1,<<,-,&,1,2,PICK,&,1,8,1,<<,-,&,4294967291,psw,NUM,&,1,32,1,<<,-,&,5,PICK,8,PICK,-,!,!,3,PICK,7,PICK,-,!,DUP,3,PICK,&,1,8,1,<<,-,&,DUP,2,2,PICK,<<,1,32,1,<<,-,&,DUP,7,PICK,|,1,32,1,<<,-,&,psw,=,4294967293,psw,NUM,&,1,32,1,<<,-,&,0,23,PICK,32,SWAP,~,SWAP,32,SWAP,~,SWAP,<,DUP,1,2,PICK,<<,1,32,1,<<,-,&,DUP,5,PICK,|,1,32,1,<<,-,&,psw,=,4294967294,psw,NUM,&,1,32,1,<<,-,&,0,27,PICK,-,!,DUP,DUP,4,PICK,|,1,32,1,<<,-,&,psw,= 221 | family: cpu 222 | EOF 223 | RUN 224 | 225 | NAME=v850load 226 | FILE=- 227 | CMDS=< 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | class AsmLoadImage : public LoadImage { 18 | private: 19 | RIO *io = nullptr; 20 | 21 | public: 22 | AsmLoadImage(RIO *io): LoadImage("radare2_program"), io(io) {} 23 | virtual void loadFill(uint1 *ptr, int4 size, const Address &addr) { 24 | r_io_read_at (io, addr.getOffset(), ptr, size); 25 | } 26 | virtual string getArchType(void) const { 27 | return "radare2"; 28 | } 29 | virtual void adjustVma(long adjust) { 30 | throw LowlevelError ("Cannot adjust radare2 virtual memory"); 31 | } 32 | }; 33 | 34 | class SleighAsm; 35 | 36 | class AssemblySlg : public AssemblyEmit { 37 | private: 38 | SleighAsm *sasm = nullptr; 39 | public: 40 | char *str = nullptr; 41 | 42 | AssemblySlg(SleighAsm *s): sasm(s) {} 43 | 44 | void dump(const Address &addr, const string &mnem, const string &body) override; 45 | 46 | ~AssemblySlg() { 47 | free (str); 48 | } 49 | }; 50 | 51 | struct PcodeOperand { 52 | PcodeOperand(uintb offset, uint4 size): type(RAM), offset(offset), size(size) {} 53 | PcodeOperand(uintb number): type(CONSTANT), number(number), size(0) {} 54 | PcodeOperand(const std::string &name, uint4 size): type(REGISTER), name(name), size(size) {} 55 | virtual ~PcodeOperand() { 56 | if (type == REGISTER) { 57 | name.~string(); 58 | } 59 | } 60 | 61 | union { 62 | std::string name; 63 | uintb offset; 64 | uintb number; 65 | }; 66 | uint4 size; 67 | 68 | enum { 69 | REGISTER, 70 | RAM, 71 | CONSTANT, 72 | UNIQUE 73 | } type; 74 | 75 | PcodeOperand(const PcodeOperand &rhs) { 76 | type = rhs.type; 77 | size = rhs.size; 78 | 79 | switch (type) { 80 | case REGISTER: name = rhs.name; break; 81 | case UNIQUE: /* Same as RAM */ 82 | case RAM: offset = rhs.offset; break; 83 | case CONSTANT: number = rhs.number; break; 84 | default: throw LowlevelError("Unexpected type of PcodeOperand found in operator==."); 85 | } 86 | } 87 | 88 | bool operator==(const PcodeOperand &rhs) const { 89 | if (type != rhs.type) { 90 | return false; 91 | } 92 | switch (type) { 93 | case REGISTER: return name == rhs.name; 94 | case UNIQUE: /* Same as RAM */ 95 | case RAM: return offset == rhs.offset && size == rhs.size; 96 | case CONSTANT: return number == rhs.number; 97 | default: throw LowlevelError("Unexpected type of PcodeOperand found in operator==."); 98 | } 99 | } 100 | bool is_unique() const { return type == UNIQUE; } 101 | bool is_const() const { return type == CONSTANT; } 102 | bool is_ram() const { return type == RAM; } 103 | bool is_reg() const { return type == REGISTER; } 104 | }; 105 | 106 | ostream &operator<<(ostream &s, const PcodeOperand &arg); 107 | 108 | typedef OpCode PcodeOpType; 109 | 110 | struct Pcodeop { 111 | PcodeOpType type; 112 | 113 | PcodeOperand *output = nullptr; 114 | PcodeOperand *input0 = nullptr; 115 | PcodeOperand *input1 = nullptr; 116 | /* input2 for STORE will use output to save memory space */ 117 | 118 | Pcodeop(PcodeOpType opc, PcodeOperand *in0, PcodeOperand *in1, PcodeOperand *out): 119 | type(opc), input0(in0), input1(in1), output(out) { 120 | } 121 | 122 | void fini() { 123 | if (output) { 124 | delete output; 125 | } 126 | if (input0) { 127 | delete input0; 128 | } 129 | if (input1) { 130 | delete input1; 131 | } 132 | } 133 | }; 134 | 135 | ostream &operator<<(ostream &s, const Pcodeop &op); 136 | 137 | struct UniquePcodeOperand: public PcodeOperand { 138 | const Pcodeop *def = nullptr; 139 | UniquePcodeOperand(const PcodeOperand *from): PcodeOperand(*from) {} 140 | ~UniquePcodeOperand() = default; 141 | }; 142 | 143 | class PcodeSlg : public PcodeEmit { 144 | private: 145 | SleighAsm *sanal = nullptr; 146 | 147 | PcodeOperand *parse_vardata(VarnodeData &data); 148 | 149 | public: 150 | std::vector pcodes; 151 | 152 | PcodeSlg(SleighAsm *s): sanal(s) {} 153 | 154 | void dump(const Address &addr, OpCode opc, VarnodeData *outvar, VarnodeData *vars, int4 isize) override { 155 | PcodeOperand *out = nullptr, *in0 = nullptr, *in1 = nullptr; 156 | 157 | if (opc == CPUI_CALLOTHER) { 158 | isize = isize > 2? 2: isize; 159 | } 160 | switch (isize) { 161 | case 3: out = parse_vardata (vars[2]); // Only for STORE 162 | case 2: in1 = parse_vardata (vars[1]); 163 | case 1: in0 = parse_vardata (vars[0]); 164 | case 0: break; 165 | default: throw LowlevelError ("Unexpexted isize in PcodeSlg::dump()"); 166 | } 167 | 168 | if (outvar) { 169 | out = parse_vardata (*outvar); 170 | } 171 | pcodes.push_back (Pcodeop(opc, in0, in1, out)); 172 | } 173 | 174 | ~PcodeSlg() { 175 | while (!pcodes.empty()) { 176 | pcodes.back().fini(); 177 | pcodes.pop_back(); 178 | } 179 | } 180 | }; 181 | 182 | struct R2Reg { 183 | std::string name; 184 | ut64 size; 185 | ut64 offset; 186 | }; 187 | 188 | class R2Sleigh; 189 | 190 | class SleighAsm { 191 | private: 192 | AsmLoadImage loader; 193 | ContextInternal context; 194 | DocumentStorage docstorage; 195 | FileManage specpaths; 196 | std::vector description; 197 | int languageindex; 198 | 199 | void initInner(RIO *io, std::string sleigh_id); 200 | void initRegMapping(void); 201 | void collectSpecfiles(void); 202 | void scanSleigh(const string &rootpath); 203 | void resolveArch(const string &archid); 204 | void buildSpecfile(DocumentStorage &store); 205 | void parseProcConfig(DocumentStorage &store); 206 | void parseCompConfig(DocumentStorage &store); 207 | void loadLanguageDescription(const string &specfile); 208 | 209 | public: 210 | static std::string getSleighHome(RConfig *cfg); 211 | R2Sleigh trans; 212 | std::string sleigh_id; 213 | int alignment = 1; 214 | int minopsz = 1; 215 | int maxopsz = 1; 216 | std::string pc_name; 217 | std::string sp_name; 218 | std::vector arg_names; // default ABI's function args 219 | std::vector ret_names; // default ABI's function retvals 220 | std::unordered_map reg_group; 221 | // To satisfy radare2's rule: reg name has to be lowercase. 222 | std::unordered_map reg_mapping; 223 | SleighAsm(): loader(nullptr), trans(nullptr, nullptr) {} 224 | void init(const char *cpu, int bits, bool bigendian, RIO *io, RConfig *cfg); 225 | int disassemble(RAnalOp *op, unsigned long long offset); 226 | int genOpcode(PcodeSlg &pcode_slg, Address &addr); 227 | std::vector getRegs(void); 228 | static RConfig *getConfig(RCore *c); 229 | static RConfig *getConfig(RAnal *a); 230 | void check(ut64 offset, const ut8 *buf, int len); 231 | }; 232 | 233 | #endif // R2GHIDRA_SLEIGHASM_H 234 | -------------------------------------------------------------------------------- /subprojects/packagefiles/ghidra-native/patches/Attic/0007-Add-some-Formatting-Options.patch: -------------------------------------------------------------------------------- 1 | From ce0bda47d99042322af318ecb425453279e8c7a4 Mon Sep 17 00:00:00 2001 2 | From: =?UTF-8?q?Florian=20M=C3=A4rkl?= 3 | Date: Thu, 25 Jul 2019 12:31:44 +0200 4 | Subject: [PATCH 07/23] Add some Formatting Options 5 | 6 | --- 7 | .../Decompiler/src/decompile/cpp/printc.cc | 60 +++++++++++++++---- 8 | .../Decompiler/src/decompile/cpp/printc.hh | 7 +++ 9 | 2 files changed, 55 insertions(+), 12 deletions(-) 10 | 11 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 12 | index 79da4cfa3..c7e290fe8 100644 13 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 14 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc 15 | @@ -353,8 +353,9 @@ void PrintC::opFunc(const PcodeOp *op) 16 | string nm = op->getOpcode()->getOperatorName(op); 17 | pushAtom(Atom(nm,optoken,EmitXml::no_color,op)); 18 | if (op->numInput() > 0) { 19 | - for(int4 i=0;inumInput()-1;++i) 20 | - pushOp(&comma,op); 21 | + for(int4 i=0;inumInput()-1;++i) { 22 | + pushOp(&comma,op); 23 | + } 24 | // implied vn's pushed on in reverse order for efficiency 25 | // see PrintLanguage::pushVnImplied 26 | for(int4 i=op->numInput()-1;i>=0;--i) 27 | @@ -1386,6 +1387,10 @@ void PrintC::resetDefaultsPrintC(void) 28 | option_nocasts = false; 29 | option_NULL = false; 30 | option_unplaced = false; 31 | + option_space_after_comma = false; 32 | + option_newline_before_else = true; 33 | + option_newline_before_opening_brace = false; 34 | + option_newline_after_prototype = true; 35 | setCStyleComments(); 36 | } 37 | 38 | @@ -1838,6 +1843,9 @@ void PrintC::emitStructDefinition(const TypeStruct *ct) 39 | iter++; 40 | if (iter != ct->endField()) { 41 | emit->print(","); // Print comma separator 42 | + if (option_space_after_comma) { 43 | + emit->spaces(1); 44 | + } 45 | emit->tagLine(); 46 | } 47 | } 48 | @@ -1935,8 +1943,12 @@ void PrintC::emitPrototypeInputs(const FuncProto *proto) 49 | else { 50 | bool printComma = false; 51 | for(int4 i=0;iprint(","); 54 | + if (printComma) { 55 | + emit->print(","); 56 | + if (option_space_after_comma) { 57 | + emit->spaces(1); 58 | + } 59 | + } 60 | ProtoParameter *param = proto->getParam(i); 61 | if (isSet(hide_thisparam) && param->isThisPointer()) 62 | continue; 63 | @@ -1954,8 +1966,12 @@ void PrintC::emitPrototypeInputs(const FuncProto *proto) 64 | } 65 | } 66 | if (proto->isDotdotdot()) { 67 | - if (sz != 0) 68 | - emit->print(","); 69 | + if (sz != 0) { 70 | + emit->print(","); 71 | + if (option_space_after_comma) { 72 | + emit->spaces(1); 73 | + } 74 | + } 75 | emit->print("..."); 76 | } 77 | } 78 | @@ -2351,7 +2367,9 @@ void PrintC::docFunction(const Funcdata *fd) 79 | emit->tagLine(); 80 | emitFunctionDeclaration(fd); // Causes us to enter function's scope 81 | emit->tagLine(); 82 | - emit->tagLine(); 83 | + if (option_newline_after_prototype) { 84 | + emit->tagLine(); 85 | + } 86 | int4 id = emit->startIndent(); 87 | emit->print("{"); 88 | emitLocalVarDecls(fd); 89 | @@ -2606,7 +2624,11 @@ void PrintC::emitBlockIf(const BlockIf *bl) 90 | } 91 | 92 | setMod(no_branch); 93 | - emit->spaces(1); 94 | + if (!option_newline_before_opening_brace) { 95 | + emit->spaces(1); 96 | + } else { 97 | + emit->tagLine(); 98 | + } 99 | int4 id = emit->startIndent(); 100 | emit->print("{"); 101 | int4 id1 = emit->beginBlock(bl->getBlock(1)); 102 | @@ -2616,9 +2638,15 @@ void PrintC::emitBlockIf(const BlockIf *bl) 103 | emit->tagLine(); 104 | emit->print("}"); 105 | if (bl->getSize()==3) { 106 | - emit->tagLine(); 107 | + if (option_newline_before_else) { 108 | + emit->tagLine(); 109 | + } 110 | emit->print("else",EmitXml::keyword_color); 111 | - emit->spaces(1); 112 | + if (option_newline_before_else) { 113 | + emit->tagLine(); 114 | + } else { 115 | + emit->spaces(1); 116 | + } 117 | int4 id = emit->startIndent(); 118 | emit->print("{"); 119 | int4 id2 = emit->beginBlock(bl->getBlock(2)); 120 | @@ -2769,7 +2797,11 @@ void PrintC::emitBlockDoWhile(const BlockDoWhile *bl) 121 | emitAnyLabelStatement(bl); 122 | emit->tagLine(); 123 | emit->print("do",EmitXml::keyword_color); 124 | - emit->spaces(1); 125 | + if (option_newline_before_opening_brace) { 126 | + emit->tagLine(); 127 | + } else { 128 | + emit->spaces(1); 129 | + } 130 | int4 id = emit->startIndent(); 131 | emit->print("{"); 132 | pushMod(); 133 | @@ -2801,7 +2833,11 @@ void PrintC::emitBlockInfLoop(const BlockInfLoop *bl) 134 | emitAnyLabelStatement(bl); 135 | emit->tagLine(); 136 | emit->print("do",EmitXml::keyword_color); 137 | - emit->spaces(1); 138 | + if (option_newline_before_opening_brace) { 139 | + emit->tagLine(); 140 | + } else { 141 | + emit->spaces(1); 142 | + } 143 | int4 id = emit->startIndent(); 144 | emit->print("{"); 145 | int4 id1 = emit->beginBlock(bl->getBlock(0)); 146 | diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 147 | index 92afe1ee1..f315d7023 100644 148 | --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 149 | +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.hh 150 | @@ -119,6 +119,10 @@ protected: 151 | bool option_nocasts; ///< Don't print a cast if \b true 152 | bool option_unplaced; ///< Set to \b true if we should display unplaced comments 153 | bool option_hide_exts; ///< Set to \b true if we should hide implied extension operations 154 | + bool option_space_after_comma; 155 | + bool option_newline_before_else; 156 | + bool option_newline_before_opening_brace; 157 | + bool option_newline_after_prototype; 158 | string nullToken; ///< Token to use for 'null' 159 | CommentSorter commsorter; ///< Container/organizer for comments in the current function 160 | 161 | @@ -205,6 +209,9 @@ public: 162 | void setCPlusPlusStyleComments(void) { setCommentDelimeter("// ","",true); } ///< Set c++-style "//" comment delimiters 163 | void setDisplayUnplaced(bool val) { option_unplaced = val; } ///< Toggle whether \e unplaced comments are displayed in the header 164 | void setHideImpliedExts(bool val) { option_hide_exts = val; } ///< Toggle whether implied extensions are hidden 165 | + void setSpaceAfterComma(bool val) { option_space_after_comma = val; } 166 | + void setNewlineBeforeOpeningBrace(bool val) { option_newline_before_opening_brace = val; } 167 | + void setNewlineAfterPrototype(bool val) { option_newline_after_prototype = val; } 168 | virtual ~PrintC(void) {} 169 | virtual void resetDefaults(void); 170 | virtual void adjustTypeOperators(void); 171 | -- 172 | 2.24.3 (Apple Git-128) 173 | 174 | -------------------------------------------------------------------------------- /src/SleighAnalValue.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2020-2024 - FXTi, pancake */ 2 | 3 | #include "SleighAnalValue.h" 4 | 5 | RAnalValueType SleighAnalValue::type_from_values(const SleighAnalValue &in0, const SleighAnalValue &in1) { 6 | if (in0.is_mem () || in1.is_mem ()) { 7 | return R_ANAL_VAL_MEM; 8 | } 9 | if (in0.is_reg () || in1.is_reg ()) { 10 | return R_ANAL_VAL_REG; 11 | } 12 | return R_ANAL_VAL_IMM; 13 | } 14 | 15 | SleighAnalValue SleighAnalValue::resolve_arg(RAnal *anal, const PcodeOperand *arg) { 16 | SleighAnalValue res; 17 | res.absolute = true; 18 | 19 | if (arg->is_const ()) { 20 | res.type = R_ANAL_VAL_IMM; 21 | res.imm = arg->number; 22 | } else if (arg->is_reg()) { 23 | res.type = R_ANAL_VAL_REG; 24 | #if R2_VERSION_NUMBER >= 50809 25 | res.reg = arg->name.c_str(); 26 | #else 27 | res.reg = r_reg_get(anal->reg, arg->name.c_str(), R_REG_TYPE_ALL); 28 | #endif 29 | } else if (arg->is_ram()) { 30 | res.type = R_ANAL_VAL_MEM; 31 | res.base = arg->offset; 32 | res.memref = arg->size; 33 | } else { // PcodeOperand::UNIQUE 34 | const Pcodeop *curr_op = ((UniquePcodeOperand *)arg)->def; 35 | SleighAnalValue in0, in1; 36 | 37 | if (curr_op->input0) { 38 | in0 = resolve_arg (anal, curr_op->input0); 39 | if (!in0.is_valid ()) { 40 | return in0; 41 | } 42 | } 43 | if (curr_op->input1) { 44 | in1 = resolve_arg (anal, curr_op->input1); 45 | if (!in1.is_valid ()) { 46 | return in1; 47 | } 48 | } 49 | 50 | switch (curr_op->type) { 51 | case CPUI_INT_ZEXT: 52 | case CPUI_INT_SEXT: 53 | case CPUI_SUBPIECE: 54 | case CPUI_COPY: 55 | res = in0; 56 | break; 57 | case CPUI_LOAD: 58 | res = in1; 59 | if (res.is_imm()) { 60 | res.base = res.imm; 61 | res.imm = 0; 62 | } 63 | res.type = R_ANAL_VAL_MEM; 64 | res.memref = curr_op->output->size; 65 | break; 66 | case CPUI_INT_ADD: 67 | case CPUI_INT_SUB: 68 | res.type = type_from_values(in0, in1); 69 | res.memref = inner_max(in0.memref, in1.memref); 70 | if (res.is_imm()) { 71 | res.imm = (curr_op->type == CPUI_INT_ADD)? in0.imm + in1.imm : in0.imm - in1.imm; 72 | } else { 73 | res.base = in0.imm + in0.base; 74 | if (curr_op->type == CPUI_INT_ADD) { 75 | res.base += (in1.imm + in1.base); 76 | } else { 77 | res.base -= (in1.imm + in1.base); 78 | } 79 | } 80 | res.mul = inner_max(in0.mul, in1.mul); // Only one of inputs should set mul 81 | res.delta = inner_max(in0.delta, in1.delta); 82 | if (in0.reg && in1.reg) { 83 | res.reg = in0.reg; 84 | res.regdelta = in1.reg; 85 | } else { 86 | res.reg = in0.reg? in0.reg: in1.reg; 87 | res.regdelta = in0.regdelta? in0.regdelta: in1.regdelta; 88 | } 89 | break; 90 | case CPUI_INT_MULT: 91 | // 3 cases: 92 | // imm (CONST) * imm (CONST) 93 | // imm (CONST) * base (RAM) 94 | // imm (CONST) * reg (REGISTER) 95 | res.type = type_from_values(in0, in1); 96 | res.memref = inner_max(in0.memref, in1.memref); 97 | if (res.is_imm()) { 98 | res.imm = in0.imm * in1.imm; 99 | } else if (in0.is_imm() && in1.is_mem()) { 100 | res.mul = in0.imm; 101 | res.delta = in1.base; 102 | } else if (in0.is_mem() && in1.is_imm()) { 103 | res.mul = in1.imm; 104 | res.delta = in0.base; 105 | } else if (in0.is_imm() && in1.is_reg()) { 106 | res.mul = in0.imm; 107 | res.regdelta = in1.reg; 108 | } else if (in0.is_reg() && in1.is_imm()) { 109 | res.mul = in1.imm; 110 | res.regdelta = in0.reg; 111 | } else { 112 | res.invalid(); 113 | } 114 | break; 115 | case CPUI_INT_AND: 116 | // Should only happen when const need some modification. 117 | res.type = in0.type; 118 | res.memref = inner_max(in0.memref, in1.memref); 119 | if (in0.is_imm() && in1.is_imm()) { 120 | res.imm = in0.imm & in1.imm; 121 | } else { 122 | res.invalid(); 123 | } 124 | break; 125 | case CPUI_INT_OR: 126 | // Should only happen when const need some modification. 127 | res.type = in0.type; 128 | res.memref = inner_max(in0.memref, in1.memref); 129 | if (in0.is_imm() && in1.is_imm()) { 130 | res.imm = in0.imm | in1.imm; 131 | } else { 132 | res.invalid(); 133 | } 134 | break; 135 | case CPUI_INT_XOR: 136 | // Should only happen when const need some modification. 137 | res.type = in0.type; 138 | res.memref = inner_max(in0.memref, in1.memref); 139 | if (in0.is_imm() && in1.is_imm()) { 140 | res.imm = in0.imm ^ in1.imm; 141 | } else { 142 | res.invalid(); 143 | } 144 | break; 145 | default: 146 | res.invalid (); 147 | break; 148 | } 149 | } 150 | return res; 151 | } 152 | 153 | std::vector SleighAnalValue::resolve_out(RAnal *anal, 154 | std::vector::const_iterator curr_op, 155 | std::vector::const_iterator end_op, 156 | const PcodeOperand *arg) 157 | { 158 | std::vector res; 159 | SleighAnalValue tmp; 160 | tmp.absolute = true; 161 | 162 | if (arg->is_const()) { 163 | tmp.type = R_ANAL_VAL_IMM; 164 | tmp.imm = arg->number; 165 | res.push_back(tmp); 166 | } else if (arg->is_reg()) { 167 | tmp.type = R_ANAL_VAL_REG; 168 | #if R2_VERSION_NUMBER >= 50809 169 | tmp.reg = arg->name.c_str(); 170 | #else 171 | tmp.reg = r_reg_get (anal->reg, arg->name.c_str(), R_REG_TYPE_ALL); 172 | #endif 173 | res.push_back (tmp); 174 | } else if (arg->is_ram()) { 175 | tmp.type = R_ANAL_VAL_MEM; 176 | tmp.base = arg->offset; 177 | tmp.memref = arg->size; 178 | res.push_back (tmp); 179 | } else { 180 | for (auto iter = ++curr_op; iter != end_op; iter++) { 181 | if (iter->type == CPUI_STORE) { 182 | if (iter->output && *iter->output == *arg && iter->input1) { 183 | tmp = resolve_arg (anal, iter->input1); 184 | if (tmp.is_valid ()) { 185 | tmp.mem (iter->output->size); 186 | res.push_back (tmp); 187 | } 188 | } 189 | } else { 190 | if ((iter->input0 && *iter->input0 == *arg) || (iter->input1 && *iter->input1 == *arg)) { 191 | if (iter->output && iter->output->is_reg ()) { 192 | tmp = SleighAnalValue (); 193 | tmp.absolute = true; 194 | tmp.type = R_ANAL_VAL_REG; 195 | #if R2_VERSION_NUMBER >= 50809 196 | // XXX this is leaking, we need to share a constant register 197 | tmp.reg = iter->output->name.c_str(); 198 | #else 199 | tmp.reg = r_reg_get(anal->reg, iter->output->name.c_str(), R_REG_TYPE_ALL); 200 | #endif 201 | res.push_back(tmp); 202 | } 203 | } 204 | } 205 | } 206 | } 207 | return res; 208 | } 209 | 210 | void SleighAnalValue::mem(uint4 size) { 211 | if (is_mem ()) { 212 | return; 213 | } 214 | if (is_imm ()) { 215 | base = imm; 216 | imm = 0; 217 | } 218 | memref = size; 219 | type = R_ANAL_VAL_MEM; 220 | } 221 | 222 | RAnalValue *SleighAnalValue::dup() const { 223 | RAnalValue *to = r_anal_value_new(); 224 | if (to != nullptr) { 225 | *to = (RAnalValue)*this; 226 | } 227 | return to; 228 | } 229 | -------------------------------------------------------------------------------- /COPYING: -------------------------------------------------------------------------------- 1 | GNU LESSER GENERAL PUBLIC LICENSE 2 | Version 3, 29 June 2007 3 | 4 | Copyright (C) 2007 Free Software Foundation, Inc. 5 | Everyone is permitted to copy and distribute verbatim copies 6 | of this license document, but changing it is not allowed. 7 | 8 | 9 | This version of the GNU Lesser General Public License incorporates 10 | the terms and conditions of version 3 of the GNU General Public 11 | License, supplemented by the additional permissions listed below. 12 | 13 | 0. Additional Definitions. 14 | 15 | As used herein, "this License" refers to version 3 of the GNU Lesser 16 | General Public License, and the "GNU GPL" refers to version 3 of the GNU 17 | General Public License. 18 | 19 | "The Library" refers to a covered work governed by this License, 20 | other than an Application or a Combined Work as defined below. 21 | 22 | An "Application" is any work that makes use of an interface provided 23 | by the Library, but which is not otherwise based on the Library. 24 | Defining a subclass of a class defined by the Library is deemed a mode 25 | of using an interface provided by the Library. 26 | 27 | A "Combined Work" is a work produced by combining or linking an 28 | Application with the Library. The particular version of the Library 29 | with which the Combined Work was made is also called the "Linked 30 | Version". 31 | 32 | The "Minimal Corresponding Source" for a Combined Work means the 33 | Corresponding Source for the Combined Work, excluding any source code 34 | for portions of the Combined Work that, considered in isolation, are 35 | based on the Application, and not on the Linked Version. 36 | 37 | The "Corresponding Application Code" for a Combined Work means the 38 | object code and/or source code for the Application, including any data 39 | and utility programs needed for reproducing the Combined Work from the 40 | Application, but excluding the System Libraries of the Combined Work. 41 | 42 | 1. Exception to Section 3 of the GNU GPL. 43 | 44 | You may convey a covered work under sections 3 and 4 of this License 45 | without being bound by section 3 of the GNU GPL. 46 | 47 | 2. Conveying Modified Versions. 48 | 49 | If you modify a copy of the Library, and, in your modifications, a 50 | facility refers to a function or data to be supplied by an Application 51 | that uses the facility (other than as an argument passed when the 52 | facility is invoked), then you may convey a copy of the modified 53 | version: 54 | 55 | a) under this License, provided that you make a good faith effort to 56 | ensure that, in the event an Application does not supply the 57 | function or data, the facility still operates, and performs 58 | whatever part of its purpose remains meaningful, or 59 | 60 | b) under the GNU GPL, with none of the additional permissions of 61 | this License applicable to that copy. 62 | 63 | 3. Object Code Incorporating Material from Library Header Files. 64 | 65 | The object code form of an Application may incorporate material from 66 | a header file that is part of the Library. You may convey such object 67 | code under terms of your choice, provided that, if the incorporated 68 | material is not limited to numerical parameters, data structure 69 | layouts and accessors, or small macros, inline functions and templates 70 | (ten or fewer lines in length), you do both of the following: 71 | 72 | a) Give prominent notice with each copy of the object code that the 73 | Library is used in it and that the Library and its use are 74 | covered by this License. 75 | 76 | b) Accompany the object code with a copy of the GNU GPL and this license 77 | document. 78 | 79 | 4. Combined Works. 80 | 81 | You may convey a Combined Work under terms of your choice that, 82 | taken together, effectively do not restrict modification of the 83 | portions of the Library contained in the Combined Work and reverse 84 | engineering for debugging such modifications, if you also do each of 85 | the following: 86 | 87 | a) Give prominent notice with each copy of the Combined Work that 88 | the Library is used in it and that the Library and its use are 89 | covered by this License. 90 | 91 | b) Accompany the Combined Work with a copy of the GNU GPL and this license 92 | document. 93 | 94 | c) For a Combined Work that displays copyright notices during 95 | execution, include the copyright notice for the Library among 96 | these notices, as well as a reference directing the user to the 97 | copies of the GNU GPL and this license document. 98 | 99 | d) Do one of the following: 100 | 101 | 0) Convey the Minimal Corresponding Source under the terms of this 102 | License, and the Corresponding Application Code in a form 103 | suitable for, and under terms that permit, the user to 104 | recombine or relink the Application with a modified version of 105 | the Linked Version to produce a modified Combined Work, in the 106 | manner specified by section 6 of the GNU GPL for conveying 107 | Corresponding Source. 108 | 109 | 1) Use a suitable shared library mechanism for linking with the 110 | Library. A suitable mechanism is one that (a) uses at run time 111 | a copy of the Library already present on the user's computer 112 | system, and (b) will operate properly with a modified version 113 | of the Library that is interface-compatible with the Linked 114 | Version. 115 | 116 | e) Provide Installation Information, but only if you would otherwise 117 | be required to provide such information under section 6 of the 118 | GNU GPL, and only to the extent that such information is 119 | necessary to install and execute a modified version of the 120 | Combined Work produced by recombining or relinking the 121 | Application with a modified version of the Linked Version. (If 122 | you use option 4d0, the Installation Information must accompany 123 | the Minimal Corresponding Source and Corresponding Application 124 | Code. If you use option 4d1, you must provide the Installation 125 | Information in the manner specified by section 6 of the GNU GPL 126 | for conveying Corresponding Source.) 127 | 128 | 5. Combined Libraries. 129 | 130 | You may place library facilities that are a work based on the 131 | Library side by side in a single library together with other library 132 | facilities that are not Applications and are not covered by this 133 | License, and convey such a combined library under terms of your 134 | choice, if you do both of the following: 135 | 136 | a) Accompany the combined library with a copy of the same work based 137 | on the Library, uncombined with any other library facilities, 138 | conveyed under the terms of this License. 139 | 140 | b) Give prominent notice with the combined library that part of it 141 | is a work based on the Library, and explaining where to find the 142 | accompanying uncombined form of the same work. 143 | 144 | 6. Revised Versions of the GNU Lesser General Public License. 145 | 146 | The Free Software Foundation may publish revised and/or new versions 147 | of the GNU Lesser General Public License from time to time. Such new 148 | versions will be similar in spirit to the present version, but may 149 | differ in detail to address new problems or concerns. 150 | 151 | Each version is given a distinguishing version number. If the 152 | Library as you received it specifies that a certain numbered version 153 | of the GNU Lesser General Public License "or any later version" 154 | applies to it, you have the option of following the terms and 155 | conditions either of that published version or of any later version 156 | published by the Free Software Foundation. If the Library as you 157 | received it does not specify a version number of the GNU Lesser 158 | General Public License, you may choose any version of the GNU Lesser 159 | General Public License ever published by the Free Software Foundation. 160 | 161 | If the Library as you received it specifies that a proxy can decide 162 | whether future versions of the GNU Lesser General Public License shall 163 | apply, that proxy's public statement of acceptance of any version is 164 | permanent authorization for you to choose that version for the 165 | Library. 166 | -------------------------------------------------------------------------------- /src/R2TypeFactory.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2022 - thestr4ng3r, pancake */ 2 | 3 | #include "R2TypeFactory.h" 4 | #include "R2Architecture.h" 5 | 6 | #include 7 | 8 | #define R2G_USE_CTYPE 0 9 | #if R2G_USE_CTYPE 10 | #include 11 | #endif 12 | #include "R2Utils.h" 13 | 14 | R2TypeFactory::R2TypeFactory(R2Architecture *arch) : TypeFactory (arch), arch (arch) { 15 | #if R2G_USE_CTYPE 16 | ctype = r_parse_ctype_new (); 17 | if (!ctype) { 18 | throw LowlevelError ("Failed to create RParseCType"); 19 | } 20 | #endif 21 | } 22 | 23 | R2TypeFactory::~R2TypeFactory() { 24 | // r_parse_ctype_free(ctype); 25 | } 26 | 27 | 28 | std::vector splitSdbArray(const std::string& str) { 29 | std::stringstream ss (str); 30 | std::string token; 31 | std::vector r; 32 | while (std::getline (ss, token, SDB_RS)) { 33 | r.push_back (token); 34 | } 35 | return r; 36 | } 37 | 38 | Datatype *R2TypeFactory::queryR2Struct(const string &n, std::set &stackTypes) { 39 | RCoreLock core(arch->getCore ()); 40 | Sdb *sdb = core->anal->sdb_types; 41 | 42 | // TODO: We REALLY need an API for this in r2 43 | const char *members = sdb_const_get (sdb, ("struct." + n).c_str (), nullptr); 44 | if (!members) { 45 | return nullptr; 46 | } 47 | std::vector fields; 48 | try { 49 | TypeStruct *r = getTypeStruct(n); 50 | std::stringstream membersStream(members); 51 | std::string memberName; 52 | while(std::getline(membersStream, memberName, SDB_RS)) { 53 | const char *memberContents = sdb_const_get(sdb, ("struct." + n + "." + memberName).c_str(), nullptr); 54 | if (!memberContents) { 55 | continue; 56 | } 57 | auto memberTokens = splitSdbArray (memberContents); 58 | if (memberTokens.size() < 3) { 59 | continue; 60 | } 61 | auto memberTypeName = memberTokens[0]; 62 | for (size_t i = 1; i < memberTokens.size () - 2; i++) { 63 | memberTypeName += "," + memberTokens[i]; 64 | } 65 | int4 offset = std::stoi (memberTokens[memberTokens.size () - 2]); 66 | int4 elements = std::stoi (memberTokens[memberTokens.size () - 1]); 67 | Datatype *memberType = fromCString (memberTypeName, nullptr, &stackTypes); 68 | if (!memberType) { 69 | arch->addWarning ("Failed to match type " + memberTypeName + " of member " + memberName + " in struct " + n); 70 | continue; 71 | } 72 | if (elements > 0) { 73 | memberType = getTypeArray (elements, memberType); 74 | } 75 | TypeField tf = { 76 | (int4)offset, // id = offset by default 77 | (int4)offset, // Currently, this is 0 most of the time: member->offset, 78 | memberTypeName, // std::string(member->name), 79 | memberType 80 | }; 81 | fields.push_back(tf); 82 | } 83 | 84 | if (fields.empty ()) { 85 | arch->addWarning ("Struct " + n + " has no fields."); 86 | return nullptr; 87 | } 88 | setFields (fields, r, 0, 0, 0); 89 | return r; 90 | } catch (std::invalid_argument &e) { 91 | arch->addWarning ("Failed to load struct " + n + " from sdb."); 92 | return nullptr; 93 | } 94 | } 95 | 96 | Datatype *R2TypeFactory::queryR2Enum(const string &n) { 97 | RCoreLock core (arch->getCore ()); 98 | RList *members = r_type_get_enum (core->anal->sdb_types, n.c_str ()); 99 | if (!members) { 100 | return nullptr; 101 | } 102 | 103 | std::vector namelist; 104 | std::vector vallist; 105 | std::vector assignlist; 106 | 107 | r_list_foreach_cpp (members, [&](RTypeEnum *member) { 108 | if (!member->name || !member->val) { 109 | return; 110 | } 111 | uintb val = std::stoull (member->val, nullptr, 0); 112 | namelist.push_back (member->name); 113 | vallist.push_back (val); 114 | assignlist.push_back (true); // all enum values from r2 have explicit values 115 | }); 116 | r_list_free (members); 117 | 118 | if (namelist.empty()) { 119 | return nullptr; 120 | } 121 | try { 122 | auto enumType = getTypeEnum(n); 123 | map namemap; 124 | TypeEnum::assignValues(namemap,namelist,vallist,assignlist,enumType); 125 | setEnumValues(namemap, enumType); 126 | return enumType; 127 | } catch (LowlevelError &e) { 128 | arch->addWarning("Failed to load " + n); 129 | return nullptr; 130 | } 131 | } 132 | 133 | Datatype *R2TypeFactory::queryR2Typedef(const string &n, std::set &stackTypes) { 134 | RCoreLock core(arch->getCore()); 135 | Sdb *sdb = core->anal->sdb_types; 136 | const char *target = sdb_const_get (sdb, ("typedef." + n).c_str (), nullptr); 137 | if(!target) { 138 | return nullptr; 139 | } 140 | Datatype *resolved = fromCString (target, nullptr, &stackTypes); 141 | if (!resolved) { 142 | return nullptr; 143 | } 144 | //Datatype *typedefd = resolved->clone (); 145 | Datatype *typedefd = getTypedef (resolved, n, 0, 0); 146 | setName (typedefd, n); // this removes the old name from the nametree 147 | setName (resolved, resolved->getName()); // add the old name back 148 | return typedefd; 149 | //return nullptr; 150 | } 151 | 152 | Datatype *R2TypeFactory::queryR2(const string &n, std::set &stackTypes) { 153 | if (stackTypes.find (n) != stackTypes.end ()) { 154 | arch->addWarning("Recursion detected while creating type " + n); 155 | return nullptr; 156 | } 157 | stackTypes.insert (n); 158 | 159 | RCoreLock core (arch->getCore ()); 160 | int kind = r_type_kind (core->anal->sdb_types, n.c_str ()); 161 | switch (kind) { 162 | case R_TYPE_STRUCT: 163 | return queryR2Struct (n, stackTypes); 164 | case R_TYPE_ENUM: 165 | return queryR2Enum (n); 166 | case R_TYPE_TYPEDEF: 167 | return queryR2Typedef (n, stackTypes); 168 | default: 169 | return nullptr; 170 | } 171 | } 172 | 173 | Datatype *R2TypeFactory::findById(const string &n, uint8 id, int4 sz, std::set &stackTypes) { 174 | // resolve basic types 175 | Datatype *r = TypeFactory::findById (n, id, sz); 176 | if (r == nullptr) { 177 | r = queryR2 (n, stackTypes); 178 | } 179 | return r; 180 | } 181 | 182 | // overriden call 183 | Datatype *R2TypeFactory::findById(const string &n, uint8 id, int4 sz) { 184 | std::set stackTypes; // to detect recursion 185 | return findById (n, id, sz, stackTypes); 186 | } 187 | 188 | Datatype *R2TypeFactory::fromCString(const string &str, string *error, std::set *stackTypes) { 189 | #if R2G_USE_CTYPE 190 | char *error_cstr = nullptr; 191 | RParseCTypeType *type = r_parse_ctype_parse (ctype, str.c_str (), &error_cstr); 192 | if (error) { 193 | *error = error_cstr ? error_cstr : ""; 194 | } 195 | if (type) { 196 | Datatype *r = fromCType (type, error, stackTypes); 197 | r_parse_ctype_type_free (type); 198 | return r; 199 | } 200 | #else 201 | #if 0 202 | Datatype *t = stackTypes ? findByName (str.c_str(), *stackTypes) : findByName (str.c_str ()); 203 | if (t == nullptr) { 204 | return findByName("ulong"); 205 | } 206 | return t; 207 | #endif 208 | #endif 209 | return nullptr; 210 | } 211 | 212 | #if 0 213 | Datatype *R2TypeFactory::fromCType(const RParseCTypeType *ctype, string *error, std::set *stackTypes) 214 | { 215 | switch(ctype->kind) 216 | { 217 | case R_PARSE_CTYPE_TYPE_KIND_IDENTIFIER: 218 | { 219 | if(ctype->identifier.kind == R_PARSE_CTYPE_IDENTIFIER_KIND_UNION) 220 | { 221 | if(error) 222 | *error = "Union types not supported in Decompiler"; 223 | return nullptr; 224 | } 225 | 226 | Datatype *r = stackTypes ? findByName(ctype->identifier.name, *stackTypes) : findByName(ctype->identifier.name); 227 | if(!r) 228 | { 229 | if(error) 230 | *error = "Unknown type identifier " + std::string(ctype->identifier.name); 231 | return nullptr; 232 | } 233 | if(ctype->identifier.kind == R_PARSE_CTYPE_IDENTIFIER_KIND_STRUCT && r->getMetatype() != TYPE_STRUCT) 234 | { 235 | if(error) 236 | *error = "Type identifier " + std::string(ctype->identifier.name) + " is not the name of a struct"; 237 | return nullptr; 238 | } 239 | if(ctype->identifier.kind == R_PARSE_CTYPE_IDENTIFIER_KIND_ENUM && !r->isEnumType()) 240 | { 241 | if(error) 242 | *error = "Type identifier " + std::string(ctype->identifier.name) + " is not the name of an enum"; 243 | return nullptr; 244 | } 245 | return r; 246 | } 247 | case R_PARSE_CTYPE_TYPE_KIND_POINTER: 248 | { 249 | Datatype *sub = fromCType(ctype->pointer.type, error, stackTypes); 250 | if(!sub) 251 | return nullptr; 252 | auto space = arch->getDefaultCodeSpace(); 253 | return this->getTypePointer(space->getAddrSize(), sub, space->getWordSize()); 254 | } 255 | case R_PARSE_CTYPE_TYPE_KIND_ARRAY: 256 | { 257 | Datatype *sub = fromCType(ctype->array.type, error, stackTypes); 258 | if(!sub) 259 | return nullptr; 260 | return this->getTypeArray(ctype->array.count, sub); 261 | } 262 | } 263 | return nullptr; 264 | } 265 | #endif 266 | -------------------------------------------------------------------------------- /src/ArchMap.cpp: -------------------------------------------------------------------------------- 1 | /* r2ghidra - LGPL - Copyright 2019-2023 - thestr4ng3r, pancake */ 2 | 3 | #include "ArchMap.h" 4 | #include 5 | #include "R2Architecture.h" 6 | #include "R2Utils.h" 7 | #include 8 | #include 9 | 10 | using namespace ghidra; 11 | 12 | std::string CompilerFromCore(RCore *core); 13 | 14 | template class BaseMapper { 15 | private: 16 | const std::function func; 17 | public: 18 | BaseMapper(const std::function &func) : func(func) {} 19 | BaseMapper(const T constant) : func([constant](RCore *core) { return constant; }) {} 20 | T Map(RCore *core) const { return func(core); } 21 | }; 22 | 23 | template class Mapper; 24 | template<> class Mapper : public BaseMapper { public: using BaseMapper::BaseMapper; }; 25 | template<> class Mapper : public BaseMapper { public: using BaseMapper::BaseMapper; }; 26 | template<> class Mapper : public BaseMapper { public: using BaseMapper::BaseMapper; }; 27 | 28 | template<> class Mapper : public BaseMapper { 29 | public: 30 | using BaseMapper::BaseMapper; 31 | Mapper(const char *constant) : BaseMapper([constant](RCore *core) { return constant; }) {} 32 | }; 33 | 34 | static const Mapper big_endian_mapper_default = std::function([](RCore *core) { 35 | return core? r_config_get_b (core->config, "cfg.bigendian"): false; 36 | }); 37 | static const Mapper bits_mapper_default = std::function([](RCore *core) { 38 | return core? (ut64)r_config_get_i (core->config, "asm.bits"): R_SYS_BITS; 39 | }); 40 | 41 | class ArchMapper { 42 | private: 43 | const Mapper arch; 44 | const Mapper flavor; 45 | const Mapper big_endian; 46 | const Mapper bits; 47 | 48 | public: 49 | const int minopsz; 50 | const int maxopsz; 51 | public: 52 | ArchMapper ( 53 | const Mapper arch, 54 | const Mapper flavor = "default", 55 | const Mapper bits = bits_mapper_default, 56 | const Mapper big_endian = big_endian_mapper_default, 57 | const int minopsz = 0, 58 | const int maxopsz = 0) 59 | : arch (arch) 60 | , flavor (flavor) 61 | , bits (bits) 62 | , big_endian (big_endian) 63 | , minopsz(minopsz) 64 | , maxopsz(maxopsz) {} 65 | 66 | std::string Map(RCore *core) const { 67 | return arch.Map(core) 68 | + ":" + (big_endian.Map(core) ? "BE" : "LE") 69 | + ":" + to_string(bits.Map(core)) 70 | + ":" + flavor.Map(core) 71 | + ":" + CompilerFromCore(core); 72 | } 73 | }; 74 | 75 | #define BITS (core? r_config_get_i(core->config, "asm.bits"): R_SYS_BITS) 76 | #define CUSTOM_BASEID(lambda) std::function([]lambda) 77 | #define CUSTOM_FLAVOR(lambda) std::function([]lambda) 78 | #define CUSTOM_BITS(lambda) std::function([]lambda) 79 | #define CUSTOM_MINOPSZ(lambda) std::function([]lambda) 80 | #define CUSTOM_MAXOPSZ(lambda) std::function([]lambda) 81 | 82 | // keys = asm.arch values 83 | static const std::map arch_map = { 84 | { "x86", { 85 | "x86", 86 | CUSTOM_FLAVOR((RCore *core) { 87 | return (BITS == 16)? "Real Mode": "default"; 88 | }), bits_mapper_default, false, 1, 16 89 | }}, 90 | { "mips", { "MIPS", "default", 91 | bits_mapper_default, big_endian_mapper_default, 4, 4 92 | }}, 93 | { "dalvik", { "Dalvik", "default", 32, false, 2, 10 }}, 94 | { "tricore", { "tricore", "default", 32, true } }, 95 | { "hexagon", { "hexagon", "default", 32, false } }, 96 | { "wasm", { "wasm", "default", 32 } }, 97 | { "6502", { "6502", "default", 16 } }, 98 | { "65c02", { "65c02", "default", 16 } }, 99 | { "java", { "JVM", "default", bits_mapper_default, true } }, 100 | { "hppa", { "pa-risc" } }, 101 | { "riscv", { "RISCV" } }, 102 | { "toy", { "Toy" } }, 103 | { "ppc", { "PowerPC" } }, 104 | { "8051", { "8051", "default", 16, true }}, 105 | { "6805", { "6805" } }, 106 | { "cr16", { "CR16C" } }, 107 | { "mcs96", { "MCS96", "default", 16 } }, 108 | { "m8c", { "M8C", "default", 16 } }, 109 | { "pic24", { "PIC-24F", "default", 24 } }, 110 | { "z80", { "z80", "default", 8 } }, 111 | { "xtensa", { "Xtensa", "default", 32 } }, 112 | { "sparc", { "sparc" } }, 113 | { "stm8", { "STM8", "default", 16, true } }, 114 | { "sh", { "SuperH4" } }, 115 | { "msp430", { "TI_MSP430" } }, 116 | { "m68k", { 117 | "68000", 118 | CUSTOM_FLAVOR ((RCore *core) { 119 | const char *cpu = r_config_get (core->config, "asm.cpu"); 120 | if (cpu != nullptr) { 121 | if (std::string("68020") == cpu) { 122 | return "MC68020"; 123 | } 124 | if (std::string("68030") == cpu) { 125 | return "MC68030"; 126 | } 127 | if (std::string("68060") == cpu) { 128 | return "Coldfire"; // may not be accurate!! 129 | } 130 | } 131 | return "default"; 132 | }), 133 | 32 } }, 134 | { "tricore", { 135 | "tricore", 136 | CUSTOM_FLAVOR ((RCore *core) { 137 | const char *cpu = r_config_get(core->config, "asm.cpu"); 138 | if (cpu != nullptr) { 139 | if (std::string("tc29x") == cpu || std::string("tc172x") == cpu || std::string("tc176x") == cpu) { 140 | return cpu; 141 | } 142 | } 143 | return "default"; 144 | }), 145 | 32 } }, 146 | { "arm", { 147 | CUSTOM_BASEID ((RCore *core) { 148 | return BITS == 64 ? "AARCH64" : "ARM"; 149 | }), 150 | CUSTOM_FLAVOR ((RCore *core) { 151 | return BITS == 64 ? "v8A" : "v7"; 152 | }), 153 | CUSTOM_BITS ((RCore *core) { 154 | return BITS == 64 ? 64 : 32; 155 | }), 156 | big_endian_mapper_default, 2, 4 157 | }}, 158 | { "avr", { 159 | CUSTOM_BASEID ((RCore *core) { 160 | return BITS == 32 ? "avr32a" : "avr8"; 161 | }), 162 | "default", 163 | CUSTOM_BITS ((RCore *core) { 164 | return BITS == 32 ? 32 : 16; 165 | })}}, 166 | 167 | { "v850", { 168 | CUSTOM_BASEID ((RCore *core) { 169 | return "V850"; 170 | }), 171 | "default", 172 | CUSTOM_BITS((RCore *core) { 173 | return 32; 174 | }), 175 | false, 176 | 2, 6 177 | }}, 178 | { "bpf", { "BPF", "default", 32, false } }, 179 | { "ebpf", { "eBPF", "default", 32, false } }, 180 | { "sbpf", { "sBPF", "default", 64, false } } 181 | }; 182 | 183 | static const std::map compiler_map = { 184 | { "elf", "gcc" }, 185 | { "pe", "windows" }, 186 | { "mach0", "clang" } 187 | }; 188 | 189 | std::string CompilerFromCore(RCore *core) { 190 | if (core == nullptr) { 191 | return "gcc"; 192 | } 193 | RBinInfo *info = r_bin_get_info (core->bin); 194 | if (!info || !info->rclass) { 195 | return std::string (); 196 | } 197 | auto comp_it = compiler_map.find (info->rclass); 198 | if (comp_it == compiler_map.end ()) { 199 | return std::string (); 200 | } 201 | 202 | return comp_it->second; 203 | } 204 | 205 | std::string SleighIdFromCore(RCore *core) { 206 | if (!core) { 207 | return "gcc"; 208 | } 209 | #if 1 210 | R2Architecture::collectSpecFiles (std::cerr); 211 | auto langs = R2Architecture::getLanguageDescriptions (); 212 | #else 213 | SleighArchitecture::collectSpecFiles (std::cerr); 214 | auto langs = SleighArchitecture::getLanguageDescriptions (); 215 | #endif 216 | if (langs.empty ()) { 217 | R_LOG_ERROR ("No languages available, make sure r2ghidra.sleighhome is set properly"); 218 | return "gcc"; 219 | } 220 | const char *arch = r_config_get (core->config, "asm.arch"); 221 | if (!strcmp (arch, "r2ghidra")) { 222 | #if R2_VERSION_NUMBER >= 50609 223 | RArchConfig *ac = core->rasm->config; 224 | return SleighIdFromSleighAsmConfig (core, ac->cpu, ac->bits, ac->big_endian, langs); 225 | #else 226 | return SleighIdFromSleighAsmConfig (core, core->rasm->cpu, core->rasm->bits, core->rasm->big_endian, langs); 227 | #endif 228 | } 229 | auto arch_it = arch_map.find (arch); 230 | if (arch_it == arch_map.end ()) { 231 | throw LowlevelError ("Could not match asm.arch " + std::string(arch) + " to sleigh arch."); 232 | } 233 | return arch_it->second.Map (core); 234 | } 235 | 236 | int ai(RCore *core, std::string cpu, int query) { 237 | size_t pos = cpu.find(":"); 238 | std::string cpuname = tolower ((pos != string::npos)? cpu.substr(0, pos): cpu); 239 | auto arch_it = arch_map.find(cpuname); 240 | if (arch_it == arch_map.end()) { 241 | return 1; // throw LowlevelError("Could not match asm.arch " + std::string(arch) + " to sleigh arch."); 242 | } 243 | const ArchMapper *am = &arch_it->second; 244 | // auto res = arch_it->second.Map(core); 245 | switch (query) { 246 | #if R2_VERSION_NUMBER >= 50909 247 | case R_ARCH_INFO_MINOP_SIZE: 248 | return am->minopsz; 249 | case R_ARCH_INFO_MAXOP_SIZE: 250 | return am->maxopsz; 251 | #else 252 | case R_ARCH_INFO_MIN_OP_SIZE: 253 | return am->minopsz; 254 | case R_ARCH_INFO_MAX_OP_SIZE: 255 | return am->maxopsz; 256 | #endif 257 | // case R_ANAL_ARCHINFO_ALIGN: return am->align; // proc.align; 258 | } 259 | return 1; 260 | } 261 | 262 | std::string SleighIdFromSleighAsmConfig(RCore *core, const char *cpu, int bits, bool bigendian, const vector &langs) { 263 | const char *colon = strchr (cpu, ':'); 264 | if (colon != nullptr && colon[1] != '\0') { 265 | // complete id specified 266 | return cpu; 267 | } 268 | auto arch_it = arch_map.find(cpu); 269 | if (arch_it != arch_map.end()) { 270 | return arch_it->second.Map (core); 271 | } 272 | const ArchMapper *am = &arch_it->second; 273 | // short form if possible 274 | std::string low_cpu = tolower (cpu); 275 | for (const auto &lang : langs) { 276 | auto proc = lang.getProcessor(); 277 | if (tolower (proc) == low_cpu) { 278 | return proc 279 | + ":" + (bigendian ? "BE" : "LE") 280 | + ":" + to_string (bits) 281 | + ":" + "default"; 282 | } 283 | } 284 | return cpu; 285 | } 286 | --------------------------------------------------------------------------------