mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-27 14:31:29 +08:00
Merge remote-tracking branch 'origin/GP-6788_CopyTrim' (Closes #8970)
This commit is contained in:
@@ -24,6 +24,7 @@ src/decompile/datatests/condconstsub.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condexesub.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/condmulti.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/convert.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/copytrim.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/deadvolatile.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/deindirect.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/deindirect2.xml||GHIDRA||||END|
|
||||
|
||||
@@ -1042,7 +1042,7 @@ void BlockGraph::findSpanningTree(vector<FlowBlock *> &preorder,vector<FlowBlock
|
||||
bool extraroots = false;
|
||||
int4 rpostcount = list.size();
|
||||
int4 rootindex = 0;
|
||||
clearEdgeFlags(~((uint4)0)); // Clear all edge flags
|
||||
clearEdgeFlags(f_irreducible|f_tree_edge|f_forward_edge|f_cross_edge|f_back_edge|f_loop_edge|f_loop_exit_edge); // Clear spanning tree
|
||||
while(preorder.size() < list.size()) {
|
||||
FlowBlock *startbl = (FlowBlock *)0;
|
||||
while(rootindex<rootlist.size()) { // Go thru blocks with no in edges
|
||||
@@ -1244,6 +1244,7 @@ void BlockGraph::clear(void)
|
||||
for(iter=list.begin();iter!=list.end();++iter)
|
||||
delete *iter;
|
||||
list.clear();
|
||||
clearAllFlags();
|
||||
}
|
||||
|
||||
void BlockGraph::markUnstructured(void)
|
||||
@@ -1352,13 +1353,16 @@ FlowBlock *BlockGraph::nextFlowAfter(const FlowBlock *bl) const
|
||||
return nextbl;
|
||||
}
|
||||
|
||||
void BlockGraph::finalTransform(Funcdata &data)
|
||||
void BlockGraph::finalTransform(Funcdata &data,bool allowOpMoves)
|
||||
|
||||
{
|
||||
if (hasFinalTransform())
|
||||
return; // Already performed
|
||||
// Recurse into all the substructures
|
||||
vector<FlowBlock *>::const_iterator iter;
|
||||
for(iter=list.begin();iter!=list.end();++iter)
|
||||
(*iter)->finalTransform(data);
|
||||
(*iter)->finalTransform(data,allowOpMoves);
|
||||
setFlag(f_final_transform); // Mark that transform has been performed
|
||||
}
|
||||
|
||||
void BlockGraph::finalizePrinting(Funcdata &data) const
|
||||
@@ -2365,14 +2369,23 @@ FlowBlock *BlockBasic::getSplitPoint(void)
|
||||
return this;
|
||||
}
|
||||
|
||||
int4 BlockBasic::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
|
||||
int4 BlockBasic::flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const
|
||||
|
||||
{
|
||||
if (op.empty()) return 2;
|
||||
PcodeOp *lastop = op.back();
|
||||
if (lastop->code() != CPUI_CBRANCH)
|
||||
return 2;
|
||||
return Funcdata::opFlipInPlaceTest(lastop,fliplist);
|
||||
int4 res;
|
||||
if (lastop->isBooleanFlip()) {
|
||||
// If the flip bit is set, don't change any ops to accomplish flip
|
||||
vector<PcodeOp *> unusedOps;
|
||||
res = Funcdata::opFlipInPlaceTest(lastop,unusedOps,allowOpRemoval);
|
||||
}
|
||||
else {
|
||||
res = Funcdata::opFlipInPlaceTest(lastop,fliplist,allowOpRemoval);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
void BlockBasic::flipInPlaceExecute(void)
|
||||
@@ -2381,7 +2394,9 @@ void BlockBasic::flipInPlaceExecute(void)
|
||||
PcodeOp *lastop = op.back();
|
||||
// This is similar to negateCondition but we don't need to set the boolean_flip flag on lastop
|
||||
// because it is getting explicitly changed
|
||||
lastop->flipFlag(PcodeOp::fallthru_true); // Flip whether the fallthru block is true/false
|
||||
lastop->flipFlag(PcodeOp::fallthru_true); // Flip whether the fallthru block is true/false
|
||||
if (lastop->isBooleanFlip()) // If the flip flag is set
|
||||
lastop->flipFlag(PcodeOp::boolean_flip); // unflip it (instead of flipping ops)
|
||||
FlowBlock::negateCondition(true); // Flip the order of outof this
|
||||
}
|
||||
|
||||
@@ -2443,6 +2458,18 @@ bool BlockBasic::isComplex(void) const
|
||||
return false;
|
||||
}
|
||||
|
||||
void BlockBasic::finalTransform(Funcdata &data,bool allowOpMoves)
|
||||
|
||||
{
|
||||
if (sizeOut() != 2) return;
|
||||
PcodeOp *cbranch = lastOp();
|
||||
if (cbranch == (PcodeOp *)0 || cbranch->code() != CPUI_CBRANCH)
|
||||
return;
|
||||
if (!cbranch->isBooleanFlip())
|
||||
return;
|
||||
data.opNormalizeFlip(cbranch);
|
||||
}
|
||||
|
||||
/// \param encoder is the stream encoder
|
||||
void FlowBlock::encodeHeader(Encoder &encoder) const
|
||||
|
||||
@@ -2552,13 +2579,14 @@ bool BlockBasic::unblockedMulti(int4 outslot) const
|
||||
// outlists
|
||||
}
|
||||
if (redundlist.empty()) return true;
|
||||
int4 inIndexToThis = blout->getInIndex(this);
|
||||
for(iter=blout->op.begin();iter!=blout->op.end();++iter) {
|
||||
multiop = *iter;
|
||||
if (multiop->code() != CPUI_MULTIEQUAL) continue;
|
||||
for(vector<const FlowBlock *>::iterator biter=redundlist.begin();biter!=redundlist.end();++biter) {
|
||||
bl = *biter;
|
||||
vnredund = multiop->getIn(blout->getInIndex(bl)); // One of the redundant varnodes
|
||||
vnremove = multiop->getIn(blout->getInIndex(this));
|
||||
vnremove = multiop->getIn(inIndexToThis);
|
||||
if (vnremove->isWritten()) {
|
||||
othermulti = vnremove->getDef();
|
||||
if ((othermulti->code()==CPUI_MULTIEQUAL)&&(othermulti->getParent()==this))
|
||||
@@ -2570,6 +2598,26 @@ bool BlockBasic::unblockedMulti(int4 outslot) const
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Was there copy propagation directly out of \b this block into a MULTIEQUAL in the immediate \e out block?
|
||||
/// If so, \b this block shouldn't be removed as the COPY may need to be put back during merge.
|
||||
/// \param outslot is the output edge to search along
|
||||
/// \return \b true if there was no immediate copy propagation, \b false otherwise
|
||||
bool BlockBasic::hasNoImmediateCopy(int4 outslot) const
|
||||
|
||||
{
|
||||
if (!hasImmedCopyEdge(outslot)) return true;
|
||||
const BlockBasic *blout = (const BlockBasic *)getOut(outslot);
|
||||
int4 inIndexToThis = blout->getInIndex(this);
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
for(iter=blout->op.begin();iter!=blout->op.end();++iter) {
|
||||
PcodeOp *multiop = *iter;
|
||||
if (multiop->code() != CPUI_MULTIEQUAL) continue;
|
||||
if (multiop->hasCopyImmed(inIndexToThis))
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// This is a crucial test for whether \b this block is doing anything substantial
|
||||
/// or is a candidate for removal. Even blocks that "do nothing" have some kind of branch
|
||||
/// and placeholder operations (MULTIEQUAL and INDIRECT) for data flowing through the block.
|
||||
@@ -2987,7 +3035,7 @@ void BlockList::printHeader(ostream &s) const
|
||||
FlowBlock::printHeader(s);
|
||||
}
|
||||
|
||||
int4 BlockCondition::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
|
||||
int4 BlockCondition::flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const
|
||||
|
||||
{
|
||||
FlowBlock *split1 = getBlock(0)->getSplitPoint();
|
||||
@@ -2996,10 +3044,10 @@ int4 BlockCondition::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
|
||||
FlowBlock *split2 = getBlock(1)->getSplitPoint();
|
||||
if (split2 == (FlowBlock *)0)
|
||||
return 2;
|
||||
int4 subtest1 = split1->flipInPlaceTest(fliplist);
|
||||
int4 subtest1 = split1->flipInPlaceTest(fliplist,allowOpRemoval);
|
||||
if (subtest1 == 2)
|
||||
return 2;
|
||||
int4 subtest2 = split2->flipInPlaceTest(fliplist);
|
||||
int4 subtest2 = split2->flipInPlaceTest(fliplist,allowOpRemoval);
|
||||
if (subtest2 == 2)
|
||||
return 2;
|
||||
return subtest1;
|
||||
@@ -3090,7 +3138,7 @@ void BlockIf::printHeader(ostream &s) const
|
||||
FlowBlock::printHeader(s);
|
||||
}
|
||||
|
||||
bool BlockIf::preferComplement(Funcdata &data)
|
||||
bool BlockIf::preferComplement(Funcdata &data,bool allowOpRemoval)
|
||||
|
||||
{
|
||||
if (getSize()!=3) // If we are an if/else
|
||||
@@ -3100,7 +3148,7 @@ bool BlockIf::preferComplement(Funcdata &data)
|
||||
if (split == (FlowBlock *)0)
|
||||
return false;
|
||||
vector<PcodeOp *> fliplist;
|
||||
if (0 != split->flipInPlaceTest(fliplist))
|
||||
if (0 != split->flipInPlaceTest(fliplist,allowOpRemoval))
|
||||
return false;
|
||||
split->flipInPlaceExecute();
|
||||
data.opFlipInPlaceExecute(fliplist);
|
||||
@@ -3353,10 +3401,11 @@ FlowBlock *BlockWhileDo::nextFlowAfter(const FlowBlock *bl) const
|
||||
/// Determine if \b this block can be printed as a \e for loop, with an \e initializer statement
|
||||
/// extracted from the previous block, and an \e iterator statement extracted from the body.
|
||||
/// \param data is the function containing \b this loop
|
||||
void BlockWhileDo::finalTransform(Funcdata &data)
|
||||
/// \param allowOpMoves is \b true if iterator and initializer ops can be moved
|
||||
void BlockWhileDo::finalTransform(Funcdata &data,bool allowOpMoves)
|
||||
|
||||
{
|
||||
BlockGraph::finalTransform(data);
|
||||
BlockGraph::finalTransform(data,allowOpMoves);
|
||||
if (!data.getArch()->analyze_for_loops) return;
|
||||
if (hasOverflowSyntax()) return;
|
||||
FlowBlock *copyBl = getFrontLeaf();
|
||||
@@ -3379,6 +3428,7 @@ void BlockWhileDo::finalTransform(Funcdata &data)
|
||||
if (iterateOp == (PcodeOp *)0) return;
|
||||
|
||||
if (iterateOp != lastOp) {
|
||||
if (!allowOpMoves) return;
|
||||
data.opUninsert(iterateOp);
|
||||
data.opInsertAfter(iterateOp, lastOp);
|
||||
}
|
||||
@@ -3391,6 +3441,7 @@ void BlockWhileDo::finalTransform(Funcdata &data)
|
||||
return;
|
||||
}
|
||||
if (initializeOp != lastOp) {
|
||||
if (!allowOpMoves) return;
|
||||
data.opUninsert(initializeOp);
|
||||
data.opInsertAfter(initializeOp, lastOp);
|
||||
}
|
||||
|
||||
@@ -102,7 +102,9 @@ public:
|
||||
f_whiledo_overflow = 0x8000,///< Set if the conditional block of a whiledo is too big to print as while(cond) { ...
|
||||
f_flip_path = 0x10000, ///< If true, out edges have been flipped since last time path was traced
|
||||
f_joined_block = 0x20000, ///< Block is a merged form of original basic blocks
|
||||
f_duplicate_block = 0x40000 ///< Block is a duplicated version of an original basic block
|
||||
f_duplicate_block = 0x40000, ///< Block is a duplicated version of an original basic block
|
||||
f_delayed_donothing = 0x80000, ///< Potential \e do \e nothing block whose removal has been delayed
|
||||
f_final_transform = 0x100000 ///< Has the final transform been run
|
||||
};
|
||||
/// \brief Boolean properties on edges
|
||||
enum edge_flags {
|
||||
@@ -114,7 +116,8 @@ public:
|
||||
f_forward_edge = 0x20, ///< An edge that jumps forward in the spanning tree
|
||||
f_cross_edge = 0x40, ///< An edge that crosses subtrees in the spanning tree
|
||||
f_back_edge = 0x80, ///< Within (reducible) graph, a back edge defining a loop
|
||||
f_loop_exit_edge = 0x100 ///< Edge exits the body of a loop
|
||||
f_loop_exit_edge = 0x100, ///< Edge exits the body of a loop
|
||||
f_immed_copy = 0x200 ///< Copy propagation has happened across the edge
|
||||
};
|
||||
private:
|
||||
uint4 flags; ///< Collection of block_flags
|
||||
@@ -154,6 +157,7 @@ private:
|
||||
protected:
|
||||
void setFlag(uint4 fl) { flags |= fl; } ///< Set a boolean property
|
||||
void clearFlag(uint4 fl) { flags &= ~fl; } ///< Clear a boolean property
|
||||
void clearAllFlags(void) { flags = 0; } ///< Clear all properties of \b this block
|
||||
public:
|
||||
FlowBlock(void); ///< Construct a block with no edges
|
||||
virtual ~FlowBlock(void) {} ///< Destructor
|
||||
@@ -239,9 +243,9 @@ public:
|
||||
virtual PcodeOp *lastOp(void) const { return (PcodeOp *)0; }
|
||||
|
||||
virtual bool negateCondition(bool toporbottom); ///< Flip the condition computed by \b this
|
||||
virtual bool preferComplement(Funcdata &data); ///< Rearrange \b this hierarchy to simplify boolean expressions
|
||||
virtual bool preferComplement(Funcdata &data,bool allowOpRemoval); ///< Rearrange \b this hierarchy to simplify boolean expressions
|
||||
virtual FlowBlock *getSplitPoint(void); ///< Get the leaf splitting block
|
||||
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist) const;
|
||||
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const;
|
||||
virtual void flipInPlaceExecute(void);
|
||||
|
||||
/// \brief Is \b this too complex to be a condition (BlockCondition)
|
||||
@@ -254,7 +258,8 @@ public:
|
||||
/// \brief Do any structure driven final transforms
|
||||
///
|
||||
/// \param data is the function to transform
|
||||
virtual void finalTransform(Funcdata &data) {}
|
||||
/// \param allowOpMoves is \b true if ops may be moved within their basic block
|
||||
virtual void finalTransform(Funcdata &data,bool allowOpMoves) {}
|
||||
|
||||
/// \brief Make any final configurations necessary to emit the block
|
||||
///
|
||||
@@ -294,6 +299,8 @@ public:
|
||||
void setLoopExit(int4 i) { setOutEdgeFlag(i,f_loop_exit_edge); } ///< Label the edge exiting \b this as a loop
|
||||
void clearLoopExit(int4 i) { clearOutEdgeFlag(i,f_loop_exit_edge); } ///< Clear the loop exit edge
|
||||
void setBackEdge(int4 i) { setOutEdgeFlag(i,f_back_edge); } ///< Label the \e back edge of a loop
|
||||
void setImmedCopyEdge(int4 i) { setOutEdgeFlag(i,f_immed_copy); } ///< Mark that an immediate COPY has propagated across the edge
|
||||
bool hasImmedCopyEdge(int4 i) const { return ((outofthis[i].label & f_immed_copy)!=0); } ///< Has an immediate COPY propagated across the edge
|
||||
bool getFlipPath(void) const { return ((flags & f_flip_path)!=0); } ///< Have out edges been flipped
|
||||
bool isJumpTarget(void) const; ///< Return \b true if non-fallthru jump flows into \b this
|
||||
FlowBlock *getFalseOut(void) const { return outofthis[0].point; } ///< Get the \b false output FlowBlock
|
||||
@@ -393,7 +400,7 @@ public:
|
||||
virtual void emit(PrintLanguage *lng) const { lng->emitBlockGraph(this); }
|
||||
virtual PcodeOp *firstOp(void) const;
|
||||
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
|
||||
virtual void finalTransform(Funcdata &data);
|
||||
virtual void finalTransform(Funcdata &data,bool allowOpMoves);
|
||||
virtual void finalizePrinting(Funcdata &data) const;
|
||||
virtual void encodeBody(Encoder &encoder) const;
|
||||
virtual void decodeBody(Decoder &decoder);
|
||||
@@ -438,6 +445,7 @@ public:
|
||||
void calcLoop(void); ///< Calculate loop edges
|
||||
void collectReachable(vector<FlowBlock *> &res,FlowBlock *bl,bool un) const; ///< Collect reachable/unreachable FlowBlocks from a given start FlowBlock
|
||||
void structureLoops(vector<FlowBlock *> &rootlist); ///< Label loop edges
|
||||
bool hasFinalTransform(void) const { return ((getFlags() & f_final_transform) != 0); } ///< Return \b true if finalTransform() has been run on \b this
|
||||
#ifdef BLOCKCONSISTENT_DEBUG
|
||||
bool isConsistent(void) const; ///< Check consistency of \b this BlockGraph
|
||||
#endif
|
||||
@@ -490,10 +498,12 @@ public:
|
||||
virtual PcodeOp *lastOp(void) const;
|
||||
virtual bool negateCondition(bool toporbottom);
|
||||
virtual FlowBlock *getSplitPoint(void);
|
||||
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist) const;
|
||||
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const;
|
||||
virtual void flipInPlaceExecute(void);
|
||||
virtual bool isComplex(void) const;
|
||||
bool unblockedMulti(int4 outslot) const; ///< Check if \b this block can be removed without introducing inconsistencies
|
||||
virtual void finalTransform(Funcdata &data,bool allowOpMoves);
|
||||
bool unblockedMulti(int4 outslot) const; ///< Check if \b this block can be removed without introducing inconsistencies
|
||||
bool hasNoImmediateCopy(int4 outslot) const; ///< Check if there have been immediate COPYs out of \b this block
|
||||
bool hasOnlyMarkers(void) const; ///< Does \b this block contain only MULTIEQUAL and INDIRECT ops
|
||||
bool isDoNothing(void) const; ///< Should \b this block should be removed
|
||||
list<PcodeOp *>::iterator beginOp(void) { return op.begin(); } ///< Return an iterator to the beginning of the PcodeOps
|
||||
@@ -504,6 +514,9 @@ public:
|
||||
bool noInterveningStatement(void) const;
|
||||
PcodeOp *findMultiequal(const vector<Varnode *> &varArray); ///< Find MULTIEQUAL with given inputs
|
||||
PcodeOp *earliestUse(Varnode *vn);
|
||||
void setDelayedDonothing(void) { setFlag(f_delayed_donothing); } ///< Mark as \e do \e nothing block with delayed removal
|
||||
void clearDelayedDonothing(void) { clearFlag(f_delayed_donothing); } ///< Clear mark for delayed removal
|
||||
bool isDelayedDonothing(void) const { return ((getFlags() & f_delayed_donothing) != 0); } ///< Is block marked for delayed removal
|
||||
static bool liftVerifyUnroll(vector<Varnode *> &varArray,int4 slot); ///< Verify given Varnodes are defined with same PcodeOp
|
||||
};
|
||||
|
||||
@@ -534,6 +547,7 @@ public:
|
||||
virtual bool negateCondition(bool toporbottom) { bool res = copy->negateCondition(true); FlowBlock::negateCondition(toporbottom); return res; }
|
||||
virtual FlowBlock *getSplitPoint(void) { return copy->getSplitPoint(); }
|
||||
virtual bool isComplex(void) const { return copy->isComplex(); }
|
||||
virtual void finalTransform(Funcdata &data,bool allowOpMoves) { return copy->finalTransform(data,allowOpMoves); }
|
||||
virtual void encodeHeader(Encoder &encoder) const;
|
||||
};
|
||||
|
||||
@@ -629,7 +643,7 @@ public:
|
||||
virtual void emit(PrintLanguage *lng) const { lng->emitBlockCondition(this); }
|
||||
virtual bool negateCondition(bool toporbottom);
|
||||
virtual FlowBlock *getSplitPoint(void) { return this; }
|
||||
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist) const;
|
||||
virtual int4 flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const;
|
||||
virtual void flipInPlaceExecute(void);
|
||||
virtual PcodeOp *lastOp(void) const;
|
||||
virtual bool isComplex(void) const { return getBlock(0)->isComplex(); }
|
||||
@@ -668,7 +682,7 @@ public:
|
||||
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);
|
||||
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;
|
||||
@@ -710,7 +724,7 @@ public:
|
||||
virtual void printHeader(ostream &s) const;
|
||||
virtual void emit(PrintLanguage *lng) const { lng->emitBlockWhileDo(this); }
|
||||
virtual FlowBlock *nextFlowAfter(const FlowBlock *bl) const;
|
||||
virtual void finalTransform(Funcdata &data);
|
||||
virtual void finalTransform(Funcdata &data,bool allowOpMoves);
|
||||
virtual void finalizePrinting(Funcdata &data) const;
|
||||
};
|
||||
|
||||
@@ -831,8 +845,9 @@ inline void FlowBlock::emit(PrintLanguage *lng) const
|
||||
/// For the instructions in this block, decide if the control-flow structure
|
||||
/// can be rearranged so that boolean expressions come out more naturally.
|
||||
/// \param data is the function to analyze
|
||||
/// \param allowOpRemoval if \b true, changes can include removal of ops
|
||||
/// \return \b true if a change was made
|
||||
inline bool FlowBlock::preferComplement(Funcdata &data)
|
||||
inline bool FlowBlock::preferComplement(Funcdata &data,bool allowOpRemoval)
|
||||
|
||||
{
|
||||
return false;
|
||||
@@ -851,15 +866,17 @@ inline FlowBlock *FlowBlock::getSplitPoint(void)
|
||||
/// \brief Test normalizing the conditional branch in \b this
|
||||
///
|
||||
/// Find the set of PcodeOp objects that need to be adjusted to flip
|
||||
/// the condition \b this FlowBlock calculates.
|
||||
/// the condition \b this FlowBlock calculates. If \b allowOpRemoval is set,
|
||||
/// the adjustment can include the removal of (BOOL_NEGATE) ops.
|
||||
///
|
||||
/// Return:
|
||||
/// - 0 if the flip would normalize the condition
|
||||
/// - 1 if the flip doesn't affect normalization of the condition
|
||||
/// - 2 if the flip produces an unnormalized condition
|
||||
/// - 1 if the flip denormalizes (or doesn't affect normalization)
|
||||
/// - 2 if a flip is not possible
|
||||
/// \param fliplist will contain the PcodeOps that need to be adjusted
|
||||
/// \param allowOpRemoval if \b true adjustments can include removal of ops
|
||||
/// \return 0 if the condition will be normalized, 1 or 2 otherwise
|
||||
inline int4 FlowBlock::flipInPlaceTest(vector<PcodeOp *> &fliplist) const
|
||||
inline int4 FlowBlock::flipInPlaceTest(vector<PcodeOp *> &fliplist,bool allowOpRemoval) const
|
||||
|
||||
{
|
||||
return 2; // By default a block will not normalize
|
||||
|
||||
@@ -2110,7 +2110,7 @@ void ConditionalJoin::clear(void)
|
||||
int4 ActionStructureTransform::apply(Funcdata &data)
|
||||
|
||||
{
|
||||
data.getStructure().finalTransform(data);
|
||||
data.getStructure().finalTransform(data,allowOpMoves);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2127,7 +2127,7 @@ int4 ActionNormalizeBranches::apply(Funcdata &data)
|
||||
if (cbranch == (PcodeOp *)0) continue;
|
||||
if (cbranch->code() != CPUI_CBRANCH) continue;
|
||||
fliplist.clear();
|
||||
if (Funcdata::opFlipInPlaceTest(cbranch,fliplist) != 0)
|
||||
if (Funcdata::opFlipInPlaceTest(cbranch,fliplist,true) != 0)
|
||||
continue;
|
||||
data.opFlipInPlaceExecute(fliplist);
|
||||
bb->flipInPlaceExecute();
|
||||
@@ -2143,6 +2143,7 @@ int4 ActionPreferComplement::apply(Funcdata &data)
|
||||
BlockGraph &graph(data.getStructure());
|
||||
|
||||
if (graph.getSize() == 0) return 0;
|
||||
if (graph.hasFinalTransform()) return 0;
|
||||
vector<BlockGraph *> vec;
|
||||
vec.push_back(&graph);
|
||||
int4 pos = 0;
|
||||
@@ -2159,7 +2160,7 @@ int4 ActionPreferComplement::apply(Funcdata &data)
|
||||
continue;
|
||||
vec.push_back((BlockGraph *)childbl);
|
||||
}
|
||||
if (curbl->preferComplement(data))
|
||||
if (curbl->preferComplement(data,allowOpMods))
|
||||
count += 1;
|
||||
}
|
||||
data.clearDeadOps(); // Clear any ops deleted during this action
|
||||
|
||||
@@ -268,11 +268,12 @@ public:
|
||||
///
|
||||
/// This is currently used to set up \e for loops via BlockWhileDo
|
||||
class ActionStructureTransform : public Action {
|
||||
bool allowOpMoves; ///< Are p-code ops allowed to be moved by \b this action
|
||||
public:
|
||||
ActionStructureTransform(const string &g) : Action(0,"structuretransform",g) {} ///< Constructor
|
||||
ActionStructureTransform(const string &g,bool allowMoves) : Action(0,"structuretransform",g) { allowOpMoves = allowMoves; } ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
if (!grouplist.contains(getGroup())) return (Action *)0;
|
||||
return new ActionStructureTransform(getGroup());
|
||||
return new ActionStructureTransform(getGroup(),allowOpMoves);
|
||||
}
|
||||
virtual int4 apply(Funcdata &data);
|
||||
};
|
||||
@@ -298,11 +299,12 @@ public:
|
||||
/// This uses the preferComplement() method on structured FlowBlocks to choose between symmetric
|
||||
/// structurings, such as an if/else where the \b true and \b false blocks can be swapped.
|
||||
class ActionPreferComplement : public Action {
|
||||
bool allowOpMods; ///< Are p-code ops allowed to be modified by \b this action
|
||||
public:
|
||||
ActionPreferComplement(const string &g) : Action(0,"prefercomplement",g) {} ///< Constructor
|
||||
ActionPreferComplement(const string &g,bool allowMods) : Action(0,"prefercomplement",g) { allowOpMods = allowMods; } ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
if (!grouplist.contains(getGroup())) return (Action *)0;
|
||||
return new ActionPreferComplement(getGroup());
|
||||
return new ActionPreferComplement(getGroup(),allowOpMods);
|
||||
}
|
||||
virtual int4 apply(Funcdata &data);
|
||||
};
|
||||
|
||||
@@ -3552,12 +3552,11 @@ int4 ActionUnreachable::apply(Funcdata &data)
|
||||
int4 ActionDoNothing::apply(Funcdata &data)
|
||||
|
||||
{ // Remove blocks that do nothing
|
||||
int4 i;
|
||||
const BlockGraph &graph(data.getBasicBlocks());
|
||||
BlockBasic *bb;
|
||||
|
||||
for(i=0;i<graph.getSize();++i) {
|
||||
bb = (BlockBasic *) graph.getBlock(i);
|
||||
for(int4 i=0;i<graph.getSize();++i) {
|
||||
BlockBasic *bb = (BlockBasic *) graph.getBlock(i);
|
||||
bb->clearDelayedDonothing();
|
||||
if (bb->isDoNothing()) {
|
||||
if ((bb->sizeOut()==1)&&(bb->getOut(0)==bb)) { // Infinite loop
|
||||
if (!bb->isDonothingLoop()) {
|
||||
@@ -3566,15 +3565,71 @@ int4 ActionDoNothing::apply(Funcdata &data)
|
||||
}
|
||||
}
|
||||
else if (bb->unblockedMulti(0)) {
|
||||
data.removeDoNothingBlock(bb);
|
||||
count += 1;
|
||||
return 0;
|
||||
if (data.isNormalizationOn() || bb->hasNoImmediateCopy(0)) {
|
||||
data.removeDoNothingBlock(bb);
|
||||
count += 1;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
// If there were immediate COPYs but the block was otherwise removable,
|
||||
// mark the block for possible late removal.
|
||||
bb->setDelayedDonothing();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// For each input to \b bl, check if all other out edges go to the same \e out block as \b bl.
|
||||
/// \param bl is the block being removed
|
||||
/// \return \b true if a redundancy would be created
|
||||
bool ActionLateDoNothing::removingCreatesRedundancy(FlowBlock *bl)
|
||||
|
||||
{
|
||||
FlowBlock *outbl = bl->getOut(0);
|
||||
for(int4 i=0;i<bl->sizeIn();++i) {
|
||||
FlowBlock *inbl = bl->getIn(i);
|
||||
if (inbl->sizeOut() == 1) continue;
|
||||
int4 count;
|
||||
for(count=0;count<inbl->sizeOut();++count) {
|
||||
FlowBlock *curbl = inbl->getOut(count);
|
||||
if (curbl != bl && curbl != outbl) // Check if this edge goes to outbl (possibly via bl)
|
||||
break;
|
||||
}
|
||||
if (count == inbl->sizeOut()) // All edges lead to outbl
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int4 ActionLateDoNothing::apply(Funcdata &data)
|
||||
|
||||
{
|
||||
const BlockGraph &graph(data.getBasicBlocks());
|
||||
vector<BlockBasic *> removeList;
|
||||
|
||||
for(int4 i=0;i<graph.getSize();++i) {
|
||||
BlockBasic *bb = (BlockBasic *) graph.getBlock(i);
|
||||
if (!bb->isDelayedDonothing()) continue;
|
||||
if (bb->isDoNothing()) {
|
||||
if (removingCreatesRedundancy(bb)) continue;
|
||||
if ((bb->sizeOut() == 1) && (bb->getOut(0) == bb)) { // Infinite loop
|
||||
if (!bb->isDonothingLoop()) {
|
||||
bb->setDonothingLoop();
|
||||
data.warning("Do nothing block with infinite loop",bb->getStart());
|
||||
}
|
||||
}
|
||||
else if (bb->unblockedMulti(0)) removeList.push_back(bb);
|
||||
}
|
||||
}
|
||||
for(int4 i=0;i<removeList.size();++i) {
|
||||
data.removeDoNothingBlock(removeList[i]);
|
||||
count += 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int4 ActionRedundBranch::apply(Funcdata &data)
|
||||
|
||||
{
|
||||
@@ -5594,10 +5649,10 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||
actmainloop->addAction( new ActionRestrictLocal("localrecovery") ); // Do before dead code removed
|
||||
actmainloop->addAction( new ActionDeadCode("deadcode") );
|
||||
actmainloop->addAction( new ActionDynamicMapping("dynamic") ); // Must come before restructurevarnode and infertypes
|
||||
actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
|
||||
actmainloop->addAction( new ActionSpacebase("base") ); // Must come before infertypes and nonzeromask
|
||||
actmainloop->addAction( new ActionNonzeroMask("analysis") );
|
||||
actmainloop->addAction( new ActionInferTypes("typerecovery") );
|
||||
actmainloop->addAction( new ActionRestructureVarnode("localrecovery") );
|
||||
actstackstall = new ActionGroup(Action::rule_repeatapply,"stackstall");
|
||||
{
|
||||
actprop = new ActionPool(Action::rule_repeatapply,"oppool1");
|
||||
@@ -5809,8 +5864,8 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||
}
|
||||
act->addAction( actcleanup );
|
||||
|
||||
act->addAction( new ActionPreferComplement("blockrecovery") );
|
||||
act->addAction( new ActionStructureTransform("blockrecovery") );
|
||||
act->addAction( new ActionPreferComplement("blockrecovery", true) );
|
||||
act->addAction( new ActionStructureTransform("blockrecovery", true) ); // Allow mods
|
||||
act->addAction( new ActionNormalizeBranches("normalizebranches") );
|
||||
act->addAction( new ActionAssignHigh("merge") );
|
||||
act->addAction( new ActionMergeRequired("merge") );
|
||||
@@ -5825,6 +5880,10 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||
act->addAction( new ActionMergeType("merge") );
|
||||
act->addAction( new ActionHideShadow("merge") );
|
||||
act->addAction( new ActionCopyMarker("merge") );
|
||||
act->addAction( new ActionLateDoNothing("blockrecovery") );
|
||||
act->addAction( new ActionBlockStructure("blockrecovery") );
|
||||
act->addAction( new ActionPreferComplement("blockrecovery", false) ); // Don't allow mods
|
||||
act->addAction( new ActionStructureTransform("blockrecovery", false) ); // Don't allow mods
|
||||
act->addAction( new ActionOutputPrototype("localrecovery") );
|
||||
act->addAction( new ActionInputPrototype("fixateproto") );
|
||||
act->addAction( new ActionMapGlobals("fixateglobals") );
|
||||
|
||||
@@ -510,6 +510,18 @@ public:
|
||||
virtual int4 apply(Funcdata &data);
|
||||
};
|
||||
|
||||
/// \brief Remove blocks that do nothing after variable merging has occurred
|
||||
class ActionLateDoNothing : public Action {
|
||||
static bool removingCreatesRedundancy(FlowBlock *bl); ///< Does removing the given block create a redundant branch point
|
||||
public:
|
||||
ActionLateDoNothing(const string &g) : Action(0,"latedonothing",g) {} ///< Constructor
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
if (!grouplist.contains(getGroup())) return (Action *)0;
|
||||
return new ActionLateDoNothing(getGroup());
|
||||
}
|
||||
virtual int4 apply(Funcdata &data);
|
||||
};
|
||||
|
||||
/// \brief Get rid of \b redundant branches: duplicate edges between the same input and output block
|
||||
class ActionRedundBranch : public Action {
|
||||
public:
|
||||
@@ -629,6 +641,7 @@ public:
|
||||
class ActionNormalizeSetup : public Action {
|
||||
public:
|
||||
ActionNormalizeSetup(const string &g) : Action(rule_onceperfunc,"normalizesetup",g) {} ///< Constructor
|
||||
virtual void reset(Funcdata &data) { data.setNormalization(true); }
|
||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||
if (!grouplist.contains(getGroup())) return (Action *)0;
|
||||
return new ActionNormalizeSetup(getGroup());
|
||||
|
||||
@@ -86,7 +86,7 @@ void Funcdata::clear(void)
|
||||
{ // Clear everything associated with decompilation (analysis)
|
||||
|
||||
flags &= ~(highlevel_on|blocks_generated|processing_started|typerecovery_start|typerecovery_on|
|
||||
double_precis_on|restart_pending);
|
||||
double_precis_on|restart_pending|normalization_on);
|
||||
clean_up_index = 0;
|
||||
high_level_index = 0;
|
||||
cast_phase_index = 0;
|
||||
|
||||
@@ -69,7 +69,8 @@ class Funcdata {
|
||||
unimplemented_present = 0x800, ///< Set if function contains unimplemented instructions
|
||||
baddata_present = 0x1000, ///< Set if function flowed into bad data
|
||||
double_precis_on = 0x2000, ///< Set if we are performing double precision recovery
|
||||
typerecovery_exceeded= 0x4000 ///< Set if data-type propagation passes reached maximum
|
||||
typerecovery_exceeded= 0x4000, ///< Set if data-type propagation passes reached maximum
|
||||
normalization_on = 0x8000 ///< Set if normalization will be performed
|
||||
};
|
||||
uint4 flags; ///< Boolean properties associated with \b this function
|
||||
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
|
||||
@@ -116,6 +117,7 @@ class Funcdata {
|
||||
// Low level block functions
|
||||
void blockRemoveInternal(BlockBasic *bb,bool unreachable);
|
||||
void branchRemoveInternal(BlockBasic *bb,int4 num);
|
||||
Varnode *createReplaceVarnode(Varnode *origvn,bool makeUnique); ///< Create a replacement for a Varnode that may be merged
|
||||
void pushMultiequals(BlockBasic *bb); ///< Push MULTIEQUAL Varnodes of the given block into the output block
|
||||
void clearBlocks(void); ///< Clear all basic blocks
|
||||
void structureReset(void); ///< Calculate initial basic block structures (after a control-flow change)
|
||||
@@ -150,6 +152,7 @@ public:
|
||||
bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Will data-type analysis be performed
|
||||
bool hasTypeRecoveryStarted(void) const { return ((flags&typerecovery_start)!=0); } ///< Has data-type recovery processes started
|
||||
bool isTypeRecoveryExceeded(void) const { return ((flags&typerecovery_exceeded)!=0); } ///< Has maximum propagation passes been reached
|
||||
bool isNormalizationOn(void) const { return ((flags&normalization_on)!=0); } ///< Will normalization be performed
|
||||
bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body
|
||||
void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body
|
||||
void setLanedRegGenerated(void) { minLanedSize = 1000000; } ///< Mark that laned registers have been collected
|
||||
@@ -180,6 +183,11 @@ public:
|
||||
/// \param val is \b true if data-type analysis is enabled
|
||||
void setTypeRecovery(bool val) { flags = val ? (flags | typerecovery_on) : (flags & ~typerecovery_on); }
|
||||
void setTypeRecoveryExceeded(void) { flags |= typerecovery_exceeded; } ///< Mark propagation passes have reached maximum
|
||||
|
||||
/// \brief Toggle whether normalization transforms will be performed on \b this function
|
||||
///
|
||||
/// \param val is \b true if normalization is enabled
|
||||
void setNormalization(bool val) { flags = val ? (flags | normalization_on) : (flags & ~normalization_on); }
|
||||
void startCastPhase(void) { cast_phase_index = vbank.getCreateIndex(); } ///< Start the \b cast insertion phase
|
||||
uint4 getCastPhaseIndex(void) const { return cast_phase_index; } ///< Get creation index at the start of \b cast insertion
|
||||
uint4 getHighLevelIndex(void) const { return high_level_index; } ///< Get creation index at the start of HighVariable creation
|
||||
@@ -494,8 +502,9 @@ public:
|
||||
PcodeOp *opStackStore(AddrSpace *spc,uintb off,PcodeOp *op,bool insertafter);
|
||||
Varnode *opBoolNegate(Varnode *vn,PcodeOp *op,bool insertafter);
|
||||
void opUndoPtradd(PcodeOp *op,bool finalize); ///< Convert a CPUI_PTRADD back into a CPUI_INT_ADD
|
||||
static int4 opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist);
|
||||
static int4 opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist,bool allowOpRemoval);
|
||||
void opFlipInPlaceExecute(vector<PcodeOp *> &fliplist);
|
||||
bool opNormalizeFlip(PcodeOp *cbranch);
|
||||
|
||||
/// \brief Start of PcodeOp objects with the given op-code
|
||||
list<PcodeOp *>::const_iterator beginOp(OpCode opc) const { return obank.begin(opc); }
|
||||
|
||||
@@ -77,6 +77,27 @@ void Funcdata::removeJumpTable(JumpTable *jt)
|
||||
jumpvec = remain;
|
||||
}
|
||||
|
||||
/// The replacement has the same address and size as the given Varnode but can optionally turned into a new \e unique.
|
||||
/// We assume the given Varnode will be destroyed but that it may already be merged into a HighVariable.
|
||||
/// If a HighVariable exists, the given Varnode is removed and the replacement is added.
|
||||
/// \param origvn is the given Varnode to be replaced
|
||||
/// \param makeUnique is \b true if the replacement should be a new \e unique
|
||||
/// \return the new replacement Varnode
|
||||
Varnode *Funcdata::createReplaceVarnode(Varnode *origvn,bool makeUnique)
|
||||
|
||||
{
|
||||
Varnode *replacevn;
|
||||
if (makeUnique)
|
||||
replacevn = newUnique(origvn->getSize(),origvn->getType());
|
||||
else
|
||||
replacevn = newVarnode(origvn->getSize(),origvn->getAddr(),origvn->getType());
|
||||
if (isHighOn()) {
|
||||
origvn->replaceInHigh(replacevn);
|
||||
replacevn->setExplicit();
|
||||
}
|
||||
return replacevn;
|
||||
}
|
||||
|
||||
/// Assuming the given basic block is being removed, force any Varnode defined by
|
||||
/// a MULTIEQUAL in the block to be defined in the output block instead. This is used
|
||||
/// as part of the basic block removal process to patch up data-flow.
|
||||
@@ -128,11 +149,8 @@ void Funcdata::pushMultiequals(BlockBasic *bb)
|
||||
}
|
||||
if (!needreplace) continue;
|
||||
// Construct artificial MULTIEQUAL
|
||||
replacevn = createReplaceVarnode(origvn, neednewunique);
|
||||
vector<Varnode *> branches;
|
||||
if (neednewunique)
|
||||
replacevn = newUnique(origvn->getSize());
|
||||
else
|
||||
replacevn = newVarnode(origvn->getSize(),origvn->getAddr());
|
||||
for(int4 i=0;i<outblock->sizeIn();++i) {
|
||||
if (outblock->getIn(i) == bb)
|
||||
branches.push_back(origvn);
|
||||
@@ -208,7 +226,7 @@ void Funcdata::branchRemoveInternal(BlockBasic *bb,int4 num)
|
||||
bblocks.removeEdge(bb,bbout); // Sever (one) connection between bb and bbout
|
||||
for(iter=bbout->beginOp();iter!=bbout->endOp();++iter) {
|
||||
op = *iter;
|
||||
if (op->code() != CPUI_MULTIEQUAL) continue;
|
||||
if (op->code() != CPUI_MULTIEQUAL) break;
|
||||
opRemoveInput(op,blocknum);
|
||||
opZeroMulti(op);
|
||||
}
|
||||
|
||||
@@ -1216,11 +1216,12 @@ Varnode *Funcdata::buildCopyTemp(Varnode *vn,PcodeOp *point)
|
||||
///
|
||||
/// The boolean Varnode is either the output of the given PcodeOp or the
|
||||
/// first input if the PcodeOp is a CBRANCH. The list of ops that need flipping is
|
||||
/// returned in an array
|
||||
/// returned in an array.
|
||||
/// \param op is the given PcodeOp
|
||||
/// \param fliplist is the array that will hold the ops to flip
|
||||
/// \return 0 if the change normalizes, 1 if the change is ambivalent, 2 if the change does not normalize
|
||||
int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
|
||||
/// \param allowOpRemoval if \b true allow for removal of BOOL_NEGATE ops to achieve flip
|
||||
/// \return 0 if the change normalizes, 1 if the change denormalizes or is ambivalent, 2 if flip in place is not possible
|
||||
int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist,bool allowOpRemoval)
|
||||
|
||||
{
|
||||
Varnode *vn;
|
||||
@@ -1230,12 +1231,19 @@ int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
|
||||
vn = op->getIn(1);
|
||||
if (vn->loneDescend() != op) return 2;
|
||||
if (!vn->isWritten()) return 2;
|
||||
return opFlipInPlaceTest(vn->getDef(),fliplist);
|
||||
subtest1 = opFlipInPlaceTest(vn->getDef(),fliplist,allowOpRemoval);
|
||||
if (subtest1 != 2 && op->isBooleanFlip())
|
||||
subtest1 = 1-subtest1;
|
||||
return subtest1;
|
||||
case CPUI_INT_EQUAL:
|
||||
case CPUI_FLOAT_EQUAL:
|
||||
fliplist.push_back(op);
|
||||
return 1;
|
||||
case CPUI_BOOL_NEGATE:
|
||||
if (!allowOpRemoval)
|
||||
return 2;
|
||||
fliplist.push_back(op);
|
||||
return 0;
|
||||
case CPUI_INT_NOTEQUAL:
|
||||
case CPUI_FLOAT_NOTEQUAL:
|
||||
fliplist.push_back(op);
|
||||
@@ -1257,13 +1265,13 @@ int4 Funcdata::opFlipInPlaceTest(PcodeOp *op,vector<PcodeOp *> &fliplist)
|
||||
vn = op->getIn(0);
|
||||
if (vn->loneDescend() != op) return 2;
|
||||
if (!vn->isWritten()) return 2;
|
||||
subtest1 = opFlipInPlaceTest(vn->getDef(),fliplist);
|
||||
subtest1 = opFlipInPlaceTest(vn->getDef(),fliplist,allowOpRemoval);
|
||||
if (subtest1 == 2)
|
||||
return 2;
|
||||
vn = op->getIn(1);
|
||||
if (vn->loneDescend() != op) return 2;
|
||||
if (!vn->isWritten()) return 2;
|
||||
subtest2 = opFlipInPlaceTest(vn->getDef(),fliplist);
|
||||
subtest2 = opFlipInPlaceTest(vn->getDef(),fliplist,allowOpRemoval);
|
||||
if (subtest2 == 2)
|
||||
return 2;
|
||||
fliplist.push_back(op);
|
||||
@@ -1314,6 +1322,31 @@ void Funcdata::opFlipInPlaceExecute(vector<PcodeOp *> &fliplist)
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Remove the \b boolean_flip flag on a CBRANCH op, without changing behavior
|
||||
///
|
||||
/// Try to flip the true/false meaning of the CBRANCH and negate the meaning of the comparison op feeding the CBRANCH.
|
||||
/// Only the \b boolean_flip flag and the comparison op's opcode are affected.
|
||||
/// \param cbranch is CBRANCH to modify
|
||||
/// \return \b true if the ops were successfully modified
|
||||
bool Funcdata::opNormalizeFlip(PcodeOp *cbranch)
|
||||
|
||||
{
|
||||
Varnode *boolVn = cbranch->getIn(1);
|
||||
if (!boolVn->isWritten()) return false;
|
||||
if (boolVn->loneDescend() != cbranch) return false;
|
||||
PcodeOp *condOp = boolVn->getDef();
|
||||
bool flipyes;
|
||||
OpCode opc = get_booleanflip(condOp->code(), flipyes);
|
||||
if (opc == CPUI_MAX) return false;
|
||||
opSetOpcode(condOp,opc); // Set the negated opcode
|
||||
if (flipyes) // Do we need to reverse the two operands
|
||||
opSwapInput(condOp,0,1);
|
||||
cbranch->flipFlag(PcodeOp::boolean_flip);
|
||||
if (opc == CPUI_INT_LESSEQUAL || opc == CPUI_INT_SLESSEQUAL)
|
||||
replaceLessequal(condOp);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Find a duplicate calculation of a given PcodeOp reading a specific Varnode
|
||||
///
|
||||
/// We only match 1 level of calculation. Additionally the duplicate must occur in the
|
||||
|
||||
@@ -124,6 +124,29 @@ bool PcodeOp::isCollapsible(void) const
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \param slot is the specific input edge being marked
|
||||
void PcodeOp::setCopyImmed(int4 slot)
|
||||
|
||||
{
|
||||
FlowBlock *inbl = parent->getIn(slot);
|
||||
int4 outedge = parent->getInRevIndex(slot);
|
||||
inbl->setImmedCopyEdge(outedge);
|
||||
addlflags |= immed_copy;
|
||||
}
|
||||
|
||||
/// \param slot is the specific input edge to test
|
||||
/// \return \b true if an immediate COPY has been propagated along the edge
|
||||
bool PcodeOp::hasCopyImmed(int4 slot) const
|
||||
|
||||
{
|
||||
if ((addlflags & immed_copy) != 0) {
|
||||
FlowBlock *inbl = parent->getIn(slot);
|
||||
int4 outedge = parent->getInRevIndex(slot);
|
||||
return inbl->hasImmedCopyEdge(outedge);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Produce a hash of the following attributes: output size, the opcode, and the identity
|
||||
/// of each input varnode. This is suitable for determining if two PcodeOps calculate identical values
|
||||
/// \return the calculated hash or 0 if the op is not cse hashable
|
||||
|
||||
@@ -116,7 +116,8 @@ public:
|
||||
hold_output = 0x80, ///< Output varnode (of call) should not be removed if it is unread
|
||||
concat_root = 0x100, ///< Output of \b this is root of a CONCAT tree
|
||||
no_indirect_collapse = 0x200, ///< Do not collapse \b this INDIRECT (via RuleIndirectCollapse)
|
||||
store_unmapped = 0x400 ///< If STORE collapses to a stack Varnode, force it to be unmapped
|
||||
store_unmapped = 0x400, ///< If STORE collapses to a stack Varnode, force it to be unmapped
|
||||
immed_copy = 0x800 ///< Copy has propagated into input of \b this op
|
||||
};
|
||||
private:
|
||||
TypeOp *opcode; ///< Pointer to class providing behavioral details of the operation
|
||||
@@ -224,6 +225,8 @@ public:
|
||||
void setNoIndirectCollapse(void) { addlflags |= no_indirect_collapse; } ///< Prevent collapse of INDIRECT
|
||||
bool isStoreUnmapped(void) const { return ((addlflags & store_unmapped)!=0); } ///< Is STORE location supposed to be unmapped
|
||||
void setStoreUnmapped(void) const { addlflags |= store_unmapped; } ///< Mark that STORE location should be unmapped
|
||||
void setCopyImmed(int4 slot); ///< Mark that a COPY propagation from the immediate input block has happened
|
||||
bool hasCopyImmed(int4 slot) const; ///< Return \b true if a COPY propagation from an immediate input block has happened
|
||||
/// \brief Return \b true if this LOADs or STOREs from a dynamic \e spacebase pointer
|
||||
bool usesSpacebasePtr(void) const { return ((flags&PcodeOp::spacebase_ptr)!=0); }
|
||||
uintm getCseHash(void) const; ///< Return hash indicating possibility of common subexpression elimination
|
||||
|
||||
@@ -3969,6 +3969,9 @@ int4 RulePropagateCopy::applyOp(PcodeOp *op,Funcdata &data)
|
||||
if (invn->isAddrTied() && op->getOut()->isAddrTied() &&
|
||||
(op->getOut()->getAddr() != invn->getAddr()))
|
||||
continue; // We must not allow merging of different addrtieds
|
||||
if (op->code() == CPUI_MULTIEQUAL && copyop->getParent() == op->getParent()->getIn(i)) {
|
||||
op->setCopyImmed(i);
|
||||
}
|
||||
}
|
||||
data.opSetInput(op,invn,i); // otherwise propagate just a single copy
|
||||
return 1;
|
||||
@@ -5496,6 +5499,8 @@ int4 RuleCondNegate::applyOp(PcodeOp *op,Funcdata &data)
|
||||
Varnode *vn,*outvn;
|
||||
|
||||
if (!op->isBooleanFlip()) return 0;
|
||||
if (data.opNormalizeFlip(op))
|
||||
return 1;
|
||||
|
||||
vn = op->getIn(1);
|
||||
newop = data.newOp(1,op->getAddr());
|
||||
|
||||
@@ -531,6 +531,19 @@ void HighVariable::remove(Varnode *vn)
|
||||
}
|
||||
}
|
||||
|
||||
/// \b this is assigned directly to the Varnode, losing any reference to a previous HighVariable,
|
||||
/// so the caller must take this into account.
|
||||
/// \param newvn is the Varnode to add to \b this
|
||||
/// \param mergeGroup is the group to associate with this merge
|
||||
void HighVariable::insert(Varnode *newvn,int2 mergeGroup)
|
||||
|
||||
{
|
||||
vector<Varnode *>::iterator iter;
|
||||
iter = lower_bound(inst.begin(),inst.end(),newvn,compareJustLoc);
|
||||
inst.insert(iter,newvn);
|
||||
newvn->setHigh(this,mergeGroup);
|
||||
}
|
||||
|
||||
/// Assuming there is a Symbol attached to \b this, run through the Varnode members
|
||||
/// until we find one with a SymbolEntry corresponding to the Symbol and return it.
|
||||
/// \return the SymbolEntry that mapped the Symbol to \b this or null if no Symbol is attached
|
||||
|
||||
@@ -156,6 +156,7 @@ private:
|
||||
bool hasCopyIn1(void) const { return ((highflags©_in1)!=0); } ///< Is there at least one COPY into \b this
|
||||
bool hasCopyIn2(void) const { return ((highflags©_in2)!=0); } ///< Is there at least two COPYs into \b this
|
||||
void remove(Varnode *vn); ///< Remove a member Varnode from \b this
|
||||
void insert(Varnode *newvn,int2 mergeGroup); ///< Directly insert a Varnode into \b this
|
||||
void mergeInternal(HighVariable *tv2,bool isspeculative); ///< Merge another HighVariable into \b this
|
||||
void merge(HighVariable *tv2,HighIntersectTest *testCache,bool isspeculative); ///< Merge with another HighVariable taking into account groups
|
||||
void setSymbol(Varnode *vn) const; ///< Update Symbol information for \b this from the given member Varnode
|
||||
|
||||
@@ -347,6 +347,25 @@ void Varnode::destroyDescend(void)
|
||||
descend.clear();
|
||||
}
|
||||
|
||||
/// We assume the replacement Varnode is initially a singleton in its own HighVariable.
|
||||
/// We swap \b this and the replacement between their respective HighVariables.
|
||||
/// \param replacevn is the replacement Varnode
|
||||
void Varnode::replaceInHigh(Varnode *replacevn)
|
||||
|
||||
{
|
||||
#ifdef CPUI_DEBUG
|
||||
if (replacevn->high->inst.size() != 1)
|
||||
throw LowlevelError("Attempting to replace with merged Varnode");
|
||||
#endif
|
||||
high->remove(this);
|
||||
HighVariable *replaceHigh = replacevn->high;
|
||||
replacevn->high = (HighVariable *)0;
|
||||
replaceHigh->inst[0] = this;
|
||||
high->insert(replacevn,mergegroup);
|
||||
high = replaceHigh;
|
||||
mergegroup = 0;
|
||||
}
|
||||
|
||||
/// Set desired boolean attributes on this Varnode and then set dirty bits if appropriate
|
||||
/// \param fl is the mask containing the list of attributes to set
|
||||
void Varnode::setFlags(uint4 fl) const
|
||||
|
||||
@@ -174,6 +174,7 @@ private:
|
||||
void addDescend(PcodeOp *op); ///< Add a descendant (reading) PcodeOp to this Varnode's list
|
||||
void eraseDescend(PcodeOp *op); ///< Erase a descendant (reading) PcodeOp from this Varnode's list
|
||||
void destroyDescend(void); ///< Clear all descendant (reading) PcodeOps
|
||||
void replaceInHigh(Varnode *replacevn); ///< Swap the given Varnode into the HighVariable for \b this
|
||||
public:
|
||||
// only to be used by HighVariable
|
||||
void setHigh(HighVariable *tv,int2 mg) { high = tv; mergegroup = mg; } ///< Set the HighVariable owning this Varnode
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<decompilertest>
|
||||
<binaryimage arch="x86:LE:64:default:gcc">
|
||||
<bytechunk space="ram" offset="0x100000" readonly="true">
|
||||
554889e5897dec8b45ec48988b048500
|
||||
1010008945fc837dec007430eb1f8b45
|
||||
ec83e80148988b1485001010008b45ec
|
||||
489889148500101000836dec01837dec
|
||||
0075db8b45fc8905b40f0000905dc355
|
||||
4889e5897dfc8975f8837dfc01750b8b
|
||||
45f88905a00f0000eb23837dfc02750e
|
||||
8b45f883c00789058c0f0000eb0f837d
|
||||
fc0475098b45f889057b0f0000905dc3
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x100000" name="myloop"/>
|
||||
<symbol space="ram" offset="0x10004f" name="myglob"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>map addr r0x101000 int4 myarr[2]</com>
|
||||
<com>map addr r0x101008 int4 globvar</com>
|
||||
<com>lo fu myloop</com>
|
||||
<com>map addr s0xffffffffffffffe4 int4 i</com>
|
||||
<com>map hash r0x10000c 5fc6319fee int4 size</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu myglob</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Copy trim #1" min="1" max="1">size = myarr\[param_1\];</stringmatch>
|
||||
<stringmatch name="Copy trim #2" min="0" max="0">for \(.*myarr\[0\] = </stringmatch>
|
||||
<stringmatch name="Copy trim #3" min="1" max="1">for \(; i != 0; i = i \+ -1\) \{
|
||||
myarr\[i\] = myarr\[i \+ -1\];
|
||||
\}
|
||||
myarr\[0\] = size;</stringmatch>
|
||||
<stringmatch name="Copy trim #4" min="0" max="0">Var1 = param_2;</stringmatch>
|
||||
<stringmatch name="Copy trim #5" min="0" max="0">globvar = iVar1;</stringmatch>
|
||||
<stringmatch name="Copy trim #6" min="1" max="1">if \(param_1 == 1\) \{
|
||||
globvar = param_2;</stringmatch>
|
||||
<stringmatch name="Copy trim #7" min="1" max="1">if \(param_1 == 2\) \{
|
||||
globvar = param_2 \+ 7;</stringmatch>
|
||||
<stringmatch name="Copy trim #8" min="1" max="1">if \(param_1 == 4\) \{
|
||||
globvar = param_2;</stringmatch>
|
||||
</decompilertest>
|
||||
@@ -33,15 +33,14 @@
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>lo fu partial1</com>
|
||||
<com>map unionfacet structunion 1 r0x1006ee 10603f2c20ffa6</com>
|
||||
<com>map unionfacet structunion 1 r0x1006ee 10603fc3e29498</com>
|
||||
<com>dec</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Partial union #1" min="1" max="1">globvar\.b\.bval1 = val;</stringmatch>
|
||||
<stringmatch name="Partial union #2" min="1" max="1">return globvar\.a\.aval2;</stringmatch>
|
||||
<stringmatch name="Partial union #3" min="1" max="1">Var1 = globvar\.a\.aval2;</stringmatch>
|
||||
<stringmatch name="Partial union #3" min="2" max="2">globvar\.a\.aval2 = param_2;</stringmatch>
|
||||
<stringmatch name="Partial union #4" min="1" max="1">globvar\.a\.aval1 = param_2 \+ 7;</stringmatch>
|
||||
<stringmatch name="Partial union #5" min="1" max="1">globvar\.b\.bval1 = 0\.5;</stringmatch>
|
||||
<stringmatch name="Partial union #6" min="1" max="1">globvar\.a\.aval2 = .Var1;</stringmatch>
|
||||
</decompilertest>
|
||||
|
||||
Reference in New Issue
Block a user