diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc index 4e3ce8b487..40cf0e718a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/ifacedecomp.cc @@ -2485,17 +2485,28 @@ void IfcAnalyzeRange::execute(istream &s) Varnode *vn = iface_read_varnode(dcp,s); vector sinks; + vector reads; sinks.push_back(vn); + for(list::const_iterator iter=vn->beginDescend();iter!=vn->endDescend();++iter) { + PcodeOp *op = *iter; + if (op->code() == CPUI_LOAD || op->code() == CPUI_STORE) + reads.push_back(op); + } Varnode *stackReg = dcp->fd->findSpacebaseInput(dcp->conf->getStackSpace()); ValueSetSolver vsSolver; - vsSolver.establishValueSets(sinks, stackReg); + vsSolver.establishValueSets(sinks, reads, stackReg); vsSolver.solve(10000); list::const_iterator iter; for(iter=vsSolver.beginValueSets();iter!=vsSolver.endValueSets();++iter) { (*iter).printRaw(*status->optr); *status->optr << endl; } - } + map::const_iterator riter; + for(riter=vsSolver.beginValueSetReads();riter!=vsSolver.endValueSetReads();++riter) { + (*riter).second.printRaw(*status->optr); + *status->optr << endl; + } +} #ifdef OPACTION_DEBUG diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.cc index 64ce4acdc9..cb3361c3b4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.cc @@ -1472,6 +1472,7 @@ void ValueSet::doWidening(const CircleRange &newRange) const Equation &landmark(equations.back()); if (landmark.slot == numParams && typeCode == landmark.typeCode) { bool leftIsStable = range.getMin() == newRange.getMin(); + range = newRange; // Preserve any new step information if (landmark.range.contains(range)) { range.widen(landmark.range,leftIsStable); return; @@ -1599,17 +1600,11 @@ bool ValueSet::iterate(void) setFull(); return true; } - typeCode = inSet1->typeCode; } else if (numParams == 2) { ValueSet *inSet1 = op->getIn(0)->getValueSet(); ValueSet *inSet2 = op->getIn(1)->getValueSet(); - typeCode = inSet1->typeCode + inSet2->typeCode; - if (inSet1->typeCode != 0 && inSet2->typeCode != 0) { // Combining two based constants - typeCode = 0; - res.setFull(vn->getSize()); - } - else if (equations.size() == 0) { + if (equations.size() == 0) { if (!res.pushForwardBinary(opCode, inSet1->range, inSet2->range, inSet1->vn->getSize(), vn->getSize(), 32)) { setFull(); return true; @@ -1668,6 +1663,57 @@ void ValueSet::printRaw(ostream &s) const range.printRaw(s); } +/// \param o is the PcodeOp reading the value set +/// \param slt is the input slot the values are coming in from +void ValueSetRead::setPcodeOp(PcodeOp *o,int4 slt) + +{ + typeCode = 0; + op = o; + slot = slt; + equationTypeCode = 100; +} + +/// \param slt is the given slot +/// \param type is the constraint characteristic +/// \param constraint is the given range +void ValueSetRead::addEquation(int4 slt,int4 type,const CircleRange &constraint) + +{ + if (slot == slt) { + equationTypeCode = type; + equationConstraint = constraint; + } +} + +/// This value set will be the same as the ValueSet of the Varnode being read but may +/// be modified due to additional control-flow constraints +void ValueSetRead::compute(void) + +{ + Varnode *vn = op->getIn(slot); + ValueSet *valueSet = vn->getValueSet(); + typeCode = valueSet->getTypeCode(); + range = valueSet->getRange(); + if (typeCode == equationTypeCode) { + if (0 != range.intersect(equationConstraint)) { + range = equationConstraint; + } + } +} + +/// \param s is the stream to print to +void ValueSetRead::printRaw(ostream &s) const + +{ + s << "Read: " << get_opname(op->code()); + if (typeCode == 0) + s << " absolute "; + else + s << " stackptr "; + range.printRaw(s); +} + /// \brief Construct an iterator over the outbound edges of the given ValueSet node /// /// Mostly this just forwards the ValueSets attached to output Varnodes @@ -1848,6 +1894,10 @@ void ValueSetSolver::applyConstraints(Varnode *vn,int4 type,const CircleRange &r FlowBlock *falseBlock = splitPoint->getFalseOut(); for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) { PcodeOp *op = *iter; + if (op->isMark()) { // Special read site being tracked + readNodes[op->getSeqNum()].addEquation(op->getSlot(vn), type, range); + continue; + } Varnode *outVn = op->getOut(); if (outVn == (Varnode *)0) continue; if (!outVn->isMark()) continue; @@ -2063,8 +2113,9 @@ void ValueSetSolver::generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch /// Given a set of sinks, find all the Varnodes that flow directly into them. /// \param sinks is the list terminating Varnodes +/// \param reads are add-on PcodeOps where we would like to know input ValueSets at the point of read /// \param stackReg (if non-NULL) gives the stack pointer (for keeping track of relative offsets) -void ValueSetSolver::establishValueSets(const vector &sinks,Varnode *stackReg) +void ValueSetSolver::establishValueSets(const vector &sinks,const vector &reads,Varnode *stackReg) { vector worklist; @@ -2107,7 +2158,21 @@ void ValueSetSolver::establishValueSets(const vector &sinks,Varnode * worklist.push_back(inVn); } } + for(int4 i=0;inumInput();++slot) { + Varnode *vn = op->getIn(slot); + if (vn->isMark()) { + readNodes[op->getSeqNum()].setPcodeOp(op, slot); + op->setMark(); // Mark read ops for equation generation stage + break; // Only 1 read allowed + } + } + } generateConstraints(worklist); + for(int4 i=0;iclearMark(); // Clear marks on read ops + establishTopologicalOrder(); for(int4 i=0;iclearMark(); @@ -2170,4 +2235,7 @@ void ValueSetSolver::solve(int4 max) curSet = curSet->next; } } + map::iterator riter; + for(riter=readNodes.begin();riter!=readNodes.end();++riter) + (*riter).second.compute(); // Calculate any follow-on value sets } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.hh index 7a726b71c1..f784829739 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/rangeutil.hh @@ -159,6 +159,29 @@ public: } ///< Construct empty partition }; +/// \brief A special form of ValueSet associated with the \e read \e point of a Varnode +/// +/// When a Varnode is read, it may have a more restricted range at the point of the read +/// compared to the full scope. This class officially stores the value set at the point +/// of the read (specified by PcodeOp and slot). It is computed as a final step after +/// the main iteration has completed. +class ValueSetRead { + friend class ValueSetSolver; + int4 typeCode; ///< 0=pure constant 1=stack relative + PcodeOp *op; ///< The PcodeOp at the point of the value set read + int4 slot; ///< The slot being read + CircleRange range; ///< Range of values or offsets in this set + int4 equationTypeCode; ///< Type code of the associated equation + CircleRange equationConstraint; ///< Constraint associated with the equation + void setPcodeOp(PcodeOp *o,int4 slt); ///< Establish \e read this value set corresponds to + void addEquation(int4 slt,int4 type,const CircleRange &constraint); ///< Insert an equation restricting \b this value set +public: + int4 getTypeCode(void) const { return typeCode; } ///< Return '0' for normal constant, '1' for spacebase relative + const CircleRange &getRange(void) const { return range; } ///< Get the actual range of values + void compute(void); ///< Compute \b this value set + void printRaw(ostream &s) const; ///< Write a text description of \b to the given stream +}; + /// \brief Class the determines a ValueSet for each Varnode in a data-flow system /// /// This class uses \e value \e set \e analysis to calculate (an overestimation of) @@ -185,6 +208,7 @@ class ValueSetSolver { }; list valueNodes; ///< Storage for all the current value sets + map readNodes; ///< Additional, after iteration, add-on value sets Partition orderPartition; ///< Value sets in iteration order list recordStorage; ///< Storage for the Partitions establishing components vector rootNodes; ///< Values treated as inputs @@ -206,11 +230,13 @@ class ValueSetSolver { bool checkRelativeConstant(Varnode *vn,int4 &typeCode,uintb &value) const; ///< Check if the given Varnode is a \e relative constant void generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch); ///< Try to find a \e relative constraint public: - void establishValueSets(const vector &sinks,Varnode *stackReg); ///< Build value sets for a data-flow system + void establishValueSets(const vector &sinks,const vector &reads,Varnode *stackReg); ///< Build value sets for a data-flow system int4 getNumIterations(void) const { return numIterations; } ///< Get the current number of iterations void solve(int4 max); ///< Iterate the ValueSet system until it stabilizes - list::const_iterator beginValueSets(void) { return valueNodes.begin(); } ///< Start of all ValueSets in the system - list::const_iterator endValueSets(void) { return valueNodes.end(); } ///< End of all ValueSets in the system + list::const_iterator beginValueSets(void) const { return valueNodes.begin(); } ///< Start of all ValueSets in the system + list::const_iterator endValueSets(void) const { return valueNodes.end(); } ///< End of all ValueSets in the system + map::const_iterator beginValueSetReads(void) const { return readNodes.begin(); } ///< Start of ValueSetReads + map::const_iterator endValueSetReads(void) const { return readNodes.end(); } ///< End of ValueSetReads }; /// \param op2 is the range to compare \b this to