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/packstructaccess.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/partialmerge.xml||GHIDRA||||END|
|
src/decompile/datatests/partialmerge.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/partialunion.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/pointercmp.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
|
src/decompile/datatests/pointerrel.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/pointersub.xml||GHIDRA||||END|
|
src/decompile/datatests/pointersub.xml||GHIDRA||||END|
|
||||||
|
|
|
@ -4732,16 +4732,19 @@ void ActionInferTypes::buildLocaltypes(Funcdata &data)
|
||||||
Datatype *ct;
|
Datatype *ct;
|
||||||
Varnode *vn;
|
Varnode *vn;
|
||||||
VarnodeLocSet::const_iterator iter;
|
VarnodeLocSet::const_iterator iter;
|
||||||
|
TypeFactory *typegrp = data.getArch()->types;
|
||||||
|
|
||||||
for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
|
for(iter=data.beginLoc();iter!=data.endLoc();++iter) {
|
||||||
vn = *iter;
|
vn = *iter;
|
||||||
if (vn->isAnnotation()) continue;
|
if (vn->isAnnotation()) continue;
|
||||||
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
|
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
|
||||||
bool needsBlock = false;
|
bool needsBlock = false;
|
||||||
if (vn->getSymbolEntry() != (SymbolEntry *)0) {
|
SymbolEntry *entry = vn->getSymbolEntry();
|
||||||
ct = data.checkSymbolType(vn);
|
if (entry != (SymbolEntry *)0 && !vn->isTypeLock() && entry->getSymbol()->isTypeLocked()) {
|
||||||
if (ct == (Datatype *)0)
|
int4 curOff = (vn->getAddr().getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
|
||||||
ct = vn->getLocalType(needsBlock);
|
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
|
else
|
||||||
ct = vn->getLocalType(needsBlock);
|
ct = vn->getLocalType(needsBlock);
|
||||||
|
@ -4956,13 +4959,9 @@ void ActionInferTypes::propagateRef(Funcdata &data,Varnode *vn,const Address &ad
|
||||||
if ((cursize!=lastsize)||(curoff!=lastoff)) {
|
if ((cursize!=lastsize)||(curoff!=lastoff)) {
|
||||||
lastoff = curoff;
|
lastoff = curoff;
|
||||||
lastsize = cursize;
|
lastsize = cursize;
|
||||||
Datatype *cur = ct;
|
lastct = typegrp->getExactPiece(ct, curoff, cursize);
|
||||||
do {
|
|
||||||
lastct = cur;
|
|
||||||
cur = cur->getSubType(curoff,&curoff);
|
|
||||||
} while(cur != (Datatype *)0);
|
|
||||||
}
|
}
|
||||||
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
|
// Try to propagate the reference type into a varnode that is pointed to by that reference
|
||||||
if (0>lastct->typeOrder(*curvn->getTempType())) {
|
if (0>lastct->typeOrder(*curvn->getTempType())) {
|
||||||
|
@ -5314,6 +5313,7 @@ void ActionDatabase::universalAction(Architecture *conf)
|
||||||
actprop->addRule( new RuleAndDistribute("analysis") );
|
actprop->addRule( new RuleAndDistribute("analysis") );
|
||||||
actprop->addRule( new RuleAndCommute("analysis") );
|
actprop->addRule( new RuleAndCommute("analysis") );
|
||||||
actprop->addRule( new RuleAndPiece("analysis") );
|
actprop->addRule( new RuleAndPiece("analysis") );
|
||||||
|
actprop->addRule( new RuleAndZext("analysis") );
|
||||||
actprop->addRule( new RuleAndCompare("analysis") );
|
actprop->addRule( new RuleAndCompare("analysis") );
|
||||||
actprop->addRule( new RuleDoubleSub("analysis") );
|
actprop->addRule( new RuleDoubleSub("analysis") );
|
||||||
actprop->addRule( new RuleDoubleShift("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 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 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);
|
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);
|
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 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
|
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;
|
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
|
/// 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.
|
/// 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
|
/// In either case, attach the appropriate Symbol to the Varnode
|
||||||
|
@ -1037,9 +1019,11 @@ void Funcdata::linkProtoPartial(Varnode *vn)
|
||||||
Varnode *rootVn = PieceNode::findRoot(vn);
|
Varnode *rootVn = PieceNode::findRoot(vn);
|
||||||
if (rootVn == vn) return;
|
if (rootVn == vn) return;
|
||||||
|
|
||||||
Varnode *nameRep = rootVn->getHigh()->getNameRepresentative();
|
HighVariable *rootHigh = rootVn->getHigh();
|
||||||
|
Varnode *nameRep = rootHigh->getNameRepresentative();
|
||||||
Symbol *sym = linkSymbol(nameRep);
|
Symbol *sym = linkSymbol(nameRep);
|
||||||
if (sym == (Symbol *)0) return;
|
if (sym == (Symbol *)0) return;
|
||||||
|
rootHigh->establishGroupSymbolOffset();
|
||||||
SymbolEntry *entry = sym->getFirstWholeMap();
|
SymbolEntry *entry = sym->getFirstWholeMap();
|
||||||
vn->setSymbolEntry(entry);
|
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->isAddrTied()) return false;
|
||||||
if (high_in->isPersist()) 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 *symbolIn = high_in->getSymbol();
|
||||||
Symbol *symbolOut = high_out->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())
|
if (high_in->getSymbolOffset() != high_out->getSymbolOffset())
|
||||||
return false; // Map to different parts of same symbol
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,6 +173,10 @@ bool Merge::mergeTestAdjacent(HighVariable *high_out,HighVariable *high_in)
|
||||||
if (symbol != (Symbol *)0)
|
if (symbol != (Symbol *)0)
|
||||||
if (symbol->isIsolated())
|
if (symbol->isIsolated())
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,7 +248,7 @@ void Merge::mergeLinear(vector<HighVariable *> &highvec)
|
||||||
|
|
||||||
if (highvec.size() <= 1) return;
|
if (highvec.size() <= 1) return;
|
||||||
for(initer=highvec.begin();initer!=highvec.end();++initer)
|
for(initer=highvec.begin();initer!=highvec.end();++initer)
|
||||||
updateHigh(*initer);
|
testCache.updateHigh(*initer);
|
||||||
sort(highvec.begin(),highvec.end(),compareHighByBlock);
|
sort(highvec.begin(),highvec.end(),compareHighByBlock);
|
||||||
for(initer=highvec.begin();initer!=highvec.end();++initer) {
|
for(initer=highvec.begin();initer!=highvec.end();++initer) {
|
||||||
high = *initer;
|
high = *initer;
|
||||||
|
@ -927,11 +926,11 @@ void Merge::mergeMultiEntry(void)
|
||||||
}
|
}
|
||||||
if (mergeList.empty()) continue;
|
if (mergeList.empty()) continue;
|
||||||
HighVariable *high = mergeList[0]->getHigh();
|
HighVariable *high = mergeList[0]->getHigh();
|
||||||
updateHigh(high);
|
testCache.updateHigh(high);
|
||||||
for(int4 i=0;i<mergeList.size();++i) {
|
for(int4 i=0;i<mergeList.size();++i) {
|
||||||
HighVariable *newHigh = mergeList[i]->getHigh();
|
HighVariable *newHigh = mergeList[i]->getHigh();
|
||||||
if (newHigh == high) continue; // Varnodes already merged
|
if (newHigh == high) continue; // Varnodes already merged
|
||||||
updateHigh(newHigh);
|
testCache.updateHigh(newHigh);
|
||||||
if (!mergeTestRequired(high, newHigh)) {
|
if (!mergeTestRequired(high, newHigh)) {
|
||||||
symbol->setMergeProblems();
|
symbol->setMergeProblems();
|
||||||
newHigh->setUnmerged();
|
newHigh->setUnmerged();
|
||||||
|
@ -1005,7 +1004,7 @@ void Merge::mergeAdjacent(void)
|
||||||
high_in = vn2->getHigh();
|
high_in = vn2->getHigh();
|
||||||
if (!mergeTestAdjacent(high_out,high_in)) continue;
|
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);
|
merge(high_out,high_in,true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1232,7 +1231,7 @@ void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 po
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (count > 0 && domCopyIsNew) {
|
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;
|
vector<HighVariable *> multiCopy;
|
||||||
list<PcodeOp *>::const_iterator iter;
|
list<PcodeOp *>::const_iterator iter;
|
||||||
PcodeOp *op;
|
PcodeOp *op;
|
||||||
HighVariable *h1,*h2,*h3;
|
HighVariable *h1;
|
||||||
Varnode *v1,*v2,*v3;
|
Varnode *v1,*v2,*v3;
|
||||||
|
VariablePiece *p1,*p2,*p3;
|
||||||
int4 val;
|
int4 val;
|
||||||
|
|
||||||
for(iter=data.beginOpAlive();iter!=data.endOpAlive();++iter) {
|
for(iter=data.beginOpAlive();iter!=data.endOpAlive();++iter) {
|
||||||
|
@ -1465,41 +1465,42 @@ void Merge::markInternalCopies(void)
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case CPUI_PIECE: // Check if output is built out of pieces of itself
|
case CPUI_PIECE: // Check if output is built out of pieces of itself
|
||||||
h1 = op->getOut()->getHigh();
|
v1 = op->getOut();
|
||||||
h2 = op->getIn(0)->getHigh();
|
v2 = op->getIn(0);
|
||||||
h3 = op->getIn(1)->getHigh();
|
v3 = op->getIn(1);
|
||||||
if (!h2->isPartialOrAddrTied()) break;
|
p1 = v1->getHigh()->piece;
|
||||||
if (!h3->isPartialOrAddrTied()) break;
|
p2 = v2->getHigh()->piece;
|
||||||
v2 = h2->getPartialOrAddrTied();
|
p3 = v3->getHigh()->piece;
|
||||||
v3 = h3->getPartialOrAddrTied();
|
if (p1 == (VariablePiece *)0) break;
|
||||||
if (v2->isAddrTied()) {
|
if (p2 == (VariablePiece *)0) break;
|
||||||
if (!h1->isAddrTied()) break;
|
if (p3 == (VariablePiece *)0) break;
|
||||||
v1 = h1->getTiedVarnode();
|
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 {
|
else {
|
||||||
if (op->getIn(0) != v2) break;
|
if (p3->getOffset() != p1->getOffset()) break;
|
||||||
if (op->getIn(1) != v3) break;
|
if (p2->getOffset() != p1->getOffset() + v3->getSize()) break;
|
||||||
v1 = op->getOut();
|
|
||||||
}
|
}
|
||||||
if (v3->overlapJoin(*v1) != 0) break;
|
|
||||||
if (v2->overlapJoin(*v1) != v3->getSize()) break;
|
|
||||||
data.opMarkNonPrinting(op);
|
data.opMarkNonPrinting(op);
|
||||||
break;
|
break;
|
||||||
case CPUI_SUBPIECE:
|
case CPUI_SUBPIECE:
|
||||||
h1 = op->getOut()->getHigh();
|
v1 = op->getOut();
|
||||||
h2 = op->getIn(0)->getHigh();
|
v2 = op->getIn(0);
|
||||||
if (!h1->isPartialOrAddrTied()) break;
|
p1 = v1->getHigh()->piece;
|
||||||
v1 = h1->getPartialOrAddrTied();
|
p2 = v2->getHigh()->piece;
|
||||||
if (v1->isAddrTied()) {
|
if (p1 == (VariablePiece *)0) break;
|
||||||
if (!h2->isAddrTied()) break;
|
if (p2 == (VariablePiece *)0) break;
|
||||||
v2 = h2->getTiedVarnode();
|
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 {
|
else {
|
||||||
if (!h1->sameGroup(h2)) break;
|
if (p2->getOffset() + val != p1->getOffset()) break;
|
||||||
v2 = op->getIn(0);
|
|
||||||
}
|
}
|
||||||
val = op->getIn(1)->getOffset();
|
|
||||||
if (v1->overlapJoin(*v2) != val) break;
|
|
||||||
data.opMarkNonPrinting(op);
|
data.opMarkNonPrinting(op);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -1528,64 +1529,6 @@ void Merge::registerProtoPartialRoot(Varnode *vn)
|
||||||
protoPartial.push_back(vn->getDef());
|
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
|
/// \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
|
/// 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 (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,&testCache,isspeculative); // Do the actual merge
|
||||||
high1->merge(high2,isspeculative); // Do the actual merge
|
|
||||||
high1->updateCover(); // Update cover now so that updateHigh won't purge cached tests
|
high1->updateCover(); // Update cover now so that updateHigh won't purge cached tests
|
||||||
|
|
||||||
return true;
|
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
|
/// \brief Clear the any cached data from the last merge process
|
||||||
///
|
///
|
||||||
/// Free up resources used by cached intersection tests etc.
|
/// Free up resources used by cached intersection tests etc.
|
||||||
void Merge::clear(void)
|
void Merge::clear(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
highedgemap.clear();
|
testCache.clear();
|
||||||
copyTrims.clear();
|
copyTrims.clear();
|
||||||
protoPartial.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
|
/// \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
|
/// 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)
|
void Merge::inflate(Varnode *a,HighVariable *high)
|
||||||
|
|
||||||
{
|
{
|
||||||
updateHigh(a->getHigh());
|
testCache.updateHigh(a->getHigh());
|
||||||
updateHigh(high);
|
testCache.updateHigh(high);
|
||||||
for(int4 i=0;i<high->numInstances();++i) {
|
for(int4 i=0;i<high->numInstances();++i) {
|
||||||
Varnode *b = high->getInstance(i);
|
Varnode *b = high->getInstance(i);
|
||||||
a->cover->merge(*b->cover);
|
a->cover->merge(*b->cover);
|
||||||
|
@ -1825,7 +1596,7 @@ bool Merge::inflateTest(Varnode *a,HighVariable *high)
|
||||||
{
|
{
|
||||||
HighVariable *ahigh = a->getHigh();
|
HighVariable *ahigh = a->getHigh();
|
||||||
|
|
||||||
updateHigh(high);
|
testCache.updateHigh(high);
|
||||||
const Cover &highCover( high->internalCover ); // Only check for intersections with cover contributing to inflate
|
const Cover &highCover( high->internalCover ); // Only check for intersections with cover contributing to inflate
|
||||||
|
|
||||||
for(int4 i=0;i<ahigh->numInstances();++i) {
|
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) {
|
for(int4 i=0;i<tmplist.size();++i) {
|
||||||
HighVariable *a = tmplist[i];
|
HighVariable *a = tmplist[i];
|
||||||
if (intersection(a,high))
|
if (testCache.intersection(a,high))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
tmplist.push_back(high);
|
tmplist.push_back(high);
|
||||||
|
|
|
@ -21,21 +21,6 @@
|
||||||
|
|
||||||
#include "op.hh"
|
#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
|
/// \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.
|
/// 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
|
/// - Merging Varnodes that hold the same data-type
|
||||||
class Merge {
|
class Merge {
|
||||||
Funcdata &data; ///< The function containing the Varnodes to be merged
|
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 *> copyTrims; ///< COPY ops inserted to facilitate merges
|
||||||
vector<PcodeOp *> protoPartial; ///< Roots of unmapped CONCAT trees
|
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 mergeTestRequired(HighVariable *high_out,HighVariable *high_in);
|
||||||
static bool mergeTestAdjacent(HighVariable *high_out,HighVariable *high_in);
|
static bool mergeTestAdjacent(HighVariable *high_out,HighVariable *high_in);
|
||||||
static bool mergeTestSpeculative(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);
|
void collectCovering(vector<Varnode *> &vlist,HighVariable *high,PcodeOp *op);
|
||||||
bool collectCorrectable(const vector<Varnode *> &vlist,list<PcodeOp *> &oplist,vector<int4> &slotlist,
|
bool collectCorrectable(const vector<Varnode *> &vlist,list<PcodeOp *> &oplist,vector<int4> &slotlist,
|
||||||
PcodeOp *op);
|
PcodeOp *op);
|
||||||
void moveIntersectTests(HighVariable *high1,HighVariable *high2);
|
|
||||||
PcodeOp *allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trimOp);
|
PcodeOp *allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trimOp);
|
||||||
void snipReads(Varnode *vn,list<PcodeOp *> &markedop);
|
void snipReads(Varnode *vn,list<PcodeOp *> &markedop);
|
||||||
void snipIndirect(PcodeOp *indop);
|
void snipIndirect(PcodeOp *indop);
|
||||||
|
@ -122,7 +101,6 @@ class Merge {
|
||||||
public:
|
public:
|
||||||
Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function
|
Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function
|
||||||
void clear(void);
|
void clear(void);
|
||||||
bool intersection(HighVariable *a,HighVariable *b);
|
|
||||||
bool inflateTest(Varnode *a,HighVariable *high);
|
bool inflateTest(Varnode *a,HighVariable *high);
|
||||||
void inflate(Varnode *a,HighVariable *high);
|
void inflate(Varnode *a,HighVariable *high);
|
||||||
bool mergeTest(HighVariable *high,vector<HighVariable *> &tmplist);
|
bool mergeTest(HighVariable *high,vector<HighVariable *> &tmplist);
|
||||||
|
|
|
@ -1685,6 +1685,44 @@ int4 RuleAndPiece::applyOp(PcodeOp *op,Funcdata &data)
|
||||||
return 1;
|
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
|
/// \class RuleAndCompare
|
||||||
/// \brief Simplify INT_ZEXT and SUBPIECE in masked comparison: `zext(V) & c == 0 => V & (c & mask) == 0`
|
/// \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 void getOpList(vector<uint4> &oplist) const;
|
||||||
virtual int4 applyOp(PcodeOp *op,Funcdata &data);
|
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 {
|
class RuleAndCompare : public Rule {
|
||||||
public:
|
public:
|
||||||
RuleAndCompare(const string &g) : Rule(g, 0, "andcompare") {} ///< Constructor
|
RuleAndCompare(const string &g) : Rule(g, 0, "andcompare") {} ///< Constructor
|
||||||
|
|
|
@ -1894,6 +1894,67 @@ int4 TypeUnion::findCompatibleResolve(Datatype *ct) const
|
||||||
return -1;
|
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)
|
TypePartialUnion::TypePartialUnion(const TypePartialUnion &op)
|
||||||
: Datatype(op)
|
: Datatype(op)
|
||||||
{
|
{
|
||||||
|
@ -3370,6 +3431,14 @@ TypeStruct *TypeFactory::getTypeStruct(const string &n)
|
||||||
return (TypeStruct *) findAdd(tmp);
|
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.
|
/// The created union will be incomplete and have no fields. They must be added later.
|
||||||
/// \param n is the name of the union
|
/// \param n is the name of the union
|
||||||
/// \return the TypeUnion object
|
/// \return the TypeUnion object
|
||||||
|
@ -3495,16 +3564,23 @@ TypePointer *TypeFactory::getTypePointerWithSpace(Datatype *ptrTo,AddrSpace *spc
|
||||||
Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
|
Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
|
||||||
|
|
||||||
{
|
{
|
||||||
uintb newOff = offset;
|
Datatype *lastType = (Datatype *)0;
|
||||||
while(ct != (Datatype *)0 && ct->getSize() > size && ct->getMetatype() != TYPE_UNION) {
|
uintb curOff = offset;
|
||||||
ct = ct->getSubType(newOff, &newOff);
|
do {
|
||||||
}
|
if (ct->getSize() <= size) {
|
||||||
if (ct == (Datatype *)0 || ct->getSize() < size)
|
|
||||||
return (Datatype *)0;
|
|
||||||
if (ct->getSize() == size)
|
if (ct->getSize() == size)
|
||||||
return ct;
|
return ct; // Perfect size match
|
||||||
if (ct->getMetatype() == TYPE_UNION) // If we hit a containing union
|
break;
|
||||||
return getTypePartialUnion((TypeUnion *)ct, newOff, size);
|
}
|
||||||
|
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;
|
return (Datatype *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,23 +99,23 @@ enum sub_metatype {
|
||||||
SUB_VOID = 22, ///< Compare as a TYPE_VOID
|
SUB_VOID = 22, ///< Compare as a TYPE_VOID
|
||||||
SUB_SPACEBASE = 21, ///< Compare as a TYPE_SPACEBASE
|
SUB_SPACEBASE = 21, ///< Compare as a TYPE_SPACEBASE
|
||||||
SUB_UNKNOWN = 20, ///< Compare as a TYPE_UNKNOWN
|
SUB_UNKNOWN = 20, ///< Compare as a TYPE_UNKNOWN
|
||||||
SUB_INT_CHAR = 19, ///< Signed 1-byte character, sub-type of TYPE_INT
|
SUB_PARTIALSTRUCT = 19, ///< Compare as TYPE_PARTIALSTRUCT
|
||||||
SUB_UINT_CHAR = 18, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
SUB_INT_CHAR = 18, ///< Signed 1-byte character, sub-type of TYPE_INT
|
||||||
SUB_INT_PLAIN = 17, ///< Compare as a plain TYPE_INT
|
SUB_UINT_CHAR = 17, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
|
||||||
SUB_UINT_PLAIN = 16, ///< Compare as a plain TYPE_UINT
|
SUB_INT_PLAIN = 16, ///< Compare as a plain TYPE_INT
|
||||||
SUB_INT_ENUM = 15, ///< Signed enum, sub-type of TYPE_INT
|
SUB_UINT_PLAIN = 15, ///< Compare as a plain TYPE_UINT
|
||||||
SUB_UINT_ENUM = 14, ///< Unsigned enum, sub-type of TYPE_UINT
|
SUB_INT_ENUM = 14, ///< Signed enum, sub-type of TYPE_INT
|
||||||
SUB_INT_UNICODE = 13, ///< Signed wide character, sub-type of TYPE_INT
|
SUB_UINT_ENUM = 13, ///< Unsigned enum, sub-type of TYPE_UINT
|
||||||
SUB_UINT_UNICODE = 12, ///< Unsigned wide character, sub-type of TYPE_UINT
|
SUB_INT_UNICODE = 12, ///< Signed wide character, sub-type of TYPE_INT
|
||||||
SUB_BOOL = 11, ///< Compare as TYPE_BOOL
|
SUB_UINT_UNICODE = 11, ///< Unsigned wide character, sub-type of TYPE_UINT
|
||||||
SUB_CODE = 10, ///< Compare as TYPE_CODE
|
SUB_BOOL = 10, ///< Compare as TYPE_BOOL
|
||||||
SUB_FLOAT = 9, ///< Compare as TYPE_FLOAT
|
SUB_CODE = 9, ///< Compare as TYPE_CODE
|
||||||
SUB_PTRREL_UNK = 8, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
|
SUB_FLOAT = 8, ///< Compare as TYPE_FLOAT
|
||||||
SUB_PTR = 7, ///< Compare as TYPE_PTR
|
SUB_PTRREL_UNK = 7, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
|
||||||
SUB_PTRREL = 6, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
|
SUB_PTR = 6, ///< Compare as TYPE_PTR
|
||||||
SUB_PTR_STRUCT = 5, ///< Pointer into struct, sub-type of TYPE_PTR
|
SUB_PTRREL = 5, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
|
||||||
SUB_ARRAY = 4, ///< Compare as TYPE_ARRAY
|
SUB_PTR_STRUCT = 4, ///< Pointer into struct, sub-type of TYPE_PTR
|
||||||
SUB_PARTIALSTRUCT = 3, ///< Compare as TYPE_PARTIALSTRUCT
|
SUB_ARRAY = 3, ///< Compare as TYPE_ARRAY
|
||||||
SUB_STRUCT = 2, ///< Compare as TYPE_STRUCT
|
SUB_STRUCT = 2, ///< Compare as TYPE_STRUCT
|
||||||
SUB_UNION = 1, ///< Compare as TYPE_UNION
|
SUB_UNION = 1, ///< Compare as TYPE_UNION
|
||||||
SUB_PARTIALUNION = 0 ///< Compare as a TYPE_PARTIALUNION
|
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);
|
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
|
/// \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
|
/// 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(const TypePartialUnion &op); ///< Construct from another TypePartialUnion
|
||||||
TypePartialUnion(TypeUnion *contain,int4 off,int4 sz,Datatype *strip); ///< Constructor
|
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
|
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 const TypeField *findTruncation(int4 off,int4 sz,const PcodeOp *op,int4 slot,int4 &newoff) const;
|
||||||
virtual int4 numDepend(void) const;
|
virtual int4 numDepend(void) const;
|
||||||
virtual Datatype *getDepend(int4 index) 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
|
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
|
TypeArray *getTypeArray(int4 as,Datatype *ao); ///< Construct an array data-type
|
||||||
TypeStruct *getTypeStruct(const string &n); ///< Create an (empty) structure
|
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
|
TypeUnion *getTypeUnion(const string &n); ///< Create an (empty) union
|
||||||
TypePartialUnion *getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz); ///< Create a partial union
|
TypePartialUnion *getTypePartialUnion(TypeUnion *contain,int4 off,int4 sz); ///< Create a partial union
|
||||||
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
|
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
|
||||||
|
|
|
@ -43,12 +43,29 @@ void VariableGroup::addPiece(VariablePiece *piece)
|
||||||
piece->group = this;
|
piece->group = this;
|
||||||
if (!pieceSet.insert(piece).second)
|
if (!pieceSet.insert(piece).second)
|
||||||
throw LowlevelError("Duplicate VariablePiece");
|
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)
|
void VariableGroup::removePiece(VariablePiece *piece)
|
||||||
|
|
||||||
{
|
{
|
||||||
pieceSet.erase(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.
|
/// 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;
|
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.
|
/// If there are no remaining references to the old VariableGroup it is deleted.
|
||||||
/// \param newGroup is the new VariableGroup to transfer \b this to
|
/// \param newGroup is the new VariableGroup to transfer \b this to
|
||||||
void VariablePiece::transferGroup(VariableGroup *newGroup)
|
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
|
int4 diff = groupOffset - op2->groupOffset; // Add to op2, or subtract from this
|
||||||
if (diff > 0)
|
if (diff > 0)
|
||||||
op2->adjustOffset(diff);
|
op2->group->adjustOffsets(diff);
|
||||||
else if (diff < 0)
|
else if (diff < 0)
|
||||||
adjustOffset(-diff);
|
group->adjustOffsets(-diff);
|
||||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator iter = op2->group->pieceSet.begin();
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator iter = op2->group->pieceSet.begin();
|
||||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator enditer = op2->group->pieceSet.end();
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator enditer = op2->group->pieceSet.end();
|
||||||
while(iter != enditer) {
|
while(iter != enditer) {
|
||||||
VariablePiece *piece = *iter;
|
VariablePiece *piece = *iter;
|
||||||
|
++iter;
|
||||||
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator matchiter = group->pieceSet.find(piece);
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator matchiter = group->pieceSet.find(piece);
|
||||||
if (matchiter != group->pieceSet.end()) {
|
if (matchiter != group->pieceSet.end()) {
|
||||||
mergePairs.push_back((*matchiter)->high);
|
mergePairs.push_back((*matchiter)->high);
|
||||||
|
@ -228,15 +235,8 @@ void HighVariable::setSymbol(Varnode *vn) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
symbol = entry->getSymbol();
|
symbol = entry->getSymbol();
|
||||||
if (vn->isProtoPartial()) {
|
if (vn->isProtoPartial() && piece != (VariablePiece *)0) {
|
||||||
Varnode *rootVn = PieceNode::findRoot(vn);
|
symboloffset = piece->getOffset() + piece->getGroup()->getSymbolOffset();
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
else if (entry->isDynamic()) // Dynamic symbols (that aren't partials) match whole variable
|
else if (entry->isDynamic()) // Dynamic symbols (that aren't partials) match whole variable
|
||||||
symboloffset = -1;
|
symboloffset = -1;
|
||||||
|
@ -249,6 +249,8 @@ void HighVariable::setSymbol(Varnode *vn) const
|
||||||
symboloffset = vn->getAddr().overlapJoin(0,entry->getAddr(),symbol->getType()->getSize()) + entry->getOffset();
|
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
|
highflags &= ~((uint4)symboldirty); // We are no longer dirty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,9 +367,17 @@ void HighVariable::updateType(void) const
|
||||||
vn = getTypeRepresentative();
|
vn = getTypeRepresentative();
|
||||||
|
|
||||||
type = vn->getType();
|
type = vn->getType();
|
||||||
if (type->hasStripped() && type->getMetatype() != TYPE_PARTIALUNION)
|
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();
|
type = type->getStripped();
|
||||||
|
}
|
||||||
// Update lock flags
|
// Update lock flags
|
||||||
flags &= ~Varnode::typelock;
|
flags &= ~Varnode::typelock;
|
||||||
if (vn->isTypeLock())
|
if (vn->isTypeLock())
|
||||||
|
@ -469,21 +479,6 @@ Varnode *HighVariable::getNameRepresentative(void) const
|
||||||
return nameRepresentative;
|
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.
|
/// 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
|
/// \param vn is the given Varnode member to remove
|
||||||
void HighVariable::remove(Varnode *vn)
|
void HighVariable::remove(Varnode *vn)
|
||||||
|
@ -551,7 +546,7 @@ void HighVariable::groupWith(int4 off,HighVariable *hi2)
|
||||||
else if (hi2->piece == (VariablePiece *)0) {
|
else if (hi2->piece == (VariablePiece *)0) {
|
||||||
int4 hi2Off = piece->getOffset() - off;
|
int4 hi2Off = piece->getOffset() - off;
|
||||||
if (hi2Off < 0) {
|
if (hi2Off < 0) {
|
||||||
piece->adjustOffset(-hi2Off);
|
piece->getGroup()->adjustOffsets(-hi2Off);
|
||||||
hi2Off = 0;
|
hi2Off = 0;
|
||||||
}
|
}
|
||||||
if ((highflags & intersectdirty) == 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.
|
/// The lists of members are merged and the other HighVariable is deleted.
|
||||||
/// \param tv2 is the other HighVariable to merge into \b this
|
/// \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
|
/// \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.
|
/// 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.
|
/// In all cases, the other HighVariable is deleted.
|
||||||
/// \param tv2 is the other HighVariable to merge into \b this
|
/// \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
|
/// \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 (tv2 == this) return;
|
||||||
|
|
||||||
|
if (testCache != (HighIntersectTest *)0)
|
||||||
|
testCache->moveIntersectTests(this,tv2);
|
||||||
if (piece == (VariablePiece *)0 && tv2->piece == (VariablePiece *)0) {
|
if (piece == (VariablePiece *)0 && tv2->piece == (VariablePiece *)0) {
|
||||||
mergeInternal(tv2,isspeculative);
|
mergeInternal(tv2,isspeculative);
|
||||||
return;
|
return;
|
||||||
|
@ -638,16 +652,18 @@ void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Reaching here both HighVariables are part of a group
|
// Reaching here both HighVariables are part of a group
|
||||||
throw LowlevelError("Merging variables in separate groups not supported");
|
if (isspeculative)
|
||||||
// vector<HighVariable *> mergePairs;
|
throw LowlevelError("Trying speculatively merge variables in separate groups");
|
||||||
// piece->combineOtherGroup(tv2->piece, mergePairs);
|
vector<HighVariable *> mergePairs;
|
||||||
// for(int4 i=0;i<mergePairs.size();i+=2) {
|
piece->combineOtherGroup(tv2->piece, mergePairs);
|
||||||
// HighVariable *high1 = mergePairs[i];
|
for(int4 i=0;i<mergePairs.size();i+=2) {
|
||||||
// HighVariable *high2 = mergePairs[i+1];
|
HighVariable *high1 = mergePairs[i];
|
||||||
// // Need to deal with cached intersect tests herev
|
HighVariable *high2 = mergePairs[i+1];
|
||||||
// high1->mergeInternal(high2, isspeculative);
|
if (testCache != (HighIntersectTest *)0)
|
||||||
// }
|
testCache->moveIntersectTests(high1, high2);
|
||||||
// piece->markIntersectionDirty();
|
high1->mergeInternal(high2, isspeculative);
|
||||||
|
}
|
||||||
|
piece->markIntersectionDirty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// All Varnode objects are assigned a HighVariable, including those that don't get names like
|
/// 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;
|
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
|
/// \param encoder is the stream encoder
|
||||||
void HighVariable::encode(Encoder &encoder) const
|
void HighVariable::encode(Encoder &encoder) const
|
||||||
|
|
||||||
|
@ -780,6 +787,8 @@ void HighVariable::encode(Encoder &encoder) const
|
||||||
else if (!isPersist() && (symbol != (Symbol *)0)) {
|
else if (!isPersist() && (symbol != (Symbol *)0)) {
|
||||||
if (symbol->getCategory() == Symbol::function_parameter)
|
if (symbol->getCategory() == Symbol::function_parameter)
|
||||||
encoder.writeString(ATTRIB_CLASS, "param");
|
encoder.writeString(ATTRIB_CLASS, "param");
|
||||||
|
else if (symbol->getScope()->isGlobal())
|
||||||
|
encoder.writeString(ATTRIB_CLASS, "global");
|
||||||
else
|
else
|
||||||
encoder.writeString(ATTRIB_CLASS, "local");
|
encoder.writeString(ATTRIB_CLASS, "local");
|
||||||
}
|
}
|
||||||
|
@ -883,3 +892,233 @@ void HighVariable::verifyCover(void) const
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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
|
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:
|
public:
|
||||||
|
VariableGroup(void) { size = 0; symbolOffset = 0; }
|
||||||
bool empty(void) const { return pieceSet.empty(); } ///< Return \b true if \b this group has no pieces
|
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 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
|
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
|
/// \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 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 updateIntersections(void) const; ///< Calculate intersections with other pieces in the group
|
||||||
void updateCover(void) const; ///< Calculate extended cover based on intersections
|
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 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 setHigh(HighVariable *newHigh) { high = newHigh; } ///< Move ownership of \b this to another HighVariable
|
||||||
void combineOtherGroup(VariablePiece *op2,vector<HighVariable *> &mergePairs); ///< Combine two VariableGroups
|
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
|
/// \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
|
/// 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 Varnode;
|
||||||
friend class Merge;
|
friend class Merge;
|
||||||
friend class VariablePiece;
|
friend class VariablePiece;
|
||||||
|
friend class HighIntersectTest;
|
||||||
vector<Varnode *> inst; ///< The member Varnode objects making up \b this HighVariable
|
vector<Varnode *> inst; ///< The member Varnode objects making up \b this HighVariable
|
||||||
int4 numMergeClasses; ///< Number of different speculative merge classes in \b this
|
int4 numMergeClasses; ///< Number of different speculative merge classes in \b this
|
||||||
mutable uint4 highflags; ///< Dirtiness flags
|
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
|
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 remove(Varnode *vn); ///< Remove a member Varnode from \b this
|
||||||
void mergeInternal(HighVariable *tv2,bool isspeculative); ///< Merge another HighVariable into \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 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 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
|
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
|
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 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 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)
|
/// \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 *getInputVarnode(void) const; ///< Find (the) input member Varnode
|
||||||
Varnode *getTypeRepresentative(void) const; ///< Get a member Varnode with the strongest data-type
|
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 *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
|
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 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
|
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 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 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 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 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
|
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
|
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 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 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 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
|
void encode(Encoder &encoder) const; ///< Encode \b this variable to stream as a \<high> element
|
||||||
#ifdef MERGEMULTI_DEBUG
|
#ifdef MERGEMULTI_DEBUG
|
||||||
void verifyCover(void) const;
|
void verifyCover(void) const;
|
||||||
|
@ -219,6 +226,42 @@ public:
|
||||||
static int4 markExpression(Varnode *vn,vector<HighVariable *> &highList); ///< Mark and collect variables in expression
|
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
|
/// 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.
|
/// HighVariables it intersects with are marked as having a dirty extended cover.
|
||||||
inline void HighVariable::coverDirty(void) const
|
inline void HighVariable::coverDirty(void) const
|
||||||
|
|
|
@ -978,6 +978,9 @@ void MapState::gatherVarnodes(const Funcdata &fd)
|
||||||
if (vn->isFree()) continue;
|
if (vn->isFree()) continue;
|
||||||
uintb start = vn->getOffset();
|
uintb start = vn->getOffset();
|
||||||
Datatype *ct = vn->getType();
|
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
|
// Do not force Varnode flags on the entry
|
||||||
// as the flags were inherited from the previous
|
// as the flags were inherited from the previous
|
||||||
// (now obsolete) entry
|
// (now obsolete) entry
|
||||||
|
@ -1008,6 +1011,7 @@ void MapState::gatherHighs(const Funcdata &fd)
|
||||||
varvec.push_back(high);
|
varvec.push_back(high);
|
||||||
uintb start = vn->getOffset();
|
uintb start = vn->getOffset();
|
||||||
Datatype *ct = high->getType(); // Get type from high
|
Datatype *ct = high->getType(); // Get type from high
|
||||||
|
if (ct->getMetatype() == TYPE_PARTIALUNION) continue;
|
||||||
addRange(start,ct,0,RangeHint::fixed,-1);
|
addRange(start,ct,0,RangeHint::fixed,-1);
|
||||||
}
|
}
|
||||||
for(int4 i=0;i<varvec.size();++i)
|
for(int4 i=0;i<varvec.size();++i)
|
||||||
|
|
|
@ -1674,20 +1674,22 @@ uint4 VarnodeBank::overlapLoc(VarnodeLocSet::const_iterator iter,vector<VarnodeL
|
||||||
Varnode *vn = *iter;
|
Varnode *vn = *iter;
|
||||||
AddrSpace *spc = vn->getSpace();
|
AddrSpace *spc = vn->getSpace();
|
||||||
uintb off = vn->getOffset();
|
uintb off = vn->getOffset();
|
||||||
uintb maxoff = off + (vn->getSize() - 1);
|
uintb maxOff = off + (vn->getSize() - 1);
|
||||||
uint4 flags = vn->getFlags();
|
uint4 flags = vn->getFlags();
|
||||||
bounds.push_back(iter);
|
bounds.push_back(iter);
|
||||||
iter = endLoc(vn->getSize(),vn->getAddr(),Varnode::written);
|
iter = endLoc(vn->getSize(),vn->getAddr(),Varnode::written);
|
||||||
bounds.push_back(iter);
|
bounds.push_back(iter);
|
||||||
while(iter != loc_tree.end()) {
|
while(iter != loc_tree.end()) {
|
||||||
vn = *iter;
|
vn = *iter;
|
||||||
if (vn->getSpace() != spc || vn->getOffset() > maxoff)
|
if (vn->getSpace() != spc || vn->getOffset() > maxOff)
|
||||||
break;
|
break;
|
||||||
if (vn->isFree()) {
|
if (vn->isFree()) {
|
||||||
iter = endLoc(vn->getSize(),vn->getAddr(),0);
|
iter = endLoc(vn->getSize(),vn->getAddr(),0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
maxoff = vn->getOffset() + (vn->getSize() - 1);
|
uintb endOff = vn->getOffset() + (vn->getSize() - 1);
|
||||||
|
if (endOff > maxOff)
|
||||||
|
maxOff = endOff;
|
||||||
flags |= vn->getFlags();
|
flags |= vn->getFlags();
|
||||||
bounds.push_back(iter);
|
bounds.push_back(iter);
|
||||||
iter = endLoc(vn->getSize(),vn->getAddr(),Varnode::written);
|
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