diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/OptionChooser.java b/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/OptionChooser.java index e2de867069..5a5e8164f4 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/OptionChooser.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/util/importer/OptionChooser.java @@ -47,11 +47,10 @@ public interface OptionChooser { * Gets the {@link Loader} arguments associated with this {@link OptionChooser} * * @return The {@link Loader} arguments associated with this {@link OptionChooser} - * @throws UnsupportedOperationException if a subclass has not implemented this method * @deprecated Use {@link ProgramLoader.Builder#loaderArgs(List)} instead */ @Deprecated(since = "12.0", forRemoval = true) public default List> getArgs() { - throw new UnsupportedOperationException(); + return List.of(); } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.cc index d81f38d851..b5e31405eb 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.cc @@ -767,7 +767,7 @@ PcodeOp *HeapSequence::buildStringCopy(void) /// the initial input and final output are gathered. /// \param indirects will hold the INDIRECT ops attached to sequence STOREs /// \param pairs will hold Varnode pairs where the first in the pair is the input and the second is the output -void HeapSequence::gatherIndirectPairs(vector &indirects,vector &pairs) +void HeapSequence::gatherIndirectPairs(vector &indirects,vector &pairs) { for(int4 i=0;i &indirects,vectorisMark()) break; invn = defOp->getIn(0); } - pairs.push_back(invn); - pairs.push_back(outvn); - data.opUnsetOutput(op); + pairs.emplace_back(invn,outvn); } } for(int4 i=0;iclearMark(); } +bool HeapSequence::IndirectPair::compareOutput(const IndirectPair *a,const IndirectPair *b) + +{ + Varnode *vn1 = a->outVn; + Varnode *vn2 = b->outVn; + if (vn1->getSpace() != vn2->getSpace()) + return vn1->getSpace()->getIndex() < vn2->getSpace()->getIndex(); + if (vn1->getOffset() != vn2->getOffset()) + return vn1->getOffset() < vn2->getOffset(); + if (vn1->getSize() != vn2->getSize()) + return vn1->getSize() < vn2->getSize(); + return false; +} + +/// Its possible that INDIRECTs collected from different \e effect ops may share +/// the same output storage. Find any output Varnodes that share storage and +/// replace all their reads with a single representative Varnode. +/// \param pairs is the list of INDIRECT pairs +/// \return \b true if the deduplication succeeded +bool HeapSequence::deduplicatePairs(vector &pairs) + +{ + if (pairs.empty()) return true; + vector copy(pairs.size(),(IndirectPair *)0); + for(int4 i=0;ioutVn; + int4 overlap = head->outVn->characterizeOverlap(*vn); + if (overlap == 1) + return false; // Partial overlap + if (overlap == 2) { + if (copy[i]->inVn != head->inVn) { + return false; // Same storage coming from different sources + } + copy[i]->markDuplicate(); + dupCount += 1; // Found a duplicate, keep the same head for next iteration + } + else // No overlap, move to next headVn + head = copy[i]; + } + if (dupCount > 0) { + head = copy[0]; + for(int4 i=1;iisDuplicate()) { + data.totalReplace(copy[i]->outVn, head->outVn); + } + else + head = copy[i]; + } + } + return true; +} /// If the STORE pointer no longer has any other uses, remove the PTRADD producing it, recursively, /// up to the base pointer. INDIRECT ops surrounding any STORE that is removed are replaced with /// INDIRECTs around the user-op replacing the STOREs. +/// \param indirects are the list of INDIRECTs cause by the STOREs +/// \param indirectPairs are the flow pairs across the STOREs that need to be preserved /// \param replaceOp is the user-op replacement for the STOREs -void HeapSequence::removeStoreOps(PcodeOp *replaceOp) +void HeapSequence::removeStoreOps(vector &indirects,vector &indirectPairs,PcodeOp *replaceOp) { - vector indirects; - vector indirectPairs; vector scratch; - gatherIndirectPairs(indirects, indirectPairs); + for(int4 i=0;igetDef()); + } for(int4 i=0;igetAddr()); data.opSetOpcode(newInd, CPUI_INDIRECT); - data.opSetOutput(newInd,outvn); - data.opSetInput(newInd,invn,0); + data.opSetOutput(newInd,indirectPairs[i].outVn); + data.opSetInput(newInd,indirectPairs[i].inVn,0); data.opSetInput(newInd,data.newVarnodeIop(replaceOp),1); data.opInsertBefore(newInd, replaceOp); } @@ -871,10 +927,15 @@ HeapSequence::HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root) bool HeapSequence::transform(void) { + vector indirects; + vector indirectPairs; + gatherIndirectPairs(indirects, indirectPairs); + if (!deduplicatePairs(indirectPairs)) + return false; PcodeOp *memCpyOp = buildStringCopy(); if (memCpyOp == (PcodeOp *)0) return false; - removeStoreOps(memCpyOp); + removeStoreOps(indirects,indirectPairs,memCpyOp); return true; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.hh index dbfc3c512a..5df6bf1b90 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/constseq.hh @@ -84,6 +84,16 @@ public: /// a single string into memory. If the transform() method is called, an explicit string is constructed, and /// the STOREs are replaced with a \b strncpy or similar CALLOTHER that takes the string as its source input. class HeapSequence : public ArraySequence { + /// \brief Helper class containing Varnode pairs that flow across a sequence of INDIRECTs + class IndirectPair { + public: + Varnode *inVn; ///< Input to INDIRECTs + Varnode *outVn; ///< Output of INDIRECTs + IndirectPair(Varnode *in,Varnode *out) { inVn = in; outVn = out; } ///< Constructor + void markDuplicate(void) { inVn = (Varnode *)0; } ///< Note that \b this is a duplicate of another pair + bool isDuplicate(void) const { return (inVn == (Varnode *)0); } ///< Return \b true if \b this is marked as a duplicate + static bool compareOutput(const IndirectPair *a,const IndirectPair *b); ///< Compare pairs by output storage + }; Varnode *basePointer; ///< Pointer that sequence is stored to uint8 baseOffset; ///< Offset relative to pointer to root STORE AddrSpace *storeSpace; ///< Address space being STOREed to @@ -98,8 +108,9 @@ class HeapSequence : public ArraySequence { bool testValue(PcodeOp *op); ///< Test if a STORE value has the matching form for the sequence bool collectStoreOps(void); ///< Collect ops STOREing into a memory region from the same root pointer PcodeOp *buildStringCopy(void); ///< Build the strncpy,wcsncpy, or memcpy function with string as input - void gatherIndirectPairs(vector &indirects,vector &pairs); - void removeStoreOps(PcodeOp *replaceOp); ///< Remove all STORE ops from the basic block + void gatherIndirectPairs(vector &indirects,vector &pairs); + bool deduplicatePairs(vector &pairs); ///< Find and eliminate duplicate INDIRECT pairs + void removeStoreOps(vector &indirects,vector &indirectPairs,PcodeOp *replaceOp); ///< Remove all STORE ops from the basic block public: HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root); bool transform(void); ///< Transform STOREs into a single memcpy user-op