solving stack STOREs

This commit is contained in:
caheckman 2019-06-18 16:26:30 -04:00
parent 2a73bca9ac
commit ec9bfa86a7
5 changed files with 112 additions and 44 deletions

View file

@ -232,7 +232,8 @@ public:
/// \return \b true if the Varnode is fully linked
bool isHeritaged(Varnode *vn) { return (heritage.heritagePass(vn->getAddr())>=0); }
const list<LoadGuard> &getLoadGuards(void) const { return heritage.getLoadGuards(); }
const list<LoadGuard> &getLoadGuards(void) const { return heritage.getLoadGuards(); } ///< Get the list of guarded LOADs
const list<LoadGuard> &getStoreGuards(void) const { return heritage.getStoreGuards(); } ///< Get the list of guarded STOREs
// Function prototype and call specification routines
int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function

View file

@ -656,18 +656,35 @@ void LoadGuard::finalizeRange(const ValueSetRead &valueSet)
void Heritage::analyzeNewLoadGuards(void)
{
if (loadGuard.empty()) return;
if (loadGuard.back().analysisState != 0) return; // Nothing new
list<LoadGuard>::iterator startIter = loadGuard.end();
bool nothingToDo = true;
if (!loadGuard.empty()) {
if (loadGuard.back().analysisState == 0) // Check if unanalyzed
nothingToDo = false;
}
if (!storeGuard.empty()) {
if (storeGuard.back().analysisState == 0)
nothingToDo = false;
}
if (nothingToDo) return;
vector<Varnode *> sinks;
vector<PcodeOp *> reads;
while(startIter != loadGuard.begin()) {
--startIter;
LoadGuard &guard( *startIter );
list<LoadGuard>::iterator loadIter = loadGuard.end();
while(loadIter != loadGuard.begin()) {
--loadIter;
LoadGuard &guard( *loadIter );
if (guard.analysisState != 0) break;
reads.push_back(guard.op);
sinks.push_back(guard.op->getIn(1)); // The CPUI_LOAD pointer
}
list<LoadGuard>::iterator storeIter = storeGuard.end();
while(storeIter != storeGuard.begin()) {
--storeIter;
LoadGuard &guard( *storeIter );
if (guard.analysisState != 0) break;
reads.push_back(guard.op);
sinks.push_back(guard.op->getIn(1)); // The CPUI_STORE pointer
}
AddrSpace *stackSpc = fd->getArch()->getStackSpace();
Varnode *stackReg = (Varnode *)0;
if (stackSpc != (AddrSpace *)0 && stackSpc->numSpacebase() > 0)
@ -678,7 +695,13 @@ void Heritage::analyzeNewLoadGuards(void)
vsSolver.solve(10000,widener);
list<LoadGuard>::iterator iter;
bool runFullAnalysis = false;
for(iter=startIter;iter!=loadGuard.end(); ++iter) {
for(iter=loadIter;iter!=loadGuard.end(); ++iter) {
LoadGuard &guard( *iter );
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
if (guard.analysisState == 0)
runFullAnalysis = true;
}
for(iter=storeIter;iter!=storeGuard.end(); ++iter) {
LoadGuard &guard( *iter );
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
if (guard.analysisState == 0)
@ -687,7 +710,11 @@ void Heritage::analyzeNewLoadGuards(void)
if (runFullAnalysis) {
WidenerFull fullWidener;
vsSolver.solve(10000, fullWidener);
for (iter = startIter; iter != loadGuard.end(); ++iter) {
for (iter = loadIter; iter != loadGuard.end(); ++iter) {
LoadGuard &guard(*iter);
guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
}
for (iter = storeIter; iter != storeGuard.end(); ++iter) {
LoadGuard &guard(*iter);
guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
}
@ -708,6 +735,20 @@ void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
loadGuard.back().set(op,spc,node.offset);
}
/// \brief Generate a guard record given an indexed STORE to a stack space
///
/// Record the STORE op and the (likely) range of addresses in the stack space that
/// might be stored to.
/// \param node is the path element containing the constructed Address
/// \param op is the STORE PcodeOp
/// \param spc is the stack space
void Heritage::generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
{
storeGuard.push_back(LoadGuard());
storeGuard.back().set(op,spc,node.offset);
}
/// \brief Trace input stackpointer to any indexed loads
///
/// Look for expressions of the form val = *(SP(i) + vn + #c), where the base stack
@ -715,7 +756,7 @@ void Heritage::generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc)
/// value is loaded from the resulting address. The LOAD operations are added to the list
/// of ops that potentially need to be guarded during a heritage pass.
/// \param spc is the particular address space with a stackpointer (into it)
void Heritage::discoverIndexedStackLoads(AddrSpace *spc)
void Heritage::discoverIndexedStackPointers(AddrSpace *spc)
{
// We need to be careful of exponential ladders, so we mark Varnodes independently of
@ -791,6 +832,13 @@ void Heritage::discoverIndexedStackLoads(AddrSpace *spc)
}
break;
}
case CPUI_STORE:
{
if (curNode.traversals != 0) {
generateStoreGuard(curNode, op, spc);
}
break;
}
default:
break;
}
@ -2039,7 +2087,7 @@ void Heritage::heritage(void)
if (pass < info->delay) continue; // It is too soon to heritage this space
if (!info->loadGuardSearch) {
info->loadGuardSearch = true;
discoverIndexedStackLoads(info->space);
discoverIndexedStackPointers(info->space);
}
needwarning = false;
iter = fd->beginLoc(space);
@ -2205,6 +2253,7 @@ void Heritage::clear(void)
merge.clear();
clearInfoList();
loadGuard.clear();
storeGuard.clear();
maxdepth = -1;
pass = 0;
}

View file

@ -204,6 +204,7 @@ class Heritage {
vector<FlowBlock *> merge; ///< Calculate merge points (blocks containing phi-nodes)
vector<HeritageInfo> infolist; ///< Heritage status for individual address spaces
list<LoadGuard> loadGuard; ///< List of LOAD operations that need to be guarded
list<LoadGuard> storeGuard; ///< List of STORE operations taking an indexed pointer to the stack
vector<PcodeOp *> loadCopyOps; ///< List of COPY ops generated by load guards
void clearInfoList(void); ///< Reset heritage status for all address spaces
@ -231,7 +232,8 @@ class Heritage {
void handleNewLoadCopies(void);
void analyzeNewLoadGuards(void);
void generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc);
void discoverIndexedStackLoads(AddrSpace *spc);
void generateStoreGuard(StackNode &node,PcodeOp *op,AddrSpace *spc);
void discoverIndexedStackPointers(AddrSpace *spc);
void guard(const Address &addr,int4 size,vector<Varnode *> &read,vector<Varnode *> &write,vector<Varnode *> &inputvars);
void guardInput(const Address &addr,int4 size,vector<Varnode *> &input);
void guardCalls(uint4 flags,const Address &addr,int4 size,vector<Varnode *> &write);
@ -270,6 +272,7 @@ public:
void clear(void); ///< Reset all analysis of heritage
void heritage(void); ///< Perform one pass of heritage
const list<LoadGuard> &getLoadGuards(void) const { return loadGuard; } ///< Get list of LOAD ops that are guarded
const list<LoadGuard> &getStoreGuards(void) const { return storeGuard; } ///< Get list of STORE ops that are guarded
};
#endif

View file

@ -796,6 +796,44 @@ void MapState::addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,i
#endif
}
/// The given LoadGuard, which may be a LOAD or STORE is converted into an appropriate
/// RangeHint, attempting to make use of any data-type or index information.
/// \param guard is the given LoadGuard
/// \param typeFactory is used to manufacture a data-type for the hint if necessary
void MapState::addGuard(const LoadGuard &guard,TypeFactory *typeFactory)
{
if (!guard.isValid()) return;
int4 step = guard.getStep();
if (step == 0) return; // No definitive sign of array access
Datatype *ct = guard.getOp()->getIn(1)->getType();
if (ct->getMetatype() == TYPE_PTR) {
ct = ((TypePointer *) ct)->getPtrTo();
while (ct->getMetatype() == TYPE_ARRAY)
ct = ((TypeArray *) ct)->getBase();
}
int4 outSize = guard.getOp()->getOut()->getSize();
if (outSize != step) {
// LOAD size doesn't match step: field in array of structures or something more unusual
if (outSize > step || (step % outSize) != 0)
return;
// Since the LOAD size divides the step and we want to preserve the arrayness
// we pretend we have an array of LOAD's size
step = outSize;
}
if (ct->getSize() != step) { // Make sure data-type matches our step size
if (step > 8)
return; // Don't manufacture primitives bigger than 8-bytes
ct = typeFactory->getBase(step, TYPE_UNKNOWN);
}
if (guard.isRangeLocked()) {
int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step;
addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1);
}
else
addRange(guard.getMinimum(),ct,0,RangeHint::open,3);
}
/// Run through all Symbols in the given map and create a corresponding RangeHint
/// to \b this collection for each Symbol.
/// \param rangemap is the given map of Symbols
@ -922,39 +960,14 @@ void MapState::gatherOpen(const Funcdata &fd)
addRange(offset,ct,0,RangeHint::open,minItems);
}
TypeFactory *typeFactory = fd.getArch()->types;
const list<LoadGuard> &loadGuard( fd.getLoadGuards() );
for(list<LoadGuard>::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter) {
const LoadGuard &guard( *iter );
if (!guard.isValid()) continue;
int4 step = guard.getStep();
if (step == 0) continue; // No definitive sign of array access
Datatype *ct = guard.getOp()->getIn(1)->getType();
if (ct->getMetatype() == TYPE_PTR) {
ct = ((TypePointer *) ct)->getPtrTo();
while (ct->getMetatype() == TYPE_ARRAY)
ct = ((TypeArray *) ct)->getBase();
}
int4 outSize = guard.getOp()->getOut()->getSize();
if (outSize != step) {
// LOAD size doesn't match step: field in array of structures or something more unusual
if (outSize > step || (step % outSize) != 0)
continue;
// Since the LOAD size divides the step and we want to preserve the arrayness
// we pretend we have an array of LOAD's size
step = outSize;
}
if (ct->getSize() != step) { // Make sure data-type matches our step size
if (step > 8)
continue; // Don't manufacture primitives bigger than 8-bytes
ct = fd.getArch()->types->getBase(step, TYPE_UNKNOWN);
}
if (guard.isRangeLocked()) {
int4 minItems = ((guard.getMaximum() - guard.getMinimum()) + 1) / step;
addRange(guard.getMinimum(),ct,0,RangeHint::open,minItems-1);
}
else
addRange(guard.getMinimum(),ct,0,RangeHint::open,3);
}
for(list<LoadGuard>::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter)
addGuard(*iter,typeFactory);
const list<LoadGuard> &storeGuard( fd.getStoreGuards() );
for(list<LoadGuard>::const_iterator iter=storeGuard.begin();iter!=storeGuard.end();++iter)
addGuard(*iter,typeFactory);
}
/// Define stack Symbols based on Varnodes.

View file

@ -76,6 +76,7 @@ public:
};
class ProtoModel;
class LoadGuard;
/// \brief A light-weight class for analyzing pointers and aliasing on the stack
///
@ -126,6 +127,7 @@ class MapState {
vector<RangeHint *>::iterator iter; ///< The current iterator into the RangeHints
Datatype *defaultType; ///< The default data-type to use for RangeHints
AliasChecker checker; ///< A collection of pointer Varnodes into our address space
void addGuard(const LoadGuard &guard,TypeFactory *typeFactory); ///< Add LoadGuard record as a hint to the collection
void addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,int4 hi); ///< Add a hint to the collection
public:
#ifdef OPACTION_DEBUG