mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +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();
|
||||
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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue