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;
|
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
|
/// \return \b true if \b this is the top of a loop
|
||||||
bool FlowBlock::hasLoopIn(void) const
|
bool FlowBlock::hasLoopIn(void) const
|
||||||
|
|
||||||
|
|
|
@ -215,6 +215,7 @@ public:
|
||||||
FlowBlock *getFrontLeaf(void); ///< Get the first leaf FlowBlock
|
FlowBlock *getFrontLeaf(void); ///< Get the first leaf FlowBlock
|
||||||
int4 calcDepth(const FlowBlock *leaf) const; ///< Get the depth of the given component 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 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 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
|
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
|
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)
|
if (flipEdge)
|
||||||
constEdge = 1 - constEdge;
|
constEdge = 1 - constEdge;
|
||||||
FlowBlock *constBlock = bl->getOut(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);
|
propagateConstant(varVn,constVn,constBlock,data);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
|
@ -1927,44 +1927,73 @@ void ValueSetSolver::establishTopologicalOrder(void)
|
||||||
/// \param vn is the given Varnode
|
/// \param vn is the given Varnode
|
||||||
/// \param type is the constraint characteristic
|
/// \param type is the constraint characteristic
|
||||||
/// \param range is the known constraint (assuming the \b true branch was taken)
|
/// \param range is the known constraint (assuming the \b true branch was taken)
|
||||||
/// \param splitPoint is the basic block making the conditional branch
|
/// \param cbranch is conditional branch creating the constraint
|
||||||
void ValueSetSolver::applyConstraints(Varnode *vn,int4 type,const CircleRange &range,FlowBlock *splitPoint)
|
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;
|
list<PcodeOp *>::const_iterator iter;
|
||||||
FlowBlock *defBlock = (FlowBlock *)0;
|
|
||||||
if (vn->isWritten()) {
|
if (vn->isWritten()) {
|
||||||
defBlock = vn->getDef()->getParent();
|
|
||||||
ValueSet *vSet = vn->getValueSet();
|
ValueSet *vSet = vn->getValueSet();
|
||||||
if (vSet->opCode == CPUI_MULTIEQUAL) {
|
if (vSet->opCode == CPUI_MULTIEQUAL) {
|
||||||
vSet->addLandmark(type,range); // Leave landmark for widening
|
vSet->addLandmark(type,range); // Leave landmark for widening
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FlowBlock *trueBlock = splitPoint->getTrueOut();
|
|
||||||
FlowBlock *falseBlock = splitPoint->getFalseOut();
|
|
||||||
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
||||||
PcodeOp *op = *iter;
|
PcodeOp *op = *iter;
|
||||||
if (op->isMark()) { // Special read site being tracked
|
Varnode *outVn = (Varnode *)0;
|
||||||
readNodes[op->getSeqNum()].addEquation(op->getSlot(vn), type, range);
|
if (!op->isMark()) { // If this is not a special read site
|
||||||
continue;
|
outVn = op->getOut(); // Make sure there is a Varnode in the system
|
||||||
|
if (outVn == (Varnode *)0) continue;
|
||||||
|
if (!outVn->isMark()) continue;
|
||||||
}
|
}
|
||||||
Varnode *outVn = op->getOut();
|
|
||||||
if (outVn == (Varnode *)0) continue;
|
|
||||||
if (!outVn->isMark()) continue;
|
|
||||||
FlowBlock *curBlock = op->getParent();
|
FlowBlock *curBlock = op->getParent();
|
||||||
|
int4 slot = op->getSlot(vn);
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if (curBlock == trueBlock) {
|
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;
|
break;
|
||||||
}
|
}
|
||||||
else if (curBlock == falseBlock) {
|
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);
|
CircleRange falseRange(range);
|
||||||
falseRange.invert();
|
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;
|
break;
|
||||||
}
|
}
|
||||||
else if (curBlock == splitPoint || curBlock == (FlowBlock *)0
|
else if (curBlock == splitPoint || curBlock == (FlowBlock *)0)
|
||||||
|| curBlock == defBlock)
|
|
||||||
break;
|
break;
|
||||||
curBlock = curBlock->getImmedDom();
|
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 lift is the given range that will be lifted
|
||||||
/// \param startVn is the starting Varnode
|
/// \param startVn is the starting Varnode
|
||||||
/// \param endVn is the given ending Varnode in the system
|
/// \param endVn is the given ending Varnode in the system
|
||||||
/// \param splitPoint is the point where control-flow splits
|
/// \param cbranch is the PcodeOp causing the control-flow split
|
||||||
void ValueSetSolver::constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,FlowBlock *splitPoint)
|
void ValueSetSolver::constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,PcodeOp *cbranch)
|
||||||
|
|
||||||
{
|
{
|
||||||
while(startVn != endVn) {
|
while(startVn != endVn) {
|
||||||
|
@ -1991,7 +2020,7 @@ void ValueSetSolver::constraintsFromPath(int4 type,CircleRange &lift,Varnode *st
|
||||||
}
|
}
|
||||||
for(;;) {
|
for(;;) {
|
||||||
Varnode *constVn;
|
Varnode *constVn;
|
||||||
applyConstraints(endVn,type,lift,splitPoint);
|
applyConstraints(endVn,type,lift,cbranch);
|
||||||
if (!endVn->isWritten()) break;
|
if (!endVn->isWritten()) break;
|
||||||
PcodeOp *op = endVn->getDef();
|
PcodeOp *op = endVn->getDef();
|
||||||
if (op->isCall() || op->isMarker()) break;
|
if (op->isCall() || op->isMarker()) break;
|
||||||
|
@ -2032,7 +2061,7 @@ void ValueSetSolver::constraintsFromCBranch(PcodeOp *cbranch)
|
||||||
if (vn->isMark()) {
|
if (vn->isMark()) {
|
||||||
CircleRange lift(true);
|
CircleRange lift(true);
|
||||||
Varnode *startVn = cbranch->getIn(1);
|
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
|
/// - Which applies at a particular \e read of the Varnode
|
||||||
///
|
///
|
||||||
/// \param worklist is the set of Varnodes in the data-flow system (all marked)
|
/// \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;
|
vector<FlowBlock *> blockList;
|
||||||
|
@ -2065,6 +2095,22 @@ void ValueSetSolver::generateConstraints(vector<Varnode *> &worklist)
|
||||||
break;
|
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)
|
for(int4 i=0;i<blockList.size();++i)
|
||||||
blockList[i]->clearMark();
|
blockList[i]->clearMark();
|
||||||
}
|
}
|
||||||
|
@ -2158,7 +2204,7 @@ void ValueSetSolver::generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch
|
||||||
endVn = op->getIn(0);
|
endVn = op->getIn(0);
|
||||||
}
|
}
|
||||||
if (endVn != (Varnode *)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.
|
/// 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)
|
for(int4 i=0;i<reads.size();++i)
|
||||||
reads[i]->clearMark(); // Clear marks on read ops
|
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
|
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
|
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 establishTopologicalOrder(void); ///< Find the optimal order for iterating through the ValueSets
|
||||||
void applyConstraints(Varnode *vn,int4 type,const CircleRange &range,FlowBlock *splitPoint);
|
void applyConstraints(Varnode *vn,int4 type,const CircleRange &range,PcodeOp *cbranch);
|
||||||
void constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,FlowBlock *splitPoint);
|
void constraintsFromPath(int4 type,CircleRange &lift,Varnode *startVn,Varnode *endVn,PcodeOp *cbranch);
|
||||||
void constraintsFromCBranch(PcodeOp *cbranch); ///< Generate constraints arising from the given branch
|
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
|
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
|
void generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch); ///< Try to find a \e relative constraint
|
||||||
public:
|
public:
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue