diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index e257c5eda5..52a585f608 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -1767,8 +1767,9 @@ BlockInfLoop *BlockGraph::newBlockInfLoop(FlowBlock *body) /// Add the new BlockSwitch to \b this, collapsing all the case FlowBlocks into it. /// \param cs is the list of case FlowBlocks +/// \param hasExit is \b true if the switch has a formal exit /// \return the new BlockSwitch -BlockSwitch *BlockGraph::newBlockSwitch(const vector &cs) +BlockSwitch *BlockGraph::newBlockSwitch(const vector &cs,bool hasExit) { FlowBlock *rootbl = cs[0]; @@ -1779,6 +1780,8 @@ BlockSwitch *BlockGraph::newBlockSwitch(const vector &cs) ret->grabCaseBasic(leafbl->subBlock(0),cs); // Must be called before the identifyInternal identifyInternal(ret,cs); addBlock(ret); + if (hasExit) + ret->forceOutputNum(1); // If there is an exit, there should be exactly 1 out edge ret->clearFlag(f_switch_out); // Don't consider this as being a switch "out" return ret; } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index d4714bb282..16d5945441 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -326,7 +326,7 @@ public: BlockWhileDo *newBlockWhileDo(FlowBlock *cond,FlowBlock *cl); ///< Build a new BlockWhileDo BlockDoWhile *newBlockDoWhile(FlowBlock *condcl); ///< Build a new BlockDoWhile BlockInfLoop *newBlockInfLoop(FlowBlock *body); ///< Build a new BlockInfLoop - BlockSwitch *newBlockSwitch(const vector &cs); ///< Build a new BlockSwitch + BlockSwitch *newBlockSwitch(const vector &cs,bool hasExit); ///< Build a new BlockSwitch void orderBlocks(void) { ///< Sort blocks using the final ordering if (list.size()!=1) sort(list.begin(),list.end(),compareFinalOrder); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc index c7d13567f3..c157b39508 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc @@ -1636,7 +1636,10 @@ bool CollapseStructure::ruleBlockSwitch(FlowBlock *bl) // Find "obvious" exitblock, is sizeIn>1 or sizeOut>1 for(int4 i=0;igetOut(i); - if (curbl == bl) return false; // Cannot exit to itself (this can happen as a goto) + if (curbl == bl) { + exitblock = curbl; // Exit back to top of switch (loop) + break; + } if (curbl->sizeOut() > 1) { exitblock = curbl; break; @@ -1673,7 +1676,6 @@ bool CollapseStructure::ruleBlockSwitch(FlowBlock *bl) if (exitblock->isGotoOut(i)) return false; for(int4 i=0;igetOut(i); - if (curbl == bl) return false; if (curbl == exitblock) continue; // The switch can go straight to the exit block if (curbl->sizeIn() > 1) return false; // A case can only have the switch fall into it if (curbl->isGotoIn(0)) return false; // In cannot be a goto @@ -1696,7 +1698,7 @@ bool CollapseStructure::ruleBlockSwitch(FlowBlock *bl) if (curbl == exitblock) continue; // Don't include exit as a case cases.push_back(curbl); } - graph.newBlockSwitch(cases); + graph.newBlockSwitch(cases,(exitblock != (FlowBlock *)0)); return true; }