LOAD protect

This commit is contained in:
caheckman 2020-05-13 14:26:00 -04:00
parent 764eec057f
commit 39cbcd33ae
5 changed files with 119 additions and 3 deletions

View file

@ -1215,6 +1215,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
{
Architecture *glb = data.getArch();
bool cachereadonly = glb->readonlypropagate;
int4 pass = data.getHeritagePass();
VarnodeLocSet::const_iterator iter;
Varnode *vn;
@ -1223,7 +1224,29 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
vn = *iter++; // Advance iterator in case vn is deleted
if (vn->isAnnotation()) continue;
int4 vnSize = vn->getSize();
if (vn->hasActionProperty()) {
if (vn->isAutoLiveHold()) {
if (pass > 0) {
if (vn->isWritten()) {
PcodeOp *loadOp = vn->getDef();
if (loadOp->code() == CPUI_LOAD) {
Varnode *ptr = loadOp->getIn(1);
if (ptr->isConstant() || ptr->isReadOnly())
continue;
if (ptr->isWritten()) {
PcodeOp *copyOp = ptr->getDef();
if (copyOp->code() == CPUI_COPY) {
ptr = copyOp->getIn(0);
if (ptr->isConstant() || ptr->isReadOnly())
continue;
}
}
}
}
vn->clearAutoLiveHold();
count += 1;
}
}
else if (vn->hasActionProperty()) {
if (cachereadonly&&vn->isReadOnly()) {
if (data.fillinReadOnly(vn)) // Try to replace vn with its lookup in LoadImage
count += 1;
@ -3383,6 +3406,84 @@ uintb ActionDeadCode::gatherConsumedReturn(Funcdata &data)
return consumeVal;
}
/// \brief Determine if the given Varnode may eventually collapse to a constant
///
/// Recursively check if the Varnode is either:
/// - Copied from a constant
/// - The result of adding constants
/// - Loaded from a pointer that is a constant
///
/// \param vn is the given Varnode
/// \param addCount is the number of CPUI_INT_ADD operations seen so far
/// \param loadCount is the number of CPUI_LOAD operations seen so far
/// \return \b true if the Varnode (might) collapse to a constant
bool ActionDeadCode::isEventualConstant(Varnode *vn,int4 addCount,int4 loadCount)
{
if (vn->isConstant()) return true;
if (!vn->isWritten()) return false;
PcodeOp *op = vn->getDef();
while(op->code() == CPUI_COPY) {
vn = op->getIn(0);
if (vn->isConstant()) return true;
if (!vn->isWritten()) return false;
op = vn->getDef();
}
switch(op->code()) {
case CPUI_INT_ADD:
if (addCount > 0) return false;
if (!isEventualConstant(op->getIn(0),addCount+1,loadCount))
return false;
return isEventualConstant(op->getIn(1),addCount+1,loadCount);
case CPUI_LOAD:
if (loadCount > 0) return false;
return isEventualConstant(op->getIn(1),0,loadCount+1);
case CPUI_INT_LEFT:
case CPUI_INT_RIGHT:
case CPUI_INT_SRIGHT:
case CPUI_INT_MULT:
if (!op->getIn(1)->isConstant())
return false;
return isEventualConstant(op->getIn(0),addCount,loadCount);
case CPUI_INT_ZEXT:
case CPUI_INT_SEXT:
return isEventualConstant(op->getIn(0),addCount,loadCount);
default:
break;
}
return false;
}
/// \brief Check if there are any unconsumed LOADs that may be from volatile addresses.
///
/// It may be too early to remove certain LOAD operations even though their result isn't
/// consumed because it be of a volatile address with side effects. If a LOAD meets this
/// criteria, it is added to the worklist and \b true is returned.
/// \param data is the function being analyzed
/// \return \b true if there was at least one LOAD added to the worklist
bool ActionDeadCode::lastChanceLoad(Funcdata &data,vector<Varnode *> &worklist)
{
if (data.getHeritagePass() > 1) return false;
if (data.isJumptableRecoveryOn()) return false;
list<PcodeOp *>::const_iterator iter = data.beginOp(CPUI_LOAD);
list<PcodeOp *>::const_iterator enditer = data.endOp(CPUI_LOAD);
bool res = false;
while(iter != enditer) {
PcodeOp *op = *iter;
++iter;
if (op->isDead()) continue;
Varnode *vn = op->getOut();
if (vn->isConsumeVacuous()) continue;
if (isEventualConstant(op->getIn(1), 0, 0)) {
pushConsumed(~(uintb)0, vn, worklist);
vn->setAutoLiveHold();
res = true;
}
}
return res;
}
int4 ActionDeadCode::apply(Funcdata &data)
{
@ -3476,6 +3577,11 @@ int4 ActionDeadCode::apply(Funcdata &data)
while(!worklist.empty())
propagateConsumed(worklist);
if (lastChanceLoad(data, worklist)) {
while(!worklist.empty())
propagateConsumed(worklist);
}
for(i=0;i<manage->numSpaces();++i) {
spc = manage->getSpace(i);
if (spc == (AddrSpace *)0 || !spc->doesDeadcode()) continue;

View file

@ -541,6 +541,8 @@ class ActionDeadCode : public Action {
static bool neverConsumed(Varnode *vn,Funcdata &data);
static void markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *> &worklist);
static uintb gatherConsumedReturn(Funcdata &data);
static bool isEventualConstant(Varnode *vn,int4 addCount,int4 loadCount);
static bool lastChanceLoad(Funcdata &data,vector<Varnode *> &worklist);
public:
ActionDeadCode(const string &g) : Action(0,"deadcode",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {

View file

@ -200,6 +200,8 @@ public:
Varnode *findSpacebaseInput(AddrSpace *id) const;
void spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const Address &rampoint,uintb origval,int4 origsize);
int4 getHeritagePass(void) const { return heritage.getPass(); } ///< Get overall count of heritage passes
/// \brief Get the number of heritage passes performed for the given address space
///
/// \param spc is the address space

View file

@ -267,6 +267,8 @@ class Heritage {
public:
Heritage(Funcdata *data); ///< Constructor
int4 getPass(void) const { return pass; } ///< Get overall count of heritage passes
/// \brief Get the pass number when the given address was heritaged
///
/// \param addr is the given address

View file

@ -102,7 +102,8 @@ public:
precishi = 0x4000000, ///< Is this Varnode the high part of a double precision value
indirectstorage = 0x8000000, ///< Is this Varnode storing a pointer to the actual symbol
hiddenretparm = 0x10000000, ///< Does this varnode point to the return value storage location
incidental_copy = 0x20000000 ///< Do copies of this varnode happen as a side-effect
incidental_copy = 0x20000000, ///< Do copies of this varnode happen as a side-effect
autolive_hold = 0x40000000 ///< Temporarily block dead-code removal of \b this
};
/// Additional boolean properties on a Varnode
enum addl_flags {
@ -228,7 +229,8 @@ public:
/// Are all Varnodes at this storage location components of the same high-level variable?
bool isAddrTied(void) const { return ((flags&(Varnode::addrtied|Varnode::insert))==(Varnode::addrtied|Varnode::insert)); }
bool isAddrForce(void) const { return ((flags&Varnode::addrforce)!=0); } ///< Is \b this value forced into a particular storage location?
bool isAutoLive(void) const { return ((flags&Varnode::addrforce)!=0); } ///< Is \b this varnode exempt from dead-code removal?
bool isAutoLive(void) const { return ((flags&(Varnode::addrforce|Varnode::autolive_hold))!=0); } ///< Is \b this varnode exempt from dead-code removal?
bool isAutoLiveHold(void) const { return ((flags&Varnode::autolive_hold)!=0); } ///< Is there a temporary hold on dead-code removal?
bool isMapped(void) const { return ((flags&Varnode::mapped)!=0); } ///< Is there or should be formal symbol information associated with \b this?
bool isUnaffected(void) const { return ((flags&Varnode::unaffected)!=0); } ///< Is \b this a value that is supposed to be preserved across the function?
bool isSpacebase(void) const { return ((flags&Varnode::spacebase)!=0); } ///< Is this location used to store the base point for a virtual address space?
@ -296,6 +298,8 @@ public:
void clearPrecisHi(void) { clearFlags(Varnode::precishi); } ///< Clear the mark indicating a double precision portion
void setWriteMask(void) { addlflags |= Varnode::writemask; } ///< Mark \b this as not a true \e write when computing SSA form
void clearWriteMask(void) { addlflags &= ~Varnode::writemask; } ///< Clear the mark indicating \b this is not a true write
void setAutoLiveHold(void) { flags |= Varnode::autolive_hold; } ///< Place temporary hold on dead code removal
void clearAutoLiveHold(void) { flags &= ~Varnode::autolive_hold; } ///< Clear temporary hold on dead code removal
void setUnsignedPrint(void) { addlflags |= Varnode::unsignedprint; } ///< Force \b this to be printed as unsigned
bool updateType(Datatype *ct,bool lock,bool override); ///< (Possibly) set the Datatype given various restrictions
void setStackStore(void) { addlflags |= Varnode::stack_store; } ///< Mark as produced by explicit CPUI_STORE