mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 17:59:46 +02:00
solving stack STOREs
This commit is contained in:
parent
2a73bca9ac
commit
ec9bfa86a7
5 changed files with 112 additions and 44 deletions
|
@ -232,7 +232,8 @@ public:
|
||||||
/// \return \b true if the Varnode is fully linked
|
/// \return \b true if the Varnode is fully linked
|
||||||
bool isHeritaged(Varnode *vn) { return (heritage.heritagePass(vn->getAddr())>=0); }
|
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
|
// Function prototype and call specification routines
|
||||||
int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function
|
int4 numCalls(void) const { return qlst.size(); } ///< Get the number of calls made by \b this function
|
||||||
|
|
|
@ -656,18 +656,35 @@ void LoadGuard::finalizeRange(const ValueSetRead &valueSet)
|
||||||
void Heritage::analyzeNewLoadGuards(void)
|
void Heritage::analyzeNewLoadGuards(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
if (loadGuard.empty()) return;
|
bool nothingToDo = true;
|
||||||
if (loadGuard.back().analysisState != 0) return; // Nothing new
|
if (!loadGuard.empty()) {
|
||||||
list<LoadGuard>::iterator startIter = loadGuard.end();
|
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<Varnode *> sinks;
|
||||||
vector<PcodeOp *> reads;
|
vector<PcodeOp *> reads;
|
||||||
while(startIter != loadGuard.begin()) {
|
list<LoadGuard>::iterator loadIter = loadGuard.end();
|
||||||
--startIter;
|
while(loadIter != loadGuard.begin()) {
|
||||||
LoadGuard &guard( *startIter );
|
--loadIter;
|
||||||
|
LoadGuard &guard( *loadIter );
|
||||||
if (guard.analysisState != 0) break;
|
if (guard.analysisState != 0) break;
|
||||||
reads.push_back(guard.op);
|
reads.push_back(guard.op);
|
||||||
sinks.push_back(guard.op->getIn(1)); // The CPUI_LOAD pointer
|
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();
|
AddrSpace *stackSpc = fd->getArch()->getStackSpace();
|
||||||
Varnode *stackReg = (Varnode *)0;
|
Varnode *stackReg = (Varnode *)0;
|
||||||
if (stackSpc != (AddrSpace *)0 && stackSpc->numSpacebase() > 0)
|
if (stackSpc != (AddrSpace *)0 && stackSpc->numSpacebase() > 0)
|
||||||
|
@ -678,7 +695,13 @@ void Heritage::analyzeNewLoadGuards(void)
|
||||||
vsSolver.solve(10000,widener);
|
vsSolver.solve(10000,widener);
|
||||||
list<LoadGuard>::iterator iter;
|
list<LoadGuard>::iterator iter;
|
||||||
bool runFullAnalysis = false;
|
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 );
|
LoadGuard &guard( *iter );
|
||||||
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
|
guard.establishRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
|
||||||
if (guard.analysisState == 0)
|
if (guard.analysisState == 0)
|
||||||
|
@ -687,7 +710,11 @@ void Heritage::analyzeNewLoadGuards(void)
|
||||||
if (runFullAnalysis) {
|
if (runFullAnalysis) {
|
||||||
WidenerFull fullWidener;
|
WidenerFull fullWidener;
|
||||||
vsSolver.solve(10000, 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);
|
LoadGuard &guard(*iter);
|
||||||
guard.finalizeRange(vsSolver.getValueSetRead(guard.op->getSeqNum()));
|
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);
|
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
|
/// \brief Trace input stackpointer to any indexed loads
|
||||||
///
|
///
|
||||||
/// Look for expressions of the form val = *(SP(i) + vn + #c), where the base stack
|
/// 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
|
/// 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.
|
/// of ops that potentially need to be guarded during a heritage pass.
|
||||||
/// \param spc is the particular address space with a stackpointer (into it)
|
/// \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
|
// We need to be careful of exponential ladders, so we mark Varnodes independently of
|
||||||
|
@ -791,6 +832,13 @@ void Heritage::discoverIndexedStackLoads(AddrSpace *spc)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case CPUI_STORE:
|
||||||
|
{
|
||||||
|
if (curNode.traversals != 0) {
|
||||||
|
generateStoreGuard(curNode, op, spc);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -2039,7 +2087,7 @@ void Heritage::heritage(void)
|
||||||
if (pass < info->delay) continue; // It is too soon to heritage this space
|
if (pass < info->delay) continue; // It is too soon to heritage this space
|
||||||
if (!info->loadGuardSearch) {
|
if (!info->loadGuardSearch) {
|
||||||
info->loadGuardSearch = true;
|
info->loadGuardSearch = true;
|
||||||
discoverIndexedStackLoads(info->space);
|
discoverIndexedStackPointers(info->space);
|
||||||
}
|
}
|
||||||
needwarning = false;
|
needwarning = false;
|
||||||
iter = fd->beginLoc(space);
|
iter = fd->beginLoc(space);
|
||||||
|
@ -2205,6 +2253,7 @@ void Heritage::clear(void)
|
||||||
merge.clear();
|
merge.clear();
|
||||||
clearInfoList();
|
clearInfoList();
|
||||||
loadGuard.clear();
|
loadGuard.clear();
|
||||||
|
storeGuard.clear();
|
||||||
maxdepth = -1;
|
maxdepth = -1;
|
||||||
pass = 0;
|
pass = 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -204,6 +204,7 @@ class Heritage {
|
||||||
vector<FlowBlock *> merge; ///< Calculate merge points (blocks containing phi-nodes)
|
vector<FlowBlock *> merge; ///< Calculate merge points (blocks containing phi-nodes)
|
||||||
vector<HeritageInfo> infolist; ///< Heritage status for individual address spaces
|
vector<HeritageInfo> infolist; ///< Heritage status for individual address spaces
|
||||||
list<LoadGuard> loadGuard; ///< List of LOAD operations that need to be guarded
|
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
|
vector<PcodeOp *> loadCopyOps; ///< List of COPY ops generated by load guards
|
||||||
void clearInfoList(void); ///< Reset heritage status for all address spaces
|
void clearInfoList(void); ///< Reset heritage status for all address spaces
|
||||||
|
|
||||||
|
@ -231,7 +232,8 @@ class Heritage {
|
||||||
void handleNewLoadCopies(void);
|
void handleNewLoadCopies(void);
|
||||||
void analyzeNewLoadGuards(void);
|
void analyzeNewLoadGuards(void);
|
||||||
void generateLoadGuard(StackNode &node,PcodeOp *op,AddrSpace *spc);
|
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 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 guardInput(const Address &addr,int4 size,vector<Varnode *> &input);
|
||||||
void guardCalls(uint4 flags,const Address &addr,int4 size,vector<Varnode *> &write);
|
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 clear(void); ///< Reset all analysis of heritage
|
||||||
void heritage(void); ///< Perform one pass 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> &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
|
#endif
|
||||||
|
|
|
@ -796,6 +796,44 @@ void MapState::addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,i
|
||||||
#endif
|
#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
|
/// Run through all Symbols in the given map and create a corresponding RangeHint
|
||||||
/// to \b this collection for each Symbol.
|
/// to \b this collection for each Symbol.
|
||||||
/// \param rangemap is the given map of Symbols
|
/// \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);
|
addRange(offset,ct,0,RangeHint::open,minItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypeFactory *typeFactory = fd.getArch()->types;
|
||||||
const list<LoadGuard> &loadGuard( fd.getLoadGuards() );
|
const list<LoadGuard> &loadGuard( fd.getLoadGuards() );
|
||||||
for(list<LoadGuard>::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter) {
|
for(list<LoadGuard>::const_iterator iter=loadGuard.begin();iter!=loadGuard.end();++iter)
|
||||||
const LoadGuard &guard( *iter );
|
addGuard(*iter,typeFactory);
|
||||||
if (!guard.isValid()) continue;
|
|
||||||
int4 step = guard.getStep();
|
const list<LoadGuard> &storeGuard( fd.getStoreGuards() );
|
||||||
if (step == 0) continue; // No definitive sign of array access
|
for(list<LoadGuard>::const_iterator iter=storeGuard.begin();iter!=storeGuard.end();++iter)
|
||||||
Datatype *ct = guard.getOp()->getIn(1)->getType();
|
addGuard(*iter,typeFactory);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Define stack Symbols based on Varnodes.
|
/// Define stack Symbols based on Varnodes.
|
||||||
|
|
|
@ -76,6 +76,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
class ProtoModel;
|
class ProtoModel;
|
||||||
|
class LoadGuard;
|
||||||
|
|
||||||
/// \brief A light-weight class for analyzing pointers and aliasing on the stack
|
/// \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
|
vector<RangeHint *>::iterator iter; ///< The current iterator into the RangeHints
|
||||||
Datatype *defaultType; ///< The default data-type to use for RangeHints
|
Datatype *defaultType; ///< The default data-type to use for RangeHints
|
||||||
AliasChecker checker; ///< A collection of pointer Varnodes into our address space
|
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
|
void addRange(uintb st,Datatype *ct,uint4 fl,RangeHint::RangeType rt,int4 hi); ///< Add a hint to the collection
|
||||||
public:
|
public:
|
||||||
#ifdef OPACTION_DEBUG
|
#ifdef OPACTION_DEBUG
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue