ValueSetRead objects

This commit is contained in:
caheckman 2019-05-31 17:28:16 -04:00
parent 16fd5df590
commit 94e289d494
3 changed files with 118 additions and 13 deletions

View file

@ -2485,17 +2485,28 @@ void IfcAnalyzeRange::execute(istream &s)
Varnode *vn = iface_read_varnode(dcp,s);
vector<Varnode *> sinks;
vector<PcodeOp *> reads;
sinks.push_back(vn);
for(list<PcodeOp *>::const_iterator iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
if (op->code() == CPUI_LOAD || op->code() == CPUI_STORE)
reads.push_back(op);
}
Varnode *stackReg = dcp->fd->findSpacebaseInput(dcp->conf->getStackSpace());
ValueSetSolver vsSolver;
vsSolver.establishValueSets(sinks, stackReg);
vsSolver.establishValueSets(sinks, reads, stackReg);
vsSolver.solve(10000);
list<ValueSet>::const_iterator iter;
for(iter=vsSolver.beginValueSets();iter!=vsSolver.endValueSets();++iter) {
(*iter).printRaw(*status->optr);
*status->optr << endl;
}
map<SeqNum,ValueSetRead>::const_iterator riter;
for(riter=vsSolver.beginValueSetReads();riter!=vsSolver.endValueSetReads();++riter) {
(*riter).second.printRaw(*status->optr);
*status->optr << endl;
}
}
#ifdef OPACTION_DEBUG

View file

@ -1472,6 +1472,7 @@ void ValueSet::doWidening(const CircleRange &newRange)
const Equation &landmark(equations.back());
if (landmark.slot == numParams && typeCode == landmark.typeCode) {
bool leftIsStable = range.getMin() == newRange.getMin();
range = newRange; // Preserve any new step information
if (landmark.range.contains(range)) {
range.widen(landmark.range,leftIsStable);
return;
@ -1599,17 +1600,11 @@ bool ValueSet::iterate(void)
setFull();
return true;
}
typeCode = inSet1->typeCode;
}
else if (numParams == 2) {
ValueSet *inSet1 = op->getIn(0)->getValueSet();
ValueSet *inSet2 = op->getIn(1)->getValueSet();
typeCode = inSet1->typeCode + inSet2->typeCode;
if (inSet1->typeCode != 0 && inSet2->typeCode != 0) { // Combining two based constants
typeCode = 0;
res.setFull(vn->getSize());
}
else if (equations.size() == 0) {
if (equations.size() == 0) {
if (!res.pushForwardBinary(opCode, inSet1->range, inSet2->range, inSet1->vn->getSize(), vn->getSize(), 32)) {
setFull();
return true;
@ -1668,6 +1663,57 @@ void ValueSet::printRaw(ostream &s) const
range.printRaw(s);
}
/// \param o is the PcodeOp reading the value set
/// \param slt is the input slot the values are coming in from
void ValueSetRead::setPcodeOp(PcodeOp *o,int4 slt)
{
typeCode = 0;
op = o;
slot = slt;
equationTypeCode = 100;
}
/// \param slt is the given slot
/// \param type is the constraint characteristic
/// \param constraint is the given range
void ValueSetRead::addEquation(int4 slt,int4 type,const CircleRange &constraint)
{
if (slot == slt) {
equationTypeCode = type;
equationConstraint = constraint;
}
}
/// This value set will be the same as the ValueSet of the Varnode being read but may
/// be modified due to additional control-flow constraints
void ValueSetRead::compute(void)
{
Varnode *vn = op->getIn(slot);
ValueSet *valueSet = vn->getValueSet();
typeCode = valueSet->getTypeCode();
range = valueSet->getRange();
if (typeCode == equationTypeCode) {
if (0 != range.intersect(equationConstraint)) {
range = equationConstraint;
}
}
}
/// \param s is the stream to print to
void ValueSetRead::printRaw(ostream &s) const
{
s << "Read: " << get_opname(op->code());
if (typeCode == 0)
s << " absolute ";
else
s << " stackptr ";
range.printRaw(s);
}
/// \brief Construct an iterator over the outbound edges of the given ValueSet node
///
/// Mostly this just forwards the ValueSets attached to output Varnodes
@ -1848,6 +1894,10 @@ void ValueSetSolver::applyConstraints(Varnode *vn,int4 type,const CircleRange &r
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();
if (outVn == (Varnode *)0) continue;
if (!outVn->isMark()) continue;
@ -2063,8 +2113,9 @@ void ValueSetSolver::generateRelativeConstraint(PcodeOp *compOp,PcodeOp *cbranch
/// Given a set of sinks, find all the Varnodes that flow directly into them.
/// \param sinks is the list terminating Varnodes
/// \param reads are add-on PcodeOps where we would like to know input ValueSets at the point of read
/// \param stackReg (if non-NULL) gives the stack pointer (for keeping track of relative offsets)
void ValueSetSolver::establishValueSets(const vector<Varnode *> &sinks,Varnode *stackReg)
void ValueSetSolver::establishValueSets(const vector<Varnode *> &sinks,const vector<PcodeOp *> &reads,Varnode *stackReg)
{
vector<Varnode *> worklist;
@ -2107,7 +2158,21 @@ void ValueSetSolver::establishValueSets(const vector<Varnode *> &sinks,Varnode *
worklist.push_back(inVn);
}
}
for(int4 i=0;i<reads.size();++i) {
PcodeOp *op = reads[i];
for(int4 slot=0;slot<op->numInput();++slot) {
Varnode *vn = op->getIn(slot);
if (vn->isMark()) {
readNodes[op->getSeqNum()].setPcodeOp(op, slot);
op->setMark(); // Mark read ops for equation generation stage
break; // Only 1 read allowed
}
}
}
generateConstraints(worklist);
for(int4 i=0;i<reads.size();++i)
reads[i]->clearMark(); // Clear marks on read ops
establishTopologicalOrder();
for(int4 i=0;i<worklist.size();++i)
worklist[i]->clearMark();
@ -2170,4 +2235,7 @@ void ValueSetSolver::solve(int4 max)
curSet = curSet->next;
}
}
map<SeqNum,ValueSetRead>::iterator riter;
for(riter=readNodes.begin();riter!=readNodes.end();++riter)
(*riter).second.compute(); // Calculate any follow-on value sets
}

View file

@ -159,6 +159,29 @@ public:
} ///< Construct empty partition
};
/// \brief A special form of ValueSet associated with the \e read \e point of a Varnode
///
/// When a Varnode is read, it may have a more restricted range at the point of the read
/// compared to the full scope. This class officially stores the value set at the point
/// of the read (specified by PcodeOp and slot). It is computed as a final step after
/// the main iteration has completed.
class ValueSetRead {
friend class ValueSetSolver;
int4 typeCode; ///< 0=pure constant 1=stack relative
PcodeOp *op; ///< The PcodeOp at the point of the value set read
int4 slot; ///< The slot being read
CircleRange range; ///< Range of values or offsets in this set
int4 equationTypeCode; ///< Type code of the associated equation
CircleRange equationConstraint; ///< Constraint associated with the equation
void setPcodeOp(PcodeOp *o,int4 slt); ///< Establish \e read this value set corresponds to
void addEquation(int4 slt,int4 type,const CircleRange &constraint); ///< Insert an equation restricting \b this value set
public:
int4 getTypeCode(void) const { return typeCode; } ///< Return '0' for normal constant, '1' for spacebase relative
const CircleRange &getRange(void) const { return range; } ///< Get the actual range of values
void compute(void); ///< Compute \b this value set
void printRaw(ostream &s) const; ///< Write a text description of \b to the given stream
};
/// \brief Class the determines a ValueSet for each Varnode in a data-flow system
///
/// This class uses \e value \e set \e analysis to calculate (an overestimation of)
@ -185,6 +208,7 @@ class ValueSetSolver {
};
list<ValueSet> valueNodes; ///< Storage for all the current value sets
map<SeqNum,ValueSetRead> readNodes; ///< Additional, after iteration, add-on value sets
Partition orderPartition; ///< Value sets in iteration order
list<Partition> recordStorage; ///< Storage for the Partitions establishing components
vector<ValueSet *> rootNodes; ///< Values treated as inputs
@ -206,11 +230,13 @@ class ValueSetSolver {
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:
void establishValueSets(const vector<Varnode *> &sinks,Varnode *stackReg); ///< Build value sets for a data-flow system
void establishValueSets(const vector<Varnode *> &sinks,const vector<PcodeOp *> &reads,Varnode *stackReg); ///< Build value sets for a data-flow system
int4 getNumIterations(void) const { return numIterations; } ///< Get the current number of iterations
void solve(int4 max); ///< Iterate the ValueSet system until it stabilizes
list<ValueSet>::const_iterator beginValueSets(void) { return valueNodes.begin(); } ///< Start of all ValueSets in the system
list<ValueSet>::const_iterator endValueSets(void) { return valueNodes.end(); } ///< End of all ValueSets in the system
list<ValueSet>::const_iterator beginValueSets(void) const { return valueNodes.begin(); } ///< Start of all ValueSets in the system
list<ValueSet>::const_iterator endValueSets(void) const { return valueNodes.end(); } ///< End of all ValueSets in the system
map<SeqNum,ValueSetRead>::const_iterator beginValueSetReads(void) const { return readNodes.begin(); } ///< Start of ValueSetReads
map<SeqNum,ValueSetRead>::const_iterator endValueSetReads(void) const { return readNodes.end(); } ///< End of ValueSetReads
};
/// \param op2 is the range to compare \b this to