diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc index 4795d86166..3d733273d4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/funcdata_block.cc @@ -610,7 +610,7 @@ void Funcdata::installSwitchDefaults(void) PcodeOp *indop = jt->getIndirectOp(); BlockBasic *ind = indop->getParent(); // Mark any switch blocks default edge - if (jt->getMostCommon() != ~((uint4)0)) // If a mostcommon was found + if (jt->getMostCommon() != -1) // If a mostcommon was found ind->setDefaultSwitch(jt->getMostCommon()); } } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc index f7b8afb132..da671f4779 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.cc @@ -1205,7 +1205,7 @@ bool JumpBasic::foldInOneGuard(Funcdata *fd,GuardRecord &guard,JumpTable *jump) // Adjust tables and control flow graph // for new jumptable destination jump->addBlockToSwitch(guardtarget,0xBAD1ABE1); - jump->setMostCommonIndex(jump->numEntries()-1); + jump->setLastAsMostCommon(); fd->pushBranch(cbranchblock,1-indpath,switchbl); guard.clear(); change = true; @@ -1452,8 +1452,8 @@ bool JumpBasic2::foldInOneGuard(Funcdata *fd,GuardRecord &guard,JumpTable *jump) // So we don't make any special mods, in case there are extra statements in these blocks // The final block in the table is the single value produced by the model2 guard - jump->setMostCommonIndex(jump->numEntries()-1); // It should be the default block - guard.clear(); // Mark that we are folded + jump->setLastAsMostCommon(); // It should be the default block + guard.clear(); // Mark that we are folded return true; } @@ -2004,7 +2004,7 @@ bool JumpAssisted::foldInGuards(Funcdata *fd,JumpTable *jump) { int4 origVal = jump->getMostCommon(); - jump->setMostCommonIndex(jump->numEntries()-1); // Default case is always the last block + jump->setLastAsMostCommon(); // Default case is always the last block return (origVal != jump->getMostCommon()); } @@ -2097,21 +2097,18 @@ void JumpTable::sanityCheck(Funcdata *fd) /// If no edge hits it, throw an exception. /// \param bl is the specific basic-block /// \return the position of the basic-block -uint4 JumpTable::block2Position(const FlowBlock *bl) const +int4 JumpTable::block2Position(const FlowBlock *bl) const { FlowBlock *parent; - uint4 position; + int4 position; - if (!isSwitchedOver()) - throw LowlevelError("Jumptable switchover has not happened yet"); - parent = indirect->getParent(); - for(position=0;positionsizeOut();++position) - if (parent->getOut(position) == bl) break; - if (position==parent->sizeOut()) + for(position=0;positionsizeIn();++position) + if (bl->getIn(position) == parent) break; + if (position==bl->sizeIn()) throw LowlevelError("Requested block, not in jumptable"); - return position; + return bl->getInRevIndex(position); } /// We are not doing a complete check, we are looking for a guard that has collapsed to "if (false)" @@ -2151,7 +2148,8 @@ JumpTable::JumpTable(Architecture *g,Address ad) origmodel = (JumpModel *)0; indirect = (PcodeOp *)0; switchVarConsume = ~((uintb)0); - mostcommon = ~((uint4)0); + mostcommon = -1; + lastBlock = -1; maxtablesize = 1024; maxaddsub = 1; maxleftright = 1; @@ -2171,7 +2169,8 @@ JumpTable::JumpTable(const JumpTable *op2) origmodel = (JumpModel *)0; indirect = (PcodeOp *)0; switchVarConsume = ~((uintb)0); - mostcommon = ~((uint4)0); + mostcommon = -1; + lastBlock = op2->lastBlock; maxtablesize = op2->maxtablesize; maxaddsub = op2->maxaddsub; maxleftright = op2->maxleftright; @@ -2202,15 +2201,10 @@ JumpTable::~JumpTable(void) int4 JumpTable::numIndicesByBlock(const FlowBlock *bl) const { - uint4 position,count; - int4 i; - - position = block2Position(bl); - count = 0; - for(i=0;i::const_iterator,vector::const_iterator> range; + range = equal_range(block2addr.begin(),block2addr.end(),val,IndexPair::compareByPosition); + return range.second - range.first; } bool JumpTable::isOverride(void) const @@ -2254,26 +2248,24 @@ void JumpTable::setOverride(const vector
&addrtable,const Address &nadd int4 JumpTable::getIndexByBlock(const FlowBlock *bl,int4 i) const { - uint4 position,count; - int4 j; - - position = block2Position(bl); - count = 0; - for(j=0;j::const_iterator iter = lower_bound(block2addr.begin(),block2addr.end(),val,IndexPair::compareByPosition); + while(iter != block2addr.end()) { + if ((*iter).blockPosition == val.blockPosition) { + if (count == i) + return (*iter).addressIndex; count += 1; } + ++iter; } throw LowlevelError("Could not get jumptable index for block"); } -/// Set the most common address destination by supplying an index into the address table -/// \param tableind is the supplied address table index -void JumpTable::setMostCommonIndex(uint4 tableind) +void JumpTable::setLastAsMostCommon(void) { - mostcommon = blocktable[tableind]; // Translate addresstable index to switch block out index + mostcommon = lastBlock; } /// This is used to add address targets from guard branches if they are @@ -2285,50 +2277,56 @@ void JumpTable::addBlockToSwitch(BlockBasic *bl,uintb lab) { addresstable.push_back(bl->getStart()); - uint4 pos = indirect->getParent()->sizeOut(); - blocktable.push_back(pos); + lastBlock = indirect->getParent()->sizeOut(); // The block WILL be added to the end of the out-edges + block2addr.push_back(IndexPair(lastBlock,addresstable.size()-1)); label.push_back(lab); } /// Convert addresses in \b this table to actual targeted basic-blocks. /// -/// This constructs a map from each address table entry to the corresponding -/// out-edge from the the basic-block containing the BRANCHIND. The most common +/// This constructs a map from each out-edge from the basic-block containing the BRANCHIND +/// to addresses in the table targetting that out-block. The most common /// address table entry is also calculated here. /// \param flow is used to resolve address targets void JumpTable::switchOver(const FlowInfo &flow) { FlowBlock *parent,*tmpbl; - uint4 pos; - int4 i,j,count,maxcount; + int4 pos; PcodeOp *op; - blocktable.clear(); - blocktable.resize(addresstable.size(),~((uint4)0)); - mostcommon = ~((uint4)0); // There is no "mostcommon" - maxcount = 1; // If the maxcount is less than 2 + block2addr.clear(); + block2addr.reserve(addresstable.size()); parent = indirect->getParent(); - for(i=0;igetParent(); for(pos=0;possizeOut();++pos) if (parent->getOut(pos) == tmpbl) break; if (pos==parent->sizeOut()) throw LowlevelError("Jumptable destination not linked"); - count = 0; - for(j=i;j::const_iterator iter = block2addr.begin(); + while(iter != block2addr.end()) { + int4 curPos = (*iter).blockPosition; + vector::const_iterator nextiter = iter; + int4 count = 0; + while(nextiter != block2addr.end() && (*nextiter).blockPosition == curPos) { + count += 1; + ++nextiter; } - if (count>maxcount) { + iter = nextiter; + if (count > maxcount) { maxcount = count; - mostcommon = pos; + mostcommon = curPos; } } } @@ -2361,15 +2359,16 @@ void JumpTable::trivialSwitchOver(void) { FlowBlock *parent; - blocktable.clear(); - blocktable.resize(addresstable.size(),~((uint4)0)); + block2addr.clear(); + block2addr.reserve(addresstable.size()); parent = indirect->getParent(); if (parent->sizeOut() != addresstable.size()) throw LowlevelError("Trivial addresstable and switch block size do not match"); for(uint4 i=0;isizeOut();++i) - blocktable[i] = i; // blocktable corresponds exactly to outlist of switch block - mostcommon = ~((uint4)0); // There is no "mostcommon" + block2addr.push_back(IndexPair(i,i)); // Addresses corresponds exactly to out-edges of switch block + lastBlock = parent->sizeOut()-1; + mostcommon = -1; // There is no "mostcommon" } /// The addresses that the raw BRANCHIND op might branch to itself are recovered, @@ -2518,7 +2517,8 @@ void JumpTable::clear(void) delete jmodel; jmodel = (JumpModel *)0; } - blocktable.clear(); + block2addr.clear(); + lastBlock = -1; label.clear(); loadpoints.clear(); indirect = (PcodeOp *)0; diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh index 70ac658039..e3a295d412 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/jumptable.hh @@ -492,17 +492,26 @@ public: /// It knows how to map from specific switch variable values to the destination /// \e case block and how to label the value. class JumpTable { + /// \brief An address table index and its corresponding out-edge + struct IndexPair { + int4 blockPosition; ///< Out-edge index for the basic-block + int4 addressIndex; /// Index of address targetting the basic-block + IndexPair(int4 pos,int4 index) { blockPosition = pos; addressIndex = index; } ///< Constructor + bool operator<(const IndexPair &op2) const; ///< Compare by position then by index + static bool compareByPosition(const IndexPair &op1,const IndexPair &op2); ///< Compare just by position + }; Architecture *glb; ///< Architecture under which this jump-table operates JumpModel *jmodel; ///< Current model of how the jump table is implemented in code JumpModel *origmodel; ///< Initial jump table model, which may be incomplete vector
addresstable; ///< Raw addresses in the jump-table - vector blocktable; ///< Addresses converted to basic blocks + vector block2addr; ///< Map from basic-blocks to address table index vector label; ///< The case label for each explicit target vector loadpoints; ///< Any recovered in-memory data for the jump-table Address opaddress; ///< Absolute address of the BRANCHIND jump PcodeOp *indirect; ///< CPUI_BRANCHIND linked to \b this jump-table uintb switchVarConsume; ///< Bits of the switch variable being consumed - uint4 mostcommon; ///< The out-edge corresponding to the most common address in the address table + int4 mostcommon; ///< The out-edge corresponding to the most common address in the address table + int4 lastBlock; ///< Block out-edge corresponding to last entry in the address table uint4 maxtablesize; ///< Maximum table size we allow to be built (sanity check) uint4 maxaddsub; ///< Maximum ADDs or SUBs to normalize uint4 maxleftright; ///< Maximum shifts to normalize @@ -512,13 +521,12 @@ class JumpTable { void recoverModel(Funcdata *fd); ///< Attempt recovery of the jump-table model void trivialSwitchOver(void); ///< Switch \b this table over to a trivial model void sanityCheck(Funcdata *fd); ///< Perform sanity check on recovered address targets - uint4 block2Position(const FlowBlock *bl) const; ///< Convert a basic-block to an out-edge index from the switch. + int4 block2Position(const FlowBlock *bl) const; ///< Convert a basic-block to an out-edge index from the switch. static bool isReachable(PcodeOp *op); ///< Check if the given PcodeOp still seems reachable in its function public: JumpTable(Architecture *g,Address ad=Address()); ///< Constructor JumpTable(const JumpTable *op2); ///< Copy constructor ~JumpTable(void); ///< Destructor - bool isSwitchedOver(void) const { return !blocktable.empty(); } ///< Return \b true if addresses converted to basic-blocks bool isRecovered(void) const { return !addresstable.empty(); } ///< Return \b true if a model has been recovered bool isLabelled(void) const { return !label.empty(); } ///< Return \b true if \e case labels are computed bool isOverride(void) const; ///< Return \b true if \b this table was manually overridden @@ -537,7 +545,7 @@ public: 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 - void setMostCommonIndex(uint4 tableind); ///< Set the most common jump-table target by index + void setLastAsMostCommon(void); ///< Set the most common jump-table target to be the last address in the table void setMostCommonBlock(uint4 bl) { mostcommon = bl; } ///< Set the most common jump-table target by out-edge void setLoadCollect(bool val) { collectloads = val; } ///< Set whether LOAD records should be collected void addBlockToSwitch(BlockBasic *bl,uintb lab); ///< Force a given basic-block to be a switch destination @@ -554,4 +562,22 @@ public: void restoreXml(const Element *el); ///< Recover \b this jump-table from a \ XML tag }; +/// \param op2 is the other IndexPair to compare with \b this +/// \return \b true if \b this is ordered before the other IndexPair +inline bool JumpTable::IndexPair::operator<(const IndexPair &op2) const + +{ + if (blockPosition != op2.blockPosition) return (blockPosition < op2.blockPosition); + return (addressIndex < op2.addressIndex); +} + +/// \param op1 is the first IndexPair to compare +/// \param op2 is the second IndexPair to compare +/// \return \b true if op1 is ordered before op2 +inline bool JumpTable::IndexPair::compareByPosition(const IndexPair &op1,const IndexPair &op2) + +{ + return (op1.blockPosition < op2.blockPosition); +} + #endif