diff --git a/Ghidra/Features/Decompiler/certification.manifest b/Ghidra/Features/Decompiler/certification.manifest index 899dd6ef50..dbaf56ed40 100644 --- a/Ghidra/Features/Decompiler/certification.manifest +++ b/Ghidra/Features/Decompiler/certification.manifest @@ -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| diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc index aa154772f7..55fc9264ea 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.cc @@ -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 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 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 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;iscopeBreak(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 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 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 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. diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh index 1cae714ed7..4cae06ac47 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/block.hh @@ -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 intothis; ///< Blocks which (can) fall into this block vector 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 &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 &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 &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 diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc index 5a2b0f5c85..1b92984c01 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/blockaction.cc @@ -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 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); diff --git a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc index f0d530d1de..6ccbfd1a98 100644 --- a/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc +++ b/Ghidra/Features/Decompiler/src/decompile/cpp/printc.cc @@ -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) { diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields.xml index 16fa515465..7cace06a59 100644 --- a/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields.xml +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields.xml @@ -89,7 +89,7 @@ f8040fbec0034704c30fb647088d5001 ptr->field5 = \(uint1\)val \+ 0x14; ptr->field7 = 100; return loadptr->field3; -if \(.*2.* < loadptr->sfield4\) +if \(loadptr->sfield4 < .*3.*\) -\(uint4\)!loadptr->fieldb & 900 return loadptr->field2; return loadptr->field5 \+ loadptr->field2; diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields2.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields2.xml index ff1c90272a..acb8f794f7 100644 --- a/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields2.xml +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/bitfields2.xml @@ -123,7 +123,7 @@ return lp->field5 \+ lp->field2; if \(lp->sfield4 < .*3.*\) return lp->field2; -if \(!+lp->fieldb\) +if \(lp->fieldb\) mStack_18\.sfield4 = \(char\)stki_a \+ .*1.*; mStack_18\.field3 = stki_b; mStack_18\.fieldb = stki_a < 10; diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/ifnoexit.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/ifnoexit.xml new file mode 100644 index 0000000000..fde3992c3b --- /dev/null +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/ifnoexit.xml @@ -0,0 +1,36 @@ + + + + +83ff64742c81ffc8000000742a81ff2c +01000075284889f04883c628c7000700 +00004883c0044839f075f1b800000000 +c3b8ffffffffc3b8feffffffc3b8fdff +ffffc3 + + + + +if \(val == 100\) \{ + return -1; + \} +if \(val == 200\) \{ + return -2; + \} +if \(val != 300\) \{ + return -3; + \} + piVar. = ptr \+ 10; + do \{ +\} while \(ptr != piVar.\); + return 0; + diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/orcompare.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/orcompare.xml index 8d28d7cd16..835113f449 100644 --- a/Ghidra/Features/Decompiler/src/decompile/datatests/orcompare.xml +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/orcompare.xml @@ -25,5 +25,5 @@ c1e20409d07510833d920f000007ba02 quit if \(a == 10 \|\| b == 0x14\) -if \(\(y != 200 && x != 100\) && z != 300\) +if \(\(y == 200 \|\| x == 100\) \|\| z == 300\) diff --git a/Ghidra/Features/Decompiler/src/decompile/datatests/sbyte.xml b/Ghidra/Features/Decompiler/src/decompile/datatests/sbyte.xml index 3f62c807bc..4b302897c4 100644 --- a/Ghidra/Features/Decompiler/src/decompile/datatests/sbyte.xml +++ b/Ghidra/Features/Decompiler/src/decompile/datatests/sbyte.xml @@ -24,7 +24,7 @@ f3c3 quit Var1 = ptr->thebyte -Var1 != 10 -Var1 != -9 -Var1 < 0x62 +Var1 == 10 +Var1 == -9 +0x61 < .Var1