mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-05 02:39:44 +02:00
Different widening strategies
This commit is contained in:
parent
8565f43e06
commit
32793712fe
3 changed files with 173 additions and 64 deletions
|
@ -2483,6 +2483,16 @@ void IfcAnalyzeRange::execute(istream &s)
|
|||
if (dcp->fd == (Funcdata *)0)
|
||||
throw IfaceExecutionError("No function selected");
|
||||
|
||||
bool useFullWidener;
|
||||
string token;
|
||||
s >> ws >> token;
|
||||
if (token == "full")
|
||||
useFullWidener = true;
|
||||
else if (token == "partial") {
|
||||
useFullWidener = false;
|
||||
}
|
||||
else
|
||||
throw IfaceParseError("Must specify \"full\" or \"partial\" widening");
|
||||
Varnode *vn = iface_read_varnode(dcp,s);
|
||||
vector<Varnode *> sinks;
|
||||
vector<PcodeOp *> reads;
|
||||
|
@ -2495,7 +2505,14 @@ void IfcAnalyzeRange::execute(istream &s)
|
|||
Varnode *stackReg = dcp->fd->findSpacebaseInput(dcp->conf->getStackSpace());
|
||||
ValueSetSolver vsSolver;
|
||||
vsSolver.establishValueSets(sinks, reads, stackReg, false);
|
||||
vsSolver.solve(10000);
|
||||
if (useFullWidener) {
|
||||
WidenerFull widener;
|
||||
vsSolver.solve(10000,widener);
|
||||
}
|
||||
else {
|
||||
WidenerNone widener;
|
||||
vsSolver.solve(10000,widener);
|
||||
}
|
||||
list<ValueSet>::const_iterator iter;
|
||||
for(iter=vsSolver.beginValueSets();iter!=vsSolver.endValueSets();++iter) {
|
||||
(*iter).printRaw(*status->optr);
|
||||
|
|
|
@ -1265,7 +1265,7 @@ bool CircleRange::pushForwardBinary(OpCode opc,const CircleRange &in1,const Circ
|
|||
step = 1; // Lose any step
|
||||
if (in1.left < in1.right) {
|
||||
left = in1.left >> sa;
|
||||
right = in1.right >> sa;
|
||||
right = ((in1.right - in1.step) >> sa) + 1;
|
||||
}
|
||||
else {
|
||||
left = 0;
|
||||
|
@ -1483,56 +1483,6 @@ void ValueSet::addEquation(int4 slot,int4 type,const CircleRange &constraint)
|
|||
equations.insert(iter,Equation(slot,type,constraint));
|
||||
}
|
||||
|
||||
/// For an iteration that isn't stabilizing attempt to widen \b this value set
|
||||
/// so that it stabilizes more rapidly on future iterations. For initial iterations,
|
||||
/// targeted widening is attempted using landmarks, otherwise \b this is widened
|
||||
/// to \e everything.
|
||||
/// \param newRange is the changed range for the current iteration
|
||||
void ValueSet::doWidening(const CircleRange &newRange)
|
||||
|
||||
{
|
||||
if (count < 2) {
|
||||
range = newRange;
|
||||
return;
|
||||
}
|
||||
else if (count == 2) {
|
||||
if (!equations.empty()) { // Look for landmark
|
||||
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;
|
||||
}
|
||||
else {
|
||||
CircleRange constraint = landmark.range;
|
||||
constraint.invert();
|
||||
if (constraint.contains(range)) {
|
||||
range.widen(constraint,leftIsStable);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (count <5) {
|
||||
range = newRange;
|
||||
return;
|
||||
}
|
||||
setFull(); // In all other cases expand to everything
|
||||
}
|
||||
|
||||
/// Give \b this value set a chance to reset its counter do to looping
|
||||
void ValueSet::looped(void)
|
||||
|
||||
{
|
||||
if (count >= 2)
|
||||
count = 2; // Reset to point just after any widening
|
||||
else
|
||||
count = 0; // Delay widening, if we haven't performed it yet
|
||||
}
|
||||
|
||||
/// Examine the input value sets that determine \b this set and decide if it
|
||||
/// is relative. In general, \b this will be relative if any of its inputs are.
|
||||
/// Certain combinations are indeterminate, which this method flags by calling
|
||||
|
@ -1578,11 +1528,11 @@ void ValueSet::computeTypeCode(void)
|
|||
/// operator defining the Varnode attached to \b this value set and pushing them
|
||||
/// forward through the operator.
|
||||
/// \return \b true if there was a change to \b this value set
|
||||
bool ValueSet::iterate(void)
|
||||
bool ValueSet::iterate(Widener &widener)
|
||||
|
||||
{
|
||||
if (!vn->isWritten()) return false;
|
||||
if (range.isFull()) return false;
|
||||
if (widener.checkFreeze(*this)) return false;
|
||||
if (count == 0)
|
||||
computeTypeCode();
|
||||
count += 1; // Count this iteration
|
||||
|
@ -1683,13 +1633,30 @@ bool ValueSet::iterate(void)
|
|||
|
||||
if (res == range)
|
||||
return false;
|
||||
if (partHead != (Partition *)0)
|
||||
doWidening(res);
|
||||
if (partHead != (Partition *)0) {
|
||||
if (!widener.doWidening(*this, range, res))
|
||||
setFull();
|
||||
}
|
||||
else
|
||||
range = res;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// If a landmark was associated with \b this value set, return its range,
|
||||
/// otherwise return null.
|
||||
/// \return the landmark range or null
|
||||
const CircleRange *ValueSet::getLandMark(void) const
|
||||
|
||||
{
|
||||
if (equations.empty())
|
||||
return (const CircleRange *)0;
|
||||
|
||||
const Equation &landmark(equations.back());
|
||||
if (landmark.slot != numParams || typeCode != landmark.typeCode)
|
||||
return (const CircleRange *)0;
|
||||
return &landmark.range;
|
||||
}
|
||||
|
||||
/// \param s is the stream to print to
|
||||
void ValueSet::printRaw(ostream &s) const
|
||||
|
||||
|
@ -1766,6 +1733,76 @@ void ValueSetRead::printRaw(ostream &s) const
|
|||
range.printRaw(s);
|
||||
}
|
||||
|
||||
int4 WidenerFull::determineIterationReset(const ValueSet &valueSet)
|
||||
|
||||
{
|
||||
if (valueSet.getCount() >= widenIteration)
|
||||
return widenIteration; // Reset to point just after any widening
|
||||
return 0; // Delay widening, if we haven't performed it yet
|
||||
}
|
||||
|
||||
bool WidenerFull::checkFreeze(const ValueSet &valueSet)
|
||||
|
||||
{
|
||||
return valueSet.getRange().isFull();
|
||||
}
|
||||
|
||||
bool WidenerFull::doWidening(const ValueSet &valueSet,CircleRange &range,const CircleRange &newRange)
|
||||
|
||||
{
|
||||
if (valueSet.getCount() < widenIteration) {
|
||||
range = newRange;
|
||||
return true;
|
||||
}
|
||||
else if (valueSet.getCount() == widenIteration) {
|
||||
const CircleRange *landmark = valueSet.getLandMark();
|
||||
if (landmark != (const CircleRange *)0) {
|
||||
bool leftIsStable = range.getMin() == newRange.getMin();
|
||||
range = newRange; // Preserve any new step information
|
||||
if (landmark->contains(range)) {
|
||||
range.widen(*landmark,leftIsStable);
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
CircleRange constraint = *landmark;
|
||||
constraint.invert();
|
||||
if (constraint.contains(range)) {
|
||||
range.widen(constraint,leftIsStable);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (valueSet.getCount() < fullIteration) {
|
||||
range = newRange;
|
||||
return true;
|
||||
}
|
||||
return false; // Indicate that constrained widening failed (set to full)
|
||||
}
|
||||
|
||||
int4 WidenerNone::determineIterationReset(const ValueSet &valueSet)
|
||||
|
||||
{
|
||||
if (valueSet.getCount() >= freezeIteration)
|
||||
return freezeIteration; // Reset to point just after any widening
|
||||
return valueSet.getCount();
|
||||
}
|
||||
|
||||
bool WidenerNone::checkFreeze(const ValueSet &valueSet)
|
||||
|
||||
{
|
||||
if (valueSet.getRange().isFull())
|
||||
return true;
|
||||
return (valueSet.getCount() >= freezeIteration);
|
||||
}
|
||||
|
||||
bool WidenerNone::doWidening(const ValueSet &valueSet,CircleRange &range,const CircleRange &newRange)
|
||||
|
||||
{
|
||||
range = newRange;
|
||||
return true;
|
||||
}
|
||||
|
||||
/// \brief Construct an iterator over the outbound edges of the given ValueSet node
|
||||
///
|
||||
/// Mostly this just forwards the ValueSets attached to output Varnodes
|
||||
|
@ -2324,7 +2361,8 @@ void ValueSetSolver::establishValueSets(const vector<Varnode *> &sinks,const vec
|
|||
/// The ValueSets are recalculated in the established topological ordering, with looping
|
||||
/// at various levels until a fixed point is reached.
|
||||
/// \param max is the maximum number of iterations to allow before forcing termination
|
||||
void ValueSetSolver::solve(int4 max)
|
||||
/// \param widener is the Widening strategy to use to accelerate stabilization
|
||||
void ValueSetSolver::solve(int4 max,Widener &widener)
|
||||
|
||||
{
|
||||
maxIterations = max;
|
||||
|
@ -2343,10 +2381,11 @@ void ValueSetSolver::solve(int4 max)
|
|||
componentStack.push_back(curSet->partHead);
|
||||
curComponent = curSet->partHead;
|
||||
curComponent->isDirty = false;
|
||||
curComponent->startNode->looped(); // Reset component counter upon entry
|
||||
// Reset component counter upon entry
|
||||
curComponent->startNode->count = widener.determineIterationReset(*curComponent->startNode);
|
||||
}
|
||||
if (curComponent != (Partition *)0) {
|
||||
if (curSet->iterate())
|
||||
if (curSet->iterate(widener))
|
||||
curComponent->isDirty = true;
|
||||
if (curComponent->stopNode != curSet) {
|
||||
curSet = curSet->next;
|
||||
|
@ -2377,7 +2416,7 @@ void ValueSetSolver::solve(int4 max)
|
|||
}
|
||||
}
|
||||
else {
|
||||
curSet->iterate();
|
||||
curSet->iterate(widener);
|
||||
curSet = curSet->next;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,6 +99,7 @@ public:
|
|||
};
|
||||
|
||||
class Partition; // Forward declaration
|
||||
class Widener; // Forward declaration
|
||||
|
||||
/// \brief A range of values attached to a Varnode within a data-flow subsystem
|
||||
///
|
||||
|
@ -139,11 +140,11 @@ private:
|
|||
void setVarnode(Varnode *v,int4 tCode); ///< Attach \b this to given Varnode and set initial values
|
||||
void addEquation(int4 slot,int4 type,const CircleRange &constraint); ///< Insert an equation restricting \b this value set
|
||||
void addLandmark(int4 type,const CircleRange &constraint) { addEquation(numParams,type,constraint); } ///< Add a widening landmark
|
||||
void doWidening(const CircleRange &newRange); ///< Widen the value set so fixed point is reached sooner
|
||||
void looped(void); ///< Mark that iteration has looped back to \b this
|
||||
void computeTypeCode(void); ///< Figure out if \b this value set is absolute or relative
|
||||
bool iterate(void); ///< Regenerate \b this value set from operator inputs
|
||||
bool iterate(Widener &widener); ///< Regenerate \b this value set from operator inputs
|
||||
public:
|
||||
int4 getCount(void) const { return count; } ///< Get the current iteration count
|
||||
const CircleRange *getLandMark(void) const; ///< Get any \e landmark range
|
||||
int4 getTypeCode(void) const { return typeCode; } ///< Return '0' for normal constant, '1' for spacebase relative
|
||||
Varnode *getVarnode(void) const { return vn; } ///< Get the Varnode attached to \b this ValueSet
|
||||
const CircleRange &getRange(void) const { return range; } ///< Get the actual range of values
|
||||
|
@ -185,6 +186,58 @@ public:
|
|||
void printRaw(ostream &s) const; ///< Write a text description of \b to the given stream
|
||||
};
|
||||
|
||||
class Widener {
|
||||
public:
|
||||
virtual ~Widener(void) {} ///< Destructor
|
||||
|
||||
/// \brief Upon entering a fresh partition, determine how the given ValueSet count should be reset
|
||||
///
|
||||
/// \param valueSet is the given value set
|
||||
/// \return the value of the iteration counter to reset to
|
||||
virtual int4 determineIterationReset(const ValueSet &valueSet)=0;
|
||||
|
||||
/// \brief Check if the given value set has been frozen for the remainder of the iteration process
|
||||
///
|
||||
/// \param valueSet is the given value set
|
||||
/// \return \b true if the valueSet will no longer change
|
||||
virtual bool checkFreeze(const ValueSet &valueSet)=0;
|
||||
|
||||
/// \brief For an iteration that isn't stabilizing attempt to widen the given ValueSet
|
||||
///
|
||||
/// Change the given range based on its previous iteration so that it stabilizes more
|
||||
/// rapidly on future iterations.
|
||||
/// \param valueSet is the given value set
|
||||
/// \param range is the previous form of the given range (and storage for the widening result)
|
||||
/// \param newRange is the current iteration of the given range
|
||||
/// \return \b true if widening succeeded
|
||||
virtual bool doWidening(const ValueSet &valueSet,CircleRange &range,const CircleRange &newRange)=0;
|
||||
};
|
||||
|
||||
/// \brief Class for doing normal widening
|
||||
///
|
||||
/// Widening is attempted at a specific iteration. If a landmark is available, it is used
|
||||
/// to do a controlled widening, holding the stable range boundary constant. Otherwise a
|
||||
/// full range is produced. At a later iteration, a full range is produced automatically.
|
||||
class WidenerFull : public Widener {
|
||||
int4 widenIteration; ///< The iteration at which widening is attempted
|
||||
int4 fullIteration; ///< The iteration at which a full range is produced
|
||||
public:
|
||||
WidenerFull(void) { widenIteration = 2; fullIteration = 5; } ///< Constructor with default iterations
|
||||
WidenerFull(int4 wide,int4 full) { widenIteration = wide; fullIteration = full; } ///< Constructor specifying iterations
|
||||
virtual int4 determineIterationReset(const ValueSet &valueSet);
|
||||
virtual bool checkFreeze(const ValueSet &valueSet);
|
||||
virtual bool doWidening(const ValueSet &valueSet,CircleRange &range,const CircleRange &newRange);
|
||||
};
|
||||
|
||||
class WidenerNone : public Widener {
|
||||
int4 freezeIteration; ///< The iteration at which all change ceases
|
||||
public:
|
||||
WidenerNone(void) { freezeIteration = 3; }
|
||||
virtual int4 determineIterationReset(const ValueSet &valueSet);
|
||||
virtual bool checkFreeze(const ValueSet &valueSet);
|
||||
virtual bool doWidening(const ValueSet &valueSet,CircleRange &range,const CircleRange &newRange);
|
||||
};
|
||||
|
||||
/// \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)
|
||||
|
@ -235,7 +288,7 @@ class ValueSetSolver {
|
|||
public:
|
||||
void establishValueSets(const vector<Varnode *> &sinks,const vector<PcodeOp *> &reads,Varnode *stackReg,bool indirectAsCopy);
|
||||
int4 getNumIterations(void) const { return numIterations; } ///< Get the current number of iterations
|
||||
void solve(int4 max); ///< Iterate the ValueSet system until it stabilizes
|
||||
void solve(int4 max,Widener &widener); ///< Iterate the ValueSet system until it stabilizes
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue