mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
LOAD protect
This commit is contained in:
parent
764eec057f
commit
39cbcd33ae
5 changed files with 119 additions and 3 deletions
|
@ -1215,6 +1215,7 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
|
||||||
{
|
{
|
||||||
Architecture *glb = data.getArch();
|
Architecture *glb = data.getArch();
|
||||||
bool cachereadonly = glb->readonlypropagate;
|
bool cachereadonly = glb->readonlypropagate;
|
||||||
|
int4 pass = data.getHeritagePass();
|
||||||
VarnodeLocSet::const_iterator iter;
|
VarnodeLocSet::const_iterator iter;
|
||||||
Varnode *vn;
|
Varnode *vn;
|
||||||
|
|
||||||
|
@ -1223,7 +1224,29 @@ int4 ActionVarnodeProps::apply(Funcdata &data)
|
||||||
vn = *iter++; // Advance iterator in case vn is deleted
|
vn = *iter++; // Advance iterator in case vn is deleted
|
||||||
if (vn->isAnnotation()) continue;
|
if (vn->isAnnotation()) continue;
|
||||||
int4 vnSize = vn->getSize();
|
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 (cachereadonly&&vn->isReadOnly()) {
|
||||||
if (data.fillinReadOnly(vn)) // Try to replace vn with its lookup in LoadImage
|
if (data.fillinReadOnly(vn)) // Try to replace vn with its lookup in LoadImage
|
||||||
count += 1;
|
count += 1;
|
||||||
|
@ -3383,6 +3406,84 @@ uintb ActionDeadCode::gatherConsumedReturn(Funcdata &data)
|
||||||
return consumeVal;
|
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)
|
int4 ActionDeadCode::apply(Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
@ -3476,6 +3577,11 @@ int4 ActionDeadCode::apply(Funcdata &data)
|
||||||
while(!worklist.empty())
|
while(!worklist.empty())
|
||||||
propagateConsumed(worklist);
|
propagateConsumed(worklist);
|
||||||
|
|
||||||
|
if (lastChanceLoad(data, worklist)) {
|
||||||
|
while(!worklist.empty())
|
||||||
|
propagateConsumed(worklist);
|
||||||
|
}
|
||||||
|
|
||||||
for(i=0;i<manage->numSpaces();++i) {
|
for(i=0;i<manage->numSpaces();++i) {
|
||||||
spc = manage->getSpace(i);
|
spc = manage->getSpace(i);
|
||||||
if (spc == (AddrSpace *)0 || !spc->doesDeadcode()) continue;
|
if (spc == (AddrSpace *)0 || !spc->doesDeadcode()) continue;
|
||||||
|
|
|
@ -541,6 +541,8 @@ class ActionDeadCode : public Action {
|
||||||
static bool neverConsumed(Varnode *vn,Funcdata &data);
|
static bool neverConsumed(Varnode *vn,Funcdata &data);
|
||||||
static void markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *> &worklist);
|
static void markConsumedParameters(FuncCallSpecs *fc,vector<Varnode *> &worklist);
|
||||||
static uintb gatherConsumedReturn(Funcdata &data);
|
static uintb gatherConsumedReturn(Funcdata &data);
|
||||||
|
static bool isEventualConstant(Varnode *vn,int4 addCount,int4 loadCount);
|
||||||
|
static bool lastChanceLoad(Funcdata &data,vector<Varnode *> &worklist);
|
||||||
public:
|
public:
|
||||||
ActionDeadCode(const string &g) : Action(0,"deadcode",g) {} ///< Constructor
|
ActionDeadCode(const string &g) : Action(0,"deadcode",g) {} ///< Constructor
|
||||||
virtual Action *clone(const ActionGroupList &grouplist) const {
|
virtual Action *clone(const ActionGroupList &grouplist) const {
|
||||||
|
|
|
@ -200,6 +200,8 @@ public:
|
||||||
Varnode *findSpacebaseInput(AddrSpace *id) const;
|
Varnode *findSpacebaseInput(AddrSpace *id) const;
|
||||||
void spacebaseConstant(PcodeOp *op,int4 slot,SymbolEntry *entry,const Address &rampoint,uintb origval,int4 origsize);
|
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
|
/// \brief Get the number of heritage passes performed for the given address space
|
||||||
///
|
///
|
||||||
/// \param spc is the address space
|
/// \param spc is the address space
|
||||||
|
|
|
@ -267,6 +267,8 @@ class Heritage {
|
||||||
public:
|
public:
|
||||||
Heritage(Funcdata *data); ///< Constructor
|
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
|
/// \brief Get the pass number when the given address was heritaged
|
||||||
///
|
///
|
||||||
/// \param addr is the given address
|
/// \param addr is the given address
|
||||||
|
|
|
@ -102,7 +102,8 @@ public:
|
||||||
precishi = 0x4000000, ///< Is this Varnode the high part of a double precision value
|
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
|
indirectstorage = 0x8000000, ///< Is this Varnode storing a pointer to the actual symbol
|
||||||
hiddenretparm = 0x10000000, ///< Does this varnode point to the return value storage location
|
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
|
/// Additional boolean properties on a Varnode
|
||||||
enum addl_flags {
|
enum addl_flags {
|
||||||
|
@ -228,7 +229,8 @@ public:
|
||||||
/// Are all Varnodes at this storage location components of the same high-level variable?
|
/// 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 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 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 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 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?
|
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 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 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 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
|
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
|
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
|
void setStackStore(void) { addlflags |= Varnode::stack_store; } ///< Mark as produced by explicit CPUI_STORE
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue