mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
value set analysis
This commit is contained in:
parent
25894ff9ae
commit
e96f39a98f
10 changed files with 1853 additions and 460 deletions
|
@ -696,6 +696,34 @@ int4 mostsigbit_set(uintb val)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Count the number of more significant zero bits before the most significant
|
||||||
|
/// one bit in the representation of the given value;
|
||||||
|
/// \param val is the given value
|
||||||
|
/// \return the number of zero bits
|
||||||
|
int4 count_leading_zeros(uintb val)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (val == 0)
|
||||||
|
return 8*sizeof(uintb);
|
||||||
|
uintb mask = ~((uintb)0);
|
||||||
|
int4 maskSize = 4*sizeof(uintb);
|
||||||
|
mask &= (mask << maskSize);
|
||||||
|
int4 bit = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
if ((mask & val)==0) {
|
||||||
|
bit += maskSize;
|
||||||
|
maskSize >>= 1;
|
||||||
|
mask |= (mask >> maskSize);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
maskSize >>= 1;
|
||||||
|
mask &= (mask << maskSize);
|
||||||
|
}
|
||||||
|
} while(maskSize != 0);
|
||||||
|
return bit;
|
||||||
|
}
|
||||||
|
|
||||||
/// Return smallest number of form 2^n-1, bigger or equal to the given value
|
/// Return smallest number of form 2^n-1, bigger or equal to the given value
|
||||||
/// \param val is the given value
|
/// \param val is the given value
|
||||||
/// \return the mask
|
/// \return the mask
|
||||||
|
|
|
@ -482,7 +482,7 @@ inline uintb pcode_left(uintb val,int4 sa) {
|
||||||
return val << sa;
|
return val << sa;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern bool signbit_negative(uintb val,int4 size); ///< Return true if the sign-big is set
|
extern bool signbit_negative(uintb val,int4 size); ///< Return true if the sign-bit is set
|
||||||
extern uintb calc_mask(int4 size); ///< Calculate a mask for a given byte size
|
extern uintb calc_mask(int4 size); ///< Calculate a mask for a given byte size
|
||||||
extern uintb uintb_negate(uintb in,int4 size); ///< Negate the \e sized value
|
extern uintb uintb_negate(uintb in,int4 size); ///< Negate the \e sized value
|
||||||
extern uintb sign_extend(uintb in,int4 sizein,int4 sizeout); ///< Sign-extend a value between two byte sizes
|
extern uintb sign_extend(uintb in,int4 sizein,int4 sizeout); ///< Sign-extend a value between two byte sizes
|
||||||
|
@ -493,7 +493,8 @@ extern void byte_swap(intb &val,int4 size); ///< Swap bytes in the given value
|
||||||
|
|
||||||
extern uintb byte_swap(uintb val,int4 size); ///< Return the given value with bytes swapped
|
extern uintb byte_swap(uintb val,int4 size); ///< Return the given value with bytes swapped
|
||||||
extern int4 leastsigbit_set(uintb val); ///< Return index of least significant bit set in given value
|
extern int4 leastsigbit_set(uintb val); ///< Return index of least significant bit set in given value
|
||||||
extern int4 mostsigbit_set(uintb val); ///< Return index of most significant bit set in given val
|
extern int4 mostsigbit_set(uintb val); ///< Return index of most significant bit set in given value
|
||||||
|
extern int4 count_leading_zeros(uintb val); ///< Return the number of leading zero bits in the given value
|
||||||
|
|
||||||
extern uintb coveringmask(uintb val); ///< Return a mask that \e covers the given value
|
extern uintb coveringmask(uintb val); ///< Return a mask that \e covers the given value
|
||||||
extern int4 bit_transitions(uintb val,int4 sz); ///< Calculate the number of bit transitions in the sized value
|
extern int4 bit_transitions(uintb val,int4 sz); ///< Calculate the number of bit transitions in the sized value
|
||||||
|
|
|
@ -129,6 +129,7 @@ void IfaceDecompCapability::registerCommands(IfaceStatus *status)
|
||||||
status->registerCom(new IfcVolatile(),"volatile");
|
status->registerCom(new IfcVolatile(),"volatile");
|
||||||
status->registerCom(new IfcPreferSplit(),"prefersplit");
|
status->registerCom(new IfcPreferSplit(),"prefersplit");
|
||||||
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
|
status->registerCom(new IfcStructureBlocks(),"structure","blocks");
|
||||||
|
status->registerCom(new IfcAnalyzeRange(), "analyze","range");
|
||||||
#ifdef CPUI_RULECOMPILE
|
#ifdef CPUI_RULECOMPILE
|
||||||
status->registerCom(new IfcParseRule(),"parse","rule");
|
status->registerCom(new IfcParseRule(),"parse","rule");
|
||||||
status->registerCom(new IfcExperimentalRules(),"experimental","rules");
|
status->registerCom(new IfcExperimentalRules(),"experimental","rules");
|
||||||
|
@ -2474,6 +2475,28 @@ void IfcCountPcode::execute(istream &s)
|
||||||
*status->optr << "Count - pcode = " << dec << count << endl;
|
*status->optr << "Count - pcode = " << dec << count << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void IfcAnalyzeRange::execute(istream &s)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (dcp->conf == (Architecture *)0)
|
||||||
|
throw IfaceExecutionError("Image not loaded");
|
||||||
|
if (dcp->fd == (Funcdata *)0)
|
||||||
|
throw IfaceExecutionError("No function selected");
|
||||||
|
|
||||||
|
Varnode *vn = iface_read_varnode(dcp,s);
|
||||||
|
vector<Varnode *> sinks;
|
||||||
|
sinks.push_back(vn);
|
||||||
|
Varnode *stackReg = dcp->fd->findSpacebaseInput(dcp->conf->getStackSpace());
|
||||||
|
ValueSetSolver vsSolver;
|
||||||
|
vsSolver.establishValueSets(sinks, stackReg);
|
||||||
|
vsSolver.solve(10000);
|
||||||
|
list<ValueSet>::const_iterator iter;
|
||||||
|
for(iter=vsSolver.beginValueSets();iter!=vsSolver.endValueSets();++iter) {
|
||||||
|
(*iter).printRaw(*status->optr);
|
||||||
|
*status->optr << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef OPACTION_DEBUG
|
#ifdef OPACTION_DEBUG
|
||||||
|
|
||||||
void IfcDebugAction::execute(istream &s)
|
void IfcDebugAction::execute(istream &s)
|
||||||
|
|
|
@ -541,6 +541,11 @@ public:
|
||||||
virtual void execute(istream &s);
|
virtual void execute(istream &s);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class IfcAnalyzeRange : public IfaceDecompCommand {
|
||||||
|
public:
|
||||||
|
virtual void execute(istream &s);
|
||||||
|
};
|
||||||
|
|
||||||
#ifdef CPUI_RULECOMPILE
|
#ifdef CPUI_RULECOMPILE
|
||||||
class IfcParseRule : public IfaceDecompCommand {
|
class IfcParseRule : public IfaceDecompCommand {
|
||||||
public:
|
public:
|
||||||
|
|
|
@ -231,11 +231,19 @@ void EmulateFunction::collectLoadPoints(vector<LoadTable> &res) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The starting value for the range and the step is preserved. The
|
||||||
|
/// ending value is set so there are exactly the given number of elements
|
||||||
|
/// in the range.
|
||||||
|
/// \param nm is the given number
|
||||||
void JumpValuesRange::truncate(int4 nm)
|
void JumpValuesRange::truncate(int4 nm)
|
||||||
|
|
||||||
{
|
{
|
||||||
// FIXME: This doesn't work if there is a stride
|
int4 rangeSize = 8*sizeof(uintb) - count_leading_zeros(range.getMask());
|
||||||
range = CircleRange(range.getMin(),range.getMin() + (nm-1),range.getMask());
|
rangeSize >>= 3;
|
||||||
|
uintb left = range.getMin();
|
||||||
|
int4 step = range.getStep();
|
||||||
|
uintb right = (left + step * nm) & range.getMask();
|
||||||
|
range.setRange(left, right, rangeSize, step);
|
||||||
}
|
}
|
||||||
|
|
||||||
uintb JumpValuesRange::getSize(void) const
|
uintb JumpValuesRange::getSize(void) const
|
||||||
|
@ -403,18 +411,21 @@ bool JumpBasic::ispoint(Varnode *vn)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void JumpBasic::setStride(Varnode *vn,CircleRange &rng)
|
/// If the some of the least significant bits of the given Varnode are known to
|
||||||
|
/// be zero, translate this into a stride for the jumptable range.
|
||||||
|
/// \param vn is the given Varnode
|
||||||
|
/// \return the calculated stride = 1,2,4,...
|
||||||
|
int4 JumpBasic::getStride(Varnode *vn)
|
||||||
|
|
||||||
{
|
{
|
||||||
uintb mask = vn->getNZMask();
|
uintb mask = vn->getNZMask();
|
||||||
int4 stride = 0;
|
int4 stride = 1;
|
||||||
while((mask&1)==0) {
|
while((mask&1)==0) {
|
||||||
mask >>= 1;
|
mask >>= 1;
|
||||||
stride += 1;
|
stride <<= 1;
|
||||||
}
|
}
|
||||||
if (stride==0) return;
|
if (stride > 32) return 1;
|
||||||
if (stride > 6) return;
|
return stride;
|
||||||
rng.setStride(stride);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uintb JumpBasic::backup2Switch(Funcdata *fd,uintb output,Varnode *outvn,Varnode *invn)
|
uintb JumpBasic::backup2Switch(Funcdata *fd,uintb output,Varnode *outvn,Varnode *invn)
|
||||||
|
@ -915,23 +926,25 @@ void JumpBasic::calcRange(Varnode *vn,CircleRange &rng) const
|
||||||
// by using the precalculated guard ranges.
|
// by using the precalculated guard ranges.
|
||||||
|
|
||||||
// Get an initial range, based on the size/type of -vn-
|
// Get an initial range, based on the size/type of -vn-
|
||||||
|
int4 stride = 1;
|
||||||
if (vn->isConstant())
|
if (vn->isConstant())
|
||||||
rng = CircleRange(vn->getOffset(),vn->getSize());
|
rng = CircleRange(vn->getOffset(),vn->getSize());
|
||||||
else if (vn->isWritten() && vn->getDef()->isBoolOutput())
|
else if (vn->isWritten() && vn->getDef()->isBoolOutput())
|
||||||
rng = CircleRange(0,1,1); // Only 0 or 1 possible
|
rng = CircleRange(0,2,1,1); // Only 0 or 1 possible
|
||||||
else { // Should we go ahead and use nzmask in all cases?
|
else { // Should we go ahead and use nzmask in all cases?
|
||||||
uintb mask = calc_mask(vn->getSize());
|
uintb maxValue = 0; // Every possible value
|
||||||
if (vn->isWritten()) {
|
if (vn->isWritten()) {
|
||||||
PcodeOp *andop = vn->getDef();
|
PcodeOp *andop = vn->getDef();
|
||||||
if (andop->code() == CPUI_INT_AND) {
|
if (andop->code() == CPUI_INT_AND) {
|
||||||
Varnode *constvn = andop->getIn(1);
|
Varnode *constvn = andop->getIn(1);
|
||||||
if (constvn->isConstant()) {
|
if (constvn->isConstant()) {
|
||||||
mask = coveringmask( constvn->getOffset() );
|
maxValue = coveringmask( constvn->getOffset() );
|
||||||
|
maxValue = (maxValue + 1) & calc_mask(vn->getSize());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rng = CircleRange(0,mask,mask);
|
stride = getStride(vn);
|
||||||
setStride(vn,rng);
|
rng = CircleRange(0,maxValue,vn->getSize(),stride);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Intersect any guard ranges which apply to -vn-
|
// Intersect any guard ranges which apply to -vn-
|
||||||
|
@ -950,7 +963,7 @@ void JumpBasic::calcRange(Varnode *vn,CircleRange &rng) const
|
||||||
// in which case the guard might not check for it. If the
|
// in which case the guard might not check for it. If the
|
||||||
// size is too big, we try only positive values
|
// size is too big, we try only positive values
|
||||||
if (rng.getSize() > 0x10000) {
|
if (rng.getSize() > 0x10000) {
|
||||||
CircleRange positive(0,rng.getMask()>>1,rng.getMask());
|
CircleRange positive(0,(rng.getMask()>>1)+1,vn->getSize(),stride);
|
||||||
positive.intersect(rng);
|
positive.intersect(rng);
|
||||||
if (!positive.isEmpty())
|
if (!positive.isEmpty())
|
||||||
rng = positive;
|
rng = positive;
|
||||||
|
|
|
@ -145,7 +145,7 @@ public:
|
||||||
void setRange(const CircleRange &rng) { range = rng; }
|
void setRange(const CircleRange &rng) { range = rng; }
|
||||||
void setStartVn(Varnode *vn) { normqvn = vn; }
|
void setStartVn(Varnode *vn) { normqvn = vn; }
|
||||||
void setStartOp(PcodeOp *op) { startop = op; }
|
void setStartOp(PcodeOp *op) { startop = op; }
|
||||||
virtual void truncate(int4 nm);
|
virtual void truncate(int4 nm); ///< Truncate the number of values to the given number
|
||||||
virtual uintb getSize(void) const;
|
virtual uintb getSize(void) const;
|
||||||
virtual bool contains(uintb val) const;
|
virtual bool contains(uintb val) const;
|
||||||
virtual bool initializeForReading(void) const;
|
virtual bool initializeForReading(void) const;
|
||||||
|
@ -233,7 +233,7 @@ protected:
|
||||||
Varnode *switchvn; // The unnormalized switch varnode
|
Varnode *switchvn; // The unnormalized switch varnode
|
||||||
static bool isprune(Varnode *vn);
|
static bool isprune(Varnode *vn);
|
||||||
static bool ispoint(Varnode *vn);
|
static bool ispoint(Varnode *vn);
|
||||||
static void setStride(Varnode *vn,CircleRange &rng);
|
static int4 getStride(Varnode *vn); ///< Get the step/stride associated with the Varnode
|
||||||
static uintb backup2Switch(Funcdata *fd,uintb output,Varnode *outvn,Varnode *invn);
|
static uintb backup2Switch(Funcdata *fd,uintb output,Varnode *outvn,Varnode *invn);
|
||||||
void findDeterminingVarnodes(PcodeOp *op,int4 slot);
|
void findDeterminingVarnodes(PcodeOp *op,int4 slot);
|
||||||
void analyzeGuards(BlockBasic *bl,int4 pathout);
|
void analyzeGuards(BlockBasic *bl,int4 pathout);
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -51,35 +51,167 @@ class CircleRange {
|
||||||
uintb mask; ///< Bit mask defining the size (modulus) and stop of the range
|
uintb mask; ///< Bit mask defining the size (modulus) and stop of the range
|
||||||
bool isempty; ///< \b true if set is empty
|
bool isempty; ///< \b true if set is empty
|
||||||
int4 step; ///< Explicit step size
|
int4 step; ///< Explicit step size
|
||||||
int4 shift; ///< Number of bits in step. Equal to log2(step)
|
|
||||||
static const char arrange[]; ///< Map from raw overlaps to normalized overlap code
|
static const char arrange[]; ///< Map from raw overlaps to normalized overlap code
|
||||||
void calcStepShift(void); ///< Calculate explicit \b step and \b skip from \b mask
|
void normalize(void); ///< Normalize the representation of full sets
|
||||||
void complement(void); ///< Set \b this to the complement of itself
|
void complement(void); ///< Set \b this to the complement of itself
|
||||||
void convertToBoolean(void); ///< Convert \b this to boolean.
|
bool convertToBoolean(void); ///< Convert \b this to boolean.
|
||||||
static bool newStride(uintb newmask,uintb &myleft,uintb &myright); ///< Recalculate range based on new size and stride
|
static bool newStride(uintb mask,int4 step,int4 oldStep,uint4 rem,uintb &myleft,uintb &myright);
|
||||||
|
static bool newDomain(uintb newMask,int4 newStep,uintb &myleft,uintb &myright);
|
||||||
static char encodeRangeOverlaps(uintb op1left,uintb op1right,uintb op2left,uintb op2right); ///< Calculate overlap code
|
static char encodeRangeOverlaps(uintb op1left,uintb op1right,uintb op2left,uintb op2right); ///< Calculate overlap code
|
||||||
public:
|
public:
|
||||||
CircleRange(void) { isempty=true; } ///< Construct an empty range
|
CircleRange(void) { isempty=true; } ///< Construct an empty range
|
||||||
CircleRange(uintb mn,uintb mx,uintb m); ///< Construct given specific boundaries.
|
CircleRange(uintb lft,uintb rgt,int4 size,int4 stp); ///< Construct given specific boundaries.
|
||||||
CircleRange(bool val); ///< Construct a boolean range
|
CircleRange(bool val); ///< Construct a boolean range
|
||||||
CircleRange(uintb val,int4 size); ///< Construct range with single value
|
CircleRange(uintb val,int4 size); ///< Construct range with single value
|
||||||
|
void setRange(uintb lft,uintb rgt,int4 size,int4 step); ///< Set directly to a specific range
|
||||||
|
void setRange(uintb val,int4 size); ///< Set range with a single value
|
||||||
|
void setFull(int4 size); ///< Set a completely full range
|
||||||
bool isEmpty(void) const { return isempty; } ///< Return \b true if \b this range is empty
|
bool isEmpty(void) const { return isempty; } ///< Return \b true if \b this range is empty
|
||||||
|
bool isFull(void) const { return ((!isempty) && (step == 1) && (left == right)); } ///< Return \b true if \b this contains all possible values
|
||||||
|
bool isSingle(void) const { return (!isempty) && (right == ((left + step)& mask)); } ///< Return \b true if \b this contains single value
|
||||||
uintb getMin(void) const { return left; } ///< Get the left boundary of the range
|
uintb getMin(void) const { return left; } ///< Get the left boundary of the range
|
||||||
uintb getMax(void) const { return (right-step)&mask; } ///< Get the right-most integer contained in the range
|
uintb getMax(void) const { return (right-step)&mask; } ///< Get the right-most integer contained in the range
|
||||||
uintb getEnd(void) const { return right; } ///< Get the right boundary of the range
|
uintb getEnd(void) const { return right; } ///< Get the right boundary of the range
|
||||||
uintb getMask(void) const { return mask; } ///< Get the mask
|
uintb getMask(void) const { return mask; } ///< Get the mask
|
||||||
uintb getSize(void) const; ///< Get the size of this range
|
uintb getSize(void) const; ///< Get the size of this range
|
||||||
|
int4 getStep(void) const { return step; } ///< Get the step for \b this range
|
||||||
|
int4 getMaxInfo(void) const; ///< Get maximum information content of range
|
||||||
|
bool operator==(const CircleRange &op2) const; ///< Equals operator
|
||||||
bool getNext(uintb &val) const { val = (val+step)&mask; return (val!=right); } ///< Advance an integer within the range
|
bool getNext(uintb &val) const { val = (val+step)&mask; return (val!=right); } ///< Advance an integer within the range
|
||||||
bool contains(const CircleRange &op2) const; ///< Check containment of another range in \b this.
|
bool contains(const CircleRange &op2) const; ///< Check containment of another range in \b this.
|
||||||
bool contains(uintb val) const; ///< Check containment of a specific integer.
|
bool contains(uintb val) const; ///< Check containment of a specific integer.
|
||||||
int4 intersect(const CircleRange &op2); ///< Intersect \b this with another range
|
int4 intersect(const CircleRange &op2); ///< Intersect \b this with another range
|
||||||
bool setNZMask(uintb nzmask,int4 size); ///< Set the range based on a putative mask.
|
bool setNZMask(uintb nzmask,int4 size); ///< Set the range based on a putative mask.
|
||||||
int4 circleUnion(const CircleRange &op2); ///< Union two ranges.
|
int4 circleUnion(const CircleRange &op2); ///< Union two ranges.
|
||||||
void setStride(int4 newshift); ///< Set a new stride on \b this range.
|
bool minimalContainer(const CircleRange &op2,int4 maxStep); ///< Construct minimal range that contains both \b this and another range
|
||||||
|
int4 invert(void); ///< Convert to complementary range
|
||||||
|
void setStride(int4 newStep,uintb rem); ///< Set a new step on \b this range.
|
||||||
|
bool pullBackUnary(OpCode opc,int4 inSize,int4 outSize); ///< Pull-back \b this through the given unary operator
|
||||||
|
bool pullBackBinary(OpCode opc,uintb val,int4 slot,int4 inSize,int4 outSize); ///< Pull-back \b this thru binary operator
|
||||||
Varnode *pullBack(PcodeOp *op,Varnode **constMarkup,bool usenzmask); ///< Pull-back \b this range through given PcodeOp.
|
Varnode *pullBack(PcodeOp *op,Varnode **constMarkup,bool usenzmask); ///< Pull-back \b this range through given PcodeOp.
|
||||||
|
bool pushForwardUnary(OpCode opc,const CircleRange &in1,int4 inSize,int4 outSize); ///< Push-forward thru given unary operator
|
||||||
|
bool pushForwardBinary(OpCode opc,const CircleRange &in1,const CircleRange &in2,int4 inSize,int4 outSize,int4 maxStep);
|
||||||
|
void widen(const CircleRange &op2,bool leftIsStable); ///< Widen the unstable bound to match containing range
|
||||||
int4 translate2Op(OpCode &opc,uintb &c,int4 &cslot) const; ///< Translate range to a comparison op
|
int4 translate2Op(OpCode &opc,uintb &c,int4 &cslot) const; ///< Translate range to a comparison op
|
||||||
|
void printRaw(ostream &s) const; ///< Write a text representation of \b this to stream
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Partition; // Forward declaration
|
||||||
|
|
||||||
|
/// \brief A range of values attached to a Varnode within a data-flow subsystem
|
||||||
|
///
|
||||||
|
/// This class acts as both the set of values for the Varnode and as a node in a
|
||||||
|
/// sub-graph overlaying the full data-flow of the function containing the Varnode.
|
||||||
|
/// The values are stored in the CircleRange field and can be interpreted either as
|
||||||
|
/// absolute values (if \b typeCode is 0) or as values relative to a stack pointer
|
||||||
|
/// or some other register (if \b typeCode is non-zero).
|
||||||
|
class ValueSet {
|
||||||
|
public:
|
||||||
|
class Equation {
|
||||||
|
friend class ValueSet;
|
||||||
|
int4 slot;
|
||||||
|
CircleRange range;
|
||||||
|
public:
|
||||||
|
Equation(int4 s,const CircleRange &rng) { slot=s; range = rng; } ///< Constructor
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
friend class ValueSetSolver;
|
||||||
|
int4 typeCode; ///< 0=pure constant 1=stack relative
|
||||||
|
Varnode *vn; ///< Varnode whose set this represents
|
||||||
|
OpCode opCode; ///< Op-code defining Varnode
|
||||||
|
int4 numParams; ///< Number of input parameters to defining operation
|
||||||
|
CircleRange range; ///< Range of values or offsets in this set
|
||||||
|
int4 count; ///< Depth first numbering / widening count
|
||||||
|
vector<Equation> equations; ///< Any equations associated with this value set
|
||||||
|
Partition *partHead; ///< If Varnode is a component head, pointer to corresponding Partition
|
||||||
|
ValueSet *next; ///< Next ValueSet to iterate
|
||||||
|
void setVarnode(Varnode *v,int4 tCode); ///< Attach \b this to given Varnode and set initial values
|
||||||
|
void addEquation(int4 slot,const CircleRange &constraint); ///< Insert an equation restricting \b this value set
|
||||||
|
void addLandmark(const CircleRange &constraint) { addEquation(numParams,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
|
||||||
|
bool iterate(void); ///< Regenerate \b this value set from operator inputs
|
||||||
|
public:
|
||||||
|
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
|
||||||
|
void printRaw(ostream &s) const; ///< Write a text description of \b to the given stream
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A range of nodes (within the weak topological ordering) that are iterated together
|
||||||
|
class Partition {
|
||||||
|
friend class ValueSetSolver;
|
||||||
|
ValueSet *startNode; ///< Starting node of component
|
||||||
|
ValueSet *stopNode; ///< Ending node of component
|
||||||
|
bool isDirty; ///< Set to \b true if a node in \b this component has changed this iteration
|
||||||
|
public:
|
||||||
|
Partition(void) {
|
||||||
|
startNode = (ValueSet *)0; stopNode = (ValueSet *)0; isDirty = false;
|
||||||
|
} ///< Construct empty partition
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \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)
|
||||||
|
/// the range of values that can reach each Varnode. The system is formed by providing
|
||||||
|
/// a set of Varnodes for which the range is desired (the sinks) via establishValueSets().
|
||||||
|
/// This creates a system of Varnodes (within the single function) that can flow to the sinks.
|
||||||
|
/// Running the method solve() does the analysis, and the caller can examine the results
|
||||||
|
/// by examining the ValueSet attached to any of the Varnodes in the system (via Varnode::getValueSet()).
|
||||||
|
class ValueSetSolver {
|
||||||
|
/// \brief An iterator over out-bound edges for a single ValueSet node in a data-flow system
|
||||||
|
///
|
||||||
|
/// This is a helper class for walking a collection of ValueSets as a graph.
|
||||||
|
/// Mostly the graph mirrors the data-flow of the Varnodes underlying the ValueSets, but
|
||||||
|
/// there is support for a simulated root node. This class acts as an iterator over the outgoing
|
||||||
|
/// edges of a particular ValueSet in the graph.
|
||||||
|
class ValueSetEdge {
|
||||||
|
const vector<ValueSet *> *rootEdges; ///< The list of nodes attached to the simulated root node (or NULL)
|
||||||
|
int4 rootPos; ///< The iterator position for the simulated root node
|
||||||
|
Varnode *vn; ///< The Varnode attached to a normal ValueSet node (or NULL)
|
||||||
|
list<PcodeOp *>::const_iterator iter; ///< The iterator position for a normal ValueSet node
|
||||||
|
public:
|
||||||
|
ValueSetEdge(ValueSet *node,const vector<ValueSet *> &roots);
|
||||||
|
ValueSet *getNext(void);
|
||||||
|
};
|
||||||
|
|
||||||
|
list<ValueSet> valueNodes; ///< Storage for all the current 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
|
||||||
|
vector<ValueSet *> nodeStack; ///< Stack used to generate the topological ordering
|
||||||
|
int4 depthFirstIndex; ///< (Global) depth first numbering for topological ordering
|
||||||
|
int4 numIterations; ///< Count of individual ValueSet iterations
|
||||||
|
int4 maxIterations; ///< Maximum number of iterations before forcing termination
|
||||||
|
void newValueSet(Varnode *vn,int4 tCode); ///< Allocate storage for a new ValueSet
|
||||||
|
static void partitionPrepend(ValueSet *vertex,Partition &part); ///< Prepend a vertex to a partition
|
||||||
|
static void partitionPrepend(const Partition &head,Partition &part); ///< Prepend full Partition to given Partition
|
||||||
|
void partitionSurround(Partition &part); ///< Create a full partition component
|
||||||
|
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,const CircleRange &range,FlowBlock *splitPoint);
|
||||||
|
void constraintsFromPath(Varnode *vn,PcodeOp *cbranch); ///< Generate constraints given a branch and matching Varnode
|
||||||
|
void constraintsFromCBranch(PcodeOp *cbranch); ///< Generate constraints arising from the given branch
|
||||||
|
void generateConstraints(vector<Varnode *> &worklist); ///< Generate constraints given a system of Varnodes
|
||||||
|
public:
|
||||||
|
void establishValueSets(const vector<Varnode *> &sinks,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
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \param op2 is the range to compare \b this to
|
||||||
|
/// \return \b true if the two ranges are equal
|
||||||
|
inline bool CircleRange::operator==(const CircleRange &op2) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (isempty != op2.isempty) return false;
|
||||||
|
if (isempty) return true;
|
||||||
|
return (left == op2.left) && (right == op2.right) && (mask == op2.mask) && (step == op2.step);
|
||||||
|
}
|
||||||
|
|
||||||
/// If two ranges are labeled [l , r) and [op2.l, op2.r), the
|
/// If two ranges are labeled [l , r) and [op2.l, op2.r), the
|
||||||
/// overlap of the ranges can be characterized by listing the four boundary
|
/// overlap of the ranges can be characterized by listing the four boundary
|
||||||
/// values in order, as the circle is traversed in a clock-wise direction. This characterization can be
|
/// values in order, as the circle is traversed in a clock-wise direction. This characterization can be
|
||||||
|
@ -111,4 +243,26 @@ inline char CircleRange::encodeRangeOverlaps(uintb op1left, uintb op1right, uint
|
||||||
return arrange[val];
|
return arrange[val];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \param vertex is the node that will be prepended
|
||||||
|
/// \param part is the Partition being modified
|
||||||
|
inline void ValueSetSolver::partitionPrepend(ValueSet *vertex,Partition &part)
|
||||||
|
|
||||||
|
{
|
||||||
|
vertex->next = part.startNode; // Attach new vertex to beginning of list
|
||||||
|
part.startNode = vertex; // Change the first value set to be the new vertex
|
||||||
|
if (part.stopNode == (ValueSet *)0)
|
||||||
|
part.stopNode = vertex;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \param head is the partition to be prepended
|
||||||
|
/// \param part is the given partition being modified (prepended to)
|
||||||
|
inline void ValueSetSolver::partitionPrepend(const Partition &head,Partition &part)
|
||||||
|
|
||||||
|
{
|
||||||
|
head.stopNode->next = part.startNode;
|
||||||
|
part.startNode = head.startNode;
|
||||||
|
if (part.stopNode == (ValueSet *)0)
|
||||||
|
part.stopNode = head.stopNode;
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -308,10 +308,10 @@ uintb AddrSpace::read(const string &s,int4 &size) const
|
||||||
offset = addressToByte(offset,wordsize);
|
offset = addressToByte(offset,wordsize);
|
||||||
enddata = (const char *) tmpdata;
|
enddata = (const char *) tmpdata;
|
||||||
if (enddata - s.c_str() == s.size()) { // If no size or offset override
|
if (enddata - s.c_str() == s.size()) { // If no size or offset override
|
||||||
size = getAddrSize(); // Return "natural" size
|
size = manage->getDefaultSize(); // Return "natural" size
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
size = getAddrSize();
|
size = manage->getDefaultSize();
|
||||||
}
|
}
|
||||||
if (append != string::npos) {
|
if (append != string::npos) {
|
||||||
enddata = s.c_str()+append;
|
enddata = s.c_str()+append;
|
||||||
|
|
|
@ -28,6 +28,7 @@ class VarnodeBank;
|
||||||
class Merge;
|
class Merge;
|
||||||
class Funcdata;
|
class Funcdata;
|
||||||
class SymbolEntry;
|
class SymbolEntry;
|
||||||
|
class ValueSet;
|
||||||
|
|
||||||
/// \brief Compare two Varnode pointers by location then definition
|
/// \brief Compare two Varnode pointers by location then definition
|
||||||
struct VarnodeCompareLocDef {
|
struct VarnodeCompareLocDef {
|
||||||
|
@ -134,7 +135,10 @@ private:
|
||||||
VarnodeDefSet::iterator defiter; ///< Iterator into VarnodeBank sorted by definition
|
VarnodeDefSet::iterator defiter; ///< Iterator into VarnodeBank sorted by definition
|
||||||
list<PcodeOp *> descend; ///< List of every op using this varnode as input
|
list<PcodeOp *> descend; ///< List of every op using this varnode as input
|
||||||
mutable Cover *cover; ///< Addresses covered by the def->use of this Varnode
|
mutable Cover *cover; ///< Addresses covered by the def->use of this Varnode
|
||||||
mutable Datatype *temptype; ///< For type propagate algorithm
|
mutable union {
|
||||||
|
Datatype *dataType; ///< For type propagate algorithm
|
||||||
|
ValueSet *valueSet;
|
||||||
|
} temp;
|
||||||
uintb consumed; ///< What parts of this varnode are used
|
uintb consumed; ///< What parts of this varnode are used
|
||||||
uintb nzm; ///< Which bits do we know are zero
|
uintb nzm; ///< Which bits do we know are zero
|
||||||
friend class VarnodeBank;
|
friend class VarnodeBank;
|
||||||
|
@ -167,8 +171,10 @@ public:
|
||||||
SymbolEntry *getSymbolEntry(void) const { return mapentry; } ///< Get symbol and scope information associated with this Varnode
|
SymbolEntry *getSymbolEntry(void) const { return mapentry; } ///< Get symbol and scope information associated with this Varnode
|
||||||
uint4 getFlags(void) const { return flags; } ///< Get all the boolean attributes
|
uint4 getFlags(void) const { return flags; } ///< Get all the boolean attributes
|
||||||
Datatype *getType(void) const { return type; } ///< Get the Datatype associated with this Varnode
|
Datatype *getType(void) const { return type; } ///< Get the Datatype associated with this Varnode
|
||||||
void setTempType(Datatype *t) const { temptype = t; } ///< Set the temporary Datatype
|
void setTempType(Datatype *t) const { temp.dataType = t; } ///< Set the temporary Datatype
|
||||||
Datatype *getTempType(void) const { return temptype; } ///< Get the temporary Datatype (used during type propagation)
|
Datatype *getTempType(void) const { return temp.dataType; } ///< Get the temporary Datatype (used during type propagation)
|
||||||
|
void setValueSet(ValueSet *v) const { temp.valueSet = v; } ///< Set the temporary ValueSet record
|
||||||
|
ValueSet *getValueSet(void) const { return temp.valueSet; } ///< Get the temporary ValueSet record
|
||||||
uint4 getCreateIndex(void) const { return create_index; } ///< Get the creation index
|
uint4 getCreateIndex(void) const { return create_index; } ///< Get the creation index
|
||||||
Cover *getCover(void) const { updateCover(); return cover; } ///< Get Varnode coverage information
|
Cover *getCover(void) const { updateCover(); return cover; } ///< Get Varnode coverage information
|
||||||
list<PcodeOp *>::const_iterator beginDescend(void) const { return descend.begin(); } ///< Get iterator to list of syntax tree descendants (reads)
|
list<PcodeOp *>::const_iterator beginDescend(void) const { return descend.begin(); } ///< Get iterator to list of syntax tree descendants (reads)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue