From ec9bfa86a77d14de6934112de4b8cc24f3158dbd Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Tue, 18 Jun 2019 16:26:30 -0400 Subject: [PATCH] solving stack STOREs --- .../Decompiler/src/decompile/cpp/funcdata.hh | 3 +- .../Decompiler/src/decompile/cpp/heritage.cc | 69 ++++++++++++++--- .../Decompiler/src/decompile/cpp/heritage.hh | 5 +- .../Decompiler/src/decompile/cpp/varmap.cc | 77 +++++++++++-------- .../Decompiler/src/decompile/cpp/varmap.hh | 2 + 5 files changed, 112 insertions(+), 44 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh index 62b402701a..f0d9f82338 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh @@ -232,7 +232,8 @@ public: /// \return \b true if the Varnode is fully linked bool isHeritaged(Varnode *vn) { return (heritage.heritagePass(vn->getAddr())>=0); } - const list &getLoadGuards(void) const { return heritage.getLoadGuards(); } + const list &getLoadGuards(void) const { return heritage.getLoadGuards(); } ///< Get the list of guarded LOADs + const list &getStoreGuards(void) const { return heritage.getStoreGuards(); } ///< Get the list of guarded STOREs // Function prototype and call specification routines int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc index 7307e4e124..d6c94f63df 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc @@ -656,18 +656,35 @@ void LoadGuard::finalizeRange(const ValueSetRead &valueSet) void Heritage::analyzeNewLoadGuards(void) { - if (loadGuard.empty()) return; - if (loadGuard.back().analysisState != 0) return; // Nothing new - list::iterator startIter = loadGuard.end(); + bool nothingToDo = true; + if (!loadGuard.empty()) { + if (loadGuard.back().analysisState == 0) // Check if unanalyzed + nothingToDo = false; + } + if (!storeGuard.empty()) { + if (storeGuard.back().analysisState == 0) + nothingToDo = false; + } + if (nothingToDo) return; + vector sinks; vector reads; - while(startIter != loadGuard.begin()) { - --startIter; - LoadGuard &guard( *startIter ); + list::iterator loadIter = loadGuard.end(); + while(loadIter != loadGuard.begin()) { + --loadIter; + LoadGuard &guard( *loadIter ); if (guard.analysisState != 0) break; reads.push_back(guard.op); sinks.push_back(guard.op->getIn(1)); // The CPUI_LOAD pointer } + list::iterator storeIter = storeGuard.end(); + while(storeIter != storeGuard.begin()) { + --storeIter; + LoadGuard &guard( *storeIter ); + if (guard.analysisState != 0) break; + reads.push_back(guard.op); + sinks.push_back(guard.op->getIn(1)); // The CPUI_STORE pointer + } AddrSpace *stackSpc = fd->getArch()->getStackSpace(); Varnode *stackReg = (Varnode *)0; if (stackSpc != (AddrSpace *)0 && stackSpc->numSpacebase() > 0) @@ -678,7 +695,13 @@ void Heritage::analyzeNewLoadGuards(void) vsSolver.solve(10000,widener); list::iterator iter; bool runFullAnalysis = false; - for(iter=startIter;iter!=loadGuard.end(); ++iter) { + for(iter=loadIter;iter!=loadGuard.end(); ++iter) { + LoadGuard &guard( *iter ); + guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum())); + if (guard.analysisState == 0) + runFullAnalysis = true; + } + for(iter=storeIter;iter!=storeGuard.end(); ++iter) { LoadGuard &guard( *iter ); guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum())); if (guard.analysisState == 0) @@ -687,7 +710,11 @@ void Heritage::analyzeNewLoadGuards(void) if (runFullAnalysis) { WidenerFull fullWidener; vsSolver.solve(10000, fullWidener); - for (iter = startIter; iter != loadGuard.end(); ++iter) { + for (iter = loadIter; iter != loadGuard.end(); ++iter) { + LoadGuard &guard(*iter); + guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum())); + } + for (iter = storeIter; iter != storeGuard.end(); ++iter) { LoadGuard &guard(*iter); guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum())); } @@ -708,6 +735,20 @@ void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc) loadGuard.back().set(op,spc,node.offset); } +/// \brief Generate a guard record given an indexed STORE to a stack space +/// +/// Record the STORE op and the (likely) range of addresses in the stack space that +/// might be stored to. +/// \param node is the path element containing the constructed Address +/// \param op is the STORE PcodeOp +/// \param spc is the stack space +void Heritage::generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc) + +{ + storeGuard.push_back(LoadGuard()); + storeGuard.back().set(op,spc,node.offset); +} + /// \brief Trace input stackpointer to any indexed loads /// /// Look for expressions of the form val = *(SP(i) + vn + #c), where the base stack @@ -715,7 +756,7 @@ void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc) /// value is loaded from the resulting address. The LOAD operations are added to the list /// of ops that potentially need to be guarded during a heritage pass. /// \param spc is the particular address space with a stackpointer (into it) -void Heritage::discoverIndexedStackLoads(AddrSpace *spc) +void Heritage::discoverIndexedStackPointers(AddrSpace *spc) { // We need to be careful of exponential ladders, so we mark Varnodes independently of @@ -791,6 +832,13 @@ void Heritage::discoverIndexedStackLoads(AddrSpace *spc) } break; } + case CPUI_STORE: + { + if (curNode.traversals != 0) { + generateStoreGuard(curNode, op, spc); + } + break; + } default: break; } @@ -2039,7 +2087,7 @@ void Heritage::heritage(void) if (pass < info->delay) continue; // It is too soon to heritage this space if (!info->loadGuardSearch) { info->loadGuardSearch = true; - discoverIndexedStackLoads(info->space); + discoverIndexedStackPointers(info->space); } needwarning = false; iter = fd->beginLoc(space); @@ -2205,6 +2253,7 @@ void Heritage::clear(void) merge.clear(); clearInfoList(); loadGuard.clear(); + storeGuard.clear(); maxdepth = -1; pass = 0; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh index eb0f58cd7b..7c1486a3ff 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh @@ -204,6 +204,7 @@ class Heritage { vector merge; ///< Calculate merge points (blocks containing phi-nodes) vector infolist; ///< Heritage status for individual address spaces list loadGuard; ///< List of LOAD operations that need to be guarded + list storeGuard; ///< List of STORE operations taking an indexed pointer to the stack vector loadCopyOps; ///< List of COPY ops generated by load guards void clearInfoList(void); ///< Reset heritage status for all address spaces @@ -231,7 +232,8 @@ class Heritage { void handleNewLoadCopies(void); void analyzeNewLoadGuards(void); void generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc); - void discoverIndexedStackLoads(AddrSpace *spc); + void generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc); + void discoverIndexedStackPointers(AddrSpace *spc); void guard(const Address &addr,int4 size,vector &read,vector &write,vector &inputvars); void guardInput(const Address &addr,int4 size,vector &input); void guardCalls(uint4 flags,const Address &addr,int4 size,vector &write); @@ -270,6 +272,7 @@ public: void clear(void); ///< Reset all analysis of heritage void heritage(void); ///< Perform one pass of heritage const list &getLoadGuards(void) const { return loadGuard; } ///< Get list of LOAD ops that are guarded + const list &getStoreGuards(void) const { return storeGuard; } ///< Get list of STORE ops that are guarded }; #endif diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc index b81bdb9058..03f8fbb378 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.cc @@ -796,6 +796,44 @@ void MapState::addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,i #endif } +/// The given LoadGuard, which may be a LOAD or STORE is converted into an appropriate +/// RangeHint, attempting to make use of any data-type or index information. +/// \param guard is the given LoadGuard +/// \param typeFactory is used to manufacture a data-type for the hint if necessary +void MapState::addGuard(const LoadGuard &guard,TypeFactory *typeFactory) + +{ + if (!guard.isValid()) return; + int4 step = guard.getStep(); + if (step == 0) return; // No definitive sign of array access + Datatype *ct = guard.getOp()->getIn(1)->getType(); + if (ct->getMetatype() == TYPE_PTR) { + ct = ((TypePointer *) ct)->getPtrTo(); + while (ct->getMetatype() == TYPE_ARRAY) + ct = ((TypeArray *) ct)->getBase(); + } + int4 outSize = guard.getOp()->getOut()->getSize(); + if (outSize != step) { + // LOAD size doesn't match step: field in array of structures or something more unusual + if (outSize > step || (step % outSize) != 0) + return; + // Since the LOAD size divides the step and we want to preserve the arrayness + // we pretend we have an array of LOAD's size + step = outSize; + } + if (ct->getSize() != step) { // Make sure data-type matches our step size + if (step > 8) + return; // Don't manufacture primitives bigger than 8-bytes + ct = typeFactory->getBase(step, TYPE_UNKNOWN); + } + if (guard.isRangeLocked()) { + int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step; + addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1); + } + else + addRange(guard.getMinimum(),ct,0,RangeHint::open,3); +} + /// Run through all Symbols in the given map and create a corresponding RangeHint /// to \b this collection for each Symbol. /// \param rangemap is the given map of Symbols @@ -922,39 +960,14 @@ void MapState::gatherOpen(const Funcdata &fd) addRange(offset,ct,0,RangeHint::open,minItems); } + TypeFactory *typeFactory = fd.getArch()->types; const list &loadGuard( fd.getLoadGuards() ); - for(list::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter) { - const LoadGuard &guard( *iter ); - if (!guard.isValid()) continue; - int4 step = guard.getStep(); - if (step == 0) continue; // No definitive sign of array access - Datatype *ct = guard.getOp()->getIn(1)->getType(); - if (ct->getMetatype() == TYPE_PTR) { - ct = ((TypePointer *) ct)->getPtrTo(); - while (ct->getMetatype() == TYPE_ARRAY) - ct = ((TypeArray *) ct)->getBase(); - } - int4 outSize = guard.getOp()->getOut()->getSize(); - if (outSize != step) { - // LOAD size doesn't match step: field in array of structures or something more unusual - if (outSize > step || (step % outSize) != 0) - continue; - // Since the LOAD size divides the step and we want to preserve the arrayness - // we pretend we have an array of LOAD's size - step = outSize; - } - if (ct->getSize() != step) { // Make sure data-type matches our step size - if (step > 8) - continue; // Don't manufacture primitives bigger than 8-bytes - ct = fd.getArch()->types->getBase(step, TYPE_UNKNOWN); - } - if (guard.isRangeLocked()) { - int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step; - addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1); - } - else - addRange(guard.getMinimum(),ct,0,RangeHint::open,3); - } + for(list::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter) + addGuard(*iter,typeFactory); + + const list &storeGuard( fd.getStoreGuards() ); + for(list::const_iterator iter=storeGuard.begin();iter!=storeGuard.end();++iter) + addGuard(*iter,typeFactory); } /// Define stack Symbols based on Varnodes. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh index da9ec45712..ebc029aa4f 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/varmap.hh @@ -76,6 +76,7 @@ public: }; class ProtoModel; +class LoadGuard; /// \brief A light-weight class for analyzing pointers and aliasing on the stack /// @@ -126,6 +127,7 @@ class MapState { vector::iterator iter; ///< The current iterator into the RangeHints Datatype *defaultType; ///< The default data-type to use for RangeHints AliasChecker checker; ///< A collection of pointer Varnodes into our address space + void addGuard(const LoadGuard &guard,TypeFactory *typeFactory); ///< Add LoadGuard record as a hint to the collection void addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,int4 hi); ///< Add a hint to the collection public: #ifdef OPACTION_DEBUG