diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index 42afbbfa24..cdfe2fca0c 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -720,6 +720,39 @@ FlowBlock *FlowBlock::findCommonBlock(FlowBlock *bl1,FlowBlock *bl2) return common; } +/// Find the most immediate dominating FlowBlock of all blocks in the given set. +/// The container must not be empty. +/// \param blockSet is the given set of blocks +/// \return the most immediate dominating FlowBlock +FlowBlock *FlowBlock::findCommonBlock(const vector &blockSet) + +{ + vector markedSet; + FlowBlock *res = blockSet[0]; + int4 bestIndex = res->getIndex(); + res->setMark(); + markedSet.push_back(res); + for(int4 i=0;igetIndex() > bestIndex) { + if (bl->isMark()) break; + bl->setMark(); + markedSet.push_back(bl); + bl = bl->getImmedDom(); + } + if (bl->isMark()) continue; + res = bl; + bestIndex = res->getIndex(); + res->setMark(); + markedSet.push_back(res); + } + for(int4 i=0;iclearMark(); + return res; +} + /// Add the given FlowBlock to the list and make \b this the parent /// Update \b index so that it has the minimum over all components /// \param bl is the given FlowBlock diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index 6c56eedee6..d4714bb282 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -257,6 +257,7 @@ public: static bool compareBlockIndex(const FlowBlock *bl1,const FlowBlock *bl2); ///< Compare FlowBlock by index static bool compareFinalOrder(const FlowBlock *bl1,const FlowBlock *bl2); ///< Final FlowBlock comparison static FlowBlock *findCommonBlock(FlowBlock *bl1,FlowBlock *bl2); ///< Find the common dominator of two FlowBlocks + static FlowBlock *findCommonBlock(const vector &blockSet); ///< Find common dominator of multiple FlowBlocks }; /// \brief A control-flow block built out of sub-components diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc index aab1dec579..3d9b14e2e0 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/coreaction.cc @@ -3579,6 +3579,7 @@ bool ActionCopyMarker::shadowedVarnode(const Varnode *vn) int4 ActionCopyMarker::apply(Funcdata &data) { + vector multiCopy; list::const_iterator iter; PcodeOp *op; HighVariable *h1,*h2,*h3; @@ -3597,8 +3598,10 @@ int4 ActionCopyMarker::apply(Funcdata &data) } else { // COPY between different HighVariables if (h1->hasCopyIn()) { // If we've seen other COPYs into this high - if (!h1->isCopyProcessed()) // and we haven't searched before, - data.getMerge().markRedundantCopies(h1); // search for redundant COPYs + if (!h1->isCopyProcessed()) { // and we haven't searched before, + multiCopy.push_back(h1); + h1->setCopyProcessed(); + } } else h1->setCopyIn(); @@ -3641,6 +3644,8 @@ int4 ActionCopyMarker::apply(Funcdata &data) break; } } + for(int4 i=0;i ©,int4 pos,int4 size) + +{ + vector blockSet; + for(int4 i=0;igetParent()); + BlockBasic *domBl = (BlockBasic *)FlowBlock::findCommonBlock(blockSet); + Varnode *rootVn = copy[pos]->getIn(0); + bool domCopyIsNew; + PcodeOp *domCopy; + Varnode *domVn; + if (domBl == copy[pos]->getParent()) { + domCopyIsNew = false; + domCopy = copy[pos]; + domVn = domCopy->getOut(); + } + else { + domCopyIsNew = true; + domCopy = data.newOp(1,domBl->getStop()); + data.opSetOpcode(domCopy, CPUI_COPY); + domVn = data.newUnique(rootVn->getSize(), rootVn->getType()); + data.opSetOutput(domCopy,domVn); + data.opSetInput(domCopy,rootVn,0); + data.opInsertEnd(domCopy, domBl); + } + // Cover created by removing all the COPYs from rootVn + Cover bCover; + for(int4 i=0;inumInstances();++i) { + Varnode *vn = high->getInstance(i); + if (vn->isWritten()) { + PcodeOp *op = vn->getDef(); + if (op->code() == CPUI_COPY) { + if (op->getIn(0)->copyShadow(rootVn)) continue; + } + } + bCover.merge(*vn->getCover()); + } + + int4 count = size; + for(int4 i=0;igetOut(); + list::const_iterator iter; + Cover aCover; + aCover.addDefPoint(domVn); + for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter) + aCover.addRefPoint(*iter, outVn); + if (bCover.intersect(aCover)>1) { + count -= 1; + op->setMark(); + } + } + + if (count <= 1) { // Don't bother if we only replace one COPY with another + for (int4 i = 0; i < size; ++i) + copy[pos + i]->setMark(); + count = 0; + if (domCopyIsNew) { + data.opDestroy(domCopy); + } + } + // Replace all non-intersecting COPYs with read of dominating Varnode + for(int4 i=0;iisMark()) + op->clearMark(); + else { + Varnode *outVn = op->getOut(); + if (outVn != domVn) { + outVn->getHigh()->remove(outVn); + data.totalReplace(outVn, domVn); + data.opDestroy(op); + } + } + } + if (count > 0 && domCopyIsNew) { + high->merge(domVn->getHigh(),false); + } +} + /// \brief Search for and mark redundant COPY ops into the given high as \e non-printing /// /// Trimming during the merge process can insert multiple COPYs from the same source. In some /// cases, one or more COPYs may be redundant and shouldn't be printed. This method searches /// for redundancy among COPY ops that assign to the given HighVariable. /// \param high is the given HighVariable -/// \return \b true if any redundant COPYs were discovered -bool Merge::markRedundantCopies(HighVariable *high) +/// \param copy is the list of COPYs coming from the same source HighVariable +/// \param pos is the starting index of a set of COPYs coming from the same Varnode +/// \param size is the number of Varnodes in the set coming from the same Varnode +void Merge::markRedundantCopies(HighVariable *high,vector ©,int4 pos,int4 size) + +{ + for (int4 i = size - 1; i > 0; --i) { + PcodeOp *subOp = copy[pos + i]; + if (subOp->isDead()) continue; + for (int4 j = i - 1; j >= 0; --j) { + // Make sure earlier index provides dominant op + PcodeOp *domOp = copy[pos + j]; + if (domOp->isDead()) continue; + if (checkCopyPair(high, domOp, subOp)) { + data.opSetFlag(subOp, PcodeOp::nonprinting); + break; + } + } + } +} + +void Merge::processCopyTrims(HighVariable *high) { - bool hasRedundant = false; vector copyIns; - high->setCopyProcessed(); // Find all the COPY ops into this HighVariable from a different HighVariable for(int4 i=0;inumInstances();++i) { Varnode *vn = high->getInstance(i); @@ -994,21 +1093,11 @@ bool Merge::markRedundantCopies(HighVariable *high) sz += 1; } if (sz > 1) { // If there is more than one COPY in a group - for(int4 i=sz-1;i>0;--i) { - PcodeOp *subOp = copyIns[pos+i]; - for(int4 j=i-1;j>=0;--j) { - // Make sure earlier index provides dominant op - if (checkCopyPair(high,copyIns[pos+j],subOp)) { - data.opSetFlag(subOp, PcodeOp::nonprinting); - hasRedundant = true; - break; - } - } - } + buildDominantCopy(high, copyIns, pos, sz); + markRedundantCopies(high, copyIns, pos, sz); } pos += sz; } - return hasRedundant; } /// \brief Perform low-level details of merging two HighVariables if possible diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh index f3f5eb3e36..f02df3502f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/merge.hh @@ -105,6 +105,8 @@ class Merge { void mergeLinear(vector &highvec); bool merge(HighVariable *high1,HighVariable *high2,bool isspeculative); bool checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp); + void buildDominantCopy(HighVariable *high,vector ©,int4 pos,int4 size); + void markRedundantCopies(HighVariable *high,vector ©,int4 pos,int4 size); public: Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function bool intersection(HighVariable *a,HighVariable *b); @@ -118,7 +120,7 @@ public: void mergeMarker(void); void mergeAdjacent(void); bool hideShadows(HighVariable *high); - bool markRedundantCopies(HighVariable *high); + void processCopyTrims(HighVariable *high); }; /// \brief Compare HighVariables by the blocks they cover diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh index 40bb6ed8f3..2bf0d27ed3 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/variable.hh @@ -63,7 +63,6 @@ private: void updateFlags(void) const; ///< (Re)derive boolean properties of \b this from the member Varnodes void updateCover(void) const; ///< (Re)derive the cover of \b this from the member Varnodes void updateType(void) const; ///< (Re)derive the data-type for \b this from the member Varnodes - void setCopyProcessed(void) const { highflags |= copy_processed; } ///< Mark that \b this has had its COPY ins processed public: HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type @@ -114,6 +113,7 @@ public: void setCopyIn(void) const { highflags |= copy_in; } ///< Mark the existence of COPY ops into \b this bool hasCopyIn(void) const { return ((highflags©_in)!=0); } ///< Are there COPY ops into \b this bool isCopyProcessed(void) const { return ((highflags©_processed)!=0); } ///< Have COPY ops into \b this been processed + void setCopyProcessed(void) const { highflags |= copy_processed; } ///< Mark that \b this has had its COPY ins processed /// \brief Determine if \b this HighVariable has an associated cover. ///