mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
reads and constraint adjustments
This commit is contained in:
parent
0c5bd081c5
commit
9cdd91a053
5 changed files with 99 additions and 27 deletions
|
@ -369,6 +369,31 @@ bool FlowBlock::dominates(const FlowBlock *subBlock) const
|
|||
return false;
|
||||
}
|
||||
|
||||
/// \brief Check if the condition from the given block holds for \b this block
|
||||
///
|
||||
/// We assume the given block has 2 out-edges and that \b this block is immediately reached by
|
||||
/// one of these two edges. Some condition holds when traversing the out-edge to \b this, and the complement
|
||||
/// of the condition holds for traversing the other out-edge. We verify that the condition holds for
|
||||
/// this entire block. More specifically, we check that that there is no path to \b this through the
|
||||
/// sibling edge, where the complement of the condition holds (unless we loop back through the conditional block).
|
||||
/// \param cond is the conditional block with 2 out-edges
|
||||
/// \return \b true if the condition holds for this block
|
||||
bool FlowBlock::restrictedByConditional(const FlowBlock *cond) const
|
||||
|
||||
{
|
||||
if (sizeIn() == 1) return true; // Its impossible for any path to come through sibling to this
|
||||
if (getImmedDom() != cond) return false; // This is not dominated by conditional block at all
|
||||
for(int4 i=0;i<sizeIn();++i) {
|
||||
const FlowBlock *inBlock = getIn(i);
|
||||
if (inBlock == cond) continue; // The unique edge from cond to this
|
||||
while(inBlock != this) {
|
||||
if (inBlock == cond) return false; // Must have come through sibling
|
||||
inBlock = inBlock->getImmedDom();
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \return \b true if \b this is the top of a loop
|
||||
bool FlowBlock::hasLoopIn(void) const
|
||||
|
||||
|
|
|
@ -215,6 +215,7 @@ public:
|
|||
FlowBlock *getFrontLeaf(void); ///< Get the first leaf FlowBlock
|
||||
int4 calcDepth(const FlowBlock *leaf) const; ///< Get the depth of the given component FlowBlock
|
||||
bool dominates(const FlowBlock *subBlock) const; ///< Does \b this block dominate the given block
|
||||
bool restrictedByConditional(const FlowBlock *cond) const;
|
||||
int4 sizeOut(void) const { return outofthis.size(); } ///< Get the number of out edges
|
||||
int4 sizeIn(void) const { return intothis.size(); } ///< Get the number of in edges
|
||||
bool hasLoopIn(void) const; ///< Is there a looping edge coming into \b this block
|
||||
|
|
|
@ -3246,7 +3246,7 @@ int4 ActionConditionalConst::apply(Funcdata &data)
|
|||
if (flipEdge)
|
||||
constEdge = 1 - constEdge;
|
||||
FlowBlock *constBlock = bl->getOut(constEdge);
|
||||
if (constBlock->sizeIn() != 1) continue; // Must only be one path to constant block directly through CBRANCH
|
||||
if (!constBlock->restrictedByConditional(bl)) continue; // Make sure condition holds
|
||||
propagateConstant(varVn,constVn,constBlock,data);
|
||||
}
|
||||
return 0;
|
||||
|
|
|
@ -1927,44 +1927,73 @@ void ValueSetSolver::establishTopologicalOrder(void)
|
|||
/// \param vn is the given Varnode
|
||||
/// \param type is the constraint characteristic
|
||||
/// \param range is the known constraint (assuming the \b true branch was taken)
|
||||
/// \param splitPoint is the basic block making the conditional branch
|
||||
void ValueSetSolver::applyConstraints(Varnode *vn,int4 type,const CircleRange &range,FlowBlock *splitPoint)
|
||||
/// \param cbranch is conditional branch creating the constraint
|
||||
void ValueSetSolver::applyConstraints(Varnode *vn,int4 type,const CircleRange &range,PcodeOp *cbranch)
|
||||
|
||||
{
|
||||
FlowBlock *splitPoint = cbranch->getParent();
|
||||
FlowBlock *trueBlock,*falseBlock;
|
||||
if (cbranch->isBooleanFlip()) {
|
||||
trueBlock = splitPoint->getFalseOut();
|
||||
falseBlock = splitPoint->getTrueOut();
|
||||
}
|
||||
else {
|
||||
trueBlock = splitPoint->getTrueOut();
|
||||
falseBlock = splitPoint->getFalseOut();
|
||||
}
|
||||
// Check if the only path to trueBlock or falseBlock is via a splitPoint out-edge induced by the condition
|
||||
bool trueIsRestricted = trueBlock->restrictedByConditional(splitPoint);
|
||||
bool falseIsRestricted = falseBlock->restrictedByConditional(splitPoint);
|
||||
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
FlowBlock *defBlock = (FlowBlock *)0;
|
||||
if (vn->isWritten()) {
|
||||
defBlock = vn->getDef()->getParent();
|
||||
ValueSet *vSet = vn->getValueSet();
|
||||
if (vSet->opCode == CPUI_MULTIEQUAL) {
|
||||
vSet->addLandmark(type,range); // Leave landmark for widening
|
||||
}
|
||||
}
|
||||
FlowBlock *trueBlock = splitPoint->getTrueOut();
|
||||
FlowBlock *falseBlock = splitPoint->getFalseOut();
|
||||
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
||||
PcodeOp *op = *iter;
|
||||
if (op->isMark()) { // Special read site being tracked
|
||||
readNodes[op->getSeqNum()].addEquation(op->getSlot(vn), type, range);
|
||||
continue;
|
||||
}
|
||||
Varnode *outVn = op->getOut();
|
||||
Varnode *outVn = (Varnode *)0;
|
||||
if (!op->isMark()) { // If this is not a special read site
|
||||
outVn = op->getOut(); // Make sure there is a Varnode in the system
|
||||
if (outVn == (Varnode *)0) continue;
|
||||
if (!outVn->isMark()) continue;
|
||||
}
|
||||
FlowBlock *curBlock = op->getParent();
|
||||
int4 slot = op->getSlot(vn);
|
||||
for(;;) {
|
||||
if (curBlock == trueBlock) {
|
||||
outVn->getValueSet()->addEquation(op->getSlot(vn), type, range);
|
||||
if (!trueIsRestricted) {
|
||||
// If its possible that both the true and false edges can reach trueBlock
|
||||
// then the only input we can restrict is a MULTIEQUAL input along the exact true edge
|
||||
if (op->code() != CPUI_MULTIEQUAL) break;
|
||||
if (op->getParent() != trueBlock) break;
|
||||
if (trueBlock->getIn(slot) != splitPoint) break;
|
||||
}
|
||||
if (outVn != (Varnode *)0)
|
||||
outVn->getValueSet()->addEquation(slot, type, range);
|
||||
else
|
||||
readNodes[op->getSeqNum()].addEquation(slot, type, range); // Special read site
|
||||
break;
|
||||
}
|
||||
else if (curBlock == falseBlock) {
|
||||
if (!falseIsRestricted) {
|
||||
// If its possible that both the true and false edges can reach falseBlock
|
||||
// then the only input we can restrict is a MULTIEQUAL input along the exact false edge
|
||||
if (op->code() != CPUI_MULTIEQUAL) break;
|
||||
if (op->getParent() != falseBlock) break;
|
||||
if (falseBlock->getIn(slot) != splitPoint) break;
|
||||
}
|
||||
CircleRange falseRange(range);
|
||||
falseRange.invert();
|
||||
outVn->getValueSet()->addEquation(op->getSlot(vn), type, falseRange);
|
||||
if (outVn != (Varnode *)0)
|
||||
outVn->getValueSet()->addEquation(slot, type, falseRange);
|
||||
else
|
||||
readNodes[op->getSeqNum()].addEquation(slot, type, falseRange); // Special read site
|
||||
break;
|
||||
}
|
||||
else if (curBlock == splitPoint || curBlock == (FlowBlock *)0
|
||||
|| curBlock == defBlock)
|
||||
else if (curBlock == splitPoint || curBlock == (FlowBlock *)0)
|
||||
break;
|
||||
curBlock = curBlock->getImmedDom();
|
||||
}
|
||||
|
@ -1980,8 +2009,8 @@ void ValueSetSolver::applyConstraints(Varnode *vn,int4 type,const CircleRange &r
|
|||
/// \param lift is the given range that will be lifted
|
||||
/// \param startVn is the starting Varnode
|
||||
/// \param endVn is the given ending Varnode in the system
|
||||
/// \param splitPoint is the point where control-flow splits
|
||||
void ValueSetSolver::constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,FlowBlock *splitPoint)
|
||||
/// \param cbranch is the PcodeOp causing the control-flow split
|
||||
void ValueSetSolver::constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,PcodeOp *cbranch)
|
||||
|
||||
{
|
||||
while(startVn != endVn) {
|
||||
|
@ -1991,7 +2020,7 @@ void ValueSetSolver::constraintsFromPath(int4 type,CircleRange &lift,Varnode *st
|
|||
}
|
||||
for(;;) {
|
||||
Varnode *constVn;
|
||||
applyConstraints(endVn,type,lift,splitPoint);
|
||||
applyConstraints(endVn,type,lift,cbranch);
|
||||
if (!endVn->isWritten()) break;
|
||||
PcodeOp *op = endVn->getDef();
|
||||
if (op->isCall() || op->isMarker()) break;
|
||||
|
@ -2032,7 +2061,7 @@ void ValueSetSolver::constraintsFromCBranch(PcodeOp *cbranch)
|
|||
if (vn->isMark()) {
|
||||
CircleRange lift(true);
|
||||
Varnode *startVn = cbranch->getIn(1);
|
||||
constraintsFromPath(0,lift,startVn,vn,cbranch->getParent());
|
||||
constraintsFromPath(0,lift,startVn,vn,cbranch);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2043,7 +2072,8 @@ void ValueSetSolver::constraintsFromCBranch(PcodeOp *cbranch)
|
|||
/// - Which applies at a particular \e read of the Varnode
|
||||
///
|
||||
/// \param worklist is the set of Varnodes in the data-flow system (all marked)
|
||||
void ValueSetSolver::generateConstraints(vector<Varnode *> &worklist)
|
||||
/// \param reads is the additional set of PcodeOps that read a Varnode from the system
|
||||
void ValueSetSolver::generateConstraints(const vector<Varnode *> &worklist,const vector<PcodeOp *> &reads)
|
||||
|
||||
{
|
||||
vector<FlowBlock *> blockList;
|
||||
|
@ -2065,6 +2095,22 @@ void ValueSetSolver::generateConstraints(vector<Varnode *> &worklist)
|
|||
break;
|
||||
}
|
||||
}
|
||||
for(int4 i=0;i<reads.size();++i) {
|
||||
BlockBasic *bl = (BlockBasic *)reads[i]->getParent()->getImmedDom();
|
||||
while(bl != (FlowBlock *)0) {
|
||||
if (!bl->isMark()) {
|
||||
bl->setMark();
|
||||
blockList.push_back(bl);
|
||||
PcodeOp *lastOp = bl->lastOp();
|
||||
if (lastOp != (PcodeOp *)0 && lastOp->code() == CPUI_CBRANCH) {
|
||||
constraintsFromCBranch(lastOp);
|
||||
}
|
||||
bl = (BlockBasic *)bl->getImmedDom();
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(int4 i=0;i<blockList.size();++i)
|
||||
blockList[i]->clearMark();
|
||||
}
|
||||
|
@ -2158,7 +2204,7 @@ void ValueSetSolver::generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch
|
|||
endVn = op->getIn(0);
|
||||
}
|
||||
if (endVn != (Varnode *)0)
|
||||
constraintsFromPath(typeCode,lift,endVn,endVn,cbranch->getParent());
|
||||
constraintsFromPath(typeCode,lift,endVn,endVn,cbranch);
|
||||
}
|
||||
|
||||
/// Given a set of sinks, find all the Varnodes that flow directly into them.
|
||||
|
@ -2242,7 +2288,7 @@ void ValueSetSolver::establishValueSets(const vector<Varnode *> &sinks,const vec
|
|||
}
|
||||
}
|
||||
}
|
||||
generateConstraints(worklist);
|
||||
generateConstraints(worklist,reads);
|
||||
for(int4 i=0;i<reads.size();++i)
|
||||
reads[i]->clearMark(); // Clear marks on read ops
|
||||
|
||||
|
|
|
@ -226,10 +226,10 @@ class ValueSetSolver {
|
|||
void component(ValueSet *vertex,Partition &part); ///< Generate a partition component given its head
|
||||
int4 visit(ValueSet *vertex,Partition &part); ///< Recursively walk the data-flow graph finding partitions
|
||||
void establishTopologicalOrder(void); ///< Find the optimal order for iterating through the ValueSets
|
||||
void applyConstraints(Varnode *vn,int4 type,const CircleRange &range,FlowBlock *splitPoint);
|
||||
void constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,FlowBlock *splitPoint);
|
||||
void applyConstraints(Varnode *vn,int4 type,const CircleRange &range,PcodeOp *cbranch);
|
||||
void constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,PcodeOp *cbranch);
|
||||
void constraintsFromCBranch(PcodeOp *cbranch); ///< Generate constraints arising from the given branch
|
||||
void generateConstraints(vector<Varnode *> &worklist); ///< Generate constraints given a system of Varnodes
|
||||
void generateConstraints(const vector<Varnode *> &worklist,const vector<PcodeOp *> &reads); ///< Generate constraints given a system of Varnodes
|
||||
bool checkRelativeConstant(Varnode *vn,int4 &typeCode,uintb &value) const; ///< Check if the given Varnode is a \e relative constant
|
||||
void generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch); ///< Try to find a \e relative constraint
|
||||
public:
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue