mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-08-18 08:22:06 +08:00
Merge remote-tracking branch 'origin/GP-7115_NormalizeIfNoExit'
This commit is contained in:
@@ -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->field5 = \(uint1\)val \+ 0x14;</stringmatch>
|
||||
<stringmatch name="Bitfields #5" min="1" max="1">ptr->field7 = 100;</stringmatch>
|
||||
<stringmatch name="Bitfields #6" min="1" max="1">return loadptr->field3;</stringmatch>
|
||||
<stringmatch name="Bitfields #7" min="1" max="1">if \(.*2.* < loadptr->sfield4\)</stringmatch>
|
||||
<stringmatch name="Bitfields #7" min="1" max="1">if \(loadptr->sfield4 < .*3.*\)</stringmatch>
|
||||
<stringmatch name="Bitfields #8" min="1" max="1">-\(uint4\)!loadptr->fieldb & 900</stringmatch>
|
||||
<stringmatch name="Bitfields #9" min="1" max="1">return loadptr->field2;</stringmatch>
|
||||
<stringmatch name="Bitfields #10" min="1" max="1">return loadptr->field5 \+ loadptr->field2;</stringmatch>
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
<stringmatch name="MIPS Bitfields #7" min="1" max="1">return lp->field5 \+ lp->field2;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #8" min="1" max="1">if \(lp->sfield4 < .*3.*\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #9" min="1" max="1">return lp->field2;</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #10" min="1" max="1">if \(!+lp->fieldb\)</stringmatch>
|
||||
<stringmatch name="MIPS Bitfields #10" min="1" max="1">if \(lp->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 < 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 && x != 100\) && 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 < 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 < .Var1</stringmatch>
|
||||
</decompilertest>
|
||||
|
||||
Reference in New Issue
Block a user