diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index 2a6114188c..7d783e7884 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -1674,13 +1674,20 @@ BlockMultiGoto *BlockGraph::newBlockMultiGoto(FlowBlock *bl,int4 outedge) } else { ret = new BlockMultiGoto(bl); + int4 origSizeOut = bl->sizeOut(); vector nodes; nodes.push_back(bl); identifyInternal(ret,nodes); addBlock(ret); ret->addEdge(targetbl); - if (targetbl != bl) // If the target is itself, edge is already removed by identifyInternal - removeEdge(ret,targetbl); + if (targetbl != bl) { + if (ret->sizeOut() != origSizeOut) { // If there are less out edges after identifyInternal + // it must have collapsed a self edge (switch out edges are already deduped) + ret->forceOutputNum(ret->sizeOut()+1); // preserve the self edge (it is not the goto edge) + } + removeEdge(ret,targetbl); // Remove the edge to the goto target + } + // else -- the goto edge is a self edge and will get removed by identifyInternal if (isdefaultedge) ret->setDefaultGoto(); } diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc index 799fb002c8..71d7d5c41a 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc @@ -84,12 +84,14 @@ void LoopBody::extendToContainer(const LoopBody &container,vector & } } -/// This updates the \b head and \b tail nodes to FlowBlock in the current collapsed graph. -/// This returns the first \b tail and passes back the head. -/// \param top is where \b head is passed back +/// This updates the \b head node to the FlowBlock in the current collapsed graph. +/// The \b tail nodes are also updated until one is found that has not collapsed into \b head. +/// This first updated \b tail is returned. The loop may still exist as a \b head node with an +/// out edge back into itself, in which case \b head is returned as the active \b tail. +/// If the loop has been completely collapsed, null is returned. /// \param graph is the containing control-flow structure -/// \return the current loop \b head -FlowBlock *LoopBody::getCurrentBounds(FlowBlock **top,FlowBlock *graph) +/// \return the current loop \b tail or null +FlowBlock *LoopBody::update(FlowBlock *graph) { while(head->getParent() != graph) @@ -101,10 +103,13 @@ FlowBlock *LoopBody::getCurrentBounds(FlowBlock **top,FlowBlock *graph) bottom = bottom->getParent(); tails[i] = bottom; if (bottom != head) { // If the loop hasn't been fully collapsed yet - *top = head; return bottom; } } + for(int4 i=head->sizeOut()-1;i>=0;--i) { + if (head->getOut(i) == head) // Check for head looping with itself + return head; + } return (FlowBlock *)0; } @@ -391,17 +396,17 @@ void LoopBody::emitLikelyEdges(list &likely,FlowBlock *graph) break; } } - likely.push_back(FloatingEdge(inbl,outbl)); + likely.emplace_back(inbl,outbl); } for(int4 i=tails.size()-1;i>=0;--i) { // Go in reverse order, to put out less preferred back-edges first if ((holdin!=(FlowBlock *)0)&&(i==0)) - likely.push_back(FloatingEdge(holdin,holdout)); // Put in delayed exit, right before final backedge + likely.emplace_back(holdin,holdout); // Put in delayed exit, right before final backedge FlowBlock *tail = tails[i]; int4 sizeout = tail->sizeOut(); for(int4 j=0;jgetOut(j); if (bl == head) // If out edge to head (back-edge for this loop) - likely.push_back(FloatingEdge(tail,head)); // emit it + likely.emplace_back(tail,head); // emit it } } } @@ -652,7 +657,7 @@ void TraceDAG::removeTrace(BlockTrace *trace) { // Record that we should now treat this edge like goto - likelygoto.push_back(FloatingEdge(trace->bottom,trace->destnode)); // Create goto record + likelygoto.emplace_back(trace->bottom,trace->destnode); // Create goto record trace->destnode->setVisitCount( trace->destnode->getVisitCount() + trace->edgelump ); // Ignore edge(s) BranchPoint *parentbp = trace->top; @@ -1194,11 +1199,21 @@ bool CollapseStructure::updateLoopBody(void) FlowBlock *loopbottom = (FlowBlock *)0; FlowBlock *looptop = (FlowBlock *)0; while (loopbodyiter != loopbody.end()) { // Last innermost loop - loopbottom = (*loopbodyiter).getCurrentBounds(&looptop,&graph); + LoopBody &curBody( *loopbodyiter ); + loopbottom = curBody.update(&graph); if (loopbottom != (FlowBlock *)0) { - if ((!likelylistfull) || - (likelyiter != likelygoto.end())) // Reaching here means, we removed edges but loop still didn't collapse + looptop = curBody.getHead(); + if (loopbottom == looptop) { // Check for single node looping back to itself + // If sizeout is 1 or 2, the loop would have collapsed, so the node is likely a switch. + likelygoto.clear(); + likelygoto.emplace_back(looptop,looptop); // Mark the loop edge as a goto + likelyiter = likelygoto.begin(); + likelylistfull = true; + return true; + } + if (!likelylistfull || likelyiter != likelygoto.end()) { break; // Loop still exists + } } ++loopbodyiter; likelylistfull = false; // Need to generate likely list for new loopbody (or no loopbody) diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.hh index 6cebf98850..4cef5f4498 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.hh @@ -55,7 +55,7 @@ class LoopBody { public: LoopBody(FlowBlock *h) { head=h; immed_container = (LoopBody *)0; depth=0; } ///< Construct with a loop head FlowBlock *getHead(void) const { return head; } ///< Return the head FlowBlock of the loop - FlowBlock *getCurrentBounds(FlowBlock **top,FlowBlock *graph); ///< Return current loop bounds (\b head and \b bottom). + FlowBlock *update(FlowBlock *graph); ///< Update loop body to current view void addTail(FlowBlock *bl) { tails.push_back(bl); } ///< Add a \e tail to the loop FlowBlock *getExitBlock(void) const { return exitblock; } ///< Get the exit FlowBlock or NULL void findBase(vector &body); ///< Mark the body FlowBlocks of \b this loop