From 8cad85e36cdf016883eeac1ef0c8d5cc62f4049a Mon Sep 17 00:00:00 2001 From: caheckman <48068198+caheckman@users.noreply.github.com> Date: Wed, 12 Jun 2019 15:07:39 -0400 Subject: [PATCH] rearrange LoadGuard class --- .../Decompiler/src/decompile/cpp/funcdata.hh | 2 + .../Decompiler/src/decompile/cpp/heritage.cc | 27 ++++------ .../Decompiler/src/decompile/cpp/heritage.hh | 52 +++++++++++++------ 3 files changed, 47 insertions(+), 34 deletions(-) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh index e9103c7fc2..62b402701a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata.hh @@ -232,6 +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(); } + // Function prototype and call specification routines int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function FuncCallSpecs *getCallSpecs(int4 i) const { return qlst[i]; } ///< Get the i-th call specification diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc index 1951ef1ba6..edb83f5e44 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.cc @@ -578,22 +578,20 @@ void Heritage::handleNewLoadCopies(void) /// /// isAnalyzed is set to \b true, if full range analysis is not needed /// \param valueSet is the calculated value set as seen by the LOAD operation -void Heritage::LoadGuard::establishRange(const ValueSetRead &valueSet) +void LoadGuard::establishRange(const ValueSetRead &valueSet) { const CircleRange &range( valueSet.getRange() ); uintb rangeSize = range.getSize(); uintb size; if (range.isEmpty()) { - step = 0; minimumOffset = pointerBase; size = 0x1000; } else if (range.isFull() || rangeSize > 0xffffff) { - step = 1; minimumOffset = pointerBase; size = 0x1000; - isAnalyzed = true; // Don't bother doing more analysis + analysisState = 1; // Don't bother doing more analysis } else { step = (rangeSize == 3) ? range.getStep() : 0; // Check for consistent step @@ -627,21 +625,20 @@ void Heritage::LoadGuard::establishRange(const ValueSetRead &valueSet) } } -void Heritage::LoadGuard::finalizeRange(const ValueSetRead &valueSet) +void LoadGuard::finalizeRange(const ValueSetRead &valueSet) { - isAnalyzed = true; // In all cases the settings determined here are final + analysisState = 1; // In all cases the settings determined here are final const CircleRange &range( valueSet.getRange() ); uintb rangeSize = range.getSize(); if (rangeSize > 1 && rangeSize < 0xffffff) { // Did we converge to something reasonable + analysisState = 2; // Mark that we got a definitive result step = range.getStep(); minimumOffset = range.getMin(); maximumOffset = range.getMax(); if (maximumOffset < minimumOffset) // Values extend into what is usually stack parameters maximumOffset = spc->getHighest(); } - if (step == 0) - step = 1; if (minimumOffset > spc->getHighest()) minimumOffset = spc->getHighest(); if (maximumOffset > spc->getHighest()) @@ -652,14 +649,14 @@ void Heritage::analyzeNewLoadGuards(void) { if (loadGuard.empty()) return; - if (loadGuard.back().isAnalyzed) return; // Nothing new + if (loadGuard.back().analysisState != 0) return; // Nothing new list::iterator startIter = loadGuard.end(); vector sinks; vector reads; while(startIter != loadGuard.begin()) { --startIter; LoadGuard &guard( *startIter ); - if (guard.isAnalyzed) break; + if (guard.analysisState != 0) break; reads.push_back(guard.op); sinks.push_back(guard.op->getIn(1)); // The CPUI_LOAD pointer } @@ -676,7 +673,7 @@ void Heritage::analyzeNewLoadGuards(void) for(iter=startIter;iter!=loadGuard.end(); ++iter) { LoadGuard &guard( *iter ); guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum())); - if (!guard.isAnalyzed) + if (guard.analysisState == 0) runFullAnalysis = true; } if (runFullAnalysis) { @@ -700,13 +697,7 @@ void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc) { loadGuard.push_back(LoadGuard()); - LoadGuard &guard( loadGuard.back() ); - guard.op = op; - guard.spc = spc; - guard.pointerBase = node.offset; - guard.minimumOffset = 0; // Initially we guard everything - guard.maximumOffset = spc->getHighest(); - guard.isAnalyzed = false; + loadGuard.back().set(op,spc,node.offset); } /// \brief Trace input stackpointer to any indexed loads diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh index 66cb2f3fba..8fef13bd01 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/heritage.hh @@ -95,6 +95,39 @@ class HeritageInfo { deadremoved = 0; deadcodedelay = delay; warningissued = false; loadGuardSearch = false; } ///< Reset }; +/// \brief Description of a LOAD operation that needs to be guarded +/// +/// Heritage maintains a list of CPUI_LOAD ops that reference the stack dynamically. These +/// can potentially alias stack Varnodes, so we maintain what (possibly limited) information +/// we known about the range of stack addresses that can be referenced. +class LoadGuard { + friend class Heritage; + PcodeOp *op; ///< The LOAD op + AddrSpace *spc; ///< The stack space being loaded from + uintb pointerBase; ///< Base offset of the pointer + uintb minimumOffset; ///< Minimum offset of the LOAD + uintb maximumOffset; ///< Maximum offset of the LOAD + int4 step; ///< Step of any access into this range (0=unknown) + int4 analysisState; ///< 0=unanalyzed, 1=analyzed(partial result), 2=analyzed(full result) + void establishRange(const ValueSetRead &valueSet); ///< Convert partial value set analysis into guard range + void finalizeRange(const ValueSetRead &valueSet); ///< Convert value set analysis to final guard range + + /// \brief Set a new unanalyzed LOAD guard that initially guards everything + /// + /// \param o is the LOAD op + /// \param s is the (stack) space it is loading from + /// \param off is the base offset that is indexed from + void set(PcodeOp *o,AddrSpace *s,uintb off) { + op = o; spc = s; pointerBase=off; minimumOffset=0; maximumOffset=s->getHighest(); step=0; analysisState=0; + } +public: + PcodeOp *getOp(void) const { return op; } ///< Get the PcodeOp being guarded + uintb getMinimum(void) const { return minimumOffset; } ///< Get minimum offset of the guarded range + uintb getMaximum(void) const { return maximumOffset; } ///< Get maximum offset of the guarded range + int4 getStep(void) const { return step; } ///< Get the calculated step associated with the range (or 0) + bool isRangeLocked(void) const { return (analysisState == 2); } ///< Return \b true if the range is fully determined +}; + /// \brief Manage the construction of Static Single Assignment (SSA) form /// /// With a specific function (Funcdata), this class links the Varnode and @@ -156,20 +189,6 @@ class Heritage { } }; - /// \brief Description of a LOAD operation that needs to be guarded - class LoadGuard { - friend class Heritage; - PcodeOp *op; ///< The LOAD op - AddrSpace *spc; ///< The stack space being loaded from - uintb pointerBase; ///< Base offset of the pointer - uintb minimumOffset; ///< Minimum offset of the LOAD - uintb maximumOffset; ///< Maximum offset of the LOAD - int4 step; ///< Step of any access into this range - bool isAnalyzed; ///< Has a range analysis been performed on \b this - void establishRange(const ValueSetRead &valueSet); ///< Convert partial value set analysis into guard range - void finalizeRange(const ValueSetRead &valueSet); ///< Convert value set analysis to final guard range - }; - Funcdata *fd; ///< The function \b this is controlling SSA construction LocationMap globaldisjoint; ///< Disjoint cover of every heritaged memory location LocationMap disjoint; ///< Disjoint cover of memory locations currently being heritaged @@ -229,6 +248,8 @@ class Heritage { void calcMultiequals(const vector &write); void renameRecurse(BlockBasic *bl,VariableStack &varstack); void bumpDeadcodeDelay(Varnode *vn); + void placeMultiequals(void); + void rename(void); public: Heritage(Funcdata *data); ///< Constructor @@ -246,9 +267,8 @@ public: void buildInfoList(void); ///< Initialize information for each space void forceRestructure(void) { maxdepth = -1; } ///< Force regeneration of basic block structures void clear(void); ///< Reset all analysis of heritage - void placeMultiequals(void); - void rename(void); void heritage(void); ///< Perform one pass of heritage + const list &getLoadGuards(void) const { return loadGuard; } ///< Get list of LOAD ops that are guarded }; #endif