mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
GP-2627 TypePartialStruct
This commit is contained in:
parent
cc35d57933
commit
2591c17f22
15 changed files with 636 additions and 433 deletions
|
@ -44,6 +44,7 @@ src/decompile/datatests/offsetarray.xml||GHIDRA||||END|
|
|||
src/decompile/datatests/packstructaccess.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/partialmerge.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/partialunion.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/piecestruct.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointercmp.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
|
||||
src/decompile/datatests/pointersub.xml||GHIDRA||||END|
|
||||
|
|
|
@ -4732,16 +4732,19 @@ void ActionInferTypes::buildLocaltypes(Funcdata &data)
|
|||
Datatype *ct;
|
||||
Varnode *vn;
|
||||
VarnodeLocSet::const_iterator iter;
|
||||
TypeFactory *typegrp = data.getArch()->types;
|
||||
|
||||
for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
|
||||
vn = *iter;
|
||||
if (vn->isAnnotation()) continue;
|
||||
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
|
||||
bool needsBlock = false;
|
||||
if (vn->getSymbolEntry() != (SymbolEntry *)0) {
|
||||
ct = data.checkSymbolType(vn);
|
||||
if (ct == (Datatype *)0)
|
||||
ct = vn->getLocalType(needsBlock);
|
||||
SymbolEntry *entry = vn->getSymbolEntry();
|
||||
if (entry != (SymbolEntry *)0 && !vn->isTypeLock() && entry->getSymbol()->isTypeLocked()) {
|
||||
int4 curOff = (vn->getAddr().getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
||||
ct = typegrp->getExactPiece(entry->getSymbol()->getType(), curOff, vn->getSize());
|
||||
if (ct == (Datatype *)0 || ct->getMetatype() == TYPE_UNKNOWN) // If we can't resolve, or resolve to UNKNOWN
|
||||
ct = vn->getLocalType(needsBlock); // Let data-type float, even though parent symbol is type-locked
|
||||
}
|
||||
else
|
||||
ct = vn->getLocalType(needsBlock);
|
||||
|
@ -4956,13 +4959,9 @@ void ActionInferTypes::propagateRef(Funcdata &data,Varnode *vn,const Address &ad
|
|||
if ((cursize!=lastsize)||(curoff!=lastoff)) {
|
||||
lastoff = curoff;
|
||||
lastsize = cursize;
|
||||
Datatype *cur = ct;
|
||||
do {
|
||||
lastct = cur;
|
||||
cur = cur->getSubType(curoff,&curoff);
|
||||
} while(cur != (Datatype *)0);
|
||||
lastct = typegrp->getExactPiece(ct, curoff, cursize);
|
||||
}
|
||||
if (lastct->getSize() != cursize) continue;
|
||||
if (lastct == (Datatype *)0) continue;
|
||||
|
||||
// Try to propagate the reference type into a varnode that is pointed to by that reference
|
||||
if (0>lastct->typeOrder(*curvn->getTempType())) {
|
||||
|
@ -5314,6 +5313,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
|||
actprop->addRule( new RuleAndDistribute("analysis") );
|
||||
actprop->addRule( new RuleAndCommute("analysis") );
|
||||
actprop->addRule( new RuleAndPiece("analysis") );
|
||||
actprop->addRule( new RuleAndZext("analysis") );
|
||||
actprop->addRule( new RuleAndCompare("analysis") );
|
||||
actprop->addRule( new RuleDoubleSub("analysis") );
|
||||
actprop->addRule( new RuleDoubleShift("analysis") );
|
||||
|
|
|
@ -390,7 +390,6 @@ public:
|
|||
bool onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const;
|
||||
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial,int4 offset,uint4 mainFlags) const;
|
||||
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool updateDatatypes,bool unmappedAliasCheck);
|
||||
Datatype *checkSymbolType(Varnode *vn); ///< Check for any delayed symbol data-type information on the given Varnode
|
||||
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
|
||||
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
|
||||
bool replaceVolatile(Varnode *vn); ///< Replace accesses of the given Varnode with \e volatile operations
|
||||
|
|
|
@ -869,24 +869,6 @@ bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool updateDatatypes
|
|||
return updateoccurred;
|
||||
}
|
||||
|
||||
/// If the Varnode is a partial of a Symbol with a \e union data-type component, we assign
|
||||
/// a partial union data-type (TypePartialUnion) to the Varnode, so that facing resolutions
|
||||
/// can be provided.
|
||||
/// \param vn is the given Varnode
|
||||
/// \return the partial data-type or null
|
||||
Datatype *Funcdata::checkSymbolType(Varnode *vn)
|
||||
|
||||
{
|
||||
if (vn->isTypeLock()) return vn->getType();
|
||||
SymbolEntry *entry = vn->getSymbolEntry();
|
||||
Symbol *sym = entry->getSymbol();
|
||||
Datatype *curType = sym->getType();
|
||||
if (curType->getSize() == vn->getSize())
|
||||
return (Datatype *)0;
|
||||
int4 curOff = (vn->getAddr().getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
||||
return glb->types->getExactPiece(curType, curOff, vn->getSize());
|
||||
}
|
||||
|
||||
/// A Varnode overlaps the given SymbolEntry. Make sure the Varnode is part of the variable
|
||||
/// underlying the Symbol. If not, remap things so that the Varnode maps to a distinct Symbol.
|
||||
/// In either case, attach the appropriate Symbol to the Varnode
|
||||
|
@ -1037,9 +1019,11 @@ void Funcdata::linkProtoPartial(Varnode *vn)
|
|||
Varnode *rootVn = PieceNode::findRoot(vn);
|
||||
if (rootVn == vn) return;
|
||||
|
||||
Varnode *nameRep = rootVn->getHigh()->getNameRepresentative();
|
||||
HighVariable *rootHigh = rootVn->getHigh();
|
||||
Varnode *nameRep = rootHigh->getNameRepresentative();
|
||||
Symbol *sym = linkSymbol(nameRep);
|
||||
if (sym == (Symbol *)0) return;
|
||||
rootHigh->establishGroupSymbolOffset();
|
||||
SymbolEntry *entry = sym->getFirstWholeMap();
|
||||
vn->setSymbolEntry(entry);
|
||||
}
|
||||
|
|
|
@ -114,6 +114,15 @@ bool Merge::mergeTestRequired(HighVariable *high_out,HighVariable *high_in)
|
|||
if (high_in->isAddrTied()) return false;
|
||||
if (high_in->isPersist()) return false;
|
||||
}
|
||||
if (high_in->piece != (VariablePiece *)0 && high_out->piece != (VariablePiece *)0) {
|
||||
VariableGroup *groupIn = high_in->piece->getGroup();
|
||||
VariableGroup *groupOut = high_out->piece->getGroup();
|
||||
if (groupIn == groupOut)
|
||||
return false;
|
||||
// At least one of the pieces must represent its whole group
|
||||
if (high_in->piece->getSize() != groupIn->getSize() && high_out->piece->getSize() != groupOut->getSize())
|
||||
return false;
|
||||
}
|
||||
|
||||
Symbol *symbolIn = high_in->getSymbol();
|
||||
Symbol *symbolOut = high_out->getSymbol();
|
||||
|
@ -123,20 +132,6 @@ bool Merge::mergeTestRequired(HighVariable *high_out,HighVariable *high_in)
|
|||
if (high_in->getSymbolOffset() != high_out->getSymbolOffset())
|
||||
return false; // Map to different parts of same symbol
|
||||
}
|
||||
|
||||
if (high_out->piece != (VariablePiece *)0 || high_in->piece != (VariablePiece *)0) {
|
||||
// Currently don't allow merging of variables that are in separate overlapping collections
|
||||
if (high_out->piece != (VariablePiece *)0 && high_in->piece != (VariablePiece *)0)
|
||||
return false;
|
||||
if (symbolIn != symbolOut) { // If we know symbols are involved, and not both the same symbol
|
||||
// Treat piece as if it were a separate symbol
|
||||
if (symbolIn != (Symbol *)0 && high_out->piece != (VariablePiece *)0)
|
||||
return false; // effectively different symbols
|
||||
if (symbolOut != (Symbol *)0 && high_in->piece != (VariablePiece *)0)
|
||||
return false; // effectively different symbols
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -178,6 +173,10 @@ bool Merge::mergeTestAdjacent(HighVariable *high_out,HighVariable *high_in)
|
|||
if (symbol != (Symbol *)0)
|
||||
if (symbol->isIsolated())
|
||||
return false;
|
||||
|
||||
// Currently don't allow speculative merging of variables that are in separate overlapping collections
|
||||
if (high_out->piece != (VariablePiece *)0 && high_in->piece != (VariablePiece *)0)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -249,7 +248,7 @@ void Merge::mergeLinear(vector<HighVariable *> &highvec)
|
|||
|
||||
if (highvec.size() <= 1) return;
|
||||
for(initer=highvec.begin();initer!=highvec.end();++initer)
|
||||
updateHigh(*initer);
|
||||
testCache.updateHigh(*initer);
|
||||
sort(highvec.begin(),highvec.end(),compareHighByBlock);
|
||||
for(initer=highvec.begin();initer!=highvec.end();++initer) {
|
||||
high = *initer;
|
||||
|
@ -927,11 +926,11 @@ void Merge::mergeMultiEntry(void)
|
|||
}
|
||||
if (mergeList.empty()) continue;
|
||||
HighVariable *high = mergeList[0]->getHigh();
|
||||
updateHigh(high);
|
||||
testCache.updateHigh(high);
|
||||
for(int4 i=0;i<mergeList.size();++i) {
|
||||
HighVariable *newHigh = mergeList[i]->getHigh();
|
||||
if (newHigh == high) continue; // Varnodes already merged
|
||||
updateHigh(newHigh);
|
||||
testCache.updateHigh(newHigh);
|
||||
if (!mergeTestRequired(high, newHigh)) {
|
||||
symbol->setMergeProblems();
|
||||
newHigh->setUnmerged();
|
||||
|
@ -1005,7 +1004,7 @@ void Merge::mergeAdjacent(void)
|
|||
high_in = vn2->getHigh();
|
||||
if (!mergeTestAdjacent(high_out,high_in)) continue;
|
||||
|
||||
if (!intersection(high_in,high_out)) // If no interval intersection
|
||||
if (!testCache.intersection(high_in,high_out)) // If no interval intersection
|
||||
merge(high_out,high_in,true);
|
||||
}
|
||||
}
|
||||
|
@ -1232,7 +1231,7 @@ void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 po
|
|||
}
|
||||
}
|
||||
if (count > 0 && domCopyIsNew) {
|
||||
high->merge(domVn->getHigh(),true);
|
||||
high->merge(domVn->getHigh(),(HighIntersectTest *)0,true);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1437,8 +1436,9 @@ void Merge::markInternalCopies(void)
|
|||
vector<HighVariable *> multiCopy;
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
PcodeOp *op;
|
||||
HighVariable *h1,*h2,*h3;
|
||||
HighVariable *h1;
|
||||
Varnode *v1,*v2,*v3;
|
||||
VariablePiece *p1,*p2,*p3;
|
||||
int4 val;
|
||||
|
||||
for(iter=data.beginOpAlive();iter!=data.endOpAlive();++iter) {
|
||||
|
@ -1465,41 +1465,42 @@ void Merge::markInternalCopies(void)
|
|||
}
|
||||
break;
|
||||
case CPUI_PIECE: // Check if output is built out of pieces of itself
|
||||
h1 = op->getOut()->getHigh();
|
||||
h2 = op->getIn(0)->getHigh();
|
||||
h3 = op->getIn(1)->getHigh();
|
||||
if (!h2->isPartialOrAddrTied()) break;
|
||||
if (!h3->isPartialOrAddrTied()) break;
|
||||
v2 = h2->getPartialOrAddrTied();
|
||||
v3 = h3->getPartialOrAddrTied();
|
||||
if (v2->isAddrTied()) {
|
||||
if (!h1->isAddrTied()) break;
|
||||
v1 = h1->getTiedVarnode();
|
||||
v1 = op->getOut();
|
||||
v2 = op->getIn(0);
|
||||
v3 = op->getIn(1);
|
||||
p1 = v1->getHigh()->piece;
|
||||
p2 = v2->getHigh()->piece;
|
||||
p3 = v3->getHigh()->piece;
|
||||
if (p1 == (VariablePiece *)0) break;
|
||||
if (p2 == (VariablePiece *)0) break;
|
||||
if (p3 == (VariablePiece *)0) break;
|
||||
if (p1->getGroup() != p2->getGroup()) break;
|
||||
if (p1->getGroup() != p3->getGroup()) break;
|
||||
if (v1->getSpace()->isBigEndian()) {
|
||||
if (p2->getOffset() != p1->getOffset()) break;
|
||||
if (p3->getOffset() != p1->getOffset() + v2->getSize()) break;
|
||||
}
|
||||
else {
|
||||
if (op->getIn(0) != v2) break;
|
||||
if (op->getIn(1) != v3) break;
|
||||
v1 = op->getOut();
|
||||
if (p3->getOffset() != p1->getOffset()) break;
|
||||
if (p2->getOffset() != p1->getOffset() + v3->getSize()) break;
|
||||
}
|
||||
if (v3->overlapJoin(*v1) != 0) break;
|
||||
if (v2->overlapJoin(*v1) != v3->getSize()) break;
|
||||
data.opMarkNonPrinting(op);
|
||||
break;
|
||||
case CPUI_SUBPIECE:
|
||||
h1 = op->getOut()->getHigh();
|
||||
h2 = op->getIn(0)->getHigh();
|
||||
if (!h1->isPartialOrAddrTied()) break;
|
||||
v1 = h1->getPartialOrAddrTied();
|
||||
if (v1->isAddrTied()) {
|
||||
if (!h2->isAddrTied()) break;
|
||||
v2 = h2->getTiedVarnode();
|
||||
v1 = op->getOut();
|
||||
v2 = op->getIn(0);
|
||||
p1 = v1->getHigh()->piece;
|
||||
p2 = v2->getHigh()->piece;
|
||||
if (p1 == (VariablePiece *)0) break;
|
||||
if (p2 == (VariablePiece *)0) break;
|
||||
if (p1->getGroup() != p2->getGroup()) break;
|
||||
val = op->getIn(1)->getOffset();
|
||||
if (v1->getSpace()->isBigEndian()) {
|
||||
if (p2->getOffset() + (v2->getSize() - v1->getSize() - val) != p1->getOffset()) break;
|
||||
}
|
||||
else {
|
||||
if (!h1->sameGroup(h2)) break;
|
||||
v2 = op->getIn(0);
|
||||
if (p2->getOffset() + val != p1->getOffset()) break;
|
||||
}
|
||||
val = op->getIn(1)->getOffset();
|
||||
if (v1->overlapJoin(*v2) != val) break;
|
||||
data.opMarkNonPrinting(op);
|
||||
break;
|
||||
default:
|
||||
|
@ -1528,64 +1529,6 @@ void Merge::registerProtoPartialRoot(Varnode *vn)
|
|||
protoPartial.push_back(vn->getDef());
|
||||
}
|
||||
|
||||
/// \brief Translate any intersection tests for \e high2 into tests for \e high1
|
||||
///
|
||||
/// The two variables will be merged and \e high2, as an object, will be freed.
|
||||
/// We update the cached intersection tests for \e high2 so that they will now apply to new merged \e high1
|
||||
/// \param high1 is the variable object being kept
|
||||
/// \param high2 is the variable object being eliminated
|
||||
void Merge::moveIntersectTests(HighVariable *high1,HighVariable *high2)
|
||||
|
||||
{
|
||||
vector<HighVariable *> yesinter; // Highs that high2 intersects
|
||||
vector<HighVariable *> nointer; // Highs that high2 does not intersect
|
||||
map<HighEdge,bool>::iterator iterfirst = highedgemap.lower_bound( HighEdge(high2,(HighVariable *)0) );
|
||||
map<HighEdge,bool>::iterator iterlast = highedgemap.lower_bound( HighEdge(high2,(HighVariable *)~((uintp)0)) );
|
||||
map<HighEdge,bool>::iterator iter;
|
||||
|
||||
for(iter=iterfirst;iter!=iterlast;++iter) {
|
||||
HighVariable *b = (*iter).first.b;
|
||||
if (b == high1) continue;
|
||||
if ((*iter).second) // Save all high2's intersections
|
||||
yesinter.push_back(b); // as they are still valid for the merge
|
||||
else {
|
||||
nointer.push_back(b);
|
||||
b->setMark(); // Mark that high2 did not intersect
|
||||
}
|
||||
}
|
||||
// Do a purge of all high2's tests
|
||||
if (iterfirst != iterlast) { // Delete all the high2 tests
|
||||
--iterlast; // Move back 1 to prevent deleting under the iterator
|
||||
for(iter=iterfirst;iter!=iterlast;++iter)
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
++iterlast; // Restore original range (with possibly new open endpoint)
|
||||
|
||||
highedgemap.erase(iterfirst,iterlast);
|
||||
}
|
||||
|
||||
iter = highedgemap.lower_bound( HighEdge(high1,(HighVariable *)0) );
|
||||
while((iter!=highedgemap.end())&&((*iter).first.a == high1)) {
|
||||
if (!(*iter).second) { // If test is intersection==false
|
||||
if (!(*iter).first.b->isMark()) // and there was no test with high2
|
||||
highedgemap.erase( iter++ ); // Delete the test
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
else // Keep any intersection==true tests
|
||||
++iter;
|
||||
}
|
||||
vector<HighVariable *>::iterator titer;
|
||||
for(titer=nointer.begin();titer!=nointer.end();++titer)
|
||||
(*titer)->clearMark();
|
||||
|
||||
// Reinsert high2's intersection==true tests for high1 now
|
||||
for(titer=yesinter.begin();titer!=yesinter.end();++titer) {
|
||||
highedgemap[ HighEdge(high1,*titer) ] = true;
|
||||
highedgemap[ HighEdge(*titer,high1) ] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Perform low-level details of merging two HighVariables if possible
|
||||
///
|
||||
/// This routine only fails (returning \b false) if there is a Cover intersection between
|
||||
|
@ -1600,197 +1543,25 @@ bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
|||
|
||||
{
|
||||
if (high1 == high2) return true; // Already merged
|
||||
if (intersection(high1,high2)) return false;
|
||||
if (testCache.intersection(high1,high2)) return false;
|
||||
|
||||
moveIntersectTests(high1, high2);
|
||||
high1->merge(high2,isspeculative); // Do the actual merge
|
||||
high1->merge(high2,&testCache,isspeculative); // Do the actual merge
|
||||
high1->updateCover(); // Update cover now so that updateHigh won't purge cached tests
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// As manipulations are made, Cover information gets out of date. A \e dirty flag is used to
|
||||
/// indicate a particular HighVariable Cover is out-of-date. This routine checks the \e dirty
|
||||
/// flag and updates the Cover information if it is set.
|
||||
/// \param a is the HighVariable to update
|
||||
/// \return \b true if the HighVariable was not originally dirty
|
||||
bool Merge::updateHigh(HighVariable *a)
|
||||
|
||||
{
|
||||
if (!a->isCoverDirty()) return true;
|
||||
|
||||
a->updateCover();
|
||||
purgeHigh(a);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// All tests for pairs where either the first or second HighVariable matches the given one
|
||||
/// are removed.
|
||||
/// \param high is the given HighVariable to purge
|
||||
void Merge::purgeHigh(HighVariable *high)
|
||||
|
||||
{
|
||||
map<HighEdge,bool>::iterator iterfirst = highedgemap.lower_bound( HighEdge(high,(HighVariable *)0) );
|
||||
map<HighEdge,bool>::iterator iterlast = highedgemap.lower_bound( HighEdge(high,(HighVariable *)~((uintp)0)) );
|
||||
|
||||
if (iterfirst == iterlast) return;
|
||||
--iterlast; // Move back 1 to prevent deleting under the iterator
|
||||
map<HighEdge,bool>::iterator iter;
|
||||
for(iter=iterfirst;iter!=iterlast;++iter)
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
++iterlast; // Restore original range (with possibly new open endpoint)
|
||||
|
||||
highedgemap.erase(iterfirst,iterlast);
|
||||
}
|
||||
|
||||
/// \brief Clear the any cached data from the last merge process
|
||||
///
|
||||
/// Free up resources used by cached intersection tests etc.
|
||||
void Merge::clear(void)
|
||||
|
||||
{
|
||||
highedgemap.clear();
|
||||
testCache.clear();
|
||||
copyTrims.clear();
|
||||
protoPartial.clear();
|
||||
}
|
||||
|
||||
/// \brief Test the intersection of two HighVariables and cache the result
|
||||
///
|
||||
/// If the Covers of the two variables intersect, this routine returns \b true. To avoid
|
||||
/// expensive computation on the Cover objects themselves, the test result associated with
|
||||
/// the pair of HighVariables is cached.
|
||||
/// \param a is the first HighVariable
|
||||
/// \param b is the second HighVariable
|
||||
/// \return \b true if the variables intersect
|
||||
bool Merge::intersection(HighVariable *a,HighVariable *b)
|
||||
|
||||
{
|
||||
if (a==b) return false;
|
||||
bool ares = updateHigh(a);
|
||||
bool bres = updateHigh(b);
|
||||
if (ares && bres) { // If neither high was dirty
|
||||
map<HighEdge,bool>::iterator iter = highedgemap.find( HighEdge(a,b) );
|
||||
if (iter != highedgemap.end()) // If previous test is present
|
||||
return (*iter).second; // Use it
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
int4 blk;
|
||||
vector<int4> blockisect;
|
||||
a->getCover().intersectList(blockisect,b->getCover(),2);
|
||||
for(blk=0;blk<blockisect.size();++blk) {
|
||||
if (blockIntersection(a,b,blockisect[blk])) {
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
highedgemap[ HighEdge(a,b) ] = res; // Cache the result
|
||||
highedgemap[ HighEdge(b,a) ] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
/// \brief Gather Varnode instances of the given HighVariable that intersect a cover on a specific block
|
||||
///
|
||||
/// \param a is the given HighVariable
|
||||
/// \param blk is the specific block number
|
||||
/// \param cover is the Cover to test for intersection
|
||||
/// \param res will hold the resulting intersecting Varnodes
|
||||
void Merge::gatherBlockVarnodes(HighVariable *a,int4 blk,const Cover &cover,vector<Varnode *> &res)
|
||||
|
||||
{
|
||||
for(int4 i=0;i<a->numInstances();++i) {
|
||||
Varnode *vn = a->getInstance(i);
|
||||
if (1<vn->getCover()->intersectByBlock(blk,cover))
|
||||
res.push_back(vn);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Test instances of a the given HighVariable for intersection on a specific block with a cover
|
||||
///
|
||||
/// A list of Varnodes has already been determined to intersect on the block. For an instance that does as
|
||||
/// well, a final test of copy shadowing is performed with the Varnode list. If there is no shadowing,
|
||||
/// a merging intersection has been found and \b true is returned.
|
||||
/// \param a is the given HighVariable
|
||||
/// \param blk is the specific block number
|
||||
/// \param cover is the Cover to test for intersection
|
||||
/// \param relOff is the relative byte offset of the HighVariable to the Varnodes
|
||||
/// \param blist is the list of Varnodes for copy shadow testing
|
||||
/// \return \b true if there is an intersection preventing merging
|
||||
bool Merge::testBlockIntersection(HighVariable *a,int4 blk,const Cover &cover,int4 relOff,const vector<Varnode *> &blist)
|
||||
|
||||
{
|
||||
for(int4 i=0;i<a->numInstances();++i) {
|
||||
Varnode *vn = a->getInstance(i);
|
||||
if (2>vn->getCover()->intersectByBlock(blk,cover)) continue;
|
||||
for(int4 j=0;j<blist.size();++j) {
|
||||
Varnode *vn2 = blist[j];
|
||||
if (1<vn2->getCover()->intersectByBlock(blk,*vn->getCover())) {
|
||||
if (vn->getSize() == vn2->getSize()) {
|
||||
if (!vn->copyShadow(vn2))
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (!vn->partialCopyShadow(vn2,relOff))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Test if two HighVariables intersect on a given BlockBasic
|
||||
///
|
||||
/// Intersections are checked only on the specified block.
|
||||
/// \param a is the first HighVariable
|
||||
/// \param b is the second HighVariable
|
||||
/// \param blk is the index of the BlockBasic on which to test intersection
|
||||
/// \return \b true if an intersection occurs in the specified block
|
||||
bool Merge::blockIntersection(HighVariable *a,HighVariable *b,int4 blk)
|
||||
|
||||
{
|
||||
vector<Varnode *> blist;
|
||||
|
||||
const Cover &aCover(a->getCover());
|
||||
const Cover &bCover(b->getCover());
|
||||
gatherBlockVarnodes(b,blk,aCover,blist);
|
||||
if (testBlockIntersection(a, blk, bCover, 0, blist))
|
||||
return true;
|
||||
if (a->piece != (VariablePiece *)0) {
|
||||
int4 baseOff = a->piece->getOffset();
|
||||
for(int4 i=0;i<a->piece->numIntersection();++i) {
|
||||
const VariablePiece *interPiece = a->piece->getIntersection(i);
|
||||
int4 off = interPiece->getOffset() - baseOff;
|
||||
if (testBlockIntersection(interPiece->getHigh(), blk, bCover, off, blist))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (b->piece != (VariablePiece *)0) {
|
||||
int4 bBaseOff = b->piece->getOffset();
|
||||
for(int4 i=0;i<b->piece->numIntersection();++i) {
|
||||
blist.clear();
|
||||
const VariablePiece *bPiece = b->piece->getIntersection(i);
|
||||
int4 bOff = bPiece->getOffset() - bBaseOff;
|
||||
gatherBlockVarnodes(bPiece->getHigh(),blk,aCover,blist);
|
||||
if (testBlockIntersection(a, blk, bCover, -bOff, blist))
|
||||
return true;
|
||||
if (a->piece != (VariablePiece *)0) {
|
||||
int4 baseOff = a->piece->getOffset();
|
||||
for(int4 j=0;j<a->piece->numIntersection();++j) {
|
||||
const VariablePiece *interPiece = a->piece->getIntersection(j);
|
||||
int4 off = (interPiece->getOffset() - baseOff) - bOff;
|
||||
if (off > 0 && off >= bPiece->getSize()) continue; // Do a piece and b piece intersect at all
|
||||
if (off < 0 && -off >= interPiece->getSize()) continue;
|
||||
if (testBlockIntersection(interPiece->getHigh(), blk, bCover, off, blist))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Inflate the Cover of a given Varnode with a HighVariable
|
||||
///
|
||||
/// An expression involving a HighVariable can be propagated to all the read sites of the
|
||||
|
@ -1802,8 +1573,8 @@ bool Merge::blockIntersection(HighVariable *a,HighVariable *b,int4 blk)
|
|||
void Merge::inflate(Varnode *a,HighVariable *high)
|
||||
|
||||
{
|
||||
updateHigh(a->getHigh());
|
||||
updateHigh(high);
|
||||
testCache.updateHigh(a->getHigh());
|
||||
testCache.updateHigh(high);
|
||||
for(int4 i=0;i<high->numInstances();++i) {
|
||||
Varnode *b = high->getInstance(i);
|
||||
a->cover->merge(*b->cover);
|
||||
|
@ -1825,7 +1596,7 @@ bool Merge::inflateTest(Varnode *a,HighVariable *high)
|
|||
{
|
||||
HighVariable *ahigh = a->getHigh();
|
||||
|
||||
updateHigh(high);
|
||||
testCache.updateHigh(high);
|
||||
const Cover &highCover( high->internalCover ); // Only check for intersections with cover contributing to inflate
|
||||
|
||||
for(int4 i=0;i<ahigh->numInstances();++i) {
|
||||
|
@ -1868,7 +1639,7 @@ bool Merge::mergeTest(HighVariable *high,vector<HighVariable *> &tmplist)
|
|||
|
||||
for(int4 i=0;i<tmplist.size();++i) {
|
||||
HighVariable *a = tmplist[i];
|
||||
if (intersection(a,high))
|
||||
if (testCache.intersection(a,high))
|
||||
return false;
|
||||
}
|
||||
tmplist.push_back(high);
|
||||
|
|
|
@ -21,21 +21,6 @@
|
|||
|
||||
#include "op.hh"
|
||||
|
||||
/// \brief A record for caching a Cover intersection test between two HighVariable objects
|
||||
///
|
||||
/// This is just a pair of HighVariable objects that can be used as a map key. The main
|
||||
/// Merge class uses it to cache intersection test results between the two variables in
|
||||
/// a map.
|
||||
class HighEdge {
|
||||
friend class Merge;
|
||||
HighVariable *a; ///< First HighVariable of the pair
|
||||
HighVariable *b; ///< Second HighVariable of the pair
|
||||
public:
|
||||
/// \brief Comparator
|
||||
bool operator<(const HighEdge &op2) const { if (a==op2.a) return (b<op2.b); return (a<op2.a); }
|
||||
HighEdge(HighVariable *c,HighVariable *d) { a=c; b=d; } ///< Constructor
|
||||
};
|
||||
|
||||
/// \brief Helper class associating a Varnode with the block where it is defined
|
||||
///
|
||||
/// This class explicitly stores a Varnode with the index of the BlockBasic that defines it.
|
||||
|
@ -79,14 +64,9 @@ class Funcdata;
|
|||
/// - Merging Varnodes that hold the same data-type
|
||||
class Merge {
|
||||
Funcdata &data; ///< The function containing the Varnodes to be merged
|
||||
map<HighEdge,bool> highedgemap; ///< A cache of intersection tests, sorted by HighVariable pair
|
||||
HighIntersectTest testCache; ///< Cached intersection tests
|
||||
vector<PcodeOp *> copyTrims; ///< COPY ops inserted to facilitate merges
|
||||
vector<PcodeOp *> protoPartial; ///< Roots of unmapped CONCAT trees
|
||||
bool updateHigh(HighVariable *a); ///< Make sure given HighVariable's Cover is up-to-date
|
||||
void purgeHigh(HighVariable *high); ///< Remove cached intersection tests for a given HighVariable
|
||||
static void gatherBlockVarnodes(HighVariable *a,int4 blk,const Cover &cover,vector<Varnode *> &res);
|
||||
static bool testBlockIntersection(HighVariable *a,int4 blk,const Cover &cover,int4 relOff,const vector<Varnode *> &blist);
|
||||
bool blockIntersection(HighVariable *a,HighVariable *b,int4 blk);
|
||||
static bool mergeTestRequired(HighVariable *high_out,HighVariable *high_in);
|
||||
static bool mergeTestAdjacent(HighVariable *high_out,HighVariable *high_in);
|
||||
static bool mergeTestSpeculative(HighVariable *high_out,HighVariable *high_in);
|
||||
|
@ -100,7 +80,6 @@ class Merge {
|
|||
void collectCovering(vector<Varnode *> &vlist,HighVariable *high,PcodeOp *op);
|
||||
bool collectCorrectable(const vector<Varnode *> &vlist,list<PcodeOp *> &oplist,vector<int4> &slotlist,
|
||||
PcodeOp *op);
|
||||
void moveIntersectTests(HighVariable *high1,HighVariable *high2);
|
||||
PcodeOp *allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trimOp);
|
||||
void snipReads(Varnode *vn,list<PcodeOp *> &markedop);
|
||||
void snipIndirect(PcodeOp *indop);
|
||||
|
@ -122,7 +101,6 @@ class Merge {
|
|||
public:
|
||||
Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function
|
||||
void clear(void);
|
||||
bool intersection(HighVariable *a,HighVariable *b);
|
||||
bool inflateTest(Varnode *a,HighVariable *high);
|
||||
void inflate(Varnode *a,HighVariable *high);
|
||||
bool mergeTest(HighVariable *high,vector<HighVariable *> &tmplist);
|
||||
|
|
|
@ -1685,6 +1685,44 @@ int4 RuleAndPiece::applyOp(PcodeOp *op,Funcdata &data)
|
|||
return 1;
|
||||
}
|
||||
|
||||
/// \class RuleAndZext
|
||||
/// \brief Convert INT_AND to INT_ZEXT where appropriate: `sext(X) & 0xffff => zext(X)`
|
||||
///
|
||||
/// Similarly `concat(Y,X) & 0xffff => zext(X)`
|
||||
void RuleAndZext::getOpList(vector<uint4> &oplist) const
|
||||
|
||||
{
|
||||
oplist.push_back(CPUI_INT_AND);
|
||||
}
|
||||
|
||||
int4 RuleAndZext::applyOp(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
Varnode *cvn1 = op->getIn(1);
|
||||
if (!cvn1->isConstant()) return 0;
|
||||
if (!op->getIn(0)->isWritten()) return 0;
|
||||
PcodeOp *otherop = op->getIn(0)->getDef();
|
||||
OpCode opc = otherop->code();
|
||||
Varnode *rootvn;
|
||||
if (opc == CPUI_INT_SEXT)
|
||||
rootvn = otherop->getIn(0);
|
||||
else if (opc == CPUI_PIECE)
|
||||
rootvn = otherop->getIn(1);
|
||||
else
|
||||
return 0;
|
||||
uintb mask = calc_mask(rootvn->getSize());
|
||||
if (mask != cvn1->getOffset())
|
||||
return 0;
|
||||
if (rootvn->isFree())
|
||||
return 0;
|
||||
if (rootvn->getSize() > sizeof(uintb)) // FIXME: Should be arbitrary precision
|
||||
return 0;
|
||||
data.opSetOpcode(op, CPUI_INT_ZEXT);
|
||||
data.opRemoveInput(op, 1);
|
||||
data.opSetInput(op, rootvn, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/// \class RuleAndCompare
|
||||
/// \brief Simplify INT_ZEXT and SUBPIECE in masked comparison: `zext(V) & c == 0 => V & (c & mask) == 0`
|
||||
///
|
||||
|
|
|
@ -374,6 +374,16 @@ public:
|
|||
virtual void getOpList(vector<uint4> &oplist) const;
|
||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||
};
|
||||
class RuleAndZext : public Rule {
|
||||
public:
|
||||
RuleAndZext(const string &g) : Rule(g, 0, "andzext") {} ///< Constructor
|
||||
virtual Rule *clone(const ActionGroupList &grouplist) const {
|
||||
if (!grouplist.contains(getGroup())) return (Rule *)0;
|
||||
return new RuleAndZext(getGroup());
|
||||
}
|
||||
virtual void getOpList(vector<uint4> &oplist) const;
|
||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
||||
};
|
||||
class RuleAndCompare : public Rule {
|
||||
public:
|
||||
RuleAndCompare(const string &g) : Rule(g, 0, "andcompare") {} ///< Constructor
|
||||
|
|
|
@ -1894,6 +1894,67 @@ int4 TypeUnion::findCompatibleResolve(Datatype *ct) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
TypePartialStruct::TypePartialStruct(const TypePartialStruct &op)
|
||||
: Datatype(op)
|
||||
{
|
||||
stripped = op.stripped;
|
||||
container = op.container;
|
||||
offset = op.offset;
|
||||
}
|
||||
|
||||
TypePartialStruct::TypePartialStruct(Datatype *contain,int4 off,int4 sz,Datatype *strip)
|
||||
: Datatype(sz,TYPE_PARTIALSTRUCT)
|
||||
{
|
||||
#ifdef CPUI_DEBUG
|
||||
if (contain->getMetatype() != TYPE_STRUCT && contain->getMetatype() != TYPE_ARRAY)
|
||||
throw new LowlevelError("Parent of partial struct is not a struture or array");
|
||||
#endif
|
||||
flags |= has_stripped;
|
||||
stripped = strip;
|
||||
container = contain;
|
||||
offset = off;
|
||||
}
|
||||
|
||||
void TypePartialStruct::printRaw(ostream &s) const
|
||||
|
||||
{
|
||||
container->printRaw(s);
|
||||
s << "[off=" << dec << offset << ",sz=" << size << ']';
|
||||
}
|
||||
|
||||
Datatype *TypePartialStruct::getSubType(uintb off,uintb *newoff) const
|
||||
|
||||
{
|
||||
off += offset;
|
||||
return container->getSubType(off, newoff);
|
||||
}
|
||||
|
||||
int4 TypePartialStruct::compare(const Datatype &op,int4 level) const
|
||||
|
||||
{
|
||||
int4 res = Datatype::compare(op,level);
|
||||
if (res != 0) return res;
|
||||
// Both must be partial
|
||||
TypePartialStruct *tp = (TypePartialStruct *) &op;
|
||||
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
|
||||
level -= 1;
|
||||
if (level < 0) {
|
||||
if (id == op.getId()) return 0;
|
||||
return (id < op.getId()) ? -1 : 1;
|
||||
}
|
||||
return container->compare(*tp->container,level); // Compare the underlying union
|
||||
}
|
||||
|
||||
int4 TypePartialStruct::compareDependency(const Datatype &op) const
|
||||
|
||||
{
|
||||
if (submeta != op.getSubMeta()) return (submeta < op.getSubMeta()) ? -1 : 1;
|
||||
TypePartialStruct *tp = (TypePartialStruct *) &op; // Both must be partial
|
||||
if (container != tp->container) return (container < tp->container) ? -1 : 1; // Compare absolute pointers
|
||||
if (offset != tp->offset) return (offset < tp->offset) ? -1 : 1;
|
||||
return (op.getSize()-size);
|
||||
}
|
||||
|
||||
TypePartialUnion::TypePartialUnion(const TypePartialUnion &op)
|
||||
: Datatype(op)
|
||||
{
|
||||
|
@ -3370,6 +3431,14 @@ TypeStruct *TypeFactory::getTypeStruct(const string &n)
|
|||
return (TypeStruct *) findAdd(tmp);
|
||||
}
|
||||
|
||||
TypePartialStruct *TypeFactory::getTypePartialStruct(Datatype *contain,int4 off,int4 sz)
|
||||
|
||||
{
|
||||
Datatype *strip = getBase(sz, TYPE_UNKNOWN);
|
||||
TypePartialStruct tps(contain,off,sz,strip);
|
||||
return (TypePartialStruct *) findAdd(tps);
|
||||
}
|
||||
|
||||
/// The created union will be incomplete and have no fields. They must be added later.
|
||||
/// \param n is the name of the union
|
||||
/// \return the TypeUnion object
|
||||
|
@ -3495,16 +3564,23 @@ TypePointer *TypeFactory::getTypePointerWithSpace(Datatype *ptrTo,AddrSpace *spc
|
|||
Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
|
||||
|
||||
{
|
||||
uintb newOff = offset;
|
||||
while(ct != (Datatype *)0 && ct->getSize() > size && ct->getMetatype() != TYPE_UNION) {
|
||||
ct = ct->getSubType(newOff, &newOff);
|
||||
}
|
||||
if (ct == (Datatype *)0 || ct->getSize() < size)
|
||||
return (Datatype *)0;
|
||||
if (ct->getSize() == size)
|
||||
return ct;
|
||||
if (ct->getMetatype() == TYPE_UNION) // If we hit a containing union
|
||||
return getTypePartialUnion((TypeUnion *)ct, newOff, size);
|
||||
Datatype *lastType = (Datatype *)0;
|
||||
uintb curOff = offset;
|
||||
do {
|
||||
if (ct->getSize() <= size) {
|
||||
if (ct->getSize() == size)
|
||||
return ct; // Perfect size match
|
||||
break;
|
||||
}
|
||||
else if (ct->getMetatype() == TYPE_UNION) {
|
||||
return getTypePartialUnion((TypeUnion *)ct, curOff, size);
|
||||
}
|
||||
lastType = ct;
|
||||
ct = ct->getSubType(curOff,&curOff);
|
||||
} while(ct != (Datatype *)0);
|
||||
// If we reach here, lastType is bigger than size
|
||||
if (lastType->getMetatype() == TYPE_STRUCT || lastType->getMetatype() == TYPE_ARRAY)
|
||||
return getTypePartialStruct(lastType, curOff, size);
|
||||
return (Datatype *)0;
|
||||
}
|
||||
|
||||
|
|
|
@ -99,23 +99,23 @@ enum sub_metatype {
|
|||
SUB_VOID = 22, ///< Compare as a TYPE_VOID
|
||||
SUB_SPACEBASE = 21, ///< Compare as a TYPE_SPACEBASE
|
||||
SUB_UNKNOWN = 20, ///< Compare as a TYPE_UNKNOWN
|
||||
SUB_INT_CHAR = 19, ///< Signed 1-byte character, sub-type of TYPE_INT
|
||||
SUB_UINT_CHAR = 18, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
||||
SUB_INT_PLAIN = 17, ///< Compare as a plain TYPE_INT
|
||||
SUB_UINT_PLAIN = 16, ///< Compare as a plain TYPE_UINT
|
||||
SUB_INT_ENUM = 15, ///< Signed enum, sub-type of TYPE_INT
|
||||
SUB_UINT_ENUM = 14, ///< Unsigned enum, sub-type of TYPE_UINT
|
||||
SUB_INT_UNICODE = 13, ///< Signed wide character, sub-type of TYPE_INT
|
||||
SUB_UINT_UNICODE = 12, ///< Unsigned wide character, sub-type of TYPE_UINT
|
||||
SUB_BOOL = 11, ///< Compare as TYPE_BOOL
|
||||
SUB_CODE = 10, ///< Compare as TYPE_CODE
|
||||
SUB_FLOAT = 9, ///< Compare as TYPE_FLOAT
|
||||
SUB_PTRREL_UNK = 8, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
|
||||
SUB_PTR = 7, ///< Compare as TYPE_PTR
|
||||
SUB_PTRREL = 6, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
|
||||
SUB_PTR_STRUCT = 5, ///< Pointer into struct, sub-type of TYPE_PTR
|
||||
SUB_ARRAY = 4, ///< Compare as TYPE_ARRAY
|
||||
SUB_PARTIALSTRUCT = 3, ///< Compare as TYPE_PARTIALSTRUCT
|
||||
SUB_PARTIALSTRUCT = 19, ///< Compare as TYPE_PARTIALSTRUCT
|
||||
SUB_INT_CHAR = 18, ///< Signed 1-byte character, sub-type of TYPE_INT
|
||||
SUB_UINT_CHAR = 17, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
||||
SUB_INT_PLAIN = 16, ///< Compare as a plain TYPE_INT
|
||||
SUB_UINT_PLAIN = 15, ///< Compare as a plain TYPE_UINT
|
||||
SUB_INT_ENUM = 14, ///< Signed enum, sub-type of TYPE_INT
|
||||
SUB_UINT_ENUM = 13, ///< Unsigned enum, sub-type of TYPE_UINT
|
||||
SUB_INT_UNICODE = 12, ///< Signed wide character, sub-type of TYPE_INT
|
||||
SUB_UINT_UNICODE = 11, ///< Unsigned wide character, sub-type of TYPE_UINT
|
||||
SUB_BOOL = 10, ///< Compare as TYPE_BOOL
|
||||
SUB_CODE = 9, ///< Compare as TYPE_CODE
|
||||
SUB_FLOAT = 8, ///< Compare as TYPE_FLOAT
|
||||
SUB_PTRREL_UNK = 7, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
|
||||
SUB_PTR = 6, ///< Compare as TYPE_PTR
|
||||
SUB_PTRREL = 5, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
|
||||
SUB_PTR_STRUCT = 4, ///< Pointer into struct, sub-type of TYPE_PTR
|
||||
SUB_ARRAY = 3, ///< Compare as TYPE_ARRAY
|
||||
SUB_STRUCT = 2, ///< Compare as TYPE_STRUCT
|
||||
SUB_UNION = 1, ///< Compare as TYPE_UNION
|
||||
SUB_PARTIALUNION = 0 ///< Compare as a TYPE_PARTIALUNION
|
||||
|
@ -484,6 +484,24 @@ public:
|
|||
virtual const TypeField *resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff);
|
||||
};
|
||||
|
||||
/// \brief A data-type that holds \e part of a TypeStruct or TypeArray
|
||||
class TypePartialStruct : public Datatype {
|
||||
friend class TypeFactory;
|
||||
Datatype *stripped; ///< The \e undefined data-type to use if a formal data-type is required.
|
||||
Datatype *container; ///< Parent structure or array of which \b this is a part
|
||||
int4 offset; ///< Byte offset within the parent where \b this starts
|
||||
public:
|
||||
TypePartialStruct(const TypePartialStruct &op); ///< Construct from another TypePartialStruct
|
||||
TypePartialStruct(Datatype *contain,int4 off,int4 sz,Datatype *strip); ///< Constructor
|
||||
Datatype *getParent(void) const { return container; } ///< Get the data-type containing \b this piece
|
||||
virtual void printRaw(ostream &s) const;
|
||||
virtual Datatype *getSubType(uintb off,uintb *newoff) const;
|
||||
virtual int4 compare(const Datatype &op,int4 level) const;
|
||||
virtual int4 compareDependency(const Datatype &op) const;
|
||||
virtual Datatype *clone(void) const { return new TypePartialStruct(*this); }
|
||||
virtual Datatype *getStripped(void) const { return stripped; }
|
||||
};
|
||||
|
||||
/// \brief An internal data-type for holding information about a variable's relative position within a union data-type
|
||||
///
|
||||
/// This is a data-type that can be assigned to a Varnode offset into a Symbol, where either the Symbol itself or
|
||||
|
@ -500,7 +518,7 @@ public:
|
|||
TypePartialUnion(const TypePartialUnion &op); ///< Construct from another TypePartialUnion
|
||||
TypePartialUnion(TypeUnion *contain,int4 off,int4 sz,Datatype *strip); ///< Constructor
|
||||
TypeUnion *getParentUnion(void) const { return container; } ///< Get the union which \b this is part of
|
||||
virtual void printRaw(ostream &s) const; ///< Print a description of the type to stream
|
||||
virtual void printRaw(ostream &s) const;
|
||||
virtual const TypeField *findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
||||
virtual int4 numDepend(void) const;
|
||||
virtual Datatype *getDepend(int4 index) const;
|
||||
|
@ -681,6 +699,7 @@ public:
|
|||
TypePointer *getTypePointerNoDepth(int4 s,Datatype *pt,uint4 ws); ///< Construct a depth limited pointer data-type
|
||||
TypeArray *getTypeArray(int4 as,Datatype *ao); ///< Construct an array data-type
|
||||
TypeStruct *getTypeStruct(const string &n); ///< Create an (empty) structure
|
||||
TypePartialStruct *getTypePartialStruct(Datatype *contain,int4 off,int4 sz); ///< Create a partial structure
|
||||
TypeUnion *getTypeUnion(const string &n); ///< Create an (empty) union
|
||||
TypePartialUnion *getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz); ///< Create a partial union
|
||||
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
|
||||
|
|
|
@ -43,12 +43,29 @@ void VariableGroup::addPiece(VariablePiece *piece)
|
|||
piece->group = this;
|
||||
if (!pieceSet.insert(piece).second)
|
||||
throw LowlevelError("Duplicate VariablePiece");
|
||||
int4 pieceMax = piece->getOffset() + piece->getSize();
|
||||
if (pieceMax > size)
|
||||
size = pieceMax;
|
||||
}
|
||||
|
||||
/// The adjustment amount must be positive, and this effectively increases the size of the group.
|
||||
/// \param amt is the given amount to add to offsets
|
||||
void VariableGroup::adjustOffsets(int4 amt)
|
||||
|
||||
{
|
||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator iter;
|
||||
|
||||
for(iter=pieceSet.begin();iter!=pieceSet.end();++iter) {
|
||||
(*iter)->groupOffset += amt;
|
||||
}
|
||||
size += amt;
|
||||
}
|
||||
|
||||
void VariableGroup::removePiece(VariablePiece *piece)
|
||||
|
||||
{
|
||||
pieceSet.erase(piece);
|
||||
// We currently don't adjust size here as removePiece is currently only called during clean up
|
||||
}
|
||||
|
||||
/// Construct piece given a HighVariable and its position within the whole.
|
||||
|
@ -134,17 +151,6 @@ void VariablePiece::updateCover(void) const
|
|||
high->highflags &= ~(uint4)HighVariable::extendcoverdirty;
|
||||
}
|
||||
|
||||
/// \param amt is the given amout to add to offset
|
||||
void VariablePiece::adjustOffset(int4 amt)
|
||||
|
||||
{
|
||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator iter;
|
||||
|
||||
for(iter=group->pieceSet.begin();iter!=group->pieceSet.end();++iter) {
|
||||
(*iter)->groupOffset += amt;
|
||||
}
|
||||
}
|
||||
|
||||
/// If there are no remaining references to the old VariableGroup it is deleted.
|
||||
/// \param newGroup is the new VariableGroup to transfer \b this to
|
||||
void VariablePiece::transferGroup(VariableGroup *newGroup)
|
||||
|
@ -169,13 +175,14 @@ void VariablePiece::combineOtherGroup(VariablePiece *op2,vector<HighVariable *>
|
|||
{
|
||||
int4 diff = groupOffset - op2->groupOffset; // Add to op2, or subtract from this
|
||||
if (diff > 0)
|
||||
op2->adjustOffset(diff);
|
||||
op2->group->adjustOffsets(diff);
|
||||
else if (diff < 0)
|
||||
adjustOffset(-diff);
|
||||
group->adjustOffsets(-diff);
|
||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator iter = op2->group->pieceSet.begin();
|
||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator enditer = op2->group->pieceSet.end();
|
||||
while(iter != enditer) {
|
||||
VariablePiece *piece = *iter;
|
||||
++iter;
|
||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator matchiter = group->pieceSet.find(piece);
|
||||
if (matchiter != group->pieceSet.end()) {
|
||||
mergePairs.push_back((*matchiter)->high);
|
||||
|
@ -228,15 +235,8 @@ void HighVariable::setSymbol(Varnode *vn) const
|
|||
}
|
||||
}
|
||||
symbol = entry->getSymbol();
|
||||
if (vn->isProtoPartial()) {
|
||||
Varnode *rootVn = PieceNode::findRoot(vn);
|
||||
if (rootVn == vn)
|
||||
throw LowlevelError("Partial varnode does not match symbol");
|
||||
|
||||
symboloffset = vn->getAddr().overlapJoin(0,rootVn->getAddr(),rootVn->getSize());
|
||||
SymbolEntry *entry = rootVn->getSymbolEntry();
|
||||
if (entry != (SymbolEntry *)0)
|
||||
symboloffset += entry->getOffset();
|
||||
if (vn->isProtoPartial() && piece != (VariablePiece *)0) {
|
||||
symboloffset = piece->getOffset() + piece->getGroup()->getSymbolOffset();
|
||||
}
|
||||
else if (entry->isDynamic()) // Dynamic symbols (that aren't partials) match whole variable
|
||||
symboloffset = -1;
|
||||
|
@ -249,6 +249,8 @@ void HighVariable::setSymbol(Varnode *vn) const
|
|||
symboloffset = vn->getAddr().overlapJoin(0,entry->getAddr(),symbol->getType()->getSize()) + entry->getOffset();
|
||||
}
|
||||
|
||||
if (type != (Datatype *)0 && type->getMetatype() == TYPE_PARTIALUNION)
|
||||
highflags |= typedirty;
|
||||
highflags &= ~((uint4)symboldirty); // We are no longer dirty
|
||||
}
|
||||
|
||||
|
@ -365,9 +367,17 @@ void HighVariable::updateType(void) const
|
|||
vn = getTypeRepresentative();
|
||||
|
||||
type = vn->getType();
|
||||
if (type->hasStripped() && type->getMetatype() != TYPE_PARTIALUNION)
|
||||
type = type->getStripped();
|
||||
|
||||
if (type->hasStripped()) {
|
||||
if (type->getMetatype() == TYPE_PARTIALUNION) {
|
||||
if (symbol != (Symbol *)0 && symboloffset != -1) {
|
||||
type_metatype meta = symbol->getType()->getMetatype();
|
||||
if (meta != TYPE_STRUCT && meta != TYPE_UNION) // If partial union does not have a bigger backing symbol
|
||||
type = type->getStripped(); // strip the partial union
|
||||
}
|
||||
}
|
||||
else
|
||||
type = type->getStripped();
|
||||
}
|
||||
// Update lock flags
|
||||
flags &= ~Varnode::typelock;
|
||||
if (vn->isTypeLock())
|
||||
|
@ -469,21 +479,6 @@ Varnode *HighVariable::getNameRepresentative(void) const
|
|||
return nameRepresentative;
|
||||
}
|
||||
|
||||
/// Find the first member that is either address tied or marked as a proto partial.
|
||||
/// \return a member Varnode acting as partial storage or null if none exist
|
||||
Varnode *HighVariable::getPartialOrAddrTied(void) const
|
||||
|
||||
{
|
||||
int4 i;
|
||||
|
||||
for(i=0;i<inst.size();++i) {
|
||||
Varnode *vn = inst[i];
|
||||
if (vn->isAddrTied() || vn->isProtoPartial())
|
||||
return vn;
|
||||
}
|
||||
return (Varnode *)0;
|
||||
}
|
||||
|
||||
/// Search for the given Varnode and cut it out of the list, marking all properties as \e dirty.
|
||||
/// \param vn is the given Varnode member to remove
|
||||
void HighVariable::remove(Varnode *vn)
|
||||
|
@ -551,7 +546,7 @@ void HighVariable::groupWith(int4 off,HighVariable *hi2)
|
|||
else if (hi2->piece == (VariablePiece *)0) {
|
||||
int4 hi2Off = piece->getOffset() - off;
|
||||
if (hi2Off < 0) {
|
||||
piece->adjustOffset(-hi2Off);
|
||||
piece->getGroup()->adjustOffsets(-hi2Off);
|
||||
hi2Off = 0;
|
||||
}
|
||||
if ((highflags & intersectdirty) == 0)
|
||||
|
@ -564,6 +559,22 @@ void HighVariable::groupWith(int4 off,HighVariable *hi2)
|
|||
}
|
||||
}
|
||||
|
||||
/// If \b this is part of a larger group and has had its \b symboloffset set, it can be used
|
||||
/// to calculate the \b symboloffset of other HighVariables in the same group, by writing it
|
||||
/// to the common VariableGroup object.
|
||||
void HighVariable::establishGroupSymbolOffset(void)
|
||||
|
||||
{
|
||||
VariableGroup *group = piece->getGroup();
|
||||
int4 off = symboloffset;
|
||||
if (off < 0)
|
||||
off = 0;
|
||||
off -= piece->getOffset();
|
||||
if (off < 0)
|
||||
throw LowlevelError("Symbol offset is incompatible with VariableGroup");
|
||||
group->setSymbolOffset(off);
|
||||
}
|
||||
|
||||
/// The lists of members are merged and the other HighVariable is deleted.
|
||||
/// \param tv2 is the other HighVariable to merge into \b this
|
||||
/// \param isspeculative is \b true to keep the new members in separate \e merge classes
|
||||
|
@ -614,12 +625,15 @@ void HighVariable::mergeInternal(HighVariable *tv2,bool isspeculative)
|
|||
/// the groups are combined into one, which may induce additional HighVariable pairs within the group to be merged.
|
||||
/// In all cases, the other HighVariable is deleted.
|
||||
/// \param tv2 is the other HighVariable to merge into \b this
|
||||
/// \param testCache if non-null is a cache of intersection tests that must be updated to reflect the merge
|
||||
/// \param isspeculative is \b true to keep the new members in separate \e merge classes
|
||||
void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
||||
void HighVariable::merge(HighVariable *tv2,HighIntersectTest *testCache,bool isspeculative)
|
||||
|
||||
{
|
||||
if (tv2 == this) return;
|
||||
|
||||
if (testCache != (HighIntersectTest *)0)
|
||||
testCache->moveIntersectTests(this,tv2);
|
||||
if (piece == (VariablePiece *)0 && tv2->piece == (VariablePiece *)0) {
|
||||
mergeInternal(tv2,isspeculative);
|
||||
return;
|
||||
|
@ -638,16 +652,18 @@ void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
|||
return;
|
||||
}
|
||||
// Reaching here both HighVariables are part of a group
|
||||
throw LowlevelError("Merging variables in separate groups not supported");
|
||||
// vector<HighVariable *> mergePairs;
|
||||
// piece->combineOtherGroup(tv2->piece, mergePairs);
|
||||
// for(int4 i=0;i<mergePairs.size();i+=2) {
|
||||
// HighVariable *high1 = mergePairs[i];
|
||||
// HighVariable *high2 = mergePairs[i+1];
|
||||
// // Need to deal with cached intersect tests herev
|
||||
// high1->mergeInternal(high2, isspeculative);
|
||||
// }
|
||||
// piece->markIntersectionDirty();
|
||||
if (isspeculative)
|
||||
throw LowlevelError("Trying speculatively merge variables in separate groups");
|
||||
vector<HighVariable *> mergePairs;
|
||||
piece->combineOtherGroup(tv2->piece, mergePairs);
|
||||
for(int4 i=0;i<mergePairs.size();i+=2) {
|
||||
HighVariable *high1 = mergePairs[i];
|
||||
HighVariable *high2 = mergePairs[i+1];
|
||||
if (testCache != (HighIntersectTest *)0)
|
||||
testCache->moveIntersectTests(high1, high2);
|
||||
high1->mergeInternal(high2, isspeculative);
|
||||
}
|
||||
piece->markIntersectionDirty();
|
||||
}
|
||||
|
||||
/// All Varnode objects are assigned a HighVariable, including those that don't get names like
|
||||
|
@ -755,15 +771,6 @@ int4 HighVariable::instanceIndex(const Varnode *vn) const
|
|||
return -1;
|
||||
}
|
||||
|
||||
/// \param op2 is the other HighVariable to compare with \b this
|
||||
/// \return \b true if they are in the same group
|
||||
bool HighVariable::sameGroup(const HighVariable *op2) const
|
||||
|
||||
{
|
||||
if (piece == (VariablePiece *)0 || op2->piece == (VariablePiece *)0) return false;
|
||||
return (piece->getGroup() == op2->piece->getGroup());
|
||||
}
|
||||
|
||||
/// \param encoder is the stream encoder
|
||||
void HighVariable::encode(Encoder &encoder) const
|
||||
|
||||
|
@ -780,6 +787,8 @@ void HighVariable::encode(Encoder &encoder) const
|
|||
else if (!isPersist() && (symbol != (Symbol *)0)) {
|
||||
if (symbol->getCategory() == Symbol::function_parameter)
|
||||
encoder.writeString(ATTRIB_CLASS, "param");
|
||||
else if (symbol->getScope()->isGlobal())
|
||||
encoder.writeString(ATTRIB_CLASS, "global");
|
||||
else
|
||||
encoder.writeString(ATTRIB_CLASS, "local");
|
||||
}
|
||||
|
@ -883,3 +892,233 @@ void HighVariable::verifyCover(void) const
|
|||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/// \brief Gather Varnode instances of the given HighVariable that intersect a cover on a specific block
|
||||
///
|
||||
/// \param a is the given HighVariable
|
||||
/// \param blk is the specific block number
|
||||
/// \param cover is the Cover to test for intersection
|
||||
/// \param res will hold the resulting intersecting Varnodes
|
||||
void HighIntersectTest::gatherBlockVarnodes(HighVariable *a,int4 blk,const Cover &cover,vector<Varnode *> &res)
|
||||
|
||||
{
|
||||
for(int4 i=0;i<a->numInstances();++i) {
|
||||
Varnode *vn = a->getInstance(i);
|
||||
if (1<vn->getCover()->intersectByBlock(blk,cover))
|
||||
res.push_back(vn);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Test instances of a the given HighVariable for intersection on a specific block with a cover
|
||||
///
|
||||
/// A list of Varnodes has already been determined to intersect on the block. For an instance that does as
|
||||
/// well, a final test of copy shadowing is performed with the Varnode list. If there is no shadowing,
|
||||
/// a merging intersection has been found and \b true is returned.
|
||||
/// \param a is the given HighVariable
|
||||
/// \param blk is the specific block number
|
||||
/// \param cover is the Cover to test for intersection
|
||||
/// \param relOff is the relative byte offset of the HighVariable to the Varnodes
|
||||
/// \param blist is the list of Varnodes for copy shadow testing
|
||||
/// \return \b true if there is an intersection preventing merging
|
||||
bool HighIntersectTest::testBlockIntersection(HighVariable *a,int4 blk,const Cover &cover,int4 relOff,
|
||||
const vector<Varnode *> &blist)
|
||||
{
|
||||
for(int4 i=0;i<a->numInstances();++i) {
|
||||
Varnode *vn = a->getInstance(i);
|
||||
if (2>vn->getCover()->intersectByBlock(blk,cover)) continue;
|
||||
for(int4 j=0;j<blist.size();++j) {
|
||||
Varnode *vn2 = blist[j];
|
||||
if (1<vn2->getCover()->intersectByBlock(blk,*vn->getCover())) {
|
||||
if (vn->getSize() == vn2->getSize()) {
|
||||
if (!vn->copyShadow(vn2))
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (!vn->partialCopyShadow(vn2,relOff))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Test if two HighVariables intersect on a given BlockBasic
|
||||
///
|
||||
/// Intersections are checked only on the specified block.
|
||||
/// \param a is the first HighVariable
|
||||
/// \param b is the second HighVariable
|
||||
/// \param blk is the index of the BlockBasic on which to test intersection
|
||||
/// \return \b true if an intersection occurs in the specified block
|
||||
bool HighIntersectTest::blockIntersection(HighVariable *a,HighVariable *b,int4 blk)
|
||||
|
||||
{
|
||||
vector<Varnode *> blist;
|
||||
|
||||
const Cover &aCover(a->getCover());
|
||||
const Cover &bCover(b->getCover());
|
||||
gatherBlockVarnodes(b,blk,aCover,blist);
|
||||
if (testBlockIntersection(a, blk, bCover, 0, blist))
|
||||
return true;
|
||||
if (a->piece != (VariablePiece *)0) {
|
||||
int4 baseOff = a->piece->getOffset();
|
||||
for(int4 i=0;i<a->piece->numIntersection();++i) {
|
||||
const VariablePiece *interPiece = a->piece->getIntersection(i);
|
||||
int4 off = interPiece->getOffset() - baseOff;
|
||||
if (testBlockIntersection(interPiece->getHigh(), blk, bCover, off, blist))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (b->piece != (VariablePiece *)0) {
|
||||
int4 bBaseOff = b->piece->getOffset();
|
||||
for(int4 i=0;i<b->piece->numIntersection();++i) {
|
||||
blist.clear();
|
||||
const VariablePiece *bPiece = b->piece->getIntersection(i);
|
||||
int4 bOff = bPiece->getOffset() - bBaseOff;
|
||||
gatherBlockVarnodes(bPiece->getHigh(),blk,aCover,blist);
|
||||
if (testBlockIntersection(a, blk, bCover, -bOff, blist))
|
||||
return true;
|
||||
if (a->piece != (VariablePiece *)0) {
|
||||
int4 baseOff = a->piece->getOffset();
|
||||
for(int4 j=0;j<a->piece->numIntersection();++j) {
|
||||
const VariablePiece *interPiece = a->piece->getIntersection(j);
|
||||
int4 off = (interPiece->getOffset() - baseOff) - bOff;
|
||||
if (off > 0 && off >= bPiece->getSize()) continue; // Do a piece and b piece intersect at all
|
||||
if (off < 0 && -off >= interPiece->getSize()) continue;
|
||||
if (testBlockIntersection(interPiece->getHigh(), blk, bCover, off, blist))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// All tests for pairs where either the first or second HighVariable matches the given one
|
||||
/// are removed.
|
||||
/// \param high is the given HighVariable to purge
|
||||
void HighIntersectTest::purgeHigh(HighVariable *high)
|
||||
|
||||
{
|
||||
map<HighEdge,bool>::iterator iterfirst = highedgemap.lower_bound( HighEdge(high,(HighVariable *)0) );
|
||||
map<HighEdge,bool>::iterator iterlast = highedgemap.lower_bound( HighEdge(high,(HighVariable *)~((uintp)0)) );
|
||||
|
||||
if (iterfirst == iterlast) return;
|
||||
--iterlast; // Move back 1 to prevent deleting under the iterator
|
||||
map<HighEdge,bool>::iterator iter;
|
||||
for(iter=iterfirst;iter!=iterlast;++iter)
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
++iterlast; // Restore original range (with possibly new open endpoint)
|
||||
|
||||
highedgemap.erase(iterfirst,iterlast);
|
||||
}
|
||||
|
||||
/// \brief Translate any intersection tests for \e high2 into tests for \e high1
|
||||
///
|
||||
/// The two variables will be merged and \e high2, as an object, will be freed.
|
||||
/// We update the cached intersection tests for \e high2 so that they will now apply to new merged \e high1
|
||||
/// \param high1 is the variable object being kept
|
||||
/// \param high2 is the variable object being eliminated
|
||||
void HighIntersectTest::moveIntersectTests(HighVariable *high1,HighVariable *high2)
|
||||
|
||||
{
|
||||
vector<HighVariable *> yesinter; // Highs that high2 intersects
|
||||
vector<HighVariable *> nointer; // Highs that high2 does not intersect
|
||||
map<HighEdge,bool>::iterator iterfirst = highedgemap.lower_bound( HighEdge(high2,(HighVariable *)0) );
|
||||
map<HighEdge,bool>::iterator iterlast = highedgemap.lower_bound( HighEdge(high2,(HighVariable *)~((uintp)0)) );
|
||||
map<HighEdge,bool>::iterator iter;
|
||||
|
||||
for(iter=iterfirst;iter!=iterlast;++iter) {
|
||||
HighVariable *b = (*iter).first.b;
|
||||
if (b == high1) continue;
|
||||
if ((*iter).second) // Save all high2's intersections
|
||||
yesinter.push_back(b); // as they are still valid for the merge
|
||||
else {
|
||||
nointer.push_back(b);
|
||||
b->setMark(); // Mark that high2 did not intersect
|
||||
}
|
||||
}
|
||||
// Do a purge of all high2's tests
|
||||
if (iterfirst != iterlast) { // Delete all the high2 tests
|
||||
--iterlast; // Move back 1 to prevent deleting under the iterator
|
||||
for(iter=iterfirst;iter!=iterlast;++iter)
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||
++iterlast; // Restore original range (with possibly new open endpoint)
|
||||
|
||||
highedgemap.erase(iterfirst,iterlast);
|
||||
}
|
||||
|
||||
iter = highedgemap.lower_bound( HighEdge(high1,(HighVariable *)0) );
|
||||
while((iter!=highedgemap.end())&&((*iter).first.a == high1)) {
|
||||
if (!(*iter).second) { // If test is intersection==false
|
||||
if (!(*iter).first.b->isMark()) // and there was no test with high2
|
||||
highedgemap.erase( iter++ ); // Delete the test
|
||||
else
|
||||
++iter;
|
||||
}
|
||||
else // Keep any intersection==true tests
|
||||
++iter;
|
||||
}
|
||||
vector<HighVariable *>::iterator titer;
|
||||
for(titer=nointer.begin();titer!=nointer.end();++titer)
|
||||
(*titer)->clearMark();
|
||||
|
||||
// Reinsert high2's intersection==true tests for high1 now
|
||||
for(titer=yesinter.begin();titer!=yesinter.end();++titer) {
|
||||
highedgemap[ HighEdge(high1,*titer) ] = true;
|
||||
highedgemap[ HighEdge(*titer,high1) ] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// As manipulations are made, Cover information gets out of date. A \e dirty flag is used to
|
||||
/// indicate a particular HighVariable Cover is out-of-date. This routine checks the \e dirty
|
||||
/// flag and updates the Cover information if it is set.
|
||||
/// \param a is the HighVariable to update
|
||||
/// \return \b true if the HighVariable was not originally dirty
|
||||
bool HighIntersectTest::updateHigh(HighVariable *a)
|
||||
|
||||
{
|
||||
if (!a->isCoverDirty()) return true;
|
||||
|
||||
a->updateCover();
|
||||
purgeHigh(a);
|
||||
return false;
|
||||
}
|
||||
|
||||
/// \brief Test the intersection of two HighVariables and cache the result
|
||||
///
|
||||
/// If the Covers of the two variables intersect, this routine returns \b true. To avoid
|
||||
/// expensive computation on the Cover objects themselves, the test result associated with
|
||||
/// the pair of HighVariables is cached.
|
||||
/// \param a is the first HighVariable
|
||||
/// \param b is the second HighVariable
|
||||
/// \return \b true if the variables intersect
|
||||
bool HighIntersectTest::intersection(HighVariable *a,HighVariable *b)
|
||||
|
||||
{
|
||||
if (a==b) return false;
|
||||
bool ares = updateHigh(a);
|
||||
bool bres = updateHigh(b);
|
||||
if (ares && bres) { // If neither high was dirty
|
||||
map<HighEdge,bool>::iterator iter = highedgemap.find( HighEdge(a,b) );
|
||||
if (iter != highedgemap.end()) // If previous test is present
|
||||
return (*iter).second; // Use it
|
||||
}
|
||||
|
||||
bool res = false;
|
||||
int4 blk;
|
||||
vector<int4> blockisect;
|
||||
a->getCover().intersectList(blockisect,b->getCover(),2);
|
||||
for(blk=0;blk<blockisect.size();++blk) {
|
||||
if (blockIntersection(a,b,blockisect[blk])) {
|
||||
res = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
highedgemap[ HighEdge(a,b) ] = res; // Cache the result
|
||||
highedgemap[ HighEdge(b,a) ] = res;
|
||||
return res;
|
||||
}
|
||||
|
||||
|
|
|
@ -48,10 +48,17 @@ class VariableGroup {
|
|||
};
|
||||
|
||||
set<VariablePiece *,PieceCompareByOffset> pieceSet; ///< The set of VariablePieces making up \b this group
|
||||
int4 size; ///< Number of contiguous bytes covered by the whole group
|
||||
int4 symbolOffset; ///< Byte offset of \b this group within its containing Symbol
|
||||
public:
|
||||
VariableGroup(void) { size = 0; symbolOffset = 0; }
|
||||
bool empty(void) const { return pieceSet.empty(); } ///< Return \b true if \b this group has no pieces
|
||||
void addPiece(VariablePiece *piece); ///< Add a new piece to \b this group
|
||||
void adjustOffsets(int4 amt); ///< Adjust offset for every piece by the given amount
|
||||
void removePiece(VariablePiece *piece); ///< Remove a piece from \b this group
|
||||
int4 getSize(void) const { return size; } ///< Get the number of bytes \b this group covers
|
||||
void setSymbolOffset(int4 val) { symbolOffset = val; } ///< Cache the symbol offset for the group
|
||||
int4 getSymbolOffset(void) const { return symbolOffset; } ///< Get offset of \b this group within its Symbol
|
||||
};
|
||||
|
||||
/// \brief Information about how a HighVariable fits into a larger group or Symbol
|
||||
|
@ -80,12 +87,13 @@ public:
|
|||
void markExtendCoverDirty(void) const; ///< Mark all intersecting pieces as having a dirty extended cover
|
||||
void updateIntersections(void) const; ///< Calculate intersections with other pieces in the group
|
||||
void updateCover(void) const; ///< Calculate extended cover based on intersections
|
||||
void adjustOffset(int4 amt); ///< Adjust every piece's offset by the given amount
|
||||
void transferGroup(VariableGroup *newGroup); ///< Transfer \b this piece to another VariableGroup
|
||||
void setHigh(HighVariable *newHigh) { high = newHigh; } ///< Move ownership of \b this to another HighVariable
|
||||
void combineOtherGroup(VariablePiece *op2,vector<HighVariable *> &mergePairs); ///< Combine two VariableGroups
|
||||
};
|
||||
|
||||
class HighIntersectTest;
|
||||
|
||||
/// \brief A high-level variable modeled as a list of low-level variables, each written once
|
||||
///
|
||||
/// In the Static Single Assignment (SSA) representation of a function's data-flow, the Varnode
|
||||
|
@ -122,6 +130,7 @@ private:
|
|||
friend class Varnode;
|
||||
friend class Merge;
|
||||
friend class VariablePiece;
|
||||
friend class HighIntersectTest;
|
||||
vector<Varnode *> inst; ///< The member Varnode objects making up \b this HighVariable
|
||||
int4 numMergeClasses; ///< Number of different speculative merge classes in \b this
|
||||
mutable uint4 highflags; ///< Dirtiness flags
|
||||
|
@ -145,7 +154,7 @@ private:
|
|||
bool hasCopyIn2(void) const { return ((highflags©_in2)!=0); } ///< Is there at least two COPYs into \b this
|
||||
void remove(Varnode *vn); ///< Remove a member Varnode from \b this
|
||||
void mergeInternal(HighVariable *tv2,bool isspeculative); ///< Merge another HighVariable into \b this
|
||||
void merge(HighVariable *tv2,bool isspeculative); ///< Merge with another HighVariable taking into account groups
|
||||
void merge(HighVariable *tv2,HighIntersectTest *testCache,bool isspeculative); ///< Merge with another HighVariable taking into account groups
|
||||
void setSymbol(Varnode *vn) const; ///< Update Symbol information for \b this from the given member Varnode
|
||||
void setSymbolReference(Symbol *sym,int4 off); ///< Attach a reference to a Symbol to \b this
|
||||
void transferPiece(HighVariable *tv2); ///< Transfer ownership of another's VariablePiece to \b this
|
||||
|
@ -167,6 +176,7 @@ public:
|
|||
Varnode *getInstance(int4 i) const { return inst[i]; } ///< Get the i-th member Varnode
|
||||
void finalizeDatatype(Datatype *tp); ///< Set a final datatype for \b this variable
|
||||
void groupWith(int4 off,HighVariable *hi2); ///< Put \b this and another HighVariable in the same intersection group
|
||||
void establishGroupSymbolOffset(void); ///< Transfer \b symbol offset of \b this to the VariableGroup
|
||||
|
||||
/// \brief Print details of the cover for \b this (for debug purposes)
|
||||
///
|
||||
|
@ -179,7 +189,6 @@ public:
|
|||
Varnode *getInputVarnode(void) const; ///< Find (the) input member Varnode
|
||||
Varnode *getTypeRepresentative(void) const; ///< Get a member Varnode with the strongest data-type
|
||||
Varnode *getNameRepresentative(void) const; ///< Get a member Varnode that dictates the naming of \b this HighVariable
|
||||
Varnode *getPartialOrAddrTied(void) const; ///< Find the first member that can act as partial symbol storage
|
||||
int4 getNumMergeClasses(void) const { return numMergeClasses; } ///< Get the number of speculative merges for \b this
|
||||
bool isMapped(void) const { updateFlags(); return ((flags&Varnode::mapped)!=0); } ///< Return \b true if \b this is mapped
|
||||
bool isPersist(void) const { updateFlags(); return ((flags&Varnode::persist)!=0); } ///< Return \b true if \b this is a global variable
|
||||
|
@ -191,7 +200,6 @@ public:
|
|||
bool isUnaffected(void) const { updateFlags(); return ((flags&Varnode::unaffected)!=0); } ///< Return \b true if \b this is an \e unaffected register
|
||||
bool isExtraOut(void) const { updateFlags(); return ((flags&(Varnode::indirect_creation|Varnode::addrtied))==Varnode::indirect_creation); } ///< Return \b true if \b this is an extra output
|
||||
bool isProtoPartial(void) const { updateFlags(); return ((flags&Varnode::proto_partial)!=0); } ///< Return \b true if \b this is a piece concatenated into a larger whole
|
||||
bool isPartialOrAddrTied(void) const { updateFlags(); return ((flags&(Varnode::addrtied|Varnode::proto_partial))!=0); } ///< Return \b true if \b this is potential partial symbol
|
||||
void setMark(void) const { flags |= Varnode::mark; } ///< Set the mark on this variable
|
||||
void clearMark(void) const { flags &= ~Varnode::mark; } ///< Clear the mark on this variable
|
||||
bool isMark(void) const { return ((flags&Varnode::mark)!=0); } ///< Return \b true if \b this is marked
|
||||
|
@ -208,7 +216,6 @@ public:
|
|||
bool isUnattached(void) const { return inst.empty(); } ///< Return \b true if \b this has no member Varnode
|
||||
bool isTypeLock(void) const { updateType(); return ((flags & Varnode::typelock)!=0); } ///< Return \b true if \b this is \e typelocked
|
||||
bool isNameLock(void) const { updateFlags(); return ((flags & Varnode::namelock)!=0); } ///< Return \b true if \b this is \e namelocked
|
||||
bool sameGroup(const HighVariable *op2) const; ///< Return \b true if \b and other variable are parts of the same variable
|
||||
void encode(Encoder &encoder) const; ///< Encode \b this variable to stream as a \<high> element
|
||||
#ifdef MERGEMULTI_DEBUG
|
||||
void verifyCover(void) const;
|
||||
|
@ -219,6 +226,42 @@ public:
|
|||
static int4 markExpression(Varnode *vn,vector<HighVariable *> &highList); ///< Mark and collect variables in expression
|
||||
};
|
||||
|
||||
/// \brief A record for caching a Cover intersection test between two HighVariable objects
|
||||
///
|
||||
/// This is just a pair of HighVariable objects that can be used as a map key. The HighIntersectTest
|
||||
/// class uses it to cache intersection test results between the two variables in a map.
|
||||
class HighEdge {
|
||||
friend class HighIntersectTest;
|
||||
HighVariable *a; ///< First HighVariable of the pair
|
||||
HighVariable *b; ///< Second HighVariable of the pair
|
||||
public:
|
||||
/// \brief Comparator
|
||||
bool operator<(const HighEdge &op2) const { if (a==op2.a) return (b<op2.b); return (a<op2.a); }
|
||||
HighEdge(HighVariable *c,HighVariable *d) { a=c; b=d; } ///< Constructor
|
||||
};
|
||||
|
||||
/// \brief A cache of Cover intersection tests for HighVariables
|
||||
///
|
||||
/// An test is performed by calling the intersect() method, which returns the result of a full
|
||||
/// Cover intersection test, taking into account, overlapping pieces, shadow Varnodes etc. The
|
||||
/// results of the test are cached in \b this object, so repeated calls do not need to perform the
|
||||
/// full calculation. The cache examines HighVariable dirtiness flags to determine if its Cover
|
||||
/// and cached tests are stale. The Cover can be externally updated, without performing a test,
|
||||
/// and still keeping the cached tests accurate, by calling the updateHigh() method. If two HighVariables
|
||||
/// to be merged, the cached tests can be updated by calling moveIntersectTest() before merging.
|
||||
class HighIntersectTest {
|
||||
map<HighEdge,bool> highedgemap; ///< A cache of intersection tests, sorted by HighVariable pair
|
||||
static void gatherBlockVarnodes(HighVariable *a,int4 blk,const Cover &cover,vector<Varnode *> &res);
|
||||
static bool testBlockIntersection(HighVariable *a,int4 blk,const Cover &cover,int4 relOff,const vector<Varnode *> &blist);
|
||||
bool blockIntersection(HighVariable *a,HighVariable *b,int4 blk);
|
||||
void purgeHigh(HighVariable *high); ///< Remove cached intersection tests for a given HighVariable
|
||||
public:
|
||||
void moveIntersectTests(HighVariable *high1,HighVariable *high2);
|
||||
bool updateHigh(HighVariable *a); ///< Make sure given HighVariable's Cover is up-to-date
|
||||
bool intersection(HighVariable *a,HighVariable *b);
|
||||
void clear(void) { highedgemap.clear(); }
|
||||
};
|
||||
|
||||
/// The internal cover is marked as dirty. If \b this is a piece of a VariableGroup, it and all the other
|
||||
/// HighVariables it intersects with are marked as having a dirty extended cover.
|
||||
inline void HighVariable::coverDirty(void) const
|
||||
|
|
|
@ -978,6 +978,9 @@ void MapState::gatherVarnodes(const Funcdata &fd)
|
|||
if (vn->isFree()) continue;
|
||||
uintb start = vn->getOffset();
|
||||
Datatype *ct = vn->getType();
|
||||
// Assume parents are present so partials aren't needed
|
||||
if (ct->getMetatype() == TYPE_PARTIALSTRUCT) continue;
|
||||
if (ct->getMetatype() == TYPE_PARTIALUNION) continue;
|
||||
// Do not force Varnode flags on the entry
|
||||
// as the flags were inherited from the previous
|
||||
// (now obsolete) entry
|
||||
|
@ -1008,6 +1011,7 @@ void MapState::gatherHighs(const Funcdata &fd)
|
|||
varvec.push_back(high);
|
||||
uintb start = vn->getOffset();
|
||||
Datatype *ct = high->getType(); // Get type from high
|
||||
if (ct->getMetatype() == TYPE_PARTIALUNION) continue;
|
||||
addRange(start,ct,0,RangeHint::fixed,-1);
|
||||
}
|
||||
for(int4 i=0;i<varvec.size();++i)
|
||||
|
|
|
@ -1674,20 +1674,22 @@ uint4 VarnodeBank::overlapLoc(VarnodeLocSet::const_iterator iter,vector<VarnodeL
|
|||
Varnode *vn = *iter;
|
||||
AddrSpace *spc = vn->getSpace();
|
||||
uintb off = vn->getOffset();
|
||||
uintb maxoff = off + (vn->getSize() - 1);
|
||||
uintb maxOff = off + (vn->getSize() - 1);
|
||||
uint4 flags = vn->getFlags();
|
||||
bounds.push_back(iter);
|
||||
iter = endLoc(vn->getSize(),vn->getAddr(),Varnode::written);
|
||||
bounds.push_back(iter);
|
||||
while(iter != loc_tree.end()) {
|
||||
vn = *iter;
|
||||
if (vn->getSpace() != spc || vn->getOffset() > maxoff)
|
||||
if (vn->getSpace() != spc || vn->getOffset() > maxOff)
|
||||
break;
|
||||
if (vn->isFree()) {
|
||||
iter = endLoc(vn->getSize(),vn->getAddr(),0);
|
||||
continue;
|
||||
}
|
||||
maxoff = vn->getOffset() + (vn->getSize() - 1);
|
||||
uintb endOff = vn->getOffset() + (vn->getSize() - 1);
|
||||
if (endOff > maxOff)
|
||||
maxOff = endOff;
|
||||
flags |= vn->getFlags();
|
||||
bounds.push_back(iter);
|
||||
iter = endLoc(vn->getSize(),vn->getAddr(),Varnode::written);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
<decompilertest>
|
||||
<binaryimage arch="x86:LE:64:default:gcc">
|
||||
<!--
|
||||
Example of logically independent values being concatenated together
|
||||
before being written into a structure, assigning to multiple fields simultaneously
|
||||
-->
|
||||
<bytechunk space="ram" offset="0x100740" readonly="true">
|
||||
554889e54883ec4089c84589c24589c8
|
||||
89f966894ddc89f166894dd88855d488
|
||||
45d04489d08845cc4489c08845c86448
|
||||
8b042528000000488945f831c00fbf45
|
||||
d88945ecc165ec100fb745dc0fb7c009
|
||||
45ec8b45ec8945f00fbe45c825ff0000
|
||||
008945ecc165ec080fbe45cc0fb6c009
|
||||
45ecc165ec080fbe45d00fb6c00945ec
|
||||
c165ec080fbe45d40fb6c00945ec8b45
|
||||
ec8945f4488d45f04889c7e81affffff
|
||||
90488b45f86448330425280000007405
|
||||
e8bbfdffffc9c3
|
||||
</bytechunk>
|
||||
<symbol space="ram" offset="0x100740" name="assign"/>
|
||||
<symbol space="ram" offset="0x1006fa" name="print"/>
|
||||
</binaryimage>
|
||||
<script>
|
||||
<com>parse line struct mypiece { int2 a; int2 b; char arr[4]; };</com>
|
||||
<com>parse line extern void assign(int2 a,int2 b,char c,char d,char e,char f);</com>
|
||||
<com>parse line extern void print(mypiece *ptr);</com>
|
||||
<com>lo fu assign</com>
|
||||
<com>decompile</com>
|
||||
<com>print C</com>
|
||||
<com>quit</com>
|
||||
</script>
|
||||
<stringmatch name="Piece Structure #1" min="1" max="1">Stack_18\.a = a;</stringmatch>
|
||||
<stringmatch name="Piece Structure #2" min="1" max="1">Stack_18\.b = b;</stringmatch>
|
||||
<stringmatch name="Piece Structure #3" min="1" max="1">Stack_18\.arr\[0\] = c;</stringmatch>
|
||||
<stringmatch name="Piece Structure #4" min="1" max="1">Stack_18\.arr\[1\] = d;</stringmatch>
|
||||
<stringmatch name="Piece Structure #5" min="1" max="1">Stack_18\.arr\[2\] = e;</stringmatch>
|
||||
<stringmatch name="Piece Structure #6" min="1" max="1">Stack_18\.arr\[3\] = f;</stringmatch>
|
||||
</decompilertest>
|
Loading…
Add table
Add a link
Reference in a new issue