Merge remote-tracking branch 'origin/GP-7115_NormalizeIfNoExit'

This commit is contained in:
Ryan Kurtz
2026-08-06 05:47:11 -04:00
10 changed files with 291 additions and 113 deletions
@@ -44,6 +44,7 @@ src/decompile/datatests/forloop_varused.xml||GHIDRA||||END|
src/decompile/datatests/forloop_withskip.xml||GHIDRA||||END|
src/decompile/datatests/gp.xml||GHIDRA||||END|
src/decompile/datatests/heapstring.xml||GHIDRA||||END|
src/decompile/datatests/ifnoexit.xml||GHIDRA||||END|
src/decompile/datatests/ifswitch.xml||GHIDRA||||END|
src/decompile/datatests/impliedfield.xml||GHIDRA||||END|
src/decompile/datatests/indproto.xml||GHIDRA||||END|
@@ -64,8 +64,12 @@ FlowBlock::FlowBlock(void)
flags = 0;
index = 0;
visitcount = 0;
numdesc = 0;
leafCount = 1;
structureDepth = 0;
parent = (FlowBlock *)0;
immed_dom = (FlowBlock *)0;
copymap = (FlowBlock *)0;
}
/// \param b is the FlowBlock coming in
@@ -690,6 +694,11 @@ string FlowBlock::typeToName(FlowBlock::block_type bt)
return "condition";
case t_if:
return "properif";
case t_ifelse:
case t_ifnoexit:
return "ifelse";
case t_ifgoto:
return "ifgoto";
case t_whiledo:
return "whiledo";
case t_dowhile:
@@ -872,6 +881,10 @@ void BlockGraph::addBlock(FlowBlock *bl)
}
bl->parent = this;
list.push_back(bl);
leafCount += bl->getBasicCount();
int4 depth = bl->getStructureDepth() + 1;
if (depth > structureDepth)
structureDepth = depth;
}
/// Force \b this FlowBlock to have the indicated number of outputs.
@@ -1383,18 +1396,7 @@ void BlockGraph::encodeBody(Encoder &encoder) const
encoder.openElement(ELEM_BHEAD);
encoder.writeSignedInteger(ATTRIB_INDEX, bl->getIndex());
FlowBlock::block_type bt = bl->getType();
string nm;
if (bt == FlowBlock::t_if) {
int4 sz = ((BlockGraph *)bl)->getSize();
if (sz == 1)
nm = "ifgoto";
else if (sz == 2)
nm = "properif";
else
nm = "ifelse";
}
else
nm = FlowBlock::typeToName(bt);
string nm = FlowBlock::typeToName(bt);
encoder.writeString(ATTRIB_TYPE, nm);
encoder.closeElement(ELEM_BHEAD);
}
@@ -1799,7 +1801,7 @@ BlockCondition *BlockGraph::newBlockCondition(FlowBlock *b1,FlowBlock *b2)
/// Add the new BlockIfGoto to \b this, collapsing the given condition FlowBlock into it.
/// \param cond is the given condition FlowBlock
/// \return the new BlockIfGoto
BlockIf *BlockGraph::newBlockIfGoto(FlowBlock *cond)
BlockIfGoto *BlockGraph::newBlockIfGoto(FlowBlock *cond)
{
if (!cond->isGotoOut(1)) // True branch must be a goto branch
@@ -1807,8 +1809,7 @@ BlockIf *BlockGraph::newBlockIfGoto(FlowBlock *cond)
const FlowBlock *out0 = cond->getOut(0);
vector<FlowBlock *> nodes;
BlockIf *ret = new BlockIf();
ret->setGotoTarget(cond->getOut(1)); // Store the target
BlockIfGoto *ret = new BlockIfGoto(cond->getOut(1)); // Goto block with specific target
nodes.push_back(cond);
identifyInternal(ret,nodes);
addBlock(ret);
@@ -1839,12 +1840,12 @@ BlockIf *BlockGraph::newBlockIf(FlowBlock *cond,FlowBlock *tc)
/// \param cond is the condition FlowBlock
/// \param tc is the true clause FlowBlock
/// \param fc is the false clause FlowBlock
/// \return the new BlockIf
BlockIf *BlockGraph::newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
/// \return the new BlockIfElse
BlockIfElse *BlockGraph::newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
{
vector<FlowBlock *> nodes;
BlockIf *ret = new BlockIf();
BlockIfElse *ret = new BlockIfElse();
nodes.push_back(cond);
nodes.push_back(tc);
nodes.push_back(fc);
@@ -1854,6 +1855,19 @@ BlockIf *BlockGraph::newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
return ret;
}
BlockIfNoExit *BlockGraph::newBlockIfNoExit(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc)
{
vector<FlowBlock *> nodes;
BlockIfNoExit *ret = new BlockIfNoExit();
nodes.push_back(cond);
nodes.push_back(tc);
nodes.push_back(fc);
identifyInternal(ret,nodes);
addBlock(ret);
return ret;
}
/// Add the new BlockWhileDo to \b this, collapsing the condition and clause into it.
/// \param cond is the condition FlowBlock
/// \param cl is the clause FlowBlock
@@ -3112,23 +3126,11 @@ void BlockCondition::encodeHeader(Encoder &encoder) const
encoder.writeString(ATTRIB_OPCODE, nm);
}
void BlockIf::markUnstructured(void)
{
BlockGraph::markUnstructured(); // Recurse
if ((gototarget != (FlowBlock *)0)&&(gototype==f_goto_goto))
markCopyBlock(gototarget,f_unstructured_targ);
}
void BlockIf::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // Condition block has multiple exits
// Blocks don't flow into one another, but share same exit block
for(int4 i=1;i<getSize();++i)
getBlock(i)->scopeBreak(curexit,curloopexit);
if ((gototarget != (FlowBlock *)0)&&(gototarget->getIndex() == curloopexit))
gototype = f_break_goto;
getBlock(1)->scopeBreak(curexit,curloopexit);
}
void BlockIf::printHeader(ostream &s) const
@@ -3138,40 +3140,6 @@ void BlockIf::printHeader(ostream &s) const
FlowBlock::printHeader(s);
}
bool BlockIf::preferComplement(Funcdata &data,bool allowOpRemoval)
{
if (getSize()!=3) // If we are an if/else
return false;
FlowBlock *split = getBlock(0)->getSplitPoint();
if (split == (FlowBlock *)0)
return false;
vector<PcodeOp *> fliplist;
if (0 != split->flipInPlaceTest(fliplist,allowOpRemoval))
return false;
split->flipInPlaceExecute();
data.opFlipInPlaceExecute(fliplist);
swapBlocks(1,2);
return true;
}
const FlowBlock *BlockIf::getExitLeaf(void) const
{ // In the special case of an ifgoto block, we do have an exit leaf
if (getSize() == 1)
return getBlock(0)->getExitLeaf();
return (FlowBlock *)0;
}
PcodeOp *BlockIf::lastOp(void) const
{ // In the special case of an ifgoto block, we do have a last op, otherwise we don't
if (getSize() == 1)
return getBlock(0)->lastOp();
return (PcodeOp *)0;
}
FlowBlock *BlockIf::nextFlowAfter(const FlowBlock *bl) const
{
@@ -3182,19 +3150,123 @@ FlowBlock *BlockIf::nextFlowAfter(const FlowBlock *bl) const
return getParent()->nextFlowAfter(this);
}
void BlockIf::encodeBody(Encoder &encoder) const
void BlockIfElse::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // Condition block has multiple exits
// Blocks don't flow into one another, but share same exit block
getBlock(1)->scopeBreak(curexit,curloopexit);
getBlock(2)->scopeBreak(curexit,curloopexit);
}
void BlockIfElse::printHeader(ostream &s) const
{
s << "If/else block ";
FlowBlock::printHeader(s);
}
bool BlockIfElse::preferComplement(Funcdata &data,bool allowOpRemoval)
{
FlowBlock *split = getBlock(0)->getSplitPoint();
if (split == (FlowBlock *)0)
return false;
vector<PcodeOp *> fliplist;
if (0 != split->flipInPlaceTest(fliplist,allowOpRemoval))
return false;
split->flipInPlaceExecute();
data.opFlipInPlaceExecute(fliplist);
swapBlocks(1,2);
return true;
}
void BlockIfNoExit::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // No fixed exit for condition block
FlowBlock *followBlock = getBlock(2);
getBlock(1)->scopeBreak(followBlock->getIndex(),curloopexit); // First body: followBlock acts as "exit"
followBlock->scopeBreak(curexit,curloopexit);
}
void BlockIfNoExit::printHeader(ostream &s) const
{
s << "If (no exit) block ";
FlowBlock::printHeader(s);
}
bool BlockIfNoExit::preferComplement(Funcdata &data,bool allowOpRemoval)
{
FlowBlock *body1 = getBlock(1);
FlowBlock *body2 = getBlock(2);
int4 diff = body1->getStructureDepth() - body2->getStructureDepth();
if (diff < 0) return false;
if (diff == 0) {
diff = body1->getBasicCount() - body2->getBasicCount();
if (diff < 0) return false;
if (diff == 0) {
uint4 halt1 = body1->getHaltType();
uint4 halt2 = body2->getHaltType();
if (halt1 > halt2)
return false;
if (halt1 < halt2)
diff = 1;
}
}
FlowBlock *split = getBlock(0)->getSplitPoint();
if (split == (FlowBlock *)0)
return false;
vector<PcodeOp *> fliplist;
int4 testResult = split->flipInPlaceTest(fliplist,allowOpRemoval);
if (2 == testResult)
return false;
if (diff == 0 && testResult != 0)
return false;
split->flipInPlaceExecute();
data.opFlipInPlaceExecute(fliplist);
swapBlocks(1,2);
return true;
}
void BlockIfGoto::scopeBreak(int4 curexit,int4 curloopexit)
{
getBlock(0)->scopeBreak(-1,curloopexit); // Condition has multiple exits
if ((gototarget != (FlowBlock *)0)&&(gototarget->getIndex() == curloopexit))
gototype = f_break_goto;
}
void BlockIfGoto::printHeader(ostream &s) const
{
s << "If goto block ";
FlowBlock::printHeader(s);
}
void BlockIfGoto::markUnstructured(void)
{
BlockGraph::markUnstructured(); // Recurse
if ((gototarget != (FlowBlock *)0)&&(gototype==f_goto_goto))
markCopyBlock(gototarget,f_unstructured_targ);
}
void BlockIfGoto::encodeBody(Encoder &encoder) const
{
BlockGraph::encodeBody(encoder);
if (getSize() == 1) { // If this is a if GOTO block
const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf);
encoder.openElement(ELEM_TARGET);
encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex());
encoder.writeSignedInteger(ATTRIB_DEPTH, depth);
encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype);
encoder.closeElement(ELEM_TARGET);
}
const FlowBlock *leaf = gototarget->getFrontLeaf();
int4 depth = gototarget->calcDepth(leaf);
encoder.openElement(ELEM_TARGET);
encoder.writeSignedInteger(ATTRIB_INDEX, leaf->getIndex());
encoder.writeSignedInteger(ATTRIB_DEPTH, depth);
encoder.writeUnsignedInteger(ATTRIB_TYPE, gototype);
encoder.closeElement(ELEM_TARGET);
}
/// Try to find a Varnode that represents the controlling \e loop \e variable for \b this loop.
@@ -30,6 +30,9 @@ class BlockGoto;
class BlockMultiGoto;
class BlockCondition;
class BlockIf;
class BlockIfElse;
class BlockIfNoExit;
class BlockIfGoto;
class BlockWhileDo;
class BlockDoWhile;
class BlockInfLoop;
@@ -76,7 +79,7 @@ public:
/// \brief The possible block types
enum block_type {
t_plain, t_basic, t_graph, t_copy, t_goto, t_multigoto, t_ls,
t_condition, t_if, t_whiledo, t_dowhile, t_switch, t_infloop
t_condition, t_if, t_ifelse, t_ifnoexit, t_ifgoto, t_whiledo, t_dowhile, t_switch, t_infloop
};
/// \brief Boolean properties of blocks
///
@@ -120,19 +123,21 @@ public:
f_immed_copy = 0x200 ///< Copy propagation has happened across the edge
};
private:
uint4 flags; ///< Collection of block_flags
FlowBlock *parent; ///< The parent block to which \b this belongs
FlowBlock *immed_dom; ///< Immediate dominating block
FlowBlock *copymap; ///< Back reference to a BlockCopy of \b this
int4 index; ///< Reference index for this block (reverse post order)
int4 visitcount; ///< A count of visits of this node for various algorithms
int4 numdesc; ///< Number of descendants of this block in spanning tree (+1)
vector<BlockEdge> intothis; ///< Blocks which (can) fall into this block
vector<BlockEdge> outofthis; ///< Blocks into which this block (can) fall
// If there are two possible outputs as the
// result of a conditional branch
// the first block in outofthis should be
// the result of the condition being false
uint4 flags; ///< Collection of block_flags
int4 index; ///< Reference index for this block (reverse post order)
int4 visitcount; ///< A count of visits of this node for various algorithms
int4 numdesc; ///< Number of descendants of this block in spanning tree (+1)
int4 leafCount; ///< Number of leaf blocks contained in \b this
int4 structureDepth; ///< Amount of nesting in structure rooted at \b this
static void replaceEdgeMap(vector<BlockEdge> &vec); ///< Update block references in edges with copy map
void addInEdge(FlowBlock *b,uint4 lab); ///< Add an edge coming into \b this
void decodeNextInEdge(Decoder &decoder,BlockMap &resolver); ///< Decode the next input edge from stream
@@ -353,6 +358,9 @@ public:
bool isGotoIn(int4 i) const { return ((intothis[i].label & (f_irreducible|f_goto_edge))!=0); } ///< Is the i-th incoming edge unstructured
bool isGotoOut(int4 i) const { return ((outofthis[i].label & (f_irreducible|f_goto_edge))!=0); } ///< Is the i-th outgoing edge unstructured
JumpTable *getJumptable(void) const; ///< Get the JumpTable associated \b this block
int4 getBasicCount(void) const { return leafCount; } ///< Get the number of basic blocks under the structure at \b this point
int4 getStructureDepth(void) const { return structureDepth; } ///< Get the nesting depth of the structure rooted at \b this point
uint4 getHaltType(void) const; ///< Get the \e halt type of the last PcodeOp in \b this
void printShortHeader(ostream &s) const; ///< Print a short identifier for the block
static block_type nameToType(const string &name); ///< Get the block_type associated with a name string
static string typeToName(block_type bt); ///< Get the name string associated with a block_type
@@ -384,6 +392,7 @@ protected:
void swapBlocks(int4 i,int4 j); ///< Swap the positions two component FlowBlocks
static void markCopyBlock(FlowBlock *bl,uint4 fl); ///< Set properties on the first leaf FlowBlock
public:
BlockGraph(void) { leafCount = 0; } ///< Construct empty structure
void clear(void); ///< Clear all component FlowBlock objects
virtual ~BlockGraph(void) { clear(); } ///< Destructor
const vector<FlowBlock *> &getList(void) const { return list; } ///< Get the list of component FlowBlock objects
@@ -426,9 +435,10 @@ public:
BlockMultiGoto *newBlockMultiGoto(FlowBlock *bl,int4 outedge); ///< Build a new BlockMultiGoto
BlockList *newBlockList(const vector<FlowBlock *> &nodes); ///< Build a new BlockList
BlockCondition *newBlockCondition(FlowBlock *b1,FlowBlock *b2); ///< Build a new BlockCondition
BlockIf *newBlockIfGoto(FlowBlock *cond); ///< Build a new BlockIfGoto
BlockIfGoto *newBlockIfGoto(FlowBlock *cond); ///< Build a new BlockIfGoto
BlockIf *newBlockIf(FlowBlock *cond,FlowBlock *tc); ///< Build a new BlockIf
BlockIf *newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc); ///< Build a new BlockIfElse
BlockIfElse *newBlockIfElse(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc); ///< Build a new BlockIfElse
BlockIfNoExit *newBlockIfNoExit(FlowBlock *cond,FlowBlock *tc,FlowBlock *fc); ///< Build a new BlockIfNoExit
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
@@ -659,10 +669,6 @@ public:
/// the block of code executed when the condition is true. If there is a third component, it
/// is the "else" block, executed when the condition is false.
///
/// If there is only one component, this represents the case where the conditionally executed
/// branch is unstructured. This is generally emitted where the conditionally executed body
/// is the single \e goto statement.
///
/// A BlockIf will always have at most one (structured) exit edge. With one component, one of the edges of
/// the conditional component is unstructured. With two components, one of the conditional block
/// edges flows to the body block, and the body's out edge and the remaining conditional block out
@@ -670,22 +676,58 @@ public:
/// \e true body block, the other conditional edge flows to the \e false body block, and outgoing
/// edges from the body blocks, if they exist, flow to the same exit block.
class BlockIf : public BlockGraph {
uint4 gototype; ///< The type of unstructured edge (if present)
FlowBlock *gototarget; ///< The target FlowBlock of the unstructured edge (if present)
public:
BlockIf(void) { gototype = f_goto_goto; gototarget = (FlowBlock *)0; } ///< Constructor
void setGotoTarget(FlowBlock *bl) { gototarget = bl; } ///< Mark the target of the unstructured edge
FlowBlock *getGotoTarget(void) const { return gototarget; } ///< Get the target of the unstructured edge
uint4 getGotoType(void) const { return gototype; } ///< Get the type of unstructured edge
virtual block_type getType(void) const { return t_if; }
virtual void markUnstructured(void);
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual void emit(PrintLanguage *lng) const { lng->emitBlockIf(this); }
virtual bool preferComplement(Funcdata &data,bool allowOpRemoval);
virtual const FlowBlock *getExitLeaf(void) const;
virtual PcodeOp *lastOp(void) const;
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
};
/// \brief An "if" with two bodies of conditionally executed code
///
/// The first component is the \e conditional block. The second component is executed if the condition is \b true.
/// The third component is the "else" clause. Both bodies have at most one \e out edge.
class BlockIfElse : public BlockIf {
public:
virtual block_type getType(void) const { return t_ifelse; }
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual bool preferComplement(Funcdata &data,bool allowOpRemoval);
};
/// \brief An "if" with two bodies of executed code, neither of which has an exit
///
/// This always has three components, the \e conditional block, and two bodies. If the condition is \b true,
/// the first body is executed. The second "else" body is treated as if it were \e following the first body,
/// and it is rendered without explicit "else" syntax.
class BlockIfNoExit : public BlockIfElse {
public:
virtual block_type getType(void) const { return t_ifnoexit; }
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual bool preferComplement(Funcdata &data,bool allowOpRemoval);
virtual PcodeOp *lastOp(void) const { return getBlock(2)->lastOp(); }
};
/// \brief An "if" with one unstructured \e goto branch
///
/// This always has one component, the condition. One of the two branches is executed as a \e goto statement,
/// the target of which is stored internally.
/// The other branch is the (structured) exit.
class BlockIfGoto : public BlockIf {
uint4 gototype; ///< The type of unstructured edge (if present)
FlowBlock *gototarget; ///< The target FlowBlock of the unstructured edge (if present)
public:
BlockIfGoto(FlowBlock *target) { gototype = f_goto_goto; gototarget = target; } ///< Constructor
FlowBlock *getGotoTarget(void) const { return gototarget; } ///< Get the target of the unstructured edge
uint4 getGotoType(void) const { return gototype; } ///< Get the type of unstructured edge
virtual block_type getType(void) const { return t_ifgoto; }
virtual void scopeBreak(int4 curexit,int4 curloopexit);
virtual void printHeader(ostream &s) const;
virtual void markUnstructured(void);
virtual const FlowBlock *getExitLeaf(void) const { return getBlock(0)->getExitLeaf(); }
virtual PcodeOp *lastOp(void) const { return getBlock(0)->lastOp(); }
virtual void encodeBody(Encoder &encoder) const;
};
@@ -905,6 +947,16 @@ inline FlowBlock *FlowBlock::nextFlowAfter(const FlowBlock *bl) const
return (FlowBlock *)0;
}
/// If the last op is a halt of execution of some form, we return its code: \b halt, \b noreturn, \b badinstruction etc.
/// If it is not a halt, or if there is no last op, 0 is returned.
/// \return the \e halt code or 0
inline uint4 FlowBlock::getHaltType(void) const
{
PcodeOp *op = lastOp();
return (op != (PcodeOp *)0) ? op->getHaltType() : 0;
}
/// \param bl1 is the first FlowBlock to compare
/// \param bl2 is the second FlowBlock to compare
/// \return true if the first comes before the second
@@ -1496,11 +1496,19 @@ bool CollapseStructure::ruleBlockIfNoExit(FlowBlock *bl)
if (clauseblock->sizeOut() != 0) continue; // Must be no way out of clause
if (clauseblock->isSwitchOut()) continue;
if (!bl->isDecisionOut(i)) continue;
// if (clauseblock->isInteriorGotoTarget()) {
// bl->setGotoBranch(i);
// return true;
// }
if (i == 0) {
FlowBlock *otherblock = bl->getOut(1);
if (otherblock->sizeIn() == 1 &&
otherblock->sizeOut() == 0 &&
!otherblock->isSwitchOut() &&
bl->isDecisionOut(1)) {
// Both out edges go to "no exit" blocks
if (bl->negateCondition(true))
dataflow_changecount += 1;
graph.newBlockIfNoExit(bl,clauseblock,otherblock);
return true;
}
}
if (i==0) { // clause must be true out of bl
if (bl->negateCondition(true))
dataflow_changecount += 1;
@@ -2217,9 +2225,9 @@ void ActionReturnSplit::gatherReturnGotos(FlowBlock *parent,vector<FlowBlock *>
if (((BlockGoto *)bl)->gotoPrints())
ret = ((BlockGoto *)bl)->getGotoTarget();
}
else if (bl->getType() == FlowBlock::t_if)
else if (bl->getType() == FlowBlock::t_ifgoto)
// if this is an ifgoto block, get target, otherwise null
ret = ((BlockIf *)bl)->getGotoTarget();
ret = ((BlockIfGoto *)bl)->getGotoTarget();
if (ret != (FlowBlock *)0) {
while(ret->getType() != FlowBlock::t_basic)
ret = ret->subBlock(0);
@@ -3037,9 +3037,10 @@ void PrintC::emitBlockIf(const BlockIf *bl)
setMod(only_branch);
condBlock->emit(this);
popMod();
if (bl->getGotoTarget() != (FlowBlock *)0) {
FlowBlock::block_type mainType = bl->getType();
if (mainType == FlowBlock::t_ifgoto) {
emit->spaces(1);
emitGotoStatement(condBlock,bl->getGotoTarget(),bl->getGotoType());
emitGotoStatement(condBlock,((const BlockIfGoto *)bl)->getGotoTarget(),((const BlockIfGoto *)bl)->getGotoType());
}
else {
setMod(no_branch);
@@ -3048,11 +3049,12 @@ void PrintC::emitBlockIf(const BlockIf *bl)
bl->getBlock(1)->emit(this);
emit->endBlock(id1);
emit->closeBraceIndent(CLOSE_CURLY, id);
if (bl->getSize() == 3) {
if (mainType == FlowBlock::t_ifelse) {
emit->tagLine();
emit->print(KEYWORD_ELSE,EmitMarkup::keyword_color);
FlowBlock *elseBlock = bl->getBlock(2);
if (elseBlock->getType() == FlowBlock::t_if) {
FlowBlock::block_type type = elseBlock->getType();
if (type == FlowBlock::t_if || type == FlowBlock::t_ifelse || type == FlowBlock::t_ifgoto) {
// Attempt to merge the "else" and "if" syntax
setMod(pending_brace);
int4 id2 = emit->beginBlock(elseBlock);
@@ -3067,6 +3069,13 @@ void PrintC::emitBlockIf(const BlockIf *bl)
emit->closeBraceIndent(CLOSE_CURLY, id2);
}
}
else if (mainType == FlowBlock::t_ifnoexit) {
// Since the first body does not exit, we don't need an "else" and curly braces for the body on the alternate path
FlowBlock *followBlock = bl->getBlock(2);
int4 id2 = emit->beginBlock(followBlock);
followBlock->emit(this);
emit->endBlock(id2);
}
}
popMod();
if (pendingBrace.getIndentId() >= 0) {
@@ -89,7 +89,7 @@ f8040fbec0034704c30fb647088d5001
<stringmatch name="Bitfields #4" min="1" max="1">ptr-&gt;field5 = \(uint1\)val \+ 0x14;</stringmatch>
<stringmatch name="Bitfields #5" min="1" max="1">ptr-&gt;field7 = 100;</stringmatch>
<stringmatch name="Bitfields #6" min="1" max="1">return loadptr-&gt;field3;</stringmatch>
<stringmatch name="Bitfields #7" min="1" max="1">if \(.*2.* &lt; loadptr-&gt;sfield4\)</stringmatch>
<stringmatch name="Bitfields #7" min="1" max="1">if \(loadptr-&gt;sfield4 &lt; .*3.*\)</stringmatch>
<stringmatch name="Bitfields #8" min="1" max="1">-\(uint4\)!loadptr-&gt;fieldb &amp; 900</stringmatch>
<stringmatch name="Bitfields #9" min="1" max="1">return loadptr-&gt;field2;</stringmatch>
<stringmatch name="Bitfields #10" min="1" max="1">return loadptr-&gt;field5 \+ loadptr-&gt;field2;</stringmatch>
@@ -123,7 +123,7 @@
<stringmatch name="MIPS Bitfields #7" min="1" max="1">return lp-&gt;field5 \+ lp-&gt;field2;</stringmatch>
<stringmatch name="MIPS Bitfields #8" min="1" max="1">if \(lp-&gt;sfield4 &lt; .*3.*\)</stringmatch>
<stringmatch name="MIPS Bitfields #9" min="1" max="1">return lp-&gt;field2;</stringmatch>
<stringmatch name="MIPS Bitfields #10" min="1" max="1">if \(!+lp-&gt;fieldb\)</stringmatch>
<stringmatch name="MIPS Bitfields #10" min="1" max="1">if \(lp-&gt;fieldb\)</stringmatch>
<stringmatch name="MIPS Bitfields #11" min="1" max="1">mStack_18\.sfield4 = \(char\)stki_a \+ .*1.*;</stringmatch>
<stringmatch name="MIPS Bitfields #12" min="1" max="1">mStack_18\.field3 = stki_b;</stringmatch>
<stringmatch name="MIPS Bitfields #13" min="1" max="1">mStack_18\.fieldb = stki_a &lt; 10;</stringmatch>
@@ -0,0 +1,36 @@
<decompilertest>
<!--
A loop body that should not be a part of nested ifs. If blocks that just return should
be displayed first.
-->
<binaryimage arch="x86:LE:64:default:gcc">
<bytechunk space="ram" offset="0x100000" readonly="true">
83ff64742c81ffc8000000742a81ff2c
01000075284889f04883c628c7000700
00004883c0044839f075f1b800000000
c3b8ffffffffc3b8feffffffc3b8fdff
ffffc3
</bytechunk>
<symbol space="ram" offset="0x100000" name="ifnoexit"/>
</binaryimage>
<script>
<com>parse line extern int4 ifnoexit(int4 val,int4 *ptr);</com>
<com>lo fu ifnoexit</com>
<com>dec</com>
<com>print C</com>
<com>quit</com>
</script>
<stringmatch name="If no exit #1" min="1" max="1">if \(val == 100\) \{
return -1;
\}</stringmatch>
<stringmatch name="If no exit #2" min="1" max="1">if \(val == 200\) \{
return -2;
\}</stringmatch>
<stringmatch name="If no exit #3" min="1" max="1">if \(val != 300\) \{
return -3;
\}
piVar. = ptr \+ 10;
do \{</stringmatch>
<stringmatch name="If no exit #4" min="1" max="1">\} while \(ptr != piVar.\);
return 0;</stringmatch>
</decompilertest>
@@ -25,5 +25,5 @@ c1e20409d07510833d920f000007ba02
<com>quit</com>
</script>
<stringmatch name="Compare INT_OR #1" min="1" max="1">if \(a == 10 \|\| b == 0x14\)</stringmatch>
<stringmatch name="Compare INT_OR #2" min="1" max="1">if \(\(y != 200 &amp;&amp; x != 100\) &amp;&amp; z != 300\)</stringmatch>
<stringmatch name="Compare INT_OR #2" min="1" max="1">if \(\(y == 200 \|\| x == 100\) \|\| z == 300\)</stringmatch>
</decompilertest>
@@ -24,7 +24,7 @@ f3c3
<com>quit</com>
</script>
<stringmatch name="Signed byte #1" min="1" max="1">Var1 = ptr->thebyte</stringmatch>
<stringmatch name="Signed byte #2" min="1" max="1">Var1 != 10</stringmatch>
<stringmatch name="Signed byte #3" min="1" max="1">Var1 != -9</stringmatch>
<stringmatch name="Signed byte #4" min="1" max="1">Var1 &lt; 0x62</stringmatch>
<stringmatch name="Signed byte #2" min="1" max="1">Var1 == 10</stringmatch>
<stringmatch name="Signed byte #3" min="1" max="1">Var1 == -9</stringmatch>
<stringmatch name="Signed byte #4" min="1" max="1">0x61 &lt; .Var1</stringmatch>
</decompilertest>