diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc index f8bceefca3..b16f794910 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.cc @@ -768,25 +768,10 @@ void FlowInfo::truncateIndirectJump(PcodeOp *op,JumpTable::RecoveryMode mode) } } -/// \brief Test if the given p-code op is a member of an array -/// -/// \param array is the array of p-code ops to search -/// \param op is the given p-code op to search for -/// \return \b true if the op is a member of the array -bool FlowInfo::isInArray(vector &array,PcodeOp *op) - -{ - for(int4 i=0;i notreached; // indirect ops that are not reachable - int4 notreachcnt = 0; clearProperties(); addrlist.push_back(data.getAddress()); while(!addrlist.empty()) // Recovering as much as possible except jumptables @@ -812,10 +797,9 @@ void FlowInfo::generateOps(void) checkContainedCall(); // Check for PIC constructions checkMultistageJumptables(); - while(notreachcnt < notreached.size()) { - tablelist.push_back(notreached[notreachcnt]); - notreachcnt += 1; - } + for(int4 i=0;i &newTables,vectorisPartial()) { - if (tablelist.size() > 1 && !isInArray(notreached,op)) { + if (tablelist.size() > 1 && jt->getRecoverCount() <= 1) { // If the recovery is incomplete with current flow AND there is more flow to generate, // AND we haven't tried to recover this table before notreached.push_back(op); // Save this op so we can try to recover the table again later diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.hh index 8f7bd48c75..360a864587 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/flow.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/flow.hh @@ -138,7 +138,6 @@ private: void recoverJumpTables(vector &newTables,vector ¬reached); void deleteCallSpec(FuncCallSpecs *fc); ///< Remove the given call site from the list for \b this function void truncateIndirectJump(PcodeOp *op,JumpTable::RecoveryMode mode); ///< Treat indirect jump as CALLIND/RETURN - static bool isInArray(vector &array,PcodeOp *op); public: FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector &q); ///< Constructor FlowInfo(Funcdata &d,PcodeOpBank &o,BlockGraph &b,vector &q,const FlowInfo *op2); ///< Cloning constructor diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc index 1d4133bf57..dfd7a0f2a1 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc @@ -491,6 +491,7 @@ JumpTable *Funcdata::installJumpTable(const Address &addr) JumpTable::RecoveryMode Funcdata::stageJumpTable(Funcdata &partial,JumpTable *jt,PcodeOp *op,FlowInfo *flow) { + jt->incrementRecoveryCount(); if (!partial.isJumptableRecoveryOn()) { // Do full analysis on the table if we haven't before partial.flags |= jumptablerecovery_on; // Mark that this Funcdata object is dedicated to jumptable recovery diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc index 1a7f301270..936bd5b8aa 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc @@ -2403,9 +2403,7 @@ JumpTable::JumpTable(Address ad) switchVarConsume = ~((uintb)0); defaultBlock = -1; lastBlock = -1; - maxaddsub = 1; - maxleftright = 1; - maxext = 1; + recoverCount = 0; displayFormat = 0; partialTable = false; collectloads = false; @@ -2424,9 +2422,7 @@ JumpTable::JumpTable(const JumpTable *op2) switchVarConsume = ~((uintb)0); defaultBlock = -1; lastBlock = op2->lastBlock; - maxaddsub = op2->maxaddsub; - maxleftright = op2->maxleftright; - maxext = op2->maxext; + recoverCount = op2->recoverCount; displayFormat = op2->displayFormat; partialTable = op2->partialTable; collectloads = op2->collectloads; @@ -2771,8 +2767,9 @@ void JumpTable::clear(void) indirect = (PcodeOp *)0; switchVarConsume = ~((uintb)0); defaultBlock = -1; + recoverCount = 0; partialTable = false; - // -opaddress- -maxtablesize- -maxaddsub- -maxleftright- -maxext- -collectloads- are permanent + // -opaddress- -maxtablesize- -collectloads- are permanent } /// The recovered addresses and case labels are encode to the stream. @@ -2871,6 +2868,7 @@ bool JumpTable::checkForMultistage(Funcdata *fd) if (addresstable.size()!=1) return false; if (partialTable) return false; if (indirect == (PcodeOp *)0) return false; + if (recoverCount > 1) return false; if (fd->getOverride().queryMultistageJumptable(indirect->getAddr())) { partialTable = true; // Mark that we need additional recovery diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh index 5a7f202135..011549e45d 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh @@ -549,6 +549,9 @@ public: fail_callother = 4 ///< Address formed by CALLOTHER }; private: + static constexpr uint4 maxaddsub = 1; ///< Maximum ADDs or SUBs to normalize + static constexpr uint4 maxleftright = 1; ///< Maximum shifts to normalize + static constexpr uint4 maxext = 1; ///< Maximum extensions to normalize /// \brief An address table index and its corresponding out-edge struct IndexPair { int4 blockPosition; ///< Out-edge index for the basic-block @@ -568,9 +571,7 @@ private: uintb switchVarConsume; ///< Bits of the switch variable being consumed int4 defaultBlock; ///< The out-edge corresponding to the \e default switch destination (-1 = undefined) int4 lastBlock; ///< Block out-edge corresponding to last entry in the address table - uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize - uint4 maxleftright; ///< Maximum shifts to normalize - uint4 maxext; ///< Maximum extensions to normalize + int4 recoverCount; ///< Number of times recovery attempted on \b this table uint4 displayFormat; ///< Display format for integer \e case values bool partialTable; ///< Set to \b true if \b this table is incomplete and needs additional recovery steps bool collectloads; ///< Set to \b true if information about in-memory model data is/should be collected @@ -598,14 +599,14 @@ public: const Address &getOpAddress(void) const { return opaddress; } ///< Get the address of the BRANCHIND for the switch PcodeOp *getIndirectOp(void) const { return indirect; } ///< Get the BRANCHIND PcodeOp void setIndirectOp(PcodeOp *ind) { opaddress = ind->getAddr(); indirect = ind; } ///< Set the BRANCHIND PcodeOp - void setNormMax(uint4 maddsub,uint4 mleftright,uint4 mext) { - maxaddsub = maddsub; maxleftright = mleftright; maxext = mext; } ///< Set the switch variable normalization model restrictions uint4 getDisplayFormat(void) const { return displayFormat; } ///< Get the display format for integer cases void setDisplayFormat(uint4 format) { displayFormat = format; } ///< Set the display format to use for integer case values void setOverride(const vector
&addrtable,const Address &naddr,uintb h,uintb sv); int4 numIndicesByBlock(const FlowBlock *bl) const; int4 getIndexByBlock(const FlowBlock *bl,int4 i) const; Address getAddressByIndex(int4 i) const { return addresstable[i]; } ///< Get the i-th address table entry + int4 getRecoverCount(void) const { return recoverCount; } ///< Get number of times a recovery has been attempted + void incrementRecoveryCount(void) { recoverCount += 1; } ///< Record that another round of recovery is being attempted void setLastAsDefault(void); ///< Set the \e default jump-table target to be the last address in the table void setDefaultBlock(int4 bl) { defaultBlock = bl; } ///< Set out-edge of the switch destination considered to be \e default void setLoadCollect(bool val) { collectloads = val; } ///< Set whether LOAD records should be collected