diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc index add7294093..af48da0786 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.cc @@ -5670,16 +5670,59 @@ AddTreeState::AddTreeState(PcodeOp *op,int4 slot) isSubtype = false; } +/// Examine a CPUI_INT_MULT element in the middle of the add tree. Determine if we treat +/// the output simply as a leaf, or if the multiply needs to be distributed to an +/// additive subtree. If the Varnode is a leaf of the tree, return \b true if +/// it is considered a multiple of the base data-type size. If the Varnode is the +/// root of another additive sub-tree, return \b true if no sub-node is a multiple. +/// \param vn is the output Varnode of the operation +/// \param op is the CPUI_INT_MULT operation +/// \return \b true if there are no multiples of the base data-type size discovered +bool AddTreeState::checkMultTerm(Varnode *vn,PcodeOp *op) + +{ + Varnode *vnconst = op->getIn(1); + Varnode *vnterm = op->getIn(0); + uintb val,rem; + + if (vnterm->isFree()) { + valid = false; + return false; + } + if (vnconst->isConstant()) { + val = vnconst->getOffset(); + if (size == 0) + rem = val; + else { + intb sval = (intb) val; + sign_extend(sval, vn->getSize() * 8 - 1); + rem = sval % size; + } + if (rem != 0) { + if ((val > size) && (size != 0)) { + valid = false; // Size is too big: pointer type must be wrong + return false; + } + return true; + } + if (rem == 0) { + multiple.push_back(vnterm); + coeff.push_back(val); + return false; + } + } + return true; +} + /// If the given Varnode is a constant or multiplicative term, update /// totals. If the Varnode is additive, traverse its sub-terms. /// \param vn is the given Varnode term -/// \return \b true if Varnode is a NON-multiple +/// \return \b true if the sub-tree rooted at the given Varnode contains no multiples bool AddTreeState::checkTerm(Varnode *vn) { uintb val; intb rem; - Varnode *vnconst,*vnterm; PcodeOp *def; if (vn == ptr) return false; @@ -5707,42 +5750,26 @@ bool AddTreeState::checkTerm(Varnode *vn) valid = false; return false; } - if (def->code() == CPUI_INT_MULT) { // Check for constant coeff indicating size - vnconst = def->getIn(1); - vnterm = def->getIn(0); - if (vnconst->isConstant()) { - val = vnconst->getOffset(); - if (size == 0) - rem = val; - else { - intb sval = (intb) val; - sign_extend(sval, vn->getSize() * 8 - 1); - rem = sval % size; - } - if (rem!=0) { - if ((val > size)&&(size!=0)) { - valid = false; // Size is too big: pointer type must be wrong - return false; - } - return true; - } - if (rem==0) { - multiple.push_back(vnterm); - coeff.push_back(val); - return false; - } - } - } + if (def->code() == CPUI_INT_MULT) // Check for constant coeff indicating size + return checkMultTerm(vn, def); + } + else if (vn->isFree()) { + valid = false; + return false; } return true; } -/// Recursively walk the sub-tree from the given root. This routine returns -/// \b true if no leaf nodes of the tree have been identified in the sub-tree. -/// In this case, this root may itself be a leaf (we don't know yet), otherwise -/// we know this root is \e not a leaf. +/// Recursively walk the sub-tree from the given root. +/// Terms that are a \e multiple of the base data-type size are accumulated either in +/// the the sum of constant multiples or the container of non-constant multiples. +/// Terms that are a \e non-multiple are accumulated either in the sum of constant +/// non-multiples or the container of non-constant non-multiples. The constant +/// non-multiples are counted twice, once in the sum, and once in the container. +/// This routine returns \b true if no node of the sub-tree is considered a multiple +/// of the base data-type size (or \b false if any node is considered a multiple). /// \param op is the root of the sub-expression to traverse -/// \return \b true if the given root might be a leaf +/// \return \b true if the given sub-tree contains no multiple nodes bool AddTreeState::spanAddTree(PcodeOp *op) { @@ -5754,12 +5781,11 @@ bool AddTreeState::spanAddTree(PcodeOp *op) if (!valid) return false; if (one_is_non&&two_is_non) return true; - // Reaching here we know either, slot 0 or 1 is a leaf if (one_is_non) nonmult.push_back(op->getIn(0)); if (two_is_non) nonmult.push_back(op->getIn(1)); - return false; // We are definitely not a leaf + return false; // At least one of the sides contains multiples } /// Make final calcultions to determine if a pointer to a sub data-type of the base diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh index faab0d4746..bd59e17700 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ruleaction.hh @@ -31,12 +31,14 @@ /// /// Given a base pointer of known data-type and an additive expression involving /// the pointer, group the terms of the expression into: -/// - Constant multiple of the base data-type +/// - A constant multiple of the base data-type /// - Non-constant multiples of the base data-type -/// - Multiples of an array element size: rewrite using PTRADD -/// - Drill down into sub-components of the base data-type: rewrite using PTRSUB -/// - Remaining offsets +/// - An constant offset to a sub-component of the base data-type +/// - An remaining terms /// +/// The \e multiple terms are rewritten using a CPUI_PTRADD. The constant offset +/// is rewritten using a CPUI_PTRSUB. Other terms are added back in. Analysis may cause +/// multiplication (CPUI_INT_MULT) by a constant to be distributed to its CPUI_INT_ADD input. class AddTreeState { PcodeOp *baseOp; ///< Base of the ADD tree Varnode *ptr; ///< The pointer varnode @@ -52,6 +54,7 @@ class AddTreeState { uintb multsum; ///< Sum of multiple constants uintb nonmultsum; ///< Sum of non-multiple constants bool isSubtype; ///< Is there a sub-type (using CPUI_PTRSUB) + bool checkMultTerm(Varnode *vn,PcodeOp *op); ///< Accumulate details of INT_MULT term and continue traversal if appropriate bool checkTerm(Varnode *vn); ///< Accumulate details of given term and continue tree traversal bool spanAddTree(PcodeOp *op); ///< Walk the given sub-tree void calcSubtype(void); ///< Calculate final sub-type offset