mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
New unnormalized switch variable calculation
This commit is contained in:
parent
6a3d7cd03e
commit
ed786460ca
2 changed files with 82 additions and 23 deletions
|
@ -562,18 +562,20 @@ static bool matching_constants(Varnode *vn1,Varnode *vn2)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \param op is the CBRANCH \e guarding the switch
|
/// \param bOp is the CBRANCH \e guarding the switch
|
||||||
|
/// \param rOp is the PcodeOp immediately reading the Varnode
|
||||||
/// \param path is the specific branch to take from the CBRANCH to reach the switch
|
/// \param path is the specific branch to take from the CBRANCH to reach the switch
|
||||||
/// \param rng is the range of values causing the switch path to be taken
|
/// \param rng is the range of values causing the switch path to be taken
|
||||||
/// \param v is the Varnode holding the value controlling the CBRANCH
|
/// \param v is the Varnode holding the value controlling the CBRANCH
|
||||||
GuardRecord::GuardRecord(PcodeOp *op,int4 path,const CircleRange &rng,Varnode *v)
|
GuardRecord::GuardRecord(PcodeOp *bOp,PcodeOp *rOp,int4 path,const CircleRange &rng,Varnode *v)
|
||||||
|
|
||||||
{
|
{
|
||||||
cbranch = op;
|
cbranch = bOp;
|
||||||
|
readOp = rOp;
|
||||||
indpath = path;
|
indpath = path;
|
||||||
range = rng;
|
range = rng;
|
||||||
vn = v;
|
vn = v;
|
||||||
baseVn = quasiCopy(v,bitsPreserved,false); // Look for varnode whose bits are copied
|
baseVn = quasiCopy(v,bitsPreserved); // Look for varnode whose bits are copied
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Determine if \b this guard applies to the given Varnode
|
/// \brief Determine if \b this guard applies to the given Varnode
|
||||||
|
@ -670,10 +672,9 @@ int4 GuardRecord::oneOffMatch(PcodeOp *op1,PcodeOp *op2)
|
||||||
/// \param vn is the given Varnode
|
/// \param vn is the given Varnode
|
||||||
/// \param bitsPreserved will hold the number of least significant bits preserved by the sequence
|
/// \param bitsPreserved will hold the number of least significant bits preserved by the sequence
|
||||||
/// \return the earliest source of the quasi-copy, which may just be the given Varnode
|
/// \return the earliest source of the quasi-copy, which may just be the given Varnode
|
||||||
Varnode *GuardRecord::quasiCopy(Varnode *vn,int4 &bitsPreserved,bool noWholeValue)
|
Varnode *GuardRecord::quasiCopy(Varnode *vn,int4 &bitsPreserved)
|
||||||
|
|
||||||
{
|
{
|
||||||
Varnode *origVn = vn;
|
|
||||||
bitsPreserved = mostsigbit_set(vn->getNZMask()) + 1;
|
bitsPreserved = mostsigbit_set(vn->getNZMask()) + 1;
|
||||||
if (bitsPreserved == 0) return vn;
|
if (bitsPreserved == 0) return vn;
|
||||||
uintb mask = 1;
|
uintb mask = 1;
|
||||||
|
@ -682,11 +683,6 @@ Varnode *GuardRecord::quasiCopy(Varnode *vn,int4 &bitsPreserved,bool noWholeValu
|
||||||
PcodeOp *op = vn->getDef();
|
PcodeOp *op = vn->getDef();
|
||||||
Varnode *constVn;
|
Varnode *constVn;
|
||||||
while(op != (PcodeOp *)0) {
|
while(op != (PcodeOp *)0) {
|
||||||
if (noWholeValue && (vn != origVn)) {
|
|
||||||
uintb inputMask = vn->getNZMask() | mask;
|
|
||||||
if (mask == inputMask)
|
|
||||||
return origVn; // vn contains whole value, -noWholeValue- indicates we should abort
|
|
||||||
}
|
|
||||||
switch(op->code()) {
|
switch(op->code()) {
|
||||||
case CPUI_COPY:
|
case CPUI_COPY:
|
||||||
vn = op->getIn(0);
|
vn = op->getIn(0);
|
||||||
|
@ -955,6 +951,29 @@ void PathMeld::meld(vector<PcodeOp *> &path,vector<int4> &slot)
|
||||||
slot.resize(cutOff);
|
slot.resize(cutOff);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The starting Varnode, common to all paths, is provided as an index.
|
||||||
|
/// All PcodeOps up to the final BRANCHIND are (un)marked.
|
||||||
|
/// \param val is \b true for marking, \b false for unmarking
|
||||||
|
/// \param startVarnode is the index of the starting PcodeOp
|
||||||
|
void PathMeld::markPaths(bool val,int4 startVarnode)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 startOp;
|
||||||
|
for(startOp=opMeld.size()-1;startOp>=0;--startOp) {
|
||||||
|
if (opMeld[startOp].rootVn == startVarnode)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (startOp < 0) return;
|
||||||
|
if (val) {
|
||||||
|
for(int4 i=0;i<=startOp;++i)
|
||||||
|
opMeld[i].op->setMark();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for(int4 i=0;i<=startOp;++i)
|
||||||
|
opMeld[i].op->clearMark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The Varnode is specified by an index into sequence of Varnodes common to all paths in \b this PathMeld.
|
/// The Varnode is specified by an index into sequence of Varnodes common to all paths in \b this PathMeld.
|
||||||
/// We find the earliest (as in executed first) PcodeOp, within \b this PathMeld that uses the Varnode as input.
|
/// We find the earliest (as in executed first) PcodeOp, within \b this PathMeld that uses the Varnode as input.
|
||||||
/// \param pos is the index of the Varnode
|
/// \param pos is the index of the Varnode
|
||||||
|
@ -1023,14 +1042,15 @@ void JumpBasic::analyzeGuards(BlockBasic *bl,int4 pathout)
|
||||||
|
|
||||||
// The boolean variable could conceivably be the switch variable
|
// The boolean variable could conceivably be the switch variable
|
||||||
int4 indpathstore = prevbl->getFlipPath() ? 1-indpath : indpath;
|
int4 indpathstore = prevbl->getFlipPath() ? 1-indpath : indpath;
|
||||||
selectguards.push_back(GuardRecord(cbranch,indpathstore,rng,vn));
|
selectguards.push_back(GuardRecord(cbranch,cbranch,indpathstore,rng,vn));
|
||||||
for(j=0;j<maxpullback;++j) {
|
for(j=0;j<maxpullback;++j) {
|
||||||
Varnode *markup; // Throw away markup information
|
Varnode *markup; // Throw away markup information
|
||||||
if (!vn->isWritten()) break;
|
if (!vn->isWritten()) break;
|
||||||
vn = rng.pullBack(vn->getDef(),&markup,usenzmask);
|
PcodeOp *readOp = vn->getDef();
|
||||||
|
vn = rng.pullBack(readOp,&markup,usenzmask);
|
||||||
if (vn == (Varnode *)0) break;
|
if (vn == (Varnode *)0) break;
|
||||||
if (rng.isEmpty()) break;
|
if (rng.isEmpty()) break;
|
||||||
selectguards.push_back(GuardRecord(cbranch,indpathstore,rng,vn));
|
selectguards.push_back(GuardRecord(cbranch,readOp,indpathstore,rng,vn));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1068,7 +1088,7 @@ void JumpBasic::calcRange(Varnode *vn,CircleRange &rng) const
|
||||||
|
|
||||||
// Intersect any guard ranges which apply to -vn-
|
// Intersect any guard ranges which apply to -vn-
|
||||||
int4 bitsPreserved;
|
int4 bitsPreserved;
|
||||||
Varnode *baseVn = GuardRecord::quasiCopy(vn, bitsPreserved, true);
|
Varnode *baseVn = GuardRecord::quasiCopy(vn, bitsPreserved);
|
||||||
vector<GuardRecord>::const_iterator iter;
|
vector<GuardRecord>::const_iterator iter;
|
||||||
for(iter=selectguards.begin();iter!=selectguards.end();++iter) {
|
for(iter=selectguards.begin();iter!=selectguards.end();++iter) {
|
||||||
const GuardRecord &guard( *iter );
|
const GuardRecord &guard( *iter );
|
||||||
|
@ -1175,7 +1195,7 @@ void JumpBasic::markFoldableGuards(void)
|
||||||
{
|
{
|
||||||
Varnode *vn = pathMeld.getVarnode(varnodeIndex);
|
Varnode *vn = pathMeld.getVarnode(varnodeIndex);
|
||||||
int4 bitsPreserved;
|
int4 bitsPreserved;
|
||||||
Varnode *baseVn = GuardRecord::quasiCopy(vn, bitsPreserved, true);
|
Varnode *baseVn = GuardRecord::quasiCopy(vn, bitsPreserved);
|
||||||
for(int4 i=0;i<selectguards.size();++i) {
|
for(int4 i=0;i<selectguards.size();++i) {
|
||||||
if (selectguards[i].valueMatch(vn,baseVn,bitsPreserved)==0) {
|
if (selectguards[i].valueMatch(vn,baseVn,bitsPreserved)==0) {
|
||||||
selectguards[i].clear(); // Indicate this is not a true guard
|
selectguards[i].clear(); // Indicate this is not a true guard
|
||||||
|
@ -1183,6 +1203,40 @@ void JumpBasic::markFoldableGuards(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \param val is \b true to set marks, \b false to clear marks
|
||||||
|
void JumpBasic::markModel(bool val)
|
||||||
|
|
||||||
|
{
|
||||||
|
pathMeld.markPaths(val, varnodeIndex);
|
||||||
|
for(int4 i=0;i<selectguards.size();++i) {
|
||||||
|
PcodeOp *op = selectguards[i].getBranch();
|
||||||
|
if (op == (PcodeOp *)0) continue;
|
||||||
|
PcodeOp *readOp = selectguards[i].getReadOp();
|
||||||
|
if (val)
|
||||||
|
readOp->setMark();
|
||||||
|
else
|
||||||
|
readOp->clearMark();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The PcodeOps in \b this model must have been previously marked with markModel().
|
||||||
|
/// Run through the descendants of the given Varnode and look for this mark.
|
||||||
|
/// \param vn is the given Varnode
|
||||||
|
/// \param trailOp is an optional known PcodeOp that leads to the model
|
||||||
|
/// \return \b true if the only flow is into \b this model
|
||||||
|
bool JumpBasic::flowsOnlyToModel(Varnode *vn,PcodeOp *trailOp)
|
||||||
|
|
||||||
|
{
|
||||||
|
list<PcodeOp *>::const_iterator iter;
|
||||||
|
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
|
||||||
|
PcodeOp *op = *iter;
|
||||||
|
if (op == trailOp) continue;
|
||||||
|
if (!op->isMark())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool JumpBasic::foldInOneGuard(Funcdata *fd,GuardRecord &guard,JumpTable *jump)
|
bool JumpBasic::foldInOneGuard(Funcdata *fd,GuardRecord &guard,JumpTable *jump)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -1275,19 +1329,18 @@ void JumpBasic::findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 i,j;
|
int4 i,j;
|
||||||
Varnode *testvn;
|
|
||||||
PcodeOp *normop;
|
|
||||||
|
|
||||||
i = varnodeIndex;
|
i = varnodeIndex;
|
||||||
normalvn = pathMeld.getVarnode(i++);
|
normalvn = pathMeld.getVarnode(i++);
|
||||||
switchvn = normalvn;
|
switchvn = normalvn;
|
||||||
|
markModel(true);
|
||||||
|
|
||||||
int4 countaddsub=0;
|
int4 countaddsub=0;
|
||||||
int4 countext=0;
|
int4 countext=0;
|
||||||
|
PcodeOp *normop = (PcodeOp *)0;
|
||||||
while(i<pathMeld.numCommonVarnode()) {
|
while(i<pathMeld.numCommonVarnode()) {
|
||||||
// Between switchvn and normalvn, should be singleuse
|
if (!flowsOnlyToModel(switchvn, normop)) break; // Switch variable should only flow into model
|
||||||
if ((switchvn != normalvn)&&(switchvn->loneDescend() == (PcodeOp *)0)) break;
|
Varnode *testvn = pathMeld.getVarnode(i);
|
||||||
testvn = pathMeld.getVarnode(i);
|
|
||||||
if (!switchvn->isWritten()) break;
|
if (!switchvn->isWritten()) break;
|
||||||
normop = switchvn->getDef();
|
normop = switchvn->getDef();
|
||||||
for(j=0;j<normop->numInput();++j)
|
for(j=0;j<normop->numInput();++j)
|
||||||
|
@ -1313,6 +1366,7 @@ void JumpBasic::findUnnormalized(uint4 maxaddsub,uint4 maxleftright,uint4 maxext
|
||||||
if (switchvn != testvn) break;
|
if (switchvn != testvn) break;
|
||||||
i += 1;
|
i += 1;
|
||||||
}
|
}
|
||||||
|
markModel(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JumpBasic::buildLabels(Funcdata *fd,vector<Address> &addresstable,vector<uintb> &label,const JumpModel *orig) const
|
void JumpBasic::buildLabels(Funcdata *fd,vector<Address> &addresstable,vector<uintb> &label,const JumpModel *orig) const
|
||||||
|
|
|
@ -82,6 +82,7 @@ public:
|
||||||
void append(const PathMeld &op2); ///< Append a new set of paths to \b this set of paths
|
void append(const PathMeld &op2); ///< Append a new set of paths to \b this set of paths
|
||||||
void clear(void); ///< Clear \b this to be an empty container
|
void clear(void); ///< Clear \b this to be an empty container
|
||||||
void meld(vector<PcodeOp *> &path,vector<int4> &slot); ///< Meld a new path into \b this container
|
void meld(vector<PcodeOp *> &path,vector<int4> &slot); ///< Meld a new path into \b this container
|
||||||
|
void markPaths(bool val,int4 startVarnode); ///< Mark PcodeOps paths from the given start
|
||||||
int4 numCommonVarnode(void) const { return commonVn.size(); } ///< Return the number of Varnodes common to all paths
|
int4 numCommonVarnode(void) const { return commonVn.size(); } ///< Return the number of Varnodes common to all paths
|
||||||
int4 numOps(void) const { return opMeld.size(); } ///< Return the number of PcodeOps across all paths
|
int4 numOps(void) const { return opMeld.size(); } ///< Return the number of PcodeOps across all paths
|
||||||
Varnode *getVarnode(int4 i) const { return commonVn[i]; } ///< Get the i-th common Varnode
|
Varnode *getVarnode(int4 i) const { return commonVn[i]; } ///< Get the i-th common Varnode
|
||||||
|
@ -128,20 +129,22 @@ class JumpTable;
|
||||||
/// description of the possible values the Varnode can hold.
|
/// description of the possible values the Varnode can hold.
|
||||||
class GuardRecord {
|
class GuardRecord {
|
||||||
PcodeOp *cbranch; ///< PcodeOp CBRANCH the branches around the switch
|
PcodeOp *cbranch; ///< PcodeOp CBRANCH the branches around the switch
|
||||||
|
PcodeOp *readOp; ///< The immediate PcodeOp causing the restriction
|
||||||
int4 indpath; ///< Specific CBRANCH path going to the switch
|
int4 indpath; ///< Specific CBRANCH path going to the switch
|
||||||
CircleRange range; ///< Range of values causing the CBRANCH to take the path to the switch
|
CircleRange range; ///< Range of values causing the CBRANCH to take the path to the switch
|
||||||
Varnode *vn; ///< The Varnode being restricted
|
Varnode *vn; ///< The Varnode being restricted
|
||||||
Varnode *baseVn; ///< Value being (quasi)copied to the Varnode
|
Varnode *baseVn; ///< Value being (quasi)copied to the Varnode
|
||||||
int4 bitsPreserved; ///< Number of bits copied (all other bits are zero)
|
int4 bitsPreserved; ///< Number of bits copied (all other bits are zero)
|
||||||
public:
|
public:
|
||||||
GuardRecord(PcodeOp *op,int4 path,const CircleRange &rng,Varnode *v); ///< Constructor
|
GuardRecord(PcodeOp *bOp,PcodeOp *rOp,int4 path,const CircleRange &rng,Varnode *v); ///< Constructor
|
||||||
PcodeOp *getBranch(void) const { return cbranch; } ///< Get the CBRANCH associated with \b this guard
|
PcodeOp *getBranch(void) const { return cbranch; } ///< Get the CBRANCH associated with \b this guard
|
||||||
|
PcodeOp *getReadOp(void) const { return readOp; } ///< Get the PcodeOp immediately causing the restriction
|
||||||
int4 getPath(void) const { return indpath; } ///< Get the specific path index going towards the switch
|
int4 getPath(void) const { return indpath; } ///< Get the specific path index going towards the switch
|
||||||
const CircleRange &getRange(void) const { return range; } ///< Get the range of values causing the switch path to be taken
|
const CircleRange &getRange(void) const { return range; } ///< Get the range of values causing the switch path to be taken
|
||||||
void clear(void) { cbranch = (PcodeOp *)0; } ///< Mark \b this guard as unused
|
void clear(void) { cbranch = (PcodeOp *)0; } ///< Mark \b this guard as unused
|
||||||
int4 valueMatch(Varnode *vn2,Varnode *baseVn2,int4 bitsPreserved2) const;
|
int4 valueMatch(Varnode *vn2,Varnode *baseVn2,int4 bitsPreserved2) const;
|
||||||
static int4 oneOffMatch(PcodeOp *op1,PcodeOp *op2);
|
static int4 oneOffMatch(PcodeOp *op1,PcodeOp *op2);
|
||||||
static Varnode *quasiCopy(Varnode *vn,int4 &bitsPreserved,bool noWholeValue);
|
static Varnode *quasiCopy(Varnode *vn,int4 &bitsPreserved);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief An iterator over values a switch variable can take
|
/// \brief An iterator over values a switch variable can take
|
||||||
|
@ -356,6 +359,8 @@ protected:
|
||||||
void findSmallestNormal(uint4 matchsize);
|
void findSmallestNormal(uint4 matchsize);
|
||||||
void findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint4 matchsize,uint4 maxtablesize);
|
void findNormalized(Funcdata *fd,BlockBasic *rootbl,int4 pathout,uint4 matchsize,uint4 maxtablesize);
|
||||||
void markFoldableGuards();
|
void markFoldableGuards();
|
||||||
|
void markModel(bool val); ///< Mark (or unmark) all PcodeOps involved in the model
|
||||||
|
bool flowsOnlyToModel(Varnode *vn,PcodeOp *trailOp); ///< Check if the given Varnode flows to anything other than \b this model
|
||||||
|
|
||||||
/// \brief Eliminate the given guard to \b this switch
|
/// \brief Eliminate the given guard to \b this switch
|
||||||
///
|
///
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue