Skip to content

Commit 5f927f3

Browse files
committed
Updated ruleBlockIfNoExit to better select branch if both are noexit.
1 parent 3c683ae commit 5f927f3

File tree

5 files changed

+104
-6
lines changed

5 files changed

+104
-6
lines changed

Ghidra/Features/Decompiler/src/decompile/cpp/block.cc

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1323,6 +1323,20 @@ void BlockGraph::restoreXmlBody(List::const_iterator &iter,List::const_iterator
13231323
}
13241324
}
13251325

1326+
int4 BlockGraph::getInnerBlockDepth(void)
1327+
1328+
{
1329+
int4 depth;
1330+
int4 maxDepth = 0;
1331+
for(int4 i=0;i<list.size();++i){
1332+
depth = list[i]->getBlockDepth();
1333+
if(depth>maxDepth){
1334+
maxDepth=depth;
1335+
}
1336+
}
1337+
return maxDepth;
1338+
}
1339+
13261340
/// This is currently just a wrapper around the FlowBlock::restoreXml()
13271341
/// that sets of the BlockMap resolver
13281342
/// \param el is the root \<block> tag
@@ -2505,6 +2519,12 @@ bool BlockBasic::isDoNothing(void) const
25052519
return hasOnlyMarkers();
25062520
}
25072521

2522+
int4 BlockBasic::getOpSize(void)
2523+
2524+
{
2525+
return op.size();
2526+
}
2527+
25082528
/// In terms of machine instructions, a basic block always covers a range of addresses,
25092529
/// from its first instruction to its last. This method establishes that range.
25102530
/// \param beg is the address of the first instruction in the block
@@ -2747,6 +2767,13 @@ FlowBlock *BlockList::getSplitPoint(void)
27472767
return getBlock(getSize()-1)->getSplitPoint();
27482768
}
27492769

2770+
int4 BlockList::getBlockDepth(void)
2771+
2772+
{
2773+
// list join block together but don't increase block depth
2774+
return getInnerBlockDepth();
2775+
}
2776+
27502777
void BlockList::printHeader(ostream &s) const
27512778

27522779
{
@@ -2831,6 +2858,13 @@ void BlockCondition::saveXmlHeader(ostream &s) const
28312858
a_v(s,"opcode",nm);
28322859
}
28332860

2861+
int4 BlockCondition::getBlockDepth(void)
2862+
2863+
{
2864+
// conditions join block together but don't increase block depth
2865+
return getInnerBlockDepth();
2866+
}
2867+
28342868
void BlockIf::markUnstructured(void)
28352869

28362870
{
@@ -3185,6 +3219,18 @@ FlowBlock *BlockSwitch::nextFlowAfter(const FlowBlock *bl) const
31853219
return getParent()->nextFlowAfter(this);
31863220
}
31873221

3222+
int4 BlockSwitch::getBlockDepth(void){
3223+
int4 i;
3224+
int4 maxDepth=0;
3225+
for(i=0;i<caseblocks.size();++i){
3226+
int4 depth=caseblocks[i].block->getBlockDepth();
3227+
if(depth>maxDepth){
3228+
maxDepth=depth;
3229+
}
3230+
}
3231+
return maxDepth+2; // +1 for switch block and +1 for case/default block
3232+
}
3233+
31883234
BlockMap::BlockMap(const BlockMap &op2)
31893235

31903236
{

Ghidra/Features/Decompiler/src/decompile/cpp/block.hh

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,7 @@ public:
181181
/// \param enditer marks the end of the XML tags
182182
/// \param resolver is used to recover FlowBlock objects based on XML references
183183
virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver) {}
184+
virtual int4 getBlockDepth(void) {return 0;} ///< Return the depth in code block of \b this
184185
void saveXmlEdges(ostream &s) const; ///< Save edge information to an XML stream
185186
void restoreXmlEdges(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver);
186187
void saveXml(ostream &s) const; ///< Write out \b this to an XML stream
@@ -299,6 +300,8 @@ public:
299300
virtual void finalizePrinting(const Funcdata &data) const;
300301
virtual void saveXmlBody(ostream &s) const;
301302
virtual void restoreXmlBody(List::const_iterator &iter,List::const_iterator enditer,BlockMap &resolver);
303+
virtual int4 getInnerBlockDepth(); ///< Return max depth of child blocks
304+
virtual int4 getBlockDepth() {return getInnerBlockDepth()+1;}
302305
void restoreXml(const Element *el,const AddrSpaceManager *m); ///< Restore \b this BlockGraph from an XML stream
303306
void addEdge(FlowBlock *begin,FlowBlock *end); ///< Add a directed edge between component FlowBlocks
304307
void addLoopEdge(FlowBlock *begin,int4 outindex); ///< Mark a given edge as a \e loop edge
@@ -401,6 +404,7 @@ public:
401404
list<PcodeOp *>::const_iterator beginOp(void) const { return op.begin(); } ///< Return an iterator to the beginning of the PcodeOps
402405
list<PcodeOp *>::const_iterator endOp(void) const { return op.end(); } ///< Return an iterator to the end of the PcodeOps
403406
bool emptyOp(void) const { return op.empty(); } ///< Return \b true if \b block contains no operations
407+
int4 getOpSize(void); ///< Number of PcodeOps contained in \b this block
404408
static bool noInterveningStatement(PcodeOp *first,int4 path,PcodeOp *last);
405409
};
406410

@@ -501,6 +505,7 @@ public:
501505
virtual PcodeOp *lastOp(void) const;
502506
virtual bool negateCondition(bool toporbottom);
503507
virtual FlowBlock *getSplitPoint(void);
508+
virtual int4 getBlockDepth(void);
504509
};
505510

506511
/// \brief Two conditional blocks combined into one conditional using BOOL_AND or BOOL_OR
@@ -530,6 +535,7 @@ public:
530535
virtual bool isComplex(void) const { return getBlock(0)->isComplex(); }
531536
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
532537
virtual void saveXmlHeader(ostream &s) const;
538+
virtual int4 getBlockDepth(void);
533539
};
534540

535541
/// \brief A basic "if" block
@@ -675,6 +681,7 @@ public:
675681
virtual void emit(PrintLanguage *lng) const { lng->emitBlockSwitch(this); }
676682
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
677683
virtual void finalizePrinting(const Funcdata &data) const;
684+
virtual int4 getBlockDepth(void);
678685
};
679686

680687
/// \brief Helper class for resolving cross-references while deserializing BlockGraph objects

Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc

Lines changed: 48 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1463,6 +1463,7 @@ bool CollapseStructure::ruleBlockIfNoExit(FlowBlock *bl)
14631463
{
14641464
FlowBlock *clauseblock;
14651465
int4 i;
1466+
int4 bestIndex=-1;
14661467

14671468
if (bl->sizeOut() != 2) return false; // Must be binary condition
14681469
if (bl->isSwitchOut()) return false;
@@ -1480,15 +1481,56 @@ bool CollapseStructure::ruleBlockIfNoExit(FlowBlock *bl)
14801481
// bl->setGotoBranch(i);
14811482
// return true;
14821483
// }
1484+
if (bestIndex==-1){
1485+
bestIndex=i;
1486+
}else{ // both match
1487+
bestIndex = selectBestNoExit(bl->getOut(0),bl->getOut(1));
1488+
}
1489+
}
1490+
if(bestIndex==-1) return false; // no match
1491+
clauseblock = bl->getOut(bestIndex);
1492+
if (bestIndex==0) { // clause must be true out of bl
1493+
if (bl->negateCondition(true))
1494+
dataflow_changecount += 1;
1495+
}
1496+
graph.newBlockIf(bl,clauseblock);
1497+
return true;
1498+
}
14831499

1484-
if (i==0) { // clause must be true out of bl
1485-
if (bl->negateCondition(true))
1486-
dataflow_changecount += 1;
1500+
/// Select the best of two NoExit branch to be collapsed by ruleBlockIfNoExit.
1501+
/// \param clause0 is the first NoExit branch
1502+
/// \param clause1 is the second NoExit branch
1503+
/// \return the index of the selected branch (0 or 1)
1504+
int4 CollapseStructure::selectBestNoExit(FlowBlock *clause0,FlowBlock *clause1)
1505+
1506+
{
1507+
// select lowest block depth
1508+
int4 depth0 = clause0->getBlockDepth();
1509+
int4 depth1 = clause1->getBlockDepth();
1510+
if (depth0<depth1)return 0;
1511+
if (depth1<depth0)return 1;
1512+
1513+
// same depth, prefer non return
1514+
bool isRet0 = clause0->lastOp()!=(PcodeOp *)0 && clause0->lastOp()->isStandardReturn();
1515+
bool isRet1 = clause1->lastOp()!=(PcodeOp *)0 && clause1->lastOp()->isStandardReturn();
1516+
if(isRet0 && !isRet1) return 1;
1517+
if(isRet1 && !isRet0) return 0;
1518+
1519+
// prefer block containing only return op
1520+
if(isRet0){ // both are return
1521+
FlowBlock* fb;
1522+
if(clause0->getType()==FlowBlock::t_copy){
1523+
fb = ((BlockCopy*)clause0)->subBlock(0);
1524+
if(fb->getType()==FlowBlock::t_basic && ((BlockBasic*)fb)->getOpSize()==1) return 0;
1525+
}
1526+
if(clause1->getType()==FlowBlock::t_copy){
1527+
fb = ((BlockCopy*)clause1)->subBlock(0);
1528+
if(fb->getType()==FlowBlock::t_basic && ((BlockBasic*)fb)->getOpSize()==1) return 1;
14871529
}
1488-
graph.newBlockIf(bl,clauseblock);
1489-
return true;
14901530
}
1491-
return false;
1531+
1532+
// fall back to previous behavior
1533+
return 0;
14921534
}
14931535

14941536
/// Try to find a while/do structure, starting with a given FlowBlock.

Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.hh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,7 @@ class CollapseStructure {
217217
bool ruleCaseFallthru(FlowBlock *bl); ///< Attempt to one switch case falling through to another
218218
int4 collapseInternal(FlowBlock *targetbl); ///< The main collapsing loop
219219
void collapseConditions(void); ///< Simplify conditionals
220+
int4 selectBestNoExit(FlowBlock *clause0,FlowBlock *clause1);
220221
public:
221222
CollapseStructure(BlockGraph &g); ///< Construct given a control-flow graph
222223
int4 getChangeCount(void) const { return dataflow_changecount; } ///< Get number of data-flow changes

Ghidra/Features/Decompiler/src/decompile/cpp/op.hh

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ public:
176176
bool isCallOrBranch(void) const { return ((flags&(PcodeOp::branch|PcodeOp::call))!=0); }
177177
/// \brief Return \b true if this op breaks fall-thru flow
178178
bool isFlowBreak(void) const { return ((flags&(PcodeOp::branch|PcodeOp::returns))!=0); }
179+
/// \brief Return \b true if this op will be decompiled as "return"
180+
bool isStandardReturn(void) const { return ((flags&PcodeOp::returns)!=0 && getHaltType()==0); }
179181
/// \brief Return \b true if this op flips the true/false meaning of its control-flow branching
180182
bool isBooleanFlip(void) const { return ((flags&PcodeOp::boolean_flip)!=0); }
181183
/// \brief Return \b true if the fall-thru branch is taken when the boolean input is true

0 commit comments

Comments
 (0)