diff --git a/.builds/freebsd.yml b/.builds/freebsd.yml index 6a51ceff..823875d2 100644 --- a/.builds/freebsd.yml +++ b/.builds/freebsd.yml @@ -16,6 +16,7 @@ sources: - https://github.com/rizinorg/rizin#stable - https://github.com/rizinorg/rz-ghidra - https://github.com/rizinorg/rizin-testbins +hottub_trigger: '.*' tasks: - rizinbuild: | cd rizin diff --git a/.builds/openbsd.yml b/.builds/openbsd.yml index 8366634c..842625b4 100644 --- a/.builds/openbsd.yml +++ b/.builds/openbsd.yml @@ -14,6 +14,7 @@ sources: - https://github.com/rizinorg/rizin#stable - https://github.com/rizinorg/rz-ghidra - https://github.com/rizinorg/rizin-testbins +hottub_trigger: '.*' tasks: - rizinbuild: | cd rizin diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a4d21d22..5ae7b3bd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -28,7 +28,7 @@ jobs: name: ${{ matrix.name }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Checkout submodules run: | git submodule init @@ -40,10 +40,10 @@ jobs: windows: runs-on: windows-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: submodules: recursive - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v4 - name: Preparing msvc toolchain uses: ilammy/msvc-dev-cmd@v1 with: @@ -52,14 +52,14 @@ jobs: run: | python -m pip install --upgrade pip pip install meson ninja PyYAML - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: repository: rizinorg/rizin path: rizin ref: stable - name: Extract rizin version shell: pwsh - run: echo "##[set-output name=branch;]$( python sys\\version.py )" + run: echo "branch=$(python sys/version.py)" >> $Env:GITHUB_OUTPUT id: extract_version working-directory: rizin - name: Build with meson + ninja diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 1efb1557..b18c662b 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -11,7 +11,7 @@ on: jobs: analyze: name: Analyze - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: # We must fetch at least the immediate parents so that if this is # a pull request then we can checkout the head. @@ -30,14 +30,14 @@ jobs: git submodule init git submodule update - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 with: - python-version: 3.8.x + python-version: 3.10.x - name: apt dependencies run: | sudo apt-get --assume-yes update - sudo apt-get --assume-yes install ninja-build libgraphviz-dev bison flex qt5-default + sudo apt-get --assume-yes install ninja-build libgraphviz-dev bison flex qtbase5-dev cmake - name: py dependencies run: | @@ -53,7 +53,7 @@ jobs: # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL - uses: github/codeql-action/init@v1 + uses: github/codeql-action/init@v2 with: languages: ${{ matrix.language }} @@ -64,4 +64,4 @@ jobs: make - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v1 + uses: github/codeql-action/analyze@v2 diff --git a/.github/workflows/coverity-scan.yml b/.github/workflows/coverity-scan.yml index abe1eeb3..baae3c4c 100644 --- a/.github/workflows/coverity-scan.yml +++ b/.github/workflows/coverity-scan.yml @@ -5,14 +5,14 @@ on: jobs: latest: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 with: submodules: true - - uses: actions/setup-python@v1 + - uses: actions/setup-python@v4 with: - python-version: 3.7.x + python-version: 3.10.x - name: Download Coverity Build Tool run: | @@ -28,7 +28,7 @@ jobs: sudo chmod -R go-w /usr/share - name: apt dependencies - run: sudo apt-get install ninja-build libgraphviz-dev bison flex qt5-default + run: sudo apt-get install ninja-build libgraphviz-dev bison flex qtbase5-dev qt5-qmake cmake - name: py dependencies run: | diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index a4c934cf..8be00b39 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -9,7 +9,7 @@ jobs: if: startsWith(github.ref, 'refs/tags/deploy-test-') || startsWith(github.ref, 'refs/tags/v') runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Checkout submodules run: | git submodule init @@ -35,10 +35,10 @@ jobs: tarball ] steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Extract version id: extract_version - run: echo ::set-output name=version::${GITHUB_REF/refs\/tags\//} + run: echo "version=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT - name: Create Release id: create_release uses: actions/create-release@v1 @@ -49,7 +49,7 @@ jobs: release_name: Release ${{ steps.extract_version.outputs.version }} draft: true prerelease: false - - uses: actions/download-artifact@v2 + - uses: actions/download-artifact@v3 - name: Display structure of downloaded files run: ls -R - name: Upload rz-ghidra src tarball diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index da2702a4..72766e20 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -6,9 +6,9 @@ on: jobs: licenses: - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: REUSE Compliance Check - uses: fsfe/reuse-action@v1.1 + uses: fsfe/reuse-action@v1 diff --git a/.travis.yml b/.travis.yml index 733c1b0b..4aa719be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,24 +10,19 @@ jobs: include: - os: linux name: X86_64 - dist: focal + dist: jammy - os: linux name: S390X arch: s390x - dist: focal + dist: jammy - os: linux name: PPC64 arch: ppc64le - dist: focal + dist: jammy - os: linux name: ARM64 arch: arm64 - dist: focal - allow_failures: - - os: linux - name: S390X - arch: s390x - dist: focal + dist: jammy addons: apt: diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b9d154a..fa6558fa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,7 +55,10 @@ set(CORE_SOURCE src/RizinPrintC.cpp src/RzCoreMutex.h src/RzCoreMutex.cpp - src/rz_ghidra.h) + src/PrettyXmlEncode.h + src/PrettyXmlEncode.cpp + src/rz_ghidra.h + src/rz_ghidra_internal.h) if(BUILD_SLEIGH_PLUGIN) set(ASM_SOURCE diff --git a/ghidra/CMakeLists.txt b/ghidra/CMakeLists.txt index a24cd57f..eef7a2a1 100644 --- a/ghidra/CMakeLists.txt +++ b/ghidra/CMakeLists.txt @@ -5,6 +5,7 @@ # Base of everything set(SOURCE_BASE_CXX # xml.cc // generated by yacc task + marshal.cc space.cc float.cc address.cc @@ -46,6 +47,7 @@ set(SOURCE_DECOMPILER_CXX funcdata.cc funcdata_block.cc funcdata_varnode.cc + unionresolve.cc funcdata_op.cc pcodeinject.cc heritage.cc diff --git a/ghidra/ghidra b/ghidra/ghidra index d8790574..d89dd09b 160000 --- a/ghidra/ghidra +++ b/ghidra/ghidra @@ -1 +1 @@ -Subproject commit d87905747fe38d2dcd7492ed2e83bbf438b156d3 +Subproject commit d89dd09b18645ba62fc202f962fdb73fb60145a7 diff --git a/src/CodeXMLParse.cpp b/src/CodeXMLParse.cpp index fa9a8539..3623c84f 100644 --- a/src/CodeXMLParse.cpp +++ b/src/CodeXMLParse.cpp @@ -139,32 +139,47 @@ void AnnotateCommentOffset(ANNOTATOR_PARAMS) void AnnotateColor(ANNOTATOR_PARAMS) { pugi::xml_attribute attr = node.attribute("color"); - if (attr.empty()) + if(attr.empty()) return; - std::string color = attr.as_string(); - if (color == "") + int color = attr.as_int(-1); + if(color < 0) return; RSyntaxHighlightType type; - if (color == "keyword") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_KEYWORD; - else if (color == "comment") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_COMMENT; - else if (color == "type") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_DATATYPE; - else if (color == "funcname") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME; - else if (color == "param") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER; - else if (color == "var") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE; - else if (color == "const") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE; - else if (color == "global") - type = RZ_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE; - else - return; + switch(color) + { + case Emit::syntax_highlight::keyword_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_KEYWORD; + break; + case Emit::syntax_highlight::comment_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_COMMENT; + break; + case Emit::syntax_highlight::type_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_DATATYPE; + break; + case Emit::syntax_highlight::funcname_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_NAME; + break; + case Emit::syntax_highlight::var_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_LOCAL_VARIABLE; + break; + case Emit::syntax_highlight::const_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_CONSTANT_VARIABLE; + break; + case Emit::syntax_highlight::param_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_FUNCTION_PARAMETER; + break; + case Emit::syntax_highlight::global_color: + type = RZ_SYNTAX_HIGHLIGHT_TYPE_GLOBAL_VARIABLE; + break; + case Emit::syntax_highlight::no_color: + case Emit::syntax_highlight::error_color: + case Emit::syntax_highlight::special_color: + default: + return; + } + RzCodeAnnotation annotation = {}; annotation.type = RZ_CODE_ANNOTATION_TYPE_SYNTAX_HIGHLIGHT; annotation.syntax_highlight.type = type; diff --git a/src/PrettyXmlEncode.cpp b/src/PrettyXmlEncode.cpp new file mode 100644 index 00000000..a1fdb777 --- /dev/null +++ b/src/PrettyXmlEncode.cpp @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: 2023 Florian Märkl +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "PrettyXmlEncode.h" + +void PrettyXmlEncode::indent() +{ + for(int i = 0; i < depth; i++) + outStream << " "; +} + +void PrettyXmlEncode::openElement(const ElementId &elemId) +{ + if(elementTagIsOpen) + outStream << ">\n"; + else + elementTagIsOpen = true; + indent(); + depth++; + outStream << '<' << elemId.getName(); +} + +void PrettyXmlEncode::closeElement(const ElementId &elemId) +{ + depth--; + if(elementTagIsOpen) + { + outStream << "/>\n"; + elementTagIsOpen = false; + } + else + { + indent(); + outStream << "\n"; + } +} + diff --git a/src/PrettyXmlEncode.h b/src/PrettyXmlEncode.h new file mode 100644 index 00000000..a0d90535 --- /dev/null +++ b/src/PrettyXmlEncode.h @@ -0,0 +1,21 @@ +// SPDX-FileCopyrightText: 2023 Florian Märkl +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef PRETTY_XML_ENCODE_H +#define PRETTY_XML_ENCODE_H + +#include + +class PrettyXmlEncode: public XmlEncode +{ + private: + int depth = 0; + void indent(); + + public: + PrettyXmlEncode(std::ostream &s) : XmlEncode(s) {} + void openElement(const ElementId &elemId) override; + void closeElement(const ElementId &elemId) override; +}; + +#endif diff --git a/src/RizinArchitecture.cpp b/src/RizinArchitecture.cpp index c4f96b0e..883604f1 100644 --- a/src/RizinArchitecture.cpp +++ b/src/RizinArchitecture.cpp @@ -37,7 +37,7 @@ std::string FilenameFromCore(RzCore *core) } RizinArchitecture::RizinArchitecture(RzCore *core, const std::string &sleigh_id) - : SleighArchitecture(FilenameFromCore(core), sleigh_id.empty() ? SleighIdFromCore(core) : sleigh_id, &cout), + : SleighArchitecture(FilenameFromCore(core), sleigh_id.empty() ? SleighIdFromCore(core) : sleigh_id, &std::cout), coreMutex(core) { } diff --git a/src/RizinCommentDatabase.h b/src/RizinCommentDatabase.h index 7d00ea95..e2bd6254 100644 --- a/src/RizinCommentDatabase.h +++ b/src/RizinCommentDatabase.h @@ -29,8 +29,8 @@ class RizinCommentDatabase : public CommentDatabase CommentSet::const_iterator beginComment(const Address &fad) const override; CommentSet::const_iterator endComment(const Address &fad) const override; - void saveXml(ostream &s) const override { cache.saveXml(s); } - void restoreXml(const Element *el, const AddrSpaceManager *trans) override { throw LowlevelError("commentdb::restoreXml unimplemented"); } + void encode(Encoder &encoder) const override { cache.encode(encoder); } + void decode(Decoder &decoder) override { throw LowlevelError("CommentDatabaseGhidra::decode unimplemented"); } }; #endif //RZ_GHIDRA_RizinCOMMENTDATABASE_H diff --git a/src/RizinScope.cpp b/src/RizinScope.cpp index 043cd4ea..695e1dda 100644 --- a/src/RizinScope.cpp +++ b/src/RizinScope.cpp @@ -7,8 +7,6 @@ #include -#include -#include #include #include "RizinUtils.h" @@ -166,47 +164,29 @@ FunctionSymbol *RizinScope::registerFunction(RzAnalysisFunction *fcn) const arch->addWarning("Function " + to_string(fcn_name) + " has no calling convention set, args may be inaccurate."); } - int4 extraPop = proto ? proto->getExtraPop() : arch->translate->getDefaultSize(); - if(extraPop == ProtoModel::extrapop_unknown) - extraPop = arch->translate->getDefaultSize(); - RangeList varRanges; // to check for overlaps - RzList *vars = rz_analysis_var_all_list(core->analysis, fcn); auto stackSpace = arch->getStackSpace(); auto addrForVar = [&](RzAnalysisVar *var, bool warn_on_fail) { - switch(var->kind) + switch(var->storage.type) { - case RZ_ANALYSIS_VAR_KIND_BPV: + case RZ_ANALYSIS_VAR_STORAGE_STACK: { uintb off; - int delta = var->delta + fcn->bp_off - extraPop; // not 100% sure if extraPop is correct here + st64 delta = var->storage.stack_off; if(delta >= 0) off = delta; else off = stackSpace->getHighest() + delta + 1; return Address(stackSpace, off); } - case RZ_ANALYSIS_VAR_KIND_REG: + case RZ_ANALYSIS_VAR_STORAGE_REG: { - RzRegItem *reg = rz_reg_index_get(core->analysis->reg, var->delta); - if(!reg) - { - if(warn_on_fail) - arch->addWarning("Register for arg " + to_string(var->name) + " not found"); - return Address(); - } - - auto ret = arch->registerAddressFromRizinReg(reg->name); + auto ret = arch->registerAddressFromRizinReg(var->storage.reg); if(ret.isInvalid() && warn_on_fail) arch->addWarning("Failed to match register " + to_string(var->name) + " for arg " + to_string(var->name)); - return ret; } - case RZ_ANALYSIS_VAR_KIND_SPV: - if(warn_on_fail) - arch->addWarning("Var " + to_string(var->name) + " is stack pointer based, which is not supported for decompilation."); - return Address(); default: if(warn_on_fail) arch->addWarning("Failed to get address for var " + to_string(var->name)); @@ -218,37 +198,36 @@ FunctionSymbol *RizinScope::registerFunction(RzAnalysisFunction *fcn) const ParamActive params(false); - if(vars) - { - rz_list_foreach_cpp(vars, [&](RzAnalysisVar *var) { - std::string typeError; - Datatype *type = var->type ? arch->getTypeFactory()->fromRzType(var->type, &typeError) : nullptr; + rz_pvector_foreach_cpp(&fcn->vars, [&](RzAnalysisVar *var) { + std::string typeError; + Datatype *type = var->type ? arch->getTypeFactory()->fromRzType(var->type, &typeError) : nullptr; + if(!type) + { + char *tstr = rz_type_as_string(core->analysis->typedb, var->type); + arch->addWarning("Failed to match type " + to_string(tstr ? tstr : "?") + " for variable " + to_string(var->name) + " to Decompiler type: " + typeError); + rz_mem_free(tstr); + type = arch->types->getBase(core->analysis->bits / 8, TYPE_UNKNOWN); if(!type) - { - char *tstr = rz_type_as_string(core->analysis->typedb, var->type); - arch->addWarning("Failed to match type " + to_string(tstr ? tstr : "?") + " for variable " + to_string(var->name) + " to Decompiler type: " + typeError); - rz_mem_free(tstr); - type = arch->types->getBase(core->analysis->bits / 8, TYPE_UNKNOWN); - if(!type) - return; - } - if(type->getSize() < 1) - { - arch->addWarning("Type " + type->getName() + " of variable " + to_string(var->name) + " has size 0"); - return; - } - var_types[var] = type; - - if(!var->isarg) - return; - auto addr = addrForVar(var, true); - if(addr.isInvalid()) - return; - params.registerTrial(addr, type->getSize()); - int4 i = params.whichTrial(addr, type->getSize()); - params.getTrial(i).markActive(); - }); - } + return true; + } + if(type->getSize() < 1) + { + arch->addWarning("Type " + type->getName() + " of variable " + to_string(var->name) + " has size 0"); + return true; + } + var_types[var] = type; + + if(!rz_analysis_var_is_arg(var)) + return true; + auto addr = addrForVar(var, true); + if(addr.isInvalid()) + return true; + params.registerTrial(addr, type->getSize()); + int4 i = params.whichTrial(addr, type->getSize()); + params.getTrial(i).markActive(); + params.getTrial(i).markUsed(); + return true; + }); if(proto) proto->deriveInputMap(¶ms); @@ -266,132 +245,139 @@ FunctionSymbol *RizinScope::registerFunction(RzAnalysisFunction *fcn) const }); }; - if(vars) - { - std::vector argsByIndex; - - rz_list_foreach_cpp(vars, [&](RzAnalysisVar *var) { - auto type_it = var_types.find(var); - if(type_it == var_types.end()) - return; - Datatype *type = type_it->second; - bool typelock = true; - - auto addr = addrForVar(var, var->isarg /* Already emitted this warning before */); - if(addr.isInvalid()) - return; - - uintb last = addr.getOffset(); - if(type->getSize() > 0) - last += type->getSize() - 1; - if(last < addr.getOffset()) - { - arch->addWarning("Variable " + to_string(var->name) + " extends beyond the stackframe. Try changing its type to something smaller."); - return; - } - bool overlap = false; - for(const auto &range : varRanges) - { - if(range.getSpace() != addr.getSpace()) - continue; - if(range.getFirst() > last) - continue; - if(range.getLast() < addr.getOffset()) - continue; - overlap = true; - break; - } - - if(overlap) - { - arch->addWarning("Detected overlap for variable " + to_string(var->name)); + std::vector argsByIndex; - if(var->isarg) // Can't have args with typelock=false, otherwise we get segfaults in the Decompiler - return; + rz_pvector_foreach_cpp(&fcn->vars, [&](RzAnalysisVar *var) { + auto type_it = var_types.find(var); + if(type_it == var_types.end()) + return true; + Datatype *type = type_it->second; + bool typelock = true; - typelock = false; - } + auto addr = addrForVar(var, rz_analysis_var_is_arg(var) /* Already emitted this warning before */); + if(addr.isInvalid()) + return true; - int4 paramIndex = -1; - if(var->isarg) - { - if(proto && !proto->possibleInputParam(addr, type->getSize())) - { - // Prevent segfaults in the Decompiler - arch->addWarning("Removing arg " + to_string(var->name) + " because it doesn't fit into ProtoModel"); - return; - } + uintb last = addr.getOffset(); + if(type->getSize() > 0) + last += type->getSize() - 1; + if(last < addr.getOffset()) + { + arch->addWarning("Variable " + to_string(var->name) + " extends beyond the stackframe. Try changing its type to something smaller."); + return true; + } + bool overlap = false; + for(const auto &range : varRanges) + { + if(range.getSpace() != addr.getSpace()) + continue; + if(range.getFirst() > last) + continue; + if(range.getLast() < addr.getOffset()) + continue; + overlap = true; + break; + } - paramIndex = params.whichTrial(addr, type->getSize()); - if(paramIndex < 0) - { - arch->addWarning("Failed to determine arg index of " + to_string(var->name)); - return; - } - } + if(overlap) + { + arch->addWarning("Detected overlap for variable " + to_string(var->name)); - varRanges.insertRange(addr.getSpace(), addr.getOffset(), last); + if(rz_analysis_var_is_arg(var)) // Can't have args with typelock=false, otherwise we get segfaults in the Decompiler + return true; - auto mapsymElement = child(symbollistElement, "mapsym"); - auto symbolElement = child(mapsymElement, "symbol", { - { "name", var->name }, - { "typelock", typelock ? "true" : "false" }, - { "namelock", "true" }, - { "readonly", "false" }, - { "cat", var->isarg ? "0" : "-1" } - }); + typelock = false; + } - if(var->isarg) + int4 paramIndex = -1; + if(rz_analysis_var_is_arg(var)) + { + if(proto && !proto->possibleInputParam(addr, type->getSize())) { - if(argsByIndex.size() < paramIndex + 1) - argsByIndex.resize(paramIndex + 1, nullptr); + // Prevent segfaults in the Decompiler + arch->addWarning("Removing arg " + to_string(var->name) + " because it doesn't fit into ProtoModel"); + return true; + } - argsByIndex[paramIndex] = symbolElement; + int4 paramTrialIndex = params.whichTrial(addr, type->getSize()); + if(paramTrialIndex < 0) + { + arch->addWarning("Failed to determine arg index of " + to_string(var->name)); + return true; + } - symbolElement->addAttribute("index", to_string(paramIndex < 0 ? 0 : paramIndex)); + paramIndex = 0; + for(int4 i = 0; i < paramTrialIndex; i++) + { + if(!params.getTrial(i).isUsed()) + continue; + paramIndex++; } + } - childType(symbolElement, type); - childAddr(mapsymElement, "addr", addr); + varRanges.insertRange(addr.getSpace(), addr.getOffset(), last); - auto rangelist = child(mapsymElement, "rangelist"); - if(var->isarg && var->kind == RZ_ANALYSIS_VAR_KIND_REG) - childRegRange(rangelist); + auto mapsymElement = child(symbollistElement, "mapsym"); + auto symbolElement = child(mapsymElement, "symbol", { + { "name", var->name }, + { "typelock", typelock ? "true" : "false" }, + { "namelock", "true" }, + { "readonly", "false" }, + { "cat", rz_analysis_var_is_arg(var) ? "0" : "-1" } }); - // Add placeholder args in gaps - for(size_t i=0; itypes->getBase(trial.getSize(), TYPE_UNKNOWN); - if(!type) - continue; + argsByIndex[paramIndex] = symbolElement; - auto mapsymElement = child(symbollistElement, "mapsym"); - auto symbolElement = child(mapsymElement, "symbol", { - { "name", "placeholder_" + to_string(i) }, - { "typelock", "true" }, - { "namelock", "true" }, - { "readonly", "false" }, - { "cat", "0" }, - { "index", to_string(i) } - }); - - childAddr(mapsymElement, "addr", trial.getAddress()); - childType(symbolElement, type); - - auto rangelist = child(mapsymElement, "rangelist"); - if(trial.getAddress().getSpace() != arch->translate->getStackSpace()) - childRegRange(rangelist); + symbolElement->addAttribute("index", to_string(paramIndex < 0 ? 0 : paramIndex)); } - } - rz_list_free(vars); + childType(symbolElement, type); + childAddr(mapsymElement, "addr", addr); + + auto rangelist = child(mapsymElement, "rangelist"); + if(rz_analysis_var_is_arg(var) && var->storage.type == RZ_ANALYSIS_VAR_STORAGE_REG) + childRegRange(rangelist); + return true; + }); + + // Add placeholder args in gaps + for(size_t i=0; itypes->getBase(trial.getSize(), TYPE_UNKNOWN); + if(!type) + continue; + + auto mapsymElement = child(symbollistElement, "mapsym"); + auto symbolElement = child(mapsymElement, "symbol", { + { "name", "placeholder_" + to_string(i) }, + { "typelock", "true" }, + { "namelock", "true" }, + { "readonly", "false" }, + { "cat", "0" }, + { "index", to_string(i) } + }); + + childAddr(mapsymElement, "addr", trial.getAddress()); + childType(symbolElement, type); + + auto rangelist = child(mapsymElement, "rangelist"); + if(trial.getAddress().getSpace() != arch->translate->getStackSpace()) + childRegRange(rangelist); + } + int4 extraPop = proto ? proto->getExtraPop() : arch->translate->getDefaultSize(); + if(extraPop == ProtoModel::extrapop_unknown) + extraPop = arch->translate->getDefaultSize(); auto prototypeElement = child(functionElement, "prototype", { { "extrapop", to_string(extraPop) }, { "model", proto ? proto->getName() : "unknown" } @@ -429,10 +415,19 @@ FunctionSymbol *RizinScope::registerFunction(RzAnalysisFunction *fcn) const child(&doc, "rangelist"); - auto sym = cache->addMapSym(&doc); + XmlDecode dec(arch, &doc); + auto sym = cache->addMapSym(dec); return dynamic_cast(sym); } +FunctionSymbol *RizinScope::registerRelocTarget(RzBinReloc *reloc) const +{ + RzCoreLock core(arch->getCore()); + if(!reloc->import || !reloc->import->name) + return nullptr; + return cache->addFunction(Address(arch->getDefaultCodeSpace(), reloc->target_vaddr), reloc->import->name); +} + Symbol *RizinScope::registerFlag(RzFlagItem *flag) const { RzCoreLock core(arch->getCore()); @@ -449,12 +444,7 @@ Symbol *RizinScope::registerFlag(RzFlagItem *flag) const auto bf = reinterpret_cast(pos); if(!bf->o) continue; - void *s = ht_up_find(bf->o->strings_db, flag->offset, nullptr); - if(s) - { - str = reinterpret_cast(s); - break; - } + str = rz_bin_object_get_string_at(bf->o, flag->offset, true); } Datatype *ptype; const char *tn = "char"; @@ -462,18 +452,24 @@ Symbol *RizinScope::registerFlag(RzFlagItem *flag) const { switch(str->type) { - case RZ_BIN_STRING_ENC_WIDE_LE: - case RZ_BIN_STRING_ENC_WIDE_BE: + case RZ_STRING_ENC_UTF16LE: + case RZ_STRING_ENC_UTF16BE: tn = "char16_t"; break; - case RZ_BIN_STRING_ENC_WIDE32_LE: - case RZ_BIN_STRING_ENC_WIDE32_BE: + case RZ_STRING_ENC_UTF32LE: + case RZ_STRING_ENC_UTF32BE: tn = "char32_t"; break; + default: + break; } } ptype = arch->types->findByName(tn); int4 sz = static_cast(flag->size) / ptype->getSize(); + if(!sz && str) // Zero string length is an error + sz = str->length; + if(!sz) + sz = 1; // The decompiler will figure out the length to display type = arch->types->getTypeArray(sz, ptype); attr |= Varnode::readonly; } @@ -544,6 +540,14 @@ Symbol *RizinScope::queryRizinAbsolute(ut64 addr, bool contain) const if(glob) return registerGlobalVar(glob); + RzBinReloc *reloc = rz_core_get_reloc_to(core, addr); + if(reloc && reloc->import) + { + auto rsym = registerRelocTarget(reloc); + if(rsym) + return rsym; + } + // TODO: register more things // TODO: correctly handle contain for flags diff --git a/src/RizinScope.h b/src/RizinScope.h index 9417cf2c..b9173a8e 100644 --- a/src/RizinScope.h +++ b/src/RizinScope.h @@ -19,6 +19,7 @@ class RizinArchitecture; typedef struct rz_analysis_function_t RzAnalysisFunction; typedef struct rz_flag_item_t RzFlagItem; typedef struct rz_analysis_var_global_t RzAnalysisVarGlobal; +typedef struct rz_bin_reloc_t RzBinReloc; class RizinScope : public Scope { @@ -30,6 +31,7 @@ class RizinScope : public Scope uint8 makeId() const { return (*next_id)++; } FunctionSymbol *registerFunction(RzAnalysisFunction *fcn) const; + FunctionSymbol *registerRelocTarget(RzBinReloc *reloc) const; Symbol *registerFlag(RzFlagItem *flag) const; Symbol *registerGlobalVar(RzAnalysisVarGlobal *glob) const; Symbol *queryRizinAbsolute(ut64 addr, bool contain) const; @@ -85,8 +87,8 @@ class RizinScope : public Scope void renameSymbol(Symbol *sym,const string &newname) override { throw LowlevelError("renameSymbol unimplemented"); } void retypeSymbol(Symbol *sym,Datatype *ct) override { throw LowlevelError("retypeSymbol unimplemented"); } string makeNameUnique(const string &nm) const override { throw LowlevelError("makeNameUnique unimplemented"); } - void saveXml(ostream &s) const override { cache->saveXml(s); } - void restoreXml(const Element *el) override { throw LowlevelError("restoreXml unimplemented"); } + void encode(Encoder &encoder) const override { cache->encode(encoder); } + void decode(Decoder &decoder) override { throw LowlevelError("decode unimplemented"); } void printEntries(ostream &s) const override { throw LowlevelError("printEntries unimplemented"); } int4 getCategorySize(int4 cat) const override { throw LowlevelError("getCategorySize unimplemented"); } Symbol *getCategorySymbol(int4 cat,int4 ind) const override { throw LowlevelError("getCategorySymbol unimplemented"); } diff --git a/src/RizinTypeFactory.cpp b/src/RizinTypeFactory.cpp index a7efde6b..cf07587e 100644 --- a/src/RizinTypeFactory.cpp +++ b/src/RizinTypeFactory.cpp @@ -53,11 +53,13 @@ Datatype *RizinTypeFactory::addRizinStruct(RzBaseType *type, StackTypes &stack_t // if(elements > 0) // memberType = getTypeArray(elements, memberType); - fields.push_back({ + TypeField tf = { + (int4)offset, // id = offset by default (int4)offset, // Currently, this is 0 most of the time: member->offset, std::string(member->name), member_type - }); + }; + fields.push_back(tf); // TODO: right now, we track member offset ourselves // which means all structs are assumed to be packed. @@ -110,7 +112,7 @@ Datatype *RizinTypeFactory::addRizinTypedef(RzBaseType *type, StackTypes &stack_ Datatype *resolved = fromRzTypeInternal(type->type, nullptr, &stack_types, true, false); // use prototype=true to avoid recursion if(!resolved) return nullptr; - Datatype *typedefd = getTypedef(resolved, type->name, 0); + Datatype *typedefd = getTypedef(resolved, type->name, 0, 0); fromRzTypeInternal(type->type, nullptr, &stack_types, false, false); // fully create the type after querying with prototype=true before return typedefd; } diff --git a/src/SleighAsm.cpp b/src/SleighAsm.cpp index 88017a53..74176d23 100644 --- a/src/SleighAsm.cpp +++ b/src/SleighAsm.cpp @@ -57,7 +57,7 @@ void SleighAsm::initInner(std::string sleigh_id) } static void parseProto(const Element *el, std::vector &arg_names, - std::vector &ret_names) + std::vector &ret_names) { if(el->getName() != "prototype") throw LowlevelError("Expecting tag"); @@ -103,7 +103,7 @@ static void parseProto(const Element *el, std::vector &arg_names, } static void parseDefaultProto(const Element *el, std::vector &arg_names, - std::vector &ret_names) + std::vector &ret_names) { const List &list(el->getChildren()); List::const_iterator iter; @@ -157,7 +157,7 @@ static std::unordered_map parseRegisterData(const Elem unused = (*iter)->getAttributeValue("unused"); rename = (*iter)->getAttributeValue("rename"); } - catch(const XmlError &e) + catch(const DecoderError &e) { std::string err_prefix("Unknown attribute: "); if(e.explain == err_prefix + "group") { /* nothing */ } @@ -181,26 +181,39 @@ static std::unordered_map parseRegisterData(const Elem * Context data is used to fill contextreg. */ void SleighAsm::parseProcConfig(DocumentStorage &store) + { const Element *el = store.getTag("processor_spec"); if(!el) throw LowlevelError("No processor configuration tag found"); - - const List &list(el->getChildren()); - List::const_iterator iter; - - for(iter = list.begin(); iter != list.end(); iter++) + XmlDecode decoder(&trans, el); + uint4 elemId = decoder.openElement(ELEM_PROCESSOR_SPEC); + for(;;) { - const string &elname((*iter)->getName()); - if(elname == "context_data") - context.restoreFromSpec(*iter, &trans); - - if(elname == "programcounter") - pc_name = (*iter)->getAttributeValue("register"); - - if(elname == "register_data") - reg_group = parseRegisterData(*iter); + uint4 subId = decoder.peekElement(); + if(subId == 0) + break; + if (subId == ELEM_PROGRAMCOUNTER) + { + decoder.openElement(); + pc_name = decoder.readString(ATTRIB_REGISTER); + decoder.closeElement(subId); + } + else if (subId == ELEM_CONTEXT_DATA) + context.decodeFromSpec(decoder); + else if (subId == ELEM_REGISTER_DATA) + { + decoder.openElement(); + parseRegisterData(decoder.getCurrentXmlElement()); + decoder.closeElement(subId); + } + else + { + decoder.openElement(); + decoder.closeElementSkipping(subId); + } } + decoder.closeElement(elemId); } /* @@ -226,7 +239,7 @@ void SleighAsm::buildSpecfile(DocumentStorage &store) Document *doc = store.openDocument(processorfile); store.registerTag(doc->getRoot()); } - catch(XmlError &err) + catch(DecoderError &err) { ostringstream serr; serr << "XML error parsing processor specification: " << processorfile; @@ -246,7 +259,7 @@ void SleighAsm::buildSpecfile(DocumentStorage &store) Document *doc = store.openDocument(compilerfile); store.registerTag(doc->getRoot()); } - catch(XmlError &err) + catch(DecoderError &err) { ostringstream serr; serr << "XML error parsing compiler specification: " << compilerfile; @@ -266,7 +279,7 @@ void SleighAsm::buildSpecfile(DocumentStorage &store) Document *doc = store.openDocument(slafile); store.registerTag(doc->getRoot()); } - catch(XmlError &err) + catch(DecoderError &err) { ostringstream serr; serr << "XML error parsing SLEIGH file: " << slafile; @@ -284,7 +297,7 @@ void SleighAsm::buildSpecfile(DocumentStorage &store) /* * From sleigh_arch.cc's resolveArchitecture() - * This function is used to reolve the index of asm.cpu in description. + * This function is used to resolve the index of asm.cpu in description. * It is stripped because asm.cpu is the result of normalizeArchitecture(). */ void SleighAsm::resolveArch(const string &archid) @@ -366,28 +379,33 @@ void SleighAsm::loadLanguageDescription(const string &specfile) if(!s) throw LowlevelError("Unable to open: " + specfile); - Document *doc; - Element *el; + XmlDecode decoder((const AddrSpaceManager *)0); try { - doc = xml_tree(s); + decoder.ingestStream(s); } - catch(XmlError &err) + catch(DecoderError &err) { throw LowlevelError("Unable to parse sleigh specfile: " + specfile); } - el = doc->getRoot(); - const List &list(el->getChildren()); - List::const_iterator iter; - for(iter = list.begin(); iter != list.end(); ++iter) - { - if((*iter)->getName() != "language") - continue; - description.push_back(LanguageDescription()); - description.back().restoreXml(*iter); + uint4 elemId = decoder.openElement(ELEM_LANGUAGE_DEFINITIONS); + for(;;) { + uint4 subId = decoder.peekElement(); + if(subId == 0) + break; + if(subId == ELEM_LANGUAGE) + { + description.emplace_back(); + description.back().decode(decoder); + } + else + { + decoder.openElement(); + decoder.closeElementSkipping(subId); + } } - delete doc; + decoder.closeElement(elemId); } /* diff --git a/src/SleighInstruction.cpp b/src/SleighInstruction.cpp index c92a163c..f5146f40 100644 --- a/src/SleighInstruction.cpp +++ b/src/SleighInstruction.cpp @@ -93,7 +93,7 @@ SleighParserContext *RizinSleigh::getParserContext(Address &addr, SleighInstruct SleighParserContext *RizinSleigh::newSleighParserContext(Address &addr, SleighInstructionPrototype *proto) { - SleighParserContext *pos = new SleighParserContext(getContextCache()); + SleighParserContext *pos = new SleighParserContext(getContextCache(), this); pos->initialize(1, 0, getConstantSpace()); pos->setAddr(addr); pos->setPrototype(proto); @@ -235,9 +235,9 @@ FlowType SleighInstructionPrototype::convertFlowFlags(FlowFlags flags) { if((flags & FLOW_LABEL) != 0) flags = FlowFlags(flags | FLOW_BRANCH_TO_END); - flags = FlowFlags(flags & (~(FLOW_CROSSBUILD | FLOW_LABEL))); + int mask = FlowFlags(flags & (~(FLOW_CROSSBUILD | FLOW_LABEL))); // NOTE: If prototype has cross-build, flow must be determined dynamically - switch(flags) + switch(mask) { // Convert flags to a standard flowtype case 0: case FLOW_BRANCH_TO_END: return FlowType::FALL_THROUGH; @@ -546,9 +546,6 @@ Address SleighInstructionPrototype::getHandleAddr(FixedHandle &hand, AddrSpace * return Address(); Address newaddr(hand.space, hand.space->wrapOffset(hand.offset_offset)); - - newaddr.toPhysical(); - // if we are in an address space, translate it // if (curSpace.isOverlaySpace()) { // newaddr = curSpace.getOverlayAddress(newaddr); diff --git a/src/SleighInstruction.h b/src/SleighInstruction.h index 011d9f66..bd047f55 100644 --- a/src/SleighInstruction.h +++ b/src/SleighInstruction.h @@ -274,7 +274,7 @@ class SleighParserContext : public ParserContext SleighInstructionPrototype *prototype = nullptr; public: - SleighParserContext(ContextCache *ccache): ParserContext(ccache) {} + SleighParserContext(ContextCache *ccache, Translate *trans): ParserContext(ccache, trans) {} SleighInstructionPrototype *getPrototype() { return prototype; } void setPrototype(SleighInstructionPrototype *p); }; diff --git a/src/analysis_ghidra.cpp b/src/analysis_ghidra.cpp index cb898f84..6adeec69 100644 --- a/src/analysis_ghidra.cpp +++ b/src/analysis_ghidra.cpp @@ -15,7 +15,7 @@ static SleighAsm sanalysis; -static int archinfo(RzAnalysis *analysis, int query) +static int archinfo(RzAnalysis *analysis, RzAnalysisInfoType query) { // This is to check if RzCore plugin set cpu properly. if(!analysis->cpu) @@ -36,7 +36,7 @@ static int archinfo(RzAnalysis *analysis, int query) return -1; } - if(query == RZ_ANALYSIS_ARCHINFO_ALIGN) + if(query == RZ_ANALYSIS_ARCHINFO_TEXT_ALIGN) return sanalysis.alignment; else return -1; @@ -809,7 +809,7 @@ static void sleigh_esil(RzAnalysis *a, RzAnalysisOp *analysis_op, ut64 addr, con const std::vector &Pcodes) { std::vector esil_stack; - stringstream ss; + std::stringstream ss; auto print_if_unique = [&esil_stack, &ss](const PcodeOperand *arg, int offset = 0) -> bool { if(arg->is_unique()) @@ -1095,6 +1095,7 @@ static void sleigh_esil(RzAnalysis *a, RzAnalysisOp *analysis_op, ut64 addr, con case CPUI_INT_LESSEQUAL: ss << "<="; break; case CPUI_INT_NOTEQUAL: ss << "==,!"; break; case CPUI_INT_EQUAL: ss << "=="; break; + default: break; } if(iter->output->is_unique()) @@ -1154,6 +1155,7 @@ static void sleigh_esil(RzAnalysis *a, RzAnalysisOp *analysis_op, ut64 addr, con case CPUI_INT_SRIGHT: ss << iter->input0->size * 8 << ",SWAP,SIGN,>>"; break; + default: break; } ss << "," << iter->output->size * 8 << ",1,<<,1,SWAP,-,&"; @@ -1327,6 +1329,7 @@ static void sleigh_esil(RzAnalysis *a, RzAnalysisOp *analysis_op, ut64 addr, con case CPUI_FLOAT_ABS: ss << ",0,I2F,F<=,!,?{,-F,}"; break; case CPUI_FLOAT_NEG: ss << ",-F"; break; case CPUI_FLOAT_FLOAT2FLOAT: /* same as below */ break; + default: break; } switch(iter->type) { @@ -1340,6 +1343,7 @@ static void sleigh_esil(RzAnalysis *a, RzAnalysisOp *analysis_op, ut64 addr, con case CPUI_FLOAT_FLOAT2FLOAT: ss << "," << iter->output->size * 8 << ",SWAP,F2F"; break; + default: break; } if(iter->output->is_unique()) @@ -1352,6 +1356,8 @@ static void sleigh_esil(RzAnalysis *a, RzAnalysisOp *analysis_op, ut64 addr, con throw LowlevelError("sleigh_esil: arguments of Pcodes are not well inited."); break; } + default: + break; } } @@ -3048,7 +3054,7 @@ static bool sleigh_esil_eq(RzAnalysisEsil *esil) return ret; } -static unordered_set float_mem; +static std::unordered_set float_mem; static bool sleigh_esil_peek4(RzAnalysisEsil *esil) // Read out { @@ -3293,11 +3299,6 @@ RzAnalysisPlugin rz_analysis_plugin_ghidra = { /* .address_bits = */ nullptr, /* .op = */ &sleigh_op, /* .get_reg_profile = */ &get_reg_profile, - /* .fingerprint_bb = */ nullptr, - /* .fingerprint_fcn = */ nullptr, - /* .diff_bb = */ nullptr, - /* .diff_fcn = */ nullptr, - /* .diff_eval = */ nullptr, /* .esil_init = */ esil_sleigh_init, /* .esil_post_loop = */ nullptr, /* .esil_trap = */ nullptr, @@ -3311,7 +3312,6 @@ RZ_API RzLibStruct rizin_plugin = { /* .data = */ &rz_analysis_plugin_ghidra, /* .version = */ RZ_VERSION, /* .free = */ nullptr, - /* .pkgname = */ "rz-ghidra" }; } #endif diff --git a/src/asm_ghidra.cpp b/src/asm_ghidra.cpp index 5f146ceb..86a5472c 100644 --- a/src/asm_ghidra.cpp +++ b/src/asm_ghidra.cpp @@ -4,6 +4,7 @@ #include #include #include "SleighAsm.h" +#include "rz_ghidra_internal.h" static SleighAsm sasm; static RzIO *rio = nullptr; @@ -36,8 +37,15 @@ static int disassemble(RzAsm *a, RzAsmOp *op, const ut8 *buf, int len) return r; } +static bool init(void **user) +{ + rz_ghidra_lib_init(); + return true; +} + static bool fini(void *p) { + rz_ghidra_lib_fini(); if(rio) rz_io_free(rio); rio = nullptr; @@ -54,7 +62,7 @@ RzAsmPlugin rz_asm_plugin_ghidra = { /* .license = */ "LGPL3", /* .bits = */ 8 | 16 | 32 | 64, /* .endian = */ 0, - /* .init = */ nullptr, + /* .init = */ &init, /* .fini = */ &fini, /* .disassemble = */ &disassemble, /* .assemble = */ nullptr, @@ -70,7 +78,6 @@ RZ_API RzLibStruct rizin_plugin = { /* .data = */ &rz_asm_plugin_ghidra, /* .version = */ RZ_VERSION, /* .free = */ nullptr, - /* .pkgname = */ "rz-ghidra" }; } #endif diff --git a/src/core_ghidra.cpp b/src/core_ghidra.cpp index 6939b997..a426a06e 100644 --- a/src/core_ghidra.cpp +++ b/src/core_ghidra.cpp @@ -7,7 +7,9 @@ #include "RizinArchitecture.h" #include "CodeXMLParse.h" #include "ArchMap.h" +#include "PrettyXmlEncode.h" #include "rz_ghidra.h" +#include "rz_ghidra_internal.h" // Windows clash #ifdef restrict @@ -74,6 +76,7 @@ static const ConfigVar cfg_var_verbose ("verbose", "true", "Show ve static std::recursive_mutex decompiler_mutex; +static int lib_init_refcount = 0; // protected by decompiler_mutex, refcounts rz_ghidra_lib_init initialization class DecompilerLock { @@ -173,7 +176,7 @@ static void Decompile(RzCore *core, ut64 addr, DecompileMode mode, std::stringst case DecompileMode::JSON: case DecompileMode::OFFSET: case DecompileMode::STATEMENTS: - arch.print->setXML(true); + arch.print->setMarkup(true); break; default: break; @@ -181,7 +184,8 @@ static void Decompile(RzCore *core, ut64 addr, DecompileMode mode, std::stringst if(mode == DecompileMode::XML) { out_stream << ""; - func->saveXml(out_stream, 0, true); + PrettyXmlEncode enc(out_stream); + func->encode(enc, 0, true); out_stream << ""; } switch(mode) @@ -199,9 +203,11 @@ static void Decompile(RzCore *core, ut64 addr, DecompileMode mode, std::stringst throw LowlevelError("Failed to parse XML code from Decompiler"); } break; - case DecompileMode::DEBUG_XML: - arch.saveXml(out_stream); + case DecompileMode::DEBUG_XML: { + PrettyXmlEncode enc(out_stream); + arch.encode(enc); break; + } default: break; } @@ -652,10 +658,27 @@ static RzCmdStatus pdgstar_handler(RzCore *core, int argc, const char **argv) { return RZ_CMD_STATUS_OK; } -static bool rz_ghidra_init(RzCore *core) +void rz_ghidra_lib_init(void) { std::lock_guard lock(decompiler_mutex); + lib_init_refcount++; startDecompilerLibrary(nullptr); +} + +void rz_ghidra_lib_fini(void) +{ + std::lock_guard lock(decompiler_mutex); + lib_init_refcount--; + if(lib_init_refcount < 0) + return; + if(lib_init_refcount == 0) + shutdownDecompilerLibrary(); +} + +static bool rz_ghidra_init(RzCore *core) +{ + std::lock_guard lock(decompiler_mutex); + rz_ghidra_lib_init(); RzConfig *cfg = core->config; rz_config_lock (cfg, false); @@ -671,7 +694,7 @@ static bool rz_ghidra_init(RzCore *core) rz_config_lock (cfg, true); auto rzcmd = core->rcmd; - RzCmdDesc *root_cd = rz_cmd_desc_group_new(rzcmd, rz_cmd_get_root(rzcmd), "pdg", pdg_handler, &pdg_help, &root_help); + RzCmdDesc *root_cd = rz_cmd_desc_group_new(rzcmd, rz_cmd_get_desc(rzcmd, "pd"), "pdg", pdg_handler, &pdg_help, &root_help); rz_cmd_desc_argv_new(rzcmd, root_cd, "pdgd", pdgd_handler, &pdgd_help); rz_cmd_desc_argv_new(rzcmd, root_cd, "pdgx", pdgx_handler, &pdgx_help); rz_cmd_desc_argv_new(rzcmd, root_cd, "pdgj", pdgj_handler, &pdgj_help); @@ -688,7 +711,11 @@ static bool rz_ghidra_init(RzCore *core) static bool rz_ghidra_fini(RzCore *core) { std::lock_guard lock(decompiler_mutex); - shutdownDecompilerLibrary(); + rz_ghidra_lib_fini(); + + auto rzcmd = core->rcmd; + RzCmdDesc *pdg_cd = rz_cmd_get_desc(rzcmd, "pdg"); + rz_cmd_desc_remove(rzcmd, pdg_cd); return true; } @@ -709,7 +736,6 @@ RZ_API RzLibStruct rizin_plugin = { /* .data = */ &rz_core_plugin_ghidra, /* .version = */ RZ_VERSION, /* .free = */ nullptr, - /* .pkgname = */ "rz-ghidra" }; } #endif diff --git a/src/rz_ghidra_internal.h b/src/rz_ghidra_internal.h new file mode 100644 index 00000000..de0f4a54 --- /dev/null +++ b/src/rz_ghidra_internal.h @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2023 Florian Märkl +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef RZ_GHIDRA_H +#define RZ_GHIDRA_H + +void rz_ghidra_lib_init(void); +void rz_ghidra_lib_fini(void); + +#endif + diff --git a/test/bins/Makefile b/test/bins/Makefile index 6f90f56f..50eef138 100644 --- a/test/bins/Makefile +++ b/test/bins/Makefile @@ -8,9 +8,15 @@ clean: dectest32: dectest.c types.h gcc -m32 -fno-pic -no-pie -fno-omit-frame-pointer -o dectest32 -O0 dectest.c +dectest32-sp: dectest.c types.h + gcc -m32 -fno-pic -no-pie -fomit-frame-pointer -o dectest32-sp -O0 dectest.c + dectest64: dectest.c types.h gcc -m64 -fno-pic -no-pie -fno-omit-frame-pointer -o dectest64 -O0 dectest.c +dectest64-sp: dectest.c types.h + gcc -m64 -fno-pic -no-pie -fomit-frame-pointer -o dectest64-sp -O0 dectest.c + rec: rec.c types_rec.h gcc -m64 -fno-pic -no-pie -fno-omit-frame-pointer -o rec -O0 rec.c diff --git a/test/bins/dectest32-sp b/test/bins/dectest32-sp new file mode 100755 index 00000000..1a648e42 Binary files /dev/null and b/test/bins/dectest32-sp differ diff --git a/test/bins/dectest64-sp b/test/bins/dectest64-sp new file mode 100755 index 00000000..acb7dcac Binary files /dev/null and b/test/bins/dectest64-sp differ diff --git a/test/db/extras/analysis_ghidra b/test/db/extras/analysis_ghidra index 7124ac2e..a5011e6b 100644 --- a/test/db/extras/analysis_ghidra +++ b/test/db/extras/analysis_ghidra @@ -52,13 +52,13 @@ type: mul 0x00000000 DIV edx type: mod ---- -0x00000000 SHR eax,1 +0x00000000 SHR eax,0x1 type: shr ---- -0x00000000 SHL eax,1 +0x00000000 SHL eax,0x1 type: shl ---- -0x00000000 SAR eax,1 +0x00000000 SAR eax,0x1 type: sar ---- 0x00000000 OR esp,dword ptr [0xfff0] @@ -81,95 +81,95 @@ e asm.arch e asm.cpu e asm.bits wx 89e1 -pdi 1 +pdq 1 ao | grep type ?e ---- wx a168a00408 -pdi 1 +pdq 1 ao | grep type ?e ---- wx a368a00408 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 8945f0 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 8b4510 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 0f4c0d03000000 -pdi 1 +pdq 1 ao | grep type ?e ---- wx cd80 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 55 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 6a00 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 5d -pdi 1 +pdq 1 ao | grep type ?e ---- wx 83f853 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 85c0 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 83c410 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 81ec88100000 -pdi 1 +pdq 1 ao | grep type ?e ---- wx f7ea -pdi 1 +pdq 1 ao | grep type ?e ---- wx f7f2 -pdi 1 +pdq 1 ao | grep type ?e ---- wx d1e8 -pdi 1 +pdq 1 ao | grep type ?e ---- wx d1e0 -pdi 1 +pdq 1 ao | grep type ?e ---- wx d1f8 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 0b25f0ff0000 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 2325f0ff0000 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 3325f0ff0000 -pdi 1 +pdq 1 ao | grep type ?e ---- wx 8703 -pdi 1 +pdq 1 ao | grep type EOF RUN @@ -187,11 +187,11 @@ CMDS=<> 0x10); + } while (*(char *)((int16_t)in_stack_00000008 + var_6h + -1) != '\n'); + *(undefined *)((int16_t)in_stack_00000008 + var_6h + -1) = 0; + return in_stack_00000008; } EOF CMDS=<ambassador = AMBASSADOR_PURE; } else { (bright->window).sunlight = bright->morning->saved_argv[1]; - iVar2 = sym.imp.strcmp((bright->window).sunlight, 0x804a05c); + iVar2 = sym.imp.strcmp((bright->window).sunlight, data.0804a05c); if (iVar2 == 0) { bright->ambassador = AMBASSADOR_REASON; } else { @@ -1825,9 +1825,88 @@ CMDS=<morning = pMVar1; + bright->morning->saved_argc = argc; + bright->morning->saved_argv = argv; + if (bright->morning->saved_argc < 2) { + bright->ambassador = AMBASSADOR_PURE; + } else { + (bright->window).sunlight = bright->morning->saved_argv[1]; + iVar2 = sym.imp.strcmp((bright->window).sunlight, "the "); + if (iVar2 == 0) { + bright->ambassador = AMBASSADOR_REASON; + } else { + iVar2 = sym.imp.strcmp((bright->window).sunlight, "dark"); + if (iVar2 == 0) { + bright->ambassador = AMBASSADOR_REVOLUTION; + } else { + iVar2 = sym.imp.strcmp((bright->window).sunlight, "third"); + if (iVar2 == 0) { + bright->ambassador = AMBASSADOR_ECHOES; + } else { + bright->ambassador = AMBASSADOR_MILLION; + } + } + } + } + // switch table (5 cases) at 0x804a070 + switch(bright->ambassador) { + case AMBASSADOR_PURE: + sym.imp.printf("pure"); + break; + case AMBASSADOR_REASON: + sym.imp.printf("reason"); + break; + case AMBASSADOR_REVOLUTION: + sym.imp.printf("revolution"); + break; + case AMBASSADOR_ECHOES: + sym.imp.printf("echoes"); + break; + case AMBASSADOR_WALL: + sym.imp.printf("wall"); + break; + default: + if (bright->ambassador == AMBASSADOR_MILLION) { + sym.imp.printf("million"); + } + break; + case 0xbad1abe1: + break; + } + sym.PrintAmbassador(bright->ambassador, in_stack_fffffff4); + return; +} +EOF +CMDS=<morning = pMVar2; + bright->morning->saved_argc = argc; + *(char ***)((int64_t)&bright->morning->saved_argv + 4) = argv; + if (bright->morning->saved_argc < 2) { + *(undefined4 *)&bright->ambassador = 0; + } else { + (bright->window).sunlight = *(char **)(*(int64_t *)((int64_t)&bright->morning->saved_argv + 4) + 8); + iVar1 = sym.imp.strcmp((bright->window).sunlight, "the "); + if (iVar1 == 0) { + *(undefined4 *)&bright->ambassador = 1; + } else { + iVar1 = sym.imp.strcmp((bright->window).sunlight, "dark"); + if (iVar1 == 0) { + *(undefined4 *)&bright->ambassador = 2; + } else { + iVar1 = sym.imp.strcmp((bright->window).sunlight, "third"); + if (iVar1 == 0) { + *(undefined4 *)&bright->ambassador = 3; + } else { + *(undefined4 *)&bright->ambassador = 1000000; + } + } + } + } + // switch table (5 cases) at 0x402088 + switch(*(int32_t *)&bright->ambassador) { + case 0: + sym.imp.printf("pure"); + break; + case 1: + sym.imp.printf("reason"); + break; + case 2: + sym.imp.printf("revolution"); + break; + case 3: + sym.imp.printf("echoes"); + break; + case 4: + sym.imp.printf("wall"); + break; + default: + if (*(int32_t *)&bright->ambassador == 1000000) { + sym.imp.printf("million"); + } + break; + case -0x452e541f: + break; + } + sym.PrintAmbassador((uint64_t)*(uint32_t *)&bright->ambassador); + return; +} +EOF +CMDS=<morning = pMVar2; @@ -1902,7 +2068,7 @@ EOF CMDS=<ambassador = AMBASSADOR_PURE; } else { (bright->window).sunlight = bright->morning->saved_argv[1]; - iVar2 = sym.imp.strcmp((bright->window).sunlight, 0x804a05c); + iVar2 = sym.imp.strcmp((bright->window).sunlight, data.0804a05c); if (iVar2 == 0) { bright->ambassador = AMBASSADOR_REASON; } else { @@ -1995,7 +2163,7 @@ void sym.Aeropause(BrightTypedefd *bright, int32_t argc, char **argv) bright->ambassador = AMBASSADOR_PURE; } else { (bright->window).sunlight = bright->morning->saved_argv[1]; - iVar2 = sym.imp.strcmp((bright->window).sunlight, 0x804a05c); + iVar2 = sym.imp.strcmp((bright->window).sunlight, data.0804a05c); if (iVar2 == 0) { bright->ambassador = AMBASSADOR_REASON; } else { @@ -2055,7 +2223,7 @@ void sym.Aeropause(BrightTypedefdPtr bright, int32_t argc, char **argv) bright->ambassador = AMBASSADOR_PURE; } else { (bright->window).sunlight = bright->morning->saved_argv[1]; - iVar2 = sym.imp.strcmp((bright->window).sunlight, 0x804a05c); + iVar2 = sym.imp.strcmp((bright->window).sunlight, data.0804a05c); if (iVar2 == 0) { bright->ambassador = AMBASSADOR_REASON; } else { @@ -2105,17 +2273,17 @@ CMDS=< - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 494f4c4920437261636b6d65204c6576656c2030 7830350a0050617373776f72 - - - + + + + 50617373776f72643a2000257300000000000000 00ffffffffffffffffffffff - - - + + + -- undefined4 main(void) { - int32_t var_78h; + int32_t var_88h; + int32_t var_7ch; sym.imp.printf("IOLI Crackme Level 0x05\n"); sym.imp.printf("Password: "); - sym.imp.scanf(0x80486b2, &var_78h); - sym.check((int32_t)&var_78h); + sym.imp.scanf(0x80486b2, &var_7ch); + sym.check((int32_t)&var_7ch); return 0; } -- |  0x08048540 |undefined4 main(void) |{ - | int32_t var_78h; + | int32_t var_88h; + | int32_t var_7ch; | 0x08048566 | sym.imp.printf("IOLI Crackme Level 0x05\n"); 0x08048572 | sym.imp.printf("Password: "); - 0x08048585 | sym.imp.scanf(0x80486b2, &var_78h); - 0x0804858a | sym.check((int32_t)&var_78h); + 0x08048585 | sym.imp.scanf(0x80486b2, &var_7ch); + 0x0804858a | sym.check((int32_t)&var_7ch); 0x0804859b | return 0; |} EOF @@ -2511,17 +2761,17 @@ FILE=rizin-testbins/elf/hello_world ARGS=-B 0x1000000000000000 EXPECT=<