diff --git a/autogen.sh b/autogen.sh index 02f1f039..16f91b97 100755 --- a/autogen.sh +++ b/autogen.sh @@ -19,7 +19,7 @@ if [ $? = 0 ]; then fi else echo "Running acr..." - acr -p + acr -p || exit 1 fi V=`./configure -qV | cut -d - -f -1` meson rewrite kwargs set project / version "$V" diff --git a/config.h.acr b/config.h.acr index fbcfc62d..6afc0b17 100644 --- a/config.h.acr +++ b/config.h.acr @@ -2,5 +2,6 @@ #define R2GHIDRA_CONFIG_H 1 #define R2GHIDRA_VERSION "@R2GHIDRA_VERSION@" +#define R2GHIDRA_USE_RXML @USE_RXML@ #endif diff --git a/config.mk.acr b/config.mk.acr index 5f408baa..b709bcac 100644 --- a/config.mk.acr +++ b/config.mk.acr @@ -13,5 +13,7 @@ R2_CFLAGS=@R2_CFLAGS@ R2_LDFLAGS=@R2_LDFLAGS@ VERSION=@VERSION@ +R2GHIDRA_USE_RXML=@USE_RXML@ + R2_USER_PLUGINS=@R2_USER_PLUGINS@ R2_LIBR_PLUGINS=@R2_LIBR_PLUGINS@ diff --git a/configure b/configure index 27711dae..9a5e4470 100755 --- a/configure +++ b/configure @@ -18,6 +18,7 @@ control_c() { exit 1 } trap control_c 2 +USE_RXML=0 split_host() { S="$" while : ; do @@ -173,6 +174,10 @@ System types: --target=TARGET configure for building compilers for TARGET [HOST] EOF2 +printf " +Optional Features: + --with-rxml use r2 apis instead of pugixml +" printf " Some influential environment variables: CXX C++ compiler command @@ -240,6 +245,7 @@ echo "AUTHOR: pancake" echo "EMAIL: pancake@nopcode.org" echo "LANGS: c++" echo "PKGCONFIG: r_core r_asm r_anal" +echo "FLAGS: --with-rxml" exit 0 ;; --cache-file) @@ -291,6 +297,7 @@ echo "PKGCONFIG: r_core r_asm r_anal" --mandir) MANDIR="$value"; ;; +"--with-rxml") USE_RXML="1"; ;; *) if [ "$value" ]; then eval "`echo $flag2=$value`" ; else echo ; echo "WARNING: Unknown flag '$flag'." >&2 ; echo ; fi ;; esac @@ -308,7 +315,7 @@ parse_options "$1" shift done -ENVWORDS="MANDIR DESCRIPTION INFODIR LIBDIR INCLUDEDIR LOCALSTATEDIR ETCDIR SYSCONFDIR DATADIR DOCDIR LIBEXECDIR SBINDIR BINDIR EPREFIX PREFIX SPREFIX TARGET HOST BUILD INSTALL INSTALL_LIB INSTALL_MAN INSTALL_PROGRAM INSTALL_PROGRAM_STRIP INSTALL_DIR INSTALL_SCRIPT INSTALL_DATA HOST_OS HOST_CPU BUILD_OS BUILD_CPU TARGET_OS TARGET_CPU VERSION VERSION_MAJOR VERSION_MINOR VERSION_PATCH VERSION_NUMBER PKGCFG_LIBDIR PKGCFG_INCDIR PKGNAME VPATH CONTACT CONTACT_NAME CONTACT_MAIL CXX CXXFLAGS LDFLAGS HAVE_LANG_CXX CPP HAVE_GIT GIT PKGCONFIG R2_CFLAGS R2_LDFLAGS HAVE_PKGCFG_R_CORE R2ASM_CFLAGS R2ASM_LDFLAGS HAVE_PKGCFG_R_ASM R2ANAL_CFLAGS R2ANAL_LDFLAGS HAVE_PKGCFG_R_ANAL HAVE_R2 R2 R2_PREFIX R2_USER_PLUGINS R2_LIBR_PLUGINS R2GHIDRA_VERSION" +ENVWORDS="MANDIR DESCRIPTION INFODIR LIBDIR INCLUDEDIR LOCALSTATEDIR ETCDIR SYSCONFDIR DATADIR DOCDIR LIBEXECDIR SBINDIR BINDIR EPREFIX PREFIX SPREFIX TARGET HOST BUILD INSTALL INSTALL_LIB INSTALL_MAN INSTALL_PROGRAM INSTALL_PROGRAM_STRIP INSTALL_DIR INSTALL_SCRIPT INSTALL_DATA HOST_OS HOST_CPU BUILD_OS BUILD_CPU TARGET_OS TARGET_CPU VERSION VERSION_MAJOR VERSION_MINOR VERSION_PATCH VERSION_NUMBER PKGCFG_LIBDIR PKGCFG_INCDIR PKGNAME VPATH CONTACT CONTACT_NAME CONTACT_MAIL CXX CXXFLAGS LDFLAGS HAVE_LANG_CXX CPP HAVE_GIT GIT PKGCONFIG R2_CFLAGS R2_LDFLAGS HAVE_PKGCFG_R_CORE R2ASM_CFLAGS R2ASM_LDFLAGS HAVE_PKGCFG_R_ASM R2ANAL_CFLAGS R2ANAL_LDFLAGS HAVE_PKGCFG_R_ANAL HAVE_R2 R2 USE_RXML R2_PREFIX R2_USER_PLUGINS R2_LIBR_PLUGINS R2GHIDRA_VERSION" create_environ @@ -559,7 +566,7 @@ do_remove if [ "$QUIET" = 0 ]; then echo echo "Final report:" -for A in VERSION R2_PREFIX PREFIX PKGCONFIG ; do +for A in USE_RXML VERSION R2_PREFIX PREFIX PKGCONFIG ; do eval VAL="\$${A}" [ -z "${VAL}" ] && VAL="\"\"" echo " - ${A} = ${VAL}" diff --git a/configure.acr b/configure.acr index 62b3d346..72c0adec 100644 --- a/configure.acr +++ b/configure.acr @@ -15,6 +15,8 @@ CHKPRG BISON bison CHKPRG FLEX flex )) +ARG_WITH USE_RXML rxml use r2 apis instead of pugixml ; + EXEC! R2_PREFIX r2 -H R2_PREFIX ; EXEC! R2_USER_PLUGINS r2 -H R2_USER_PLUGINS ; EXEC! R2_LIBR_PLUGINS r2 -H R2_LIBR_PLUGINS ; @@ -23,4 +25,4 @@ R2GHIDRA_VERSION = $VERSION ; SUBDIRS config.mk config.h Makefile ; -REPORT VERSION R2_PREFIX PREFIX PKGCONFIG ; +REPORT USE_RXML VERSION R2_PREFIX PREFIX PKGCONFIG ; diff --git a/meson.build b/meson.build index a0982b5a..4cb02e61 100644 --- a/meson.build +++ b/meson.build @@ -3,7 +3,7 @@ project( ['c', 'cpp'], license : 'LGPL3', meson_version : '>=0.50.1', - version : '6.1.4', +version : '6.1.4', default_options : ['c_std=c11', 'cpp_std=c++20'] ) @@ -101,7 +101,15 @@ ghidra_incs = ghidra.get_variable('incs') libdecomp_static = ghidra.get_variable('libdecomp_static') slgh_static = ghidra.get_variable('slgh_static') -pugixml = subproject('pugixml').get_variable('pugixml_dep') +r2ghidra_deps = [r_core, zlib] +r2ghidra_cpp_args = [] +if get_option('rxml') + r2ghidra_cpp_args += ['-DR2GHIDRA_USE_RXML=1'] +else + pugixml = subproject('pugixml').get_variable('pugixml_dep') + r2ghidra_deps += pugixml + r2ghidra_cpp_args += ['-DR2GHIDRA_USE_RXML=0'] +endif r2ghidra_core_sources = [ r2ghidra_sources, @@ -121,7 +129,8 @@ sleighc_sources = [ r2ghidra_core_plugin = shared_library('core_r2ghidra', r2ghidra_core_sources, link_with: libdecomp_static, - dependencies: [r_core, zlib, pugixml], + dependencies: r2ghidra_deps, + cpp_args: r2ghidra_cpp_args, override_options : ['c_std=c11', 'cpp_std=c++20'], include_directories: [ghidra_incs, r2ghidra_incdirs], install: true, diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 00000000..2ce3c9c7 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1 @@ +option('rxml', type: 'boolean', value: true, description: 'Use radare2 rxml APIs instead of pugixml') diff --git a/src/CodeXMLParse.cpp b/src/CodeXMLParse.cpp index 3084bd2e..b0b41973 100644 --- a/src/CodeXMLParse.cpp +++ b/src/CodeXMLParse.cpp @@ -7,12 +7,15 @@ #endif #define TEST_UNKNOWN_NODES 0 -#define USE_RXML 0 /* only for r2-5.8 */ + +#ifndef R2GHIDRA_USE_RXML +#define R2GHIDRA_USE_RXML 1 +#endif #include #include -#if USE_RXML -#include +#if R2GHIDRA_USE_RXML +#include "r_util/r_xml.h" #else #include #endif @@ -46,6 +49,142 @@ struct ParseCodeXMLContext { } }; +#if R2GHIDRA_USE_RXML +#define ANNOTATOR_RXML_PARAMS RXmlNode *node, ParseCodeXMLContext *ctx, std::vector *out +#define ANNOTATOR_RXML [](ANNOTATOR_RXML_PARAMS) -> void + +void AnnotateOprefRxml(ANNOTATOR_RXML_PARAMS) { + const char *opref_str = rxml_dom_get_attribute(node, "opref"); + if (!opref_str) { + return; + } + ut64 opref = r_num_get(NULL, opref_str); + if (opref == UT64_MAX) { + return; + } + auto opit = ctx->ops.find((uintm)opref); + if (opit == ctx->ops.end()) { + return; + } + auto op = opit->second; + + out->emplace_back(); + auto &annotation = out->back(); + annotation = {}; + annotation.type = R_CODEMETA_TYPE_OFFSET; + annotation.offset.offset = op->getAddr().getOffset(); +} + +void AnnotateFunctionNameRxml(ANNOTATOR_RXML_PARAMS) { + const char *func_name = rxml_dom_child_value(node); + if (!func_name) { + return; + } + RCodeMetaItem annotation = {}; + annotation.type = R_CODEMETA_TYPE_FUNCTION_NAME; + const char *opref_str = rxml_dom_get_attribute(node, "opref"); + if (!opref_str) { + if (ctx->func->getName() == func_name) { + annotation.reference.name = strdup(ctx->func->getName().c_str()); + annotation.reference.offset = ctx->func->getAddress().getOffset(); + out->push_back(annotation); + // Code below makes an offset annotation for the function name(for the currently decompiled function) + RCodeMetaItem offsetAnnotation = {}; + offsetAnnotation.type = R_CODEMETA_TYPE_OFFSET; + offsetAnnotation.offset.offset = annotation.reference.offset; + out->push_back(offsetAnnotation); + } + return; + } + ut64 opref = r_num_get(NULL, opref_str); + if (opref == UT64_MAX) { + return; + } + auto opit = ctx->ops.find((uintm)opref); + if (opit == ctx->ops.end()) { + return; + } + PcodeOp *op = opit->second; + FuncCallSpecs *call_func_spec = ctx->func->getCallSpecs(op); + if (call_func_spec) { + annotation.reference.name = strdup(call_func_spec->getName().c_str()); + annotation.reference.offset = call_func_spec->getEntryAddress().getOffset(); + out->push_back(annotation); + } +} + +void AnnotateCommentOffsetRxml(ANNOTATOR_RXML_PARAMS) { + const char *off_str = rxml_dom_get_attribute(node, "off"); + if (!off_str) { + return; + } + ut64 off = r_num_get(NULL, off_str); + if (off == UT64_MAX) { + return; + } + out->emplace_back(); + auto &annotation = out->back(); + annotation = {}; + annotation.type = R_CODEMETA_TYPE_OFFSET; + annotation.offset.offset = off; +} + +void AnnotateColorRxml(ANNOTATOR_RXML_PARAMS); +void AnnotateVariableRxml(ANNOTATOR_RXML_PARAMS); + +static const std::map> annotators_rxml = { + { "statement", { AnnotateOprefRxml } }, + { "op", { AnnotateOprefRxml, AnnotateColorRxml } }, + { "comment", { AnnotateCommentOffsetRxml, AnnotateColorRxml } }, + { "variable", { AnnotateVariableRxml, AnnotateColorRxml } }, + { "funcname", { AnnotateFunctionNameRxml, AnnotateColorRxml } }, + { "type", { AnnotateColorRxml } }, + { "syntax", { AnnotateColorRxml } } +}; + +static void ParseNodeRxml(RXmlNode *node, ParseCodeXMLContext *ctx, std::ostream &stream, RCodeMeta *code) { + if (rxml_dom_is_text(node)) { + char* cleaned = strdup(node->text ? node->text : ""); + if (strlen(cleaned) > 1) { + r_str_trim(cleaned); + } + stream << cleaned; + R_FREE(cleaned); + return; + } + + std::vector annotations; + + const char *name = rxml_dom_name(node); + if (name && !strcmp(name, "break")) { + stream << "\n"; + int indent = rxml_dom_attr_int(node, "indent", 0); + stream << std::string(indent, ' '); + } else if (name) { + auto it = annotators_rxml.find(name); + if (it != annotators_rxml.end()) { + auto &callbacks = it->second; + for (auto &callback : callbacks) { + callback(node, ctx, &annotations); + } + for (auto &annotation : annotations) { + annotation.start = stream.tellp(); + } + } + } + + for (RXmlNode *child = rxml_dom_first_child(node); child; child = rxml_dom_next_sibling(child)) { + ParseNodeRxml(child, ctx, stream, code); + } + + for (auto &annotation : annotations) { + annotation.end = stream.tellp(); + RCodeMetaItem *item = r_codemeta_item_clone(&annotation); + r_codemeta_add_item(code, item); + } +} + +#else #define ANNOTATOR_PARAMS pugi::xml_node node, ParseCodeXMLContext *ctx, std::vector *out #define ANNOTATOR [](ANNOTATOR_PARAMS) -> void @@ -124,17 +263,23 @@ void AnnotateCommentOffset(ANNOTATOR_PARAMS) { annotation.type = R_CODEMETA_TYPE_OFFSET; annotation.offset.offset = off; } +#endif /** * Translate Ghidra's color annotations, which are essentially * loose token classes of the high level decompiled source code. **/ +#if R2GHIDRA_USE_RXML +void AnnotateColorRxml(ANNOTATOR_RXML_PARAMS) { + int color = rxml_dom_attr_int(node, "color", -1); +#else void AnnotateColor(ANNOTATOR_PARAMS) { pugi::xml_attribute attr = node.attribute("color"); if (attr.empty ()) { return; } int color = attr.as_int(-1); +#endif if (color < 0) { return; } @@ -169,32 +314,9 @@ void AnnotateColor(ANNOTATOR_PARAMS) { case Emit::syntax_highlight::error_color: case Emit::syntax_highlight::special_color: #endif - default: +default: return; } -#if 0 - std::string color = attr.as_string(); - RSyntaxHighlightType type; - if (color == "keyword") { - type = R_SYNTAX_HIGHLIGHT_TYPE_KEYWORD; - } else if (color == "comment") { - type = R_SYNTAX_HIGHLIGHT_TYPE_COMMENT; - } else if (color == "type") { - type = R_SYNTAX_HIGHLIGHT_TYPE_DATATYPE; - } else if (color == "funcname") { - type = R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME; - } else if (color == "param") { - type = R_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER; - } else if (color == "var") { - type = R_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE; - } else if (color == "const") { - type = R_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE; - } else if (color == "global") { - type = R_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE; - } else { - return; - } -#endif RCodeMetaItem annotation = {}; annotation.type = R_CODEMETA_TYPE_SYNTAX_HIGHLIGHT; annotation.syntax_highlight.type = type; @@ -228,6 +350,24 @@ void AnnotateLocalVariable(Symbol *symbol, std::vector *out) { out->push_back (annotation); } +#if R2GHIDRA_USE_RXML +void AnnotateVariableRxml(ANNOTATOR_RXML_PARAMS) { + const char* varref_str = rxml_dom_get_attribute(node, "varref"); + if (!varref_str) { + RXmlNode* parent = rxml_dom_parent(node); + const char *parent_name = rxml_dom_name(parent); + if (parent_name && !strcmp(parent_name, "vardecl")) { + const char* symref_str = rxml_dom_get_attribute(parent, "symref"); + if (symref_str) { + ut64 symref = r_num_get(NULL, symref_str); + Symbol *symbol = ctx->symbols[symref]; + AnnotateLocalVariable (symbol, out); + } + } + return; + } + ut64 varref = r_num_get(NULL, varref_str); +#else void AnnotateVariable(ANNOTATOR_PARAMS) { pugi::xml_attribute attr = node.attribute ("varref"); if (attr.empty ()) { @@ -241,6 +381,7 @@ void AnnotateVariable(ANNOTATOR_PARAMS) { return; } ut64 varref = attr.as_ullong(UT64_MAX); +#endif if (varref == UT64_MAX) { return; } @@ -264,6 +405,7 @@ void AnnotateVariable(ANNOTATOR_PARAMS) { } } +#if !R2GHIDRA_USE_RXML static const std::map > annotators = { { "statement", { AnnotateOpref } }, { "op", { AnnotateOpref, AnnotateColor } }, @@ -345,19 +487,35 @@ static void ParseNode(pugi::xml_node node, ParseCodeXMLContext *ctx, std::ostrea } #endif } +#endif R_API RCodeMeta *ParseCodeXML(ghidra::Funcdata *func, const char *xml) { +#if R2GHIDRA_USE_RXML + RXmlNode *doc = rxml_dom_parse(xml); + if (!doc) { + return nullptr; + } +#else pugi::xml_document doc; if(!doc.load_string (xml, pugi::parse_default | pugi::parse_ws_pcdata)) { return nullptr; } +#endif std::stringstream ss; RCodeMeta *code = r_codemeta_new(""); if (!code) { +#if R2GHIDRA_USE_RXML + rxml_dom_free(doc); +#endif return nullptr; } ParseCodeXMLContext ctx (func); +#if R2GHIDRA_USE_RXML + ParseNodeRxml (rxml_dom_first_child(doc), &ctx, ss, code); + rxml_dom_free(doc); +#else ParseNode (doc.child ("function"), &ctx, ss, code); +#endif std::string str = ss.str (); code->code = strdup (str.c_str ()); return code; diff --git a/src/Makefile b/src/Makefile index dcd505eb..e0d78b84 100644 --- a/src/Makefile +++ b/src/Makefile @@ -25,6 +25,10 @@ R2GHIDRA_SRCS+=SleighInstruction.cpp R2G_PLUG_SRCS= anal_ghidra.cpp core_ghidra.cpp R2G_PLUG_SRCS+= anal_ghidra_plugin.o core_ghidra_plugin.o +#R2GHIDRA_USE_RXML?=1 +CXXFLAGS+=-DR2GHIDRA_USE_RXML=$(R2GHIDRA_USE_RXML) + +ifeq ($(R2GHIDRA_USE_RXML),0) PUGIXML_HOME=../subprojects/pugixml/src/ PUGIXML_CFLAGS=-I$(PUGIXML_HOME) PUGIXML_SRCS= $(PUGIXML_HOME)/pugixml.cpp @@ -35,6 +39,7 @@ $(PUGIXML_OBJS): $(PUGIXML_SRCS) $(CXX) -c $(R2_LDFLAGS) $(CXXFLAGS) -o $@ $< CXXFLAGS+=$(PUGIXML_CFLAGS) +endif # CXXFLAGS+=-DR2GHIDRA_SLEIGHHOME_DEFAULT=\"$(GHIDRA_HOME)\" R2GHIDRA_OBJS=$(subst .cpp,.o,$(R2GHIDRA_SRCS)) @@ -75,7 +80,7 @@ endif subprojects-zlib: ../subprojects/zlib/libz.a clean: - rm -f *.o $(PUGIXML_HOME)/*.o + rm -f *.o $(PUGIXML_OBJS) rm -f *.o $(GHIDRA_DECOMPILER)/*.o rm -f $(R2G_CORE_PLUGIN) $(R2G_ASM_PLUGIN) $(R2G_ANAL_PLUGIN) sleighc