mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 02:09:44 +02:00
Merge remote-tracking branch 'origin/GP-2845_PartialMerging'
This commit is contained in:
commit
a04f7fbb03
9 changed files with 818 additions and 77 deletions
|
@ -39,6 +39,7 @@ src/decompile/datatests/noforloop_globcall.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END|
|
src/decompile/datatests/noforloop_iterused.xml||GHIDRA||||END|
|
||||||
src/decompile/datatests/offsetarray.xml||GHIDRA||||END|
|
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/partialunion.xml||GHIDRA||||END|
|
src/decompile/datatests/partialunion.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|
|
||||||
|
|
|
@ -356,6 +356,10 @@ public:
|
||||||
VarnodeLocSet::const_iterator endLoc(int4 s,const Address &addr,const Address &pc,uintm uniq=~((uintm)0)) const {
|
VarnodeLocSet::const_iterator endLoc(int4 s,const Address &addr,const Address &pc,uintm uniq=~((uintm)0)) const {
|
||||||
return vbank.endLoc(s,addr,pc,uniq); }
|
return vbank.endLoc(s,addr,pc,uniq); }
|
||||||
|
|
||||||
|
/// \brief Given start, return maximal range of overlapping Varnodes
|
||||||
|
uint4 overlapLoc(VarnodeLocSet::const_iterator iter,vector<VarnodeLocSet::const_iterator> &bounds) const {
|
||||||
|
return vbank.overlapLoc(iter,bounds); }
|
||||||
|
|
||||||
/// \brief Start of all Varnodes sorted by definition address
|
/// \brief Start of all Varnodes sorted by definition address
|
||||||
VarnodeDefSet::const_iterator beginDef(void) const { return vbank.beginDef(); }
|
VarnodeDefSet::const_iterator beginDef(void) const { return vbank.beginDef(); }
|
||||||
|
|
||||||
|
|
|
@ -112,6 +112,10 @@ bool Merge::mergeTestRequired(HighVariable *high_out,HighVariable *high_in)
|
||||||
return false; // Map to different parts of same symbol
|
return false; // Map to different parts of same symbol
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -433,6 +437,7 @@ void Merge::eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort
|
||||||
map<int4,CoverBlock>::const_iterator iter,enditer;
|
map<int4,CoverBlock>::const_iterator iter,enditer;
|
||||||
Varnode *vn2;
|
Varnode *vn2;
|
||||||
int4 boundtype;
|
int4 boundtype;
|
||||||
|
int4 overlaptype;
|
||||||
bool insertop;
|
bool insertop;
|
||||||
|
|
||||||
for(oiter=vn->beginDescend();oiter!=vn->endDescend();++oiter) {
|
for(oiter=vn->beginDescend();oiter!=vn->endDescend();++oiter) {
|
||||||
|
@ -456,6 +461,13 @@ void Merge::eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort
|
||||||
if (vn2 == vn) continue;
|
if (vn2 == vn) continue;
|
||||||
boundtype = single.containVarnodeDef(vn2);
|
boundtype = single.containVarnodeDef(vn2);
|
||||||
if (boundtype == 0) continue;
|
if (boundtype == 0) continue;
|
||||||
|
overlaptype = vn->characterizeOverlap(*vn2);
|
||||||
|
if (overlaptype == 0) continue; // No overlap in storage
|
||||||
|
if (overlaptype == 1) { // Partial overlap
|
||||||
|
int4 off = (int4)(vn->getOffset() - vn2->getOffset());
|
||||||
|
if (vn->partialCopyShadow(vn2,off))
|
||||||
|
continue; // SUBPIECE shadow, not a new value
|
||||||
|
}
|
||||||
if (boundtype == 2) { // We have to resolve things defined at same place
|
if (boundtype == 2) { // We have to resolve things defined at same place
|
||||||
if (vn2->getDef() == (PcodeOp *)0) {
|
if (vn2->getDef() == (PcodeOp *)0) {
|
||||||
if (vn->getDef() == (PcodeOp *)0) {
|
if (vn->getDef() == (PcodeOp *)0) {
|
||||||
|
@ -483,7 +495,13 @@ void Merge::eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort
|
||||||
if (indop->code() != CPUI_INDIRECT) continue;
|
if (indop->code() != CPUI_INDIRECT) continue;
|
||||||
// The vn2 INDIRECT must be linked to the read op
|
// The vn2 INDIRECT must be linked to the read op
|
||||||
if (op != PcodeOp::getOpFromConst(indop->getIn(1)->getAddr())) continue;
|
if (op != PcodeOp::getOpFromConst(indop->getIn(1)->getAddr())) continue;
|
||||||
if (vn->copyShadow(indop->getIn(0))) continue; // If INDIRECT input shadows vn, don't consider as intersection
|
if (overlaptype != 1) {
|
||||||
|
if (vn->copyShadow(indop->getIn(0))) continue; // If INDIRECT input shadows vn, don't consider as intersection
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
int4 off = (int4)(vn->getOffset() - vn2->getOffset());
|
||||||
|
if (vn->partialCopyShadow(indop->getIn(0),off)) continue;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
insertop = true;
|
insertop = true;
|
||||||
break; // No need to continue iterating through varnodes in block
|
break; // No need to continue iterating through varnodes in block
|
||||||
|
@ -500,7 +518,7 @@ void Merge::eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort
|
||||||
///
|
///
|
||||||
/// The list of Varnodes to be merged is provided as a range in the main location sorted
|
/// The list of Varnodes to be merged is provided as a range in the main location sorted
|
||||||
/// container. Any discovered intersection is \b snipped by splitting data-flow for one of
|
/// container. Any discovered intersection is \b snipped by splitting data-flow for one of
|
||||||
/// the Varnodes into two or more flows, which involves insert new COPY ops and temporaries.
|
/// the Varnodes into two or more flows, which involves inserting new COPY ops and temporaries.
|
||||||
/// \param startiter is the beginning of the range of Varnodes with the same storage address
|
/// \param startiter is the beginning of the range of Varnodes with the same storage address
|
||||||
/// \param enditer is the end of the range
|
/// \param enditer is the end of the range
|
||||||
void Merge::unifyAddress(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::const_iterator enditer)
|
void Merge::unifyAddress(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::const_iterator enditer)
|
||||||
|
@ -513,14 +531,14 @@ void Merge::unifyAddress(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::
|
||||||
|
|
||||||
for(iter=startiter;iter!=enditer;++iter) {
|
for(iter=startiter;iter!=enditer;++iter) {
|
||||||
vn = *iter;
|
vn = *iter;
|
||||||
|
if (vn->isFree()) continue;
|
||||||
isectlist.push_back(vn);
|
isectlist.push_back(vn);
|
||||||
}
|
}
|
||||||
blocksort.resize(isectlist.size());
|
blocksort.resize(isectlist.size());
|
||||||
for(int4 i=0;i<isectlist.size();++i)
|
for(int4 i=0;i<isectlist.size();++i)
|
||||||
blocksort[i].set(isectlist[i]);
|
blocksort[i].set(isectlist[i]);
|
||||||
stable_sort(blocksort.begin(),blocksort.end());
|
stable_sort(blocksort.begin(),blocksort.end());
|
||||||
// BEWARE, its possible that eliminate_intersect
|
|
||||||
// will insert new varnodes in the original range
|
|
||||||
for(int4 i=0;i<isectlist.size();++i)
|
for(int4 i=0;i<isectlist.size();++i)
|
||||||
eliminateIntersect(isectlist[i],blocksort);
|
eliminateIntersect(isectlist[i],blocksort);
|
||||||
}
|
}
|
||||||
|
@ -534,23 +552,41 @@ void Merge::unifyAddress(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::
|
||||||
void Merge::mergeAddrTied(void)
|
void Merge::mergeAddrTied(void)
|
||||||
|
|
||||||
{
|
{
|
||||||
bool addrtied;
|
VarnodeLocSet::const_iterator startiter;
|
||||||
VarnodeLocSet::const_iterator startiter,enditer,iter;
|
vector<VarnodeLocSet::const_iterator> bounds;
|
||||||
for(startiter=data.beginLoc();startiter!=data.endLoc();) {
|
for(startiter=data.beginLoc();startiter!=data.endLoc();) {
|
||||||
addrtied = false;
|
AddrSpace *spc = (*startiter)->getSpace();
|
||||||
enditer = data.endLoc((*startiter)->getSize(),(*startiter)->getAddr(),Varnode::written);
|
spacetype type = spc->getType();
|
||||||
for(iter=startiter;iter!=enditer;++iter) {
|
if (type != IPTR_PROCESSOR && type != IPTR_SPACEBASE) {
|
||||||
if ((*iter)->isAddrTied()) {
|
startiter = data.endLoc(spc); // Skip over the whole space
|
||||||
addrtied = true;
|
continue;
|
||||||
break;
|
}
|
||||||
|
VarnodeLocSet::const_iterator finaliter = data.endLoc(spc);
|
||||||
|
while(startiter != finaliter) {
|
||||||
|
Varnode *vn = *startiter;
|
||||||
|
if (vn->isFree()) {
|
||||||
|
startiter = data.endLoc(vn->getSize(),vn->getAddr(),0); // Skip over any free Varnodes
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
bounds.clear();
|
||||||
|
uint4 flags = data.overlapLoc(startiter,bounds); // Collect maximally overlapping range of Varnodes
|
||||||
|
int4 max = bounds.size() - 1; // Index of last iterator
|
||||||
|
if ((flags & Varnode::addrtied) != 0) {
|
||||||
|
unifyAddress(startiter,bounds[max]);
|
||||||
|
for(int4 i=0;i<max;i+=2) { // Skip last iterator
|
||||||
|
mergeRangeMust(bounds[i],bounds[i+1]);
|
||||||
|
}
|
||||||
|
if (max > 2) {
|
||||||
|
Varnode *vn1 = *bounds[0];
|
||||||
|
for(int4 i=2;i<max;i+=2) {
|
||||||
|
Varnode *vn2 = *bounds[i];
|
||||||
|
int4 off = (int4)(vn2->getOffset() - vn1->getOffset());
|
||||||
|
vn2->getHigh()->groupWith(off, vn1->getHigh());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
startiter = bounds[max];
|
||||||
}
|
}
|
||||||
if (addrtied) {
|
|
||||||
unifyAddress(startiter,enditer); // unify_address may stick varnodes in our range
|
|
||||||
enditer = data.endLoc((*startiter)->getSize(),(*startiter)->getAddr(),Varnode::written);
|
|
||||||
mergeRangeMust(startiter,enditer);
|
|
||||||
}
|
|
||||||
startiter = data.endLoc((*startiter)->getSize(),(*startiter)->getAddr(),0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1396,23 +1432,15 @@ void Merge::markInternalCopies(void)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Perform low-level details of merging two HighVariables if possible
|
/// \brief Translate any intersection tests for \e high2 into tests for \e high1
|
||||||
///
|
///
|
||||||
/// This routine only fails (returning \b false) if there is a Cover intersection between
|
/// The two variables will be merged and \e high2, as an object, will be freed.
|
||||||
/// the two variables. Otherwise, all the Varnode instances from the second HighVariable
|
/// We update the cached intersection tests for \e high2 so that they will now apply to new merged \e high1
|
||||||
/// are merged into the first and its Cover is updated. The cached intersection tests are
|
/// \param high1 is the variable object being kept
|
||||||
/// also updated to reflect the merge.
|
/// \param high2 is the variable object being eliminated
|
||||||
/// \param high1 is the first HighVariable being merged
|
void Merge::moveIntersectTests(HighVariable *high1,HighVariable *high2)
|
||||||
/// \param high2 is the second
|
|
||||||
/// \param isspeculative is \b true if the desired merge is speculative
|
|
||||||
/// \return \b true if the merge was successful
|
|
||||||
bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
if (high1 == high2) return true; // Already merged
|
|
||||||
if (intersection(high1,high2)) return false;
|
|
||||||
|
|
||||||
// Translate any tests for high2 into tests for high1
|
|
||||||
vector<HighVariable *> yesinter; // Highs that high2 intersects
|
vector<HighVariable *> yesinter; // Highs that high2 intersects
|
||||||
vector<HighVariable *> nointer; // Highs that high2 does not intersect
|
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 iterfirst = highedgemap.lower_bound( HighEdge(high2,(HighVariable *)0) );
|
||||||
|
@ -1420,7 +1448,7 @@ bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
||||||
map<HighEdge,bool>::iterator iter;
|
map<HighEdge,bool>::iterator iter;
|
||||||
|
|
||||||
for(iter=iterfirst;iter!=iterlast;++iter) {
|
for(iter=iterfirst;iter!=iterlast;++iter) {
|
||||||
HighVariable *b = (*iter).first.b;
|
HighVariable *b = (*iter).first.b;
|
||||||
if (b == high1) continue;
|
if (b == high1) continue;
|
||||||
if ((*iter).second) // Save all high2's intersections
|
if ((*iter).second) // Save all high2's intersections
|
||||||
yesinter.push_back(b); // as they are still valid for the merge
|
yesinter.push_back(b); // as they are still valid for the merge
|
||||||
|
@ -1436,7 +1464,7 @@ bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
||||||
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
highedgemap.erase( HighEdge( (*iter).first.b, (*iter).first.a) );
|
||||||
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)
|
++iterlast; // Restore original range (with possibly new open endpoint)
|
||||||
|
|
||||||
highedgemap.erase(iterfirst,iterlast);
|
highedgemap.erase(iterfirst,iterlast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1454,13 +1482,33 @@ bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
||||||
vector<HighVariable *>::iterator titer;
|
vector<HighVariable *>::iterator titer;
|
||||||
for(titer=nointer.begin();titer!=nointer.end();++titer)
|
for(titer=nointer.begin();titer!=nointer.end();++titer)
|
||||||
(*titer)->clearMark();
|
(*titer)->clearMark();
|
||||||
// Reinsert high2's intersection==true tests for high1 now
|
|
||||||
|
// Reinsert high2's intersection==true tests for high1 now
|
||||||
for(titer=yesinter.begin();titer!=yesinter.end();++titer) {
|
for(titer=yesinter.begin();titer!=yesinter.end();++titer) {
|
||||||
highedgemap[ HighEdge(high1,*titer) ] = true;
|
highedgemap[ HighEdge(high1,*titer) ] = true;
|
||||||
highedgemap[ HighEdge(*titer,high1) ] = true;
|
highedgemap[ HighEdge(*titer,high1) ] = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Perform low-level details of merging two HighVariables if possible
|
||||||
|
///
|
||||||
|
/// This routine only fails (returning \b false) if there is a Cover intersection between
|
||||||
|
/// the two variables. Otherwise, all the Varnode instances from the second HighVariable
|
||||||
|
/// are merged into the first and its Cover is updated. The second variable is deleted.
|
||||||
|
/// The cached intersection tests are also updated to reflect the merge.
|
||||||
|
/// \param high1 is the first HighVariable being merged
|
||||||
|
/// \param high2 is the second
|
||||||
|
/// \param isspeculative is \b true if the desired merge is speculative
|
||||||
|
/// \return \b true if the merge was successful
|
||||||
|
bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (high1 == high2) return true; // Already merged
|
||||||
|
if (intersection(high1,high2)) return false;
|
||||||
|
|
||||||
|
moveIntersectTests(high1, high2);
|
||||||
high1->merge(high2,isspeculative); // Do the actual merge
|
high1->merge(high2,isspeculative); // Do the actual merge
|
||||||
high1->updateCover();
|
high1->updateCover(); // Update cover now so that updateHigh won't purge cached tests
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -1473,10 +1521,8 @@ bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
||||||
bool Merge::updateHigh(HighVariable *a)
|
bool Merge::updateHigh(HighVariable *a)
|
||||||
|
|
||||||
{
|
{
|
||||||
if ((a->highflags&HighVariable::coverdirty)==0) return true;
|
if (!a->isCoverDirty()) return true;
|
||||||
|
|
||||||
for(int4 i=0;i<a->numInstances();++i)
|
|
||||||
a->getInstance(i)->updateCover();
|
|
||||||
a->updateCover();
|
a->updateCover();
|
||||||
purgeHigh(a);
|
purgeHigh(a);
|
||||||
return false;
|
return false;
|
||||||
|
@ -1525,7 +1571,7 @@ bool Merge::intersection(HighVariable *a,HighVariable *b)
|
||||||
bool res = false;
|
bool res = false;
|
||||||
int4 blk;
|
int4 blk;
|
||||||
vector<int4> blockisect;
|
vector<int4> blockisect;
|
||||||
a->wholecover.intersectList(blockisect,b->wholecover,2);
|
a->getCover().intersectList(blockisect,b->getCover(),2);
|
||||||
for(blk=0;blk<blockisect.size();++blk) {
|
for(blk=0;blk<blockisect.size();++blk) {
|
||||||
if (blockIntersection(a,b,blockisect[blk])) {
|
if (blockIntersection(a,b,blockisect[blk])) {
|
||||||
res = true;
|
res = true;
|
||||||
|
@ -1537,6 +1583,56 @@ bool Merge::intersection(HighVariable *a,HighVariable *b)
|
||||||
return 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
|
/// \brief Test if two HighVariables intersect on a given BlockBasic
|
||||||
///
|
///
|
||||||
/// Intersections are checked only on the specified block.
|
/// Intersections are checked only on the specified block.
|
||||||
|
@ -1549,19 +1645,40 @@ bool Merge::blockIntersection(HighVariable *a,HighVariable *b,int4 blk)
|
||||||
{
|
{
|
||||||
vector<Varnode *> blist;
|
vector<Varnode *> blist;
|
||||||
|
|
||||||
for(int4 i=0;i<b->numInstances();++i) {
|
const Cover &aCover(a->getCover());
|
||||||
Varnode *vn = b->getInstance(i);
|
const Cover &bCover(b->getCover());
|
||||||
if (1<vn->getCover()->intersectByBlock(blk,a->wholecover))
|
gatherBlockVarnodes(b,blk,aCover,blist);
|
||||||
blist.push_back(vn);
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
for(int4 i=0;i<a->numInstances();++i) {
|
if (b->piece != (VariablePiece *)0) {
|
||||||
Varnode *vn = a->getInstance(i);
|
int4 bBaseOff = b->piece->getOffset();
|
||||||
if (2>vn->getCover()->intersectByBlock(blk,b->wholecover)) continue;
|
for(int4 i=0;i<b->piece->numIntersection();++i) {
|
||||||
for(int4 j=0;j<blist.size();++j) {
|
blist.clear();
|
||||||
Varnode *vn2 = blist[j];
|
const VariablePiece *bPiece = b->piece->getIntersection(i);
|
||||||
if (1<vn2->getCover()->intersectByBlock(blk,*vn->getCover()))
|
int4 bOff = bPiece->getOffset() - bBaseOff;
|
||||||
if (!vn->copyShadow(vn2))
|
gatherBlockVarnodes(bPiece->getHigh(),blk,aCover,blist);
|
||||||
return true;
|
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;
|
return false;
|
||||||
|
@ -1595,24 +1712,38 @@ void Merge::inflate(Varnode *a,HighVariable *high)
|
||||||
/// Varnode is not part of the HighVariable.
|
/// Varnode is not part of the HighVariable.
|
||||||
/// \param a is the given Varnode to inflate
|
/// \param a is the given Varnode to inflate
|
||||||
/// \param high is the HighVariable being propagated
|
/// \param high is the HighVariable being propagated
|
||||||
/// \return \b true if the Varnode can be inflated without intersection
|
/// \return \b true if inflating the Varnode causes an intersection
|
||||||
bool Merge::inflateTest(Varnode *a,HighVariable *high)
|
bool Merge::inflateTest(Varnode *a,HighVariable *high)
|
||||||
|
|
||||||
{
|
{
|
||||||
HighVariable *ahigh = a->getHigh();
|
HighVariable *ahigh = a->getHigh();
|
||||||
bool res = false;
|
|
||||||
|
|
||||||
updateHigh(high);
|
updateHigh(high);
|
||||||
|
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) {
|
||||||
Varnode *b = ahigh->getInstance(i);
|
Varnode *b = ahigh->getInstance(i);
|
||||||
if (b->copyShadow(a)) continue;
|
if (b->copyShadow(a)) continue; // Intersection with a or shadows of a is allowed
|
||||||
if (2==b->getCover()->intersect( high->wholecover )) {
|
if (2==b->getCover()->intersect( highCover )) {
|
||||||
res = true;
|
return true;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return res;
|
VariablePiece *piece = ahigh->piece;
|
||||||
|
if (piece != (VariablePiece *)0) {
|
||||||
|
piece->updateIntersections();
|
||||||
|
for(int4 i=0;i<piece->numIntersection();++i) {
|
||||||
|
const VariablePiece *otherPiece = piece->getIntersection(i);
|
||||||
|
HighVariable *otherHigh = otherPiece->getHigh();
|
||||||
|
int4 off = otherPiece->getOffset() - piece->getOffset();
|
||||||
|
for(int4 i=0;i<otherHigh->numInstances();++i) {
|
||||||
|
Varnode *b = otherHigh->getInstance(i);
|
||||||
|
if (b->partialCopyShadow(a, off)) continue; // Intersection with partial shadow of a is allowed
|
||||||
|
if (2==b->getCover()->intersect( highCover ))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Test for intersections between a given HighVariable and a list of other HighVariables
|
/// \brief Test for intersections between a given HighVariable and a list of other HighVariables
|
||||||
|
|
|
@ -83,6 +83,8 @@ class Merge {
|
||||||
vector<PcodeOp *> copyTrims; ///< COPY ops inserted to facilitate merges
|
vector<PcodeOp *> copyTrims; ///< COPY ops inserted to facilitate merges
|
||||||
bool updateHigh(HighVariable *a); ///< Make sure given HighVariable's Cover is up-to-date
|
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
|
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);
|
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);
|
||||||
|
@ -96,6 +98,7 @@ 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);
|
||||||
|
@ -148,7 +151,7 @@ public:
|
||||||
inline bool Merge::compareHighByBlock(const HighVariable *a,const HighVariable *b)
|
inline bool Merge::compareHighByBlock(const HighVariable *a,const HighVariable *b)
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 result = a->wholecover.compareTo(b->wholecover);
|
int4 result = a->getCover().compareTo(b->getCover());
|
||||||
if ( result == 0 ) {
|
if ( result == 0 ) {
|
||||||
Varnode *v1 = a->getInstance( 0 );
|
Varnode *v1 = a->getInstance( 0 );
|
||||||
Varnode *v2 = b->getInstance( 0 );
|
Varnode *v2 = b->getInstance( 0 );
|
||||||
|
|
|
@ -23,6 +23,170 @@ AttributeId ATTRIB_SYMREF = AttributeId("symref",68);
|
||||||
|
|
||||||
ElementId ELEM_HIGH = ElementId("high",82);
|
ElementId ELEM_HIGH = ElementId("high",82);
|
||||||
|
|
||||||
|
/// Compare by offset within the group, then by size.
|
||||||
|
/// \param op2 is the other piece to compare with \b this
|
||||||
|
/// \return \b true if \b this should be ordered before the other piece
|
||||||
|
bool VariableGroup::PieceCompareByOffset::operator()(const VariablePiece *a,const VariablePiece *b) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (a->getOffset() != b->getOffset())
|
||||||
|
return (a->getOffset() < b->getOffset());
|
||||||
|
return (a->getSize() < b->getSize());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The VariablePiece takes partial ownership of \b this, via refCount.
|
||||||
|
/// \param piece is the new piece to add
|
||||||
|
void VariableGroup::addPiece(VariablePiece *piece)
|
||||||
|
|
||||||
|
{
|
||||||
|
piece->group = this;
|
||||||
|
if (!pieceSet.insert(piece).second)
|
||||||
|
throw LowlevelError("Duplicate VariablePiece");
|
||||||
|
}
|
||||||
|
|
||||||
|
void VariableGroup::removePiece(VariablePiece *piece)
|
||||||
|
|
||||||
|
{
|
||||||
|
pieceSet.erase(piece);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct piece given a HighVariable and its position within the whole.
|
||||||
|
/// If \b this is the first piece in the group, allocate a new VariableGroup object.
|
||||||
|
/// \param h is the given HighVariable to treat as a piece
|
||||||
|
/// \param offset is the byte offset of the piece within the whole
|
||||||
|
/// \param grp is another HighVariable in the whole, or null if \b this is the first piece
|
||||||
|
VariablePiece::VariablePiece(HighVariable *h,int4 offset,HighVariable *grp)
|
||||||
|
|
||||||
|
{
|
||||||
|
high = h;
|
||||||
|
groupOffset = offset;
|
||||||
|
size = h->getInstance(0)->getSize();
|
||||||
|
if (grp != (HighVariable *)0)
|
||||||
|
group = grp->piece->getGroup();
|
||||||
|
else
|
||||||
|
group = new VariableGroup();
|
||||||
|
group->addPiece(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
VariablePiece::~VariablePiece(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
group->removePiece(this);
|
||||||
|
if (group->empty())
|
||||||
|
delete group;
|
||||||
|
else
|
||||||
|
markIntersectionDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
void VariablePiece::markIntersectionDirty(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::const_iterator iter;
|
||||||
|
|
||||||
|
for(iter=group->pieceSet.begin();iter!=group->pieceSet.end();++iter)
|
||||||
|
(*iter)->high->highflags |= (HighVariable::intersectdirty | HighVariable::extendcoverdirty);
|
||||||
|
}
|
||||||
|
|
||||||
|
void VariablePiece::markExtendCoverDirty(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((high->highflags & HighVariable::intersectdirty)!=0)
|
||||||
|
return; // intersection list itself is dirty, extended covers will be recomputed anyway
|
||||||
|
for(int4 i=0;i<intersection.size();++i) {
|
||||||
|
intersection[i]->high->highflags |= HighVariable::extendcoverdirty;
|
||||||
|
}
|
||||||
|
high->highflags |= HighVariable::extendcoverdirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Compute list of exactly the HighVariable pieces that intersect with \b this.
|
||||||
|
void VariablePiece::updateIntersections(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((high->highflags & HighVariable::intersectdirty)==0) return;
|
||||||
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::const_iterator iter;
|
||||||
|
|
||||||
|
int4 endOffset = groupOffset + size;
|
||||||
|
intersection.clear();
|
||||||
|
for(iter=group->pieceSet.begin();iter!=group->pieceSet.end();++iter) {
|
||||||
|
VariablePiece *otherPiece = *iter;
|
||||||
|
if (otherPiece == this) continue;
|
||||||
|
if (endOffset <= otherPiece->groupOffset) continue;
|
||||||
|
int4 otherEndOffset = otherPiece->groupOffset + otherPiece->size;
|
||||||
|
if (groupOffset >= otherEndOffset) continue;
|
||||||
|
intersection.push_back(otherPiece);
|
||||||
|
}
|
||||||
|
high->highflags &= ~(uint4)HighVariable::intersectdirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Union internal covers of all pieces intersecting with \b this.
|
||||||
|
void VariablePiece::updateCover(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((high->highflags & (HighVariable::coverdirty | HighVariable::extendcoverdirty))==0) return;
|
||||||
|
high->updateInternalCover();
|
||||||
|
cover = high->internalCover;
|
||||||
|
for(int4 i=0;i<intersection.size();++i) {
|
||||||
|
const HighVariable *high = intersection[i]->high;
|
||||||
|
high->updateInternalCover();
|
||||||
|
cover.merge(high->internalCover);
|
||||||
|
}
|
||||||
|
high->highflags &= ~(uint4)HighVariable::extendcoverdirty;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \param amt is the given amout to add to offset
|
||||||
|
void VariablePiece::adjustOffset(int4 amt)
|
||||||
|
|
||||||
|
{
|
||||||
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator iter;
|
||||||
|
|
||||||
|
for(iter=group->pieceSet.begin();iter!=group->pieceSet.end();++iter) {
|
||||||
|
(*iter)->groupOffset += amt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// If there are no remaining references to the old VariableGroup it is deleted.
|
||||||
|
/// \param newGropu is the new VariableGroup to transfer \b this to
|
||||||
|
void VariablePiece::transferGroup(VariableGroup *newGroup)
|
||||||
|
|
||||||
|
{
|
||||||
|
group->removePiece(this);
|
||||||
|
if (group->empty())
|
||||||
|
delete group;
|
||||||
|
newGroup->addPiece(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Combine the VariableGroup associated with the given other VariablePiece and the VariableGroup of \b this
|
||||||
|
/// into one group. Combining in this way requires pieces of the same size and offset to be merged. This
|
||||||
|
/// method does not do the merging but passes back a list of HighVariable pairs that need to be merged.
|
||||||
|
/// The first element in the pair will have its VariablePiece in the new group, and the second element
|
||||||
|
/// will have its VariablePiece freed in preparation for the merge.
|
||||||
|
/// Offsets are adjusted so that \b this and the given other piece have the same offset;
|
||||||
|
/// \param op2 is the given other VariablePiece
|
||||||
|
/// \param mergePairs passes back the collection of HighVariable pairs that must be merged
|
||||||
|
void VariablePiece::combineOtherGroup(VariablePiece *op2,vector<HighVariable *> &mergePairs)
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 diff = groupOffset - op2->groupOffset; // Add to op2, or subtract from this
|
||||||
|
if (diff > 0)
|
||||||
|
op2->adjustOffset(diff);
|
||||||
|
else if (diff < 0)
|
||||||
|
adjustOffset(-diff);
|
||||||
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator iter = op2->group->pieceSet.begin();
|
||||||
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator enditer = op2->group->pieceSet.end();
|
||||||
|
while(iter != enditer) {
|
||||||
|
VariablePiece *piece = *iter;
|
||||||
|
set<VariablePiece *,VariableGroup::PieceCompareByOffset>::iterator matchiter = group->pieceSet.find(piece);
|
||||||
|
if (matchiter != group->pieceSet.end()) {
|
||||||
|
mergePairs.push_back((*matchiter)->high);
|
||||||
|
mergePairs.push_back(piece->high);
|
||||||
|
piece->high->piece = (VariablePiece *)0; // Detach HighVariable from its original VariablePiece
|
||||||
|
delete piece;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
piece->transferGroup(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The new instance starts off with no associate Symbol and all properties marked as \e dirty.
|
/// The new instance starts off with no associate Symbol and all properties marked as \e dirty.
|
||||||
/// \param vn is the single Varnode member
|
/// \param vn is the single Varnode member
|
||||||
HighVariable::HighVariable(Varnode *vn)
|
HighVariable::HighVariable(Varnode *vn)
|
||||||
|
@ -32,6 +196,7 @@ HighVariable::HighVariable(Varnode *vn)
|
||||||
highflags = flagsdirty | namerepdirty | typedirty | coverdirty;
|
highflags = flagsdirty | namerepdirty | typedirty | coverdirty;
|
||||||
flags = 0;
|
flags = 0;
|
||||||
type = (Datatype *)0;
|
type = (Datatype *)0;
|
||||||
|
piece = (VariablePiece *)0;
|
||||||
symbol = (Symbol *)0;
|
symbol = (Symbol *)0;
|
||||||
nameRepresentative = (Varnode *)0;
|
nameRepresentative = (Varnode *)0;
|
||||||
symboloffset = -1;
|
symboloffset = -1;
|
||||||
|
@ -41,6 +206,13 @@ HighVariable::HighVariable(Varnode *vn)
|
||||||
setSymbol(vn);
|
setSymbol(vn);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HighVariable::~HighVariable(void)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (piece != (VariablePiece *)0)
|
||||||
|
delete piece;
|
||||||
|
}
|
||||||
|
|
||||||
/// The given Varnode \b must be a member and \b must have a non-null SymbolEntry
|
/// The given Varnode \b must be a member and \b must have a non-null SymbolEntry
|
||||||
void HighVariable::setSymbol(Varnode *vn) const
|
void HighVariable::setSymbol(Varnode *vn) const
|
||||||
|
|
||||||
|
@ -82,19 +254,41 @@ void HighVariable::setSymbolReference(Symbol *sym,int4 off)
|
||||||
highflags &= ~((uint4)symboldirty);
|
highflags &= ~((uint4)symboldirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HighVariable::transferPiece(HighVariable *tv2)
|
||||||
|
|
||||||
|
{
|
||||||
|
piece = tv2->piece;
|
||||||
|
tv2->piece = (VariablePiece *)0;
|
||||||
|
piece->setHigh(this);
|
||||||
|
highflags |= (tv2->highflags & (intersectdirty | extendcoverdirty));
|
||||||
|
tv2->highflags &= ~(uint4)(intersectdirty | extendcoverdirty);
|
||||||
|
}
|
||||||
|
|
||||||
/// Only update if the cover is marked as \e dirty.
|
/// Only update if the cover is marked as \e dirty.
|
||||||
/// Merge the covers of all Varnode instances.
|
/// Merge the covers of all Varnode instances.
|
||||||
|
void HighVariable::updateInternalCover(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if ((highflags & coverdirty) != 0) {
|
||||||
|
internalCover.clear();
|
||||||
|
if (inst[0]->hasCover()) {
|
||||||
|
for(int4 i = 0;i < inst.size();++i)
|
||||||
|
internalCover.merge(*inst[i]->getCover());
|
||||||
|
}
|
||||||
|
highflags &= ~coverdirty;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This is \b only called by the Merge class which knows when to call it properly.
|
/// This is \b only called by the Merge class which knows when to call it properly.
|
||||||
void HighVariable::updateCover(void) const
|
void HighVariable::updateCover(void) const
|
||||||
|
|
||||||
{
|
{
|
||||||
if ((highflags & coverdirty)==0) return; // Cover info is upto date
|
if (piece == (VariablePiece *)0)
|
||||||
highflags &= ~coverdirty;
|
updateInternalCover();
|
||||||
|
else {
|
||||||
wholecover.clear();
|
piece->updateIntersections();
|
||||||
if (!inst[0]->hasCover()) return;
|
piece->updateCover();
|
||||||
for(int4 i=0;i<inst.size();++i)
|
}
|
||||||
wholecover.merge(*inst[i]->getCover());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Only update if flags are marked as \e dirty.
|
/// Only update if flags are marked as \e dirty.
|
||||||
|
@ -275,6 +469,8 @@ void HighVariable::remove(Varnode *vn)
|
||||||
highflags |= (flagsdirty|namerepdirty|coverdirty|typedirty);
|
highflags |= (flagsdirty|namerepdirty|coverdirty|typedirty);
|
||||||
if (vn->getSymbolEntry() != (SymbolEntry *)0)
|
if (vn->getSymbolEntry() != (SymbolEntry *)0)
|
||||||
highflags |= symboldirty;
|
highflags |= symboldirty;
|
||||||
|
if (piece != (VariablePiece *)0)
|
||||||
|
piece->markExtendCoverDirty();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,16 +500,49 @@ void HighVariable::finalizeDatatype(Datatype *tp)
|
||||||
highflags |= type_finalized;
|
highflags |= type_finalized;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// If one of the HighVariables is already in a group, the other HighVariable is added to this group.
|
||||||
|
/// \param off is the relative byte offset of \b this with the other HighVariable
|
||||||
|
/// \param hi2 is the other HighVariable
|
||||||
|
void HighVariable::groupWith(int4 off,HighVariable *hi2)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (piece == (VariablePiece *)0 && hi2->piece == (VariablePiece *)0) {
|
||||||
|
hi2->piece = new VariablePiece(hi2,0);
|
||||||
|
piece = new VariablePiece(this,off,hi2);
|
||||||
|
hi2->piece->markIntersectionDirty();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (piece == (VariablePiece *)0) {
|
||||||
|
if ((hi2->highflags & intersectdirty) == 0)
|
||||||
|
hi2->piece->markIntersectionDirty();
|
||||||
|
highflags |= intersectdirty | extendcoverdirty;
|
||||||
|
off += hi2->piece->getOffset();
|
||||||
|
piece = new VariablePiece(this,off,hi2);
|
||||||
|
}
|
||||||
|
else if (hi2->piece == (VariablePiece *)0) {
|
||||||
|
int4 hi2Off = piece->getOffset() - off;
|
||||||
|
if (hi2Off < 0) {
|
||||||
|
piece->adjustOffset(-hi2Off);
|
||||||
|
hi2Off = 0;
|
||||||
|
}
|
||||||
|
if ((highflags & intersectdirty) == 0)
|
||||||
|
piece->markIntersectionDirty();
|
||||||
|
hi2->highflags |= intersectdirty | extendcoverdirty;
|
||||||
|
hi2->piece = new VariablePiece(hi2,hi2Off,this);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw LowlevelError("Cannot group HighVariables that are already grouped");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
void HighVariable::mergeInternal(HighVariable *tv2,bool isspeculative)
|
||||||
|
|
||||||
{
|
{
|
||||||
int4 i;
|
int4 i;
|
||||||
|
|
||||||
if (tv2 == this) return;
|
|
||||||
|
|
||||||
highflags |= (flagsdirty|namerepdirty|typedirty);
|
highflags |= (flagsdirty|namerepdirty|typedirty);
|
||||||
if (tv2->symbol != (Symbol *)0) { // Check if we inherit a Symbol
|
if (tv2->symbol != (Symbol *)0) { // Check if we inherit a Symbol
|
||||||
if ((tv2->highflags & symboldirty)==0) {
|
if ((tv2->highflags & symboldirty)==0) {
|
||||||
|
@ -344,13 +573,54 @@ void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
||||||
tv2->inst.clear();
|
tv2->inst.clear();
|
||||||
|
|
||||||
if (((highflags&coverdirty)==0)&&((tv2->highflags&coverdirty)==0))
|
if (((highflags&coverdirty)==0)&&((tv2->highflags&coverdirty)==0))
|
||||||
wholecover.merge(tv2->wholecover);
|
internalCover.merge(tv2->internalCover);
|
||||||
else
|
else
|
||||||
highflags |= coverdirty;
|
highflags |= coverdirty;
|
||||||
|
|
||||||
delete tv2;
|
delete tv2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The HighVariables are merged internally as with mergeInternal. If \b this is part of a VariableGroup,
|
||||||
|
/// extended covers of the group may be affected. If both HighVariables are part of separate groups,
|
||||||
|
/// the groups are combined into one, which may induce additional HighVariable pairs within the group to be merged.
|
||||||
|
/// In all cases, the other HighVariable is deleted.
|
||||||
|
/// \param tv2 is the other HighVariable to merge into \b this
|
||||||
|
/// \param isspeculative is \b true to keep the new members in separate \e merge classes
|
||||||
|
void HighVariable::merge(HighVariable *tv2,bool isspeculative)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (tv2 == this) return;
|
||||||
|
|
||||||
|
if (piece == (VariablePiece *)0 && tv2->piece == (VariablePiece *)0) {
|
||||||
|
mergeInternal(tv2,isspeculative);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (tv2->piece == (VariablePiece *)0) {
|
||||||
|
// Keep group that this is already in
|
||||||
|
piece->markExtendCoverDirty();
|
||||||
|
mergeInternal(tv2,isspeculative);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (piece == (VariablePiece *)0) {
|
||||||
|
// Move ownership of the VariablePiece object from the HighVariable that will be freed
|
||||||
|
transferPiece(tv2);
|
||||||
|
piece->markExtendCoverDirty();
|
||||||
|
mergeInternal(tv2,isspeculative);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Reaching here both HighVariables are part of a group
|
||||||
|
throw LowlevelError("Merging variables in separate groups not supported");
|
||||||
|
// vector<HighVariable *> mergePairs;
|
||||||
|
// piece->combineOtherGroup(tv2->piece, mergePairs);
|
||||||
|
// for(int4 i=0;i<mergePairs.size();i+=2) {
|
||||||
|
// HighVariable *high1 = mergePairs[i];
|
||||||
|
// HighVariable *high2 = mergePairs[i+1];
|
||||||
|
// // Need to deal with cached intersect tests herev
|
||||||
|
// high1->mergeInternal(high2, isspeculative);
|
||||||
|
// }
|
||||||
|
// piece->markIntersectionDirty();
|
||||||
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
/// indirect variables, constants, and annotations. Determine if \b this, as inherited from its
|
/// indirect variables, constants, and annotations. Determine if \b this, as inherited from its
|
||||||
/// member Varnodes, can have a name.
|
/// member Varnodes, can have a name.
|
||||||
|
|
|
@ -29,6 +29,63 @@ extern AttributeId ATTRIB_SYMREF; ///< Marshaling attribute "symref"
|
||||||
|
|
||||||
extern ElementId ELEM_HIGH; ///< Marshaling element \<high>
|
extern ElementId ELEM_HIGH; ///< Marshaling element \<high>
|
||||||
|
|
||||||
|
class HighVariable; ///< Forward declaration
|
||||||
|
class VariablePiece; ///< Forward declaration
|
||||||
|
|
||||||
|
/// \brief A collection of HighVariable objects that overlap
|
||||||
|
///
|
||||||
|
/// A HighVariable represents a variable or partial variable that is manipulated as a unit by the (de)compiler.
|
||||||
|
/// A formal Symbol may be manipulated using multiple HighVariables that in principal can overlap. For a set of
|
||||||
|
/// HighVariable objects that mutually overlap, a VariableGroup is a central access point for information about
|
||||||
|
/// the intersections. The information is used in particular to extend HighVariable Cover objects to take into
|
||||||
|
/// account the intersections.
|
||||||
|
class VariableGroup {
|
||||||
|
friend class VariablePiece;
|
||||||
|
|
||||||
|
/// \brief Compare two VariablePiece pointers by offset then by size
|
||||||
|
struct PieceCompareByOffset {
|
||||||
|
bool operator()(const VariablePiece *a,const VariablePiece *b) const; ///< Comparison operator
|
||||||
|
};
|
||||||
|
|
||||||
|
set<VariablePiece *,PieceCompareByOffset> pieceSet; ///< The set of VariablePieces making up \b this group
|
||||||
|
public:
|
||||||
|
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 removePiece(VariablePiece *piece); ///< Remove a piece from \b this group
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Information about how a HighVariable fits into a larger group or Symbol
|
||||||
|
///
|
||||||
|
/// This is an extension to a HighVariable object that is assigned if the HighVariable is part of a
|
||||||
|
/// group of mutually overlapping HighVariables. It describes the overlaps and how they affect the HighVariable Cover.
|
||||||
|
class VariablePiece {
|
||||||
|
friend class VariableGroup;
|
||||||
|
VariableGroup *group; ///< Group to which \b this piece belongs
|
||||||
|
HighVariable *high; ///< HighVariable owning \b this piece
|
||||||
|
int4 groupOffset; ///< Byte offset of \b this piece within the group
|
||||||
|
int4 size; ///< Number of bytes in \b this piece
|
||||||
|
mutable vector<const VariablePiece *> intersection; ///< List of VariablePieces \b this piece intersects with
|
||||||
|
mutable Cover cover; ///< Extended cover for the piece, taking into account intersections
|
||||||
|
public:
|
||||||
|
VariablePiece(HighVariable *h,int4 offset,HighVariable *grp=(HighVariable *)0);
|
||||||
|
~VariablePiece(void); ///< Destructor
|
||||||
|
HighVariable *getHigh(void) const { return high; } ///< Get the HighVariable associate with \b this piece
|
||||||
|
VariableGroup *getGroup(void) const { return group; } ///< Get the central group
|
||||||
|
int4 getOffset(void) const { return groupOffset; } ///< Get the offset of \b this within its group
|
||||||
|
int4 getSize(void) const { return size; } ///< Return the number of bytes in \b this piece.
|
||||||
|
const Cover &getCover(void) const { return cover; } ///< Get the cover associated with \b this piece.
|
||||||
|
int4 numIntersection(void) const { return intersection.size(); } ///< Get number of pieces \b this intersects with
|
||||||
|
const VariablePiece *getIntersection(int4 i) const { return intersection[i]; } ///< Get i-th piece \b this intersects with
|
||||||
|
void markIntersectionDirty(void) const; ///< Mark all pieces as needing intersection recalculation
|
||||||
|
void markExtendCoverDirty(void) const; ///< Mark all intersecting pieces as having a dirty extended cover
|
||||||
|
void updateIntersections(void) const; ///< Calculate intersections with other pieces in the group
|
||||||
|
void updateCover(void) const; ///< Calculate extended cover based on intersections
|
||||||
|
void adjustOffset(int4 amt); ///< Adjust every piece's offset by the given amount
|
||||||
|
void transferGroup(VariableGroup *newGroup); ///< Transfer \b this piece to another VariableGroup
|
||||||
|
void setHigh(HighVariable *newHigh) { high = newHigh; } ///< Move ownership of \b this to another HighVariable
|
||||||
|
void combineOtherGroup(VariablePiece *op2,vector<HighVariable *> &mergePairs); ///< Combine two VariableGroups
|
||||||
|
};
|
||||||
|
|
||||||
/// \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
|
||||||
|
@ -57,23 +114,28 @@ public:
|
||||||
copy_in1 = 0x20, ///< There exists at least 1 COPY into \b this HighVariable from other HighVariables
|
copy_in1 = 0x20, ///< There exists at least 1 COPY into \b this HighVariable from other HighVariables
|
||||||
copy_in2 = 0x40, ///< There exists at least 2 COPYs into \b this HighVariable from other HighVariables
|
copy_in2 = 0x40, ///< There exists at least 2 COPYs into \b this HighVariable from other HighVariables
|
||||||
type_finalized = 0x80, ///< Set if a final data-type is locked in and dirtying is disabled
|
type_finalized = 0x80, ///< Set if a final data-type is locked in and dirtying is disabled
|
||||||
unmerged = 0x100 ///< Set if part of a multi-entry Symbol but did not get merged with other SymbolEntrys
|
unmerged = 0x100, ///< Set if part of a multi-entry Symbol but did not get merged with other SymbolEntrys
|
||||||
|
intersectdirty = 0x200, ///< Set if intersections with other HighVariables needs to be recomputed
|
||||||
|
extendcoverdirty = 0x400 ///< Set if extended cover needs to be recomputed
|
||||||
};
|
};
|
||||||
private:
|
private:
|
||||||
friend class Varnode;
|
friend class Varnode;
|
||||||
friend class Merge;
|
friend class Merge;
|
||||||
|
friend class VariablePiece;
|
||||||
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
|
||||||
mutable uint4 flags; ///< Boolean properties inherited from Varnode members
|
mutable uint4 flags; ///< Boolean properties inherited from Varnode members
|
||||||
mutable Datatype *type; ///< The data-type for \b this
|
mutable Datatype *type; ///< The data-type for \b this
|
||||||
mutable Varnode *nameRepresentative; ///< The storage location used to generate a Symbol name
|
mutable Varnode *nameRepresentative; ///< The storage location used to generate a Symbol name
|
||||||
mutable Cover wholecover; ///< The ranges of code addresses covered by this HighVariable
|
mutable Cover internalCover; ///< The ranges of code addresses covered by this HighVariable
|
||||||
|
mutable VariablePiece *piece; ///< Additional info about intersections with other pieces (if non-null)
|
||||||
mutable Symbol *symbol; ///< The Symbol \b this HighVariable is tied to
|
mutable Symbol *symbol; ///< The Symbol \b this HighVariable is tied to
|
||||||
mutable int4 symboloffset; ///< -1=perfect symbol match >=0, offset
|
mutable int4 symboloffset; ///< -1=perfect symbol match >=0, offset
|
||||||
int4 instanceIndex(const Varnode *vn) const; ///< Find the index of a specific Varnode member
|
int4 instanceIndex(const Varnode *vn) const; ///< Find the index of a specific Varnode member
|
||||||
void updateFlags(void) const; ///< (Re)derive boolean properties of \b this from the member Varnodes
|
void updateFlags(void) const; ///< (Re)derive boolean properties of \b this from the member Varnodes
|
||||||
void updateCover(void) const; ///< (Re)derive the cover of \b this from the member Varnodes
|
void updateInternalCover(void) const; ///< (Re)derive the internal cover of \b this from the member Varnodes
|
||||||
|
void updateCover(void) const; ///< (Re)derive the external cover of \b this, as a union of internal covers
|
||||||
void updateType(void) const; ///< (Re)derive the data-type for \b this from the member Varnodes
|
void updateType(void) const; ///< (Re)derive the data-type for \b this from the member Varnodes
|
||||||
void updateSymbol(void) const; ///< (Re)derive the Symbol and offset for \b this from member Varnodes
|
void updateSymbol(void) const; ///< (Re)derive the Symbol and offset for \b this from member Varnodes
|
||||||
void setCopyIn1(void) const { highflags |= copy_in1; } ///< Mark the existence of one COPY into \b this
|
void setCopyIn1(void) const { highflags |= copy_in1; } ///< Mark the existence of one COPY into \b this
|
||||||
|
@ -82,28 +144,34 @@ private:
|
||||||
bool hasCopyIn1(void) const { return ((highflags©_in1)!=0); } ///< Is there at least one COPY into \b this
|
bool hasCopyIn1(void) const { return ((highflags©_in1)!=0); } ///< Is there at least one COPY into \b this
|
||||||
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 merge(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 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 flagsDirty(void) const { highflags |= flagsdirty | namerepdirty; } ///< Mark the boolean properties as \e dirty
|
void flagsDirty(void) const { highflags |= flagsdirty | namerepdirty; } ///< Mark the boolean properties as \e dirty
|
||||||
void coverDirty(void) const { highflags |= coverdirty; } ///< Mark the cover as \e dirty
|
void coverDirty(void) const; ///< Mark the cover as \e dirty
|
||||||
void typeDirty(void) const { highflags |= typedirty; } ///< Mark the data-type as \e dirty
|
void typeDirty(void) const { highflags |= typedirty; } ///< Mark the data-type as \e dirty
|
||||||
void symbolDirty(void) const { highflags |= symboldirty; } ///< Mark the symbol as \e dirty
|
void symbolDirty(void) const { highflags |= symboldirty; } ///< Mark the symbol as \e dirty
|
||||||
void setUnmerged(void) const { highflags |= unmerged; } ///< Mark \b this as having merge problems
|
void setUnmerged(void) const { highflags |= unmerged; } ///< Mark \b this as having merge problems
|
||||||
|
bool isCoverDirty(void) const; ///< Is the cover returned by getCover() up-to-date
|
||||||
public:
|
public:
|
||||||
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
||||||
|
~HighVariable(void); ///< Destructor
|
||||||
Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type
|
Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type
|
||||||
|
const Cover &getCover(void) const; ///< Get cover data for \b this variable
|
||||||
Symbol *getSymbol(void) const { updateSymbol(); return symbol; } ///< Get the Symbol associated with \b this or null
|
Symbol *getSymbol(void) const { updateSymbol(); return symbol; } ///< Get the Symbol associated with \b this or null
|
||||||
SymbolEntry *getSymbolEntry(void) const; /// Get the SymbolEntry mapping to \b this or null
|
SymbolEntry *getSymbolEntry(void) const; /// Get the SymbolEntry mapping to \b this or null
|
||||||
int4 getSymbolOffset(void) const { return symboloffset; } ///< Get the Symbol offset associated with \b this
|
int4 getSymbolOffset(void) const { return symboloffset; } ///< Get the Symbol offset associated with \b this
|
||||||
int4 numInstances(void) const { return inst.size(); } ///< Get the number of member Varnodes \b this has
|
int4 numInstances(void) const { return inst.size(); } ///< Get the number of member Varnodes \b this has
|
||||||
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
|
||||||
|
|
||||||
/// \brief Print details of the cover for \b this (for debug purposes)
|
/// \brief Print details of the cover for \b this (for debug purposes)
|
||||||
///
|
///
|
||||||
/// \param s is the output stream
|
/// \param s is the output stream
|
||||||
void printCover(ostream &s) const { if ((highflags&HighVariable::coverdirty)==0) wholecover.print(s); else s << "Cover dirty"; }
|
void printCover(ostream &s) const { if ((highflags&HighVariable::coverdirty)==0) internalCover.print(s); else s << "Cover dirty"; }
|
||||||
|
|
||||||
void printInfo(ostream &s) const; ///< Print information about \b this HighVariable to stream
|
void printInfo(ostream &s) const; ///< Print information about \b this HighVariable to stream
|
||||||
bool hasName(void) const; ///< Check if \b this HighVariable can be named
|
bool hasName(void) const; ///< Check if \b this HighVariable can be named
|
||||||
|
@ -147,4 +215,33 @@ 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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// The internal cover is marked as dirty. If \b this is a piece of a VariableGroup, it and all the other
|
||||||
|
/// HighVariables it intersects with are marked as having a dirty extended cover.
|
||||||
|
inline void HighVariable::coverDirty(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
highflags |= coverdirty;
|
||||||
|
if (piece != (VariablePiece *)0)
|
||||||
|
piece->markExtendCoverDirty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The cover could either by the internal one or the extended one if \b this is part of a Variable Group.
|
||||||
|
/// \return \b true if the cover needs to be recomputed.
|
||||||
|
inline bool HighVariable::isCoverDirty(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
return ((highflags & (coverdirty | extendcoverdirty)) != 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The returns the internal cover unless \b this is part of a VariableGroup, in which case the
|
||||||
|
/// extended cover is returned.
|
||||||
|
/// \return the cover associated with \b this variable
|
||||||
|
inline const Cover &HighVariable::getCover(void) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (piece == (VariablePiece *)0)
|
||||||
|
return internalCover;
|
||||||
|
return piece->getCover();
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -878,6 +878,135 @@ bool Varnode::copyShadow(const Varnode *op2) const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Try to find a SUBPIECE operation producing the value in \b this from the given \b whole Varnode
|
||||||
|
///
|
||||||
|
/// The amount of truncation producing \b this must be known apriori. Allow for COPY and MULTIEQUAL operations
|
||||||
|
/// in the flow path from \b whole to \b this. This method will search recursively through branches
|
||||||
|
/// of MULTIEQUAL up to a maximum depth.
|
||||||
|
/// \param leastByte is the number of least significant bytes being truncated from \b whole to get \b this
|
||||||
|
/// \param whole is the given whole Varnode
|
||||||
|
/// \param recurse is the current depth of recursion
|
||||||
|
/// \return \b true if \b this and \b whole have the prescribed SUBPIECE relationship
|
||||||
|
bool Varnode::findSubpieceShadow(int4 leastByte,const Varnode *whole,int4 recurse) const
|
||||||
|
|
||||||
|
{
|
||||||
|
const Varnode *vn = this;
|
||||||
|
while( vn->isWritten() && vn->getDef()->code() == CPUI_COPY)
|
||||||
|
vn = vn->getDef()->getIn(0);
|
||||||
|
if (!vn->isWritten()) {
|
||||||
|
if (vn->isConstant()) {
|
||||||
|
while( whole->isWritten() && whole->getDef()->code() == CPUI_COPY)
|
||||||
|
whole = whole->getDef()->getIn(0);
|
||||||
|
if (!whole->isConstant()) return false;
|
||||||
|
uintb off = whole->getOffset() >> leastByte*8;
|
||||||
|
off &= calc_mask(vn->getSize());
|
||||||
|
return (off == vn->getOffset());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
OpCode opc = vn->getDef()->code();
|
||||||
|
if (opc == CPUI_SUBPIECE) {
|
||||||
|
const Varnode *tmpvn = vn->getDef()->getIn(0);
|
||||||
|
int4 off = (int4)vn->getDef()->getIn(1)->getOffset();
|
||||||
|
if (off != leastByte || tmpvn->getSize() != whole->getSize())
|
||||||
|
return false;
|
||||||
|
if (tmpvn == whole) return true;
|
||||||
|
while(tmpvn->isWritten() && tmpvn->getDef()->code() == CPUI_COPY) {
|
||||||
|
tmpvn = tmpvn->getDef()->getIn(0);
|
||||||
|
if (tmpvn == whole) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (opc == CPUI_MULTIEQUAL) {
|
||||||
|
recurse += 1;
|
||||||
|
if (recurse > 1) return false; // Truncate the recursion at maximum depth
|
||||||
|
while( whole->isWritten() && whole->getDef()->code() == CPUI_COPY)
|
||||||
|
whole = whole->getDef()->getIn(0);
|
||||||
|
if (!whole->isWritten()) return false;
|
||||||
|
const PcodeOp *bigOp = whole->getDef();
|
||||||
|
if (bigOp->code() != CPUI_MULTIEQUAL) return false;
|
||||||
|
const PcodeOp *smallOp = vn->getDef();
|
||||||
|
if (bigOp->getParent() != smallOp->getParent()) return false;
|
||||||
|
// Recurse search through all branches of the two MULTIEQUALs
|
||||||
|
for(int4 i=0;i<smallOp->numInput();++i) {
|
||||||
|
if (!smallOp->getIn(i)->findSubpieceShadow(leastByte, bigOp->getIn(i), recurse))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true; // All branches were copy shadows
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Varnode::findPieceShadow(int4 leastByte,const Varnode *piece) const
|
||||||
|
|
||||||
|
{
|
||||||
|
const Varnode *vn = this;
|
||||||
|
while( vn->isWritten() && vn->getDef()->code() == CPUI_COPY)
|
||||||
|
vn = vn->getDef()->getIn(0);
|
||||||
|
if (!vn->isWritten()) return false;
|
||||||
|
OpCode opc = vn->getDef()->code();
|
||||||
|
if (opc == CPUI_PIECE) {
|
||||||
|
const Varnode *tmpvn = vn->getDef()->getIn(1); // Least significant part
|
||||||
|
if (leastByte >= tmpvn->getSize()) {
|
||||||
|
leastByte -= tmpvn->getSize();
|
||||||
|
tmpvn = vn->getDef()->getIn(0);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (piece->getSize() + leastByte > tmpvn->getSize()) return false;
|
||||||
|
}
|
||||||
|
if (leastByte == 0 && tmpvn->getSize() == piece->getSize()) {
|
||||||
|
if (tmpvn == piece) return true;
|
||||||
|
while(tmpvn->isWritten() && tmpvn->getDef()->code() == CPUI_COPY) {
|
||||||
|
tmpvn = tmpvn->getDef()->getIn(0);
|
||||||
|
if (tmpvn == piece) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// CPUI_PIECE input is too big, recursively search for another CPUI_PIECE
|
||||||
|
return tmpvn->findPieceShadow(leastByte, piece);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For \b this and another Varnode, establish that either:
|
||||||
|
/// - bigger = CONCAT(smaller,..) or
|
||||||
|
/// - smaller = SUBPIECE(bigger)
|
||||||
|
///
|
||||||
|
/// Check through COPY chains and verify that the form of the CONCAT or SUBPIECE matches
|
||||||
|
/// a given relative offset between the Varnodes.
|
||||||
|
/// \param op2 is the Varnode to compare to \b this
|
||||||
|
/// \param relOff is the putative relative byte offset of \b this to \b op2
|
||||||
|
/// \return \b true if one Varnode is contained, as a value, in the other
|
||||||
|
bool Varnode::partialCopyShadow(const Varnode *op2,int4 relOff) const
|
||||||
|
|
||||||
|
{
|
||||||
|
const Varnode *vn;
|
||||||
|
|
||||||
|
if (size < op2->size) {
|
||||||
|
vn = this;
|
||||||
|
}
|
||||||
|
else if (size > op2->size) {
|
||||||
|
vn = op2;
|
||||||
|
op2 = this;
|
||||||
|
relOff = -relOff;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
if (relOff < 0)
|
||||||
|
return false; // Not proper containment
|
||||||
|
if (relOff + vn->getSize() > op2->getSize())
|
||||||
|
return false; // Not proper containment
|
||||||
|
|
||||||
|
bool bigEndian = getSpace()->isBigEndian();
|
||||||
|
int4 leastByte = bigEndian ? (op2->getSize() - vn->getSize()) - relOff : relOff;
|
||||||
|
if (vn->findSubpieceShadow(leastByte, op2, 0))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (op2->findPieceShadow(leastByte, vn))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
/// Compare term order of two Varnodes. Used in Term Rewriting strategies to order operands of commutative ops
|
/// Compare term order of two Varnodes. Used in Term Rewriting strategies to order operands of commutative ops
|
||||||
/// \param op is the Varnode to order against \b this
|
/// \param op is the Varnode to order against \b this
|
||||||
/// \return -1 if \b this comes before \b op, 1 if op before this, or 0
|
/// \return -1 if \b this comes before \b op, 1 if op before this, or 0
|
||||||
|
@ -1487,6 +1616,44 @@ VarnodeLocSet::const_iterator VarnodeBank::endLoc(int4 s,const Address &addr,
|
||||||
return iter;
|
return iter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \brief Given start, return maximal range of overlapping Varnodes
|
||||||
|
///
|
||||||
|
/// Advance the iterator until no Varnodes after the iterator intersect any Varnodes
|
||||||
|
/// from the initial Varnode through the current iterator. The range is returned as pairs
|
||||||
|
/// of iterators to subranges. One subrange for each set of Varnodes with the same size and starting address.
|
||||||
|
/// A final iterator to the next Varnode after the overlapping set is also passed back.
|
||||||
|
/// \param iter is an iterator to the given start Varnode
|
||||||
|
/// \param bounds holds the array of iterator pairs passed back
|
||||||
|
/// \return the union of Varnode flags across the range
|
||||||
|
uint4 VarnodeBank::overlapLoc(VarnodeLocSet::const_iterator iter,vector<VarnodeLocSet::const_iterator> &bounds) const
|
||||||
|
|
||||||
|
{
|
||||||
|
Varnode *vn = *iter;
|
||||||
|
AddrSpace *spc = vn->getSpace();
|
||||||
|
uintb off = vn->getOffset();
|
||||||
|
uintb maxoff = off + (vn->getSize() - 1);
|
||||||
|
uint4 flags = vn->getFlags();
|
||||||
|
bounds.push_back(iter);
|
||||||
|
iter = endLoc(vn->getSize(),vn->getAddr(),Varnode::written);
|
||||||
|
bounds.push_back(iter);
|
||||||
|
while(iter != loc_tree.end()) {
|
||||||
|
vn = *iter;
|
||||||
|
if (vn->getSpace() != spc || vn->getOffset() > maxoff)
|
||||||
|
break;
|
||||||
|
if (vn->isFree()) {
|
||||||
|
iter = endLoc(vn->getSize(),vn->getAddr(),0);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
maxoff = vn->getOffset() + (vn->getSize() - 1);
|
||||||
|
flags |= vn->getFlags();
|
||||||
|
bounds.push_back(iter);
|
||||||
|
iter = endLoc(vn->getSize(),vn->getAddr(),Varnode::written);
|
||||||
|
bounds.push_back(iter);
|
||||||
|
}
|
||||||
|
bounds.push_back(iter);
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
|
||||||
/// \brief Beginning of varnodes with set definition property
|
/// \brief Beginning of varnodes with set definition property
|
||||||
///
|
///
|
||||||
/// Get an iterator to Varnodes in definition order restricted with the
|
/// Get an iterator to Varnodes in definition order restricted with the
|
||||||
|
|
|
@ -331,6 +331,9 @@ public:
|
||||||
Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information
|
Datatype *getLocalType(bool &blockup) const; ///< Calculate type of Varnode based on local information
|
||||||
bool isBooleanValue(bool useAnnotation) const; ///< Does \b this Varnode hold a formal boolean value
|
bool isBooleanValue(bool useAnnotation) const; ///< Does \b this Varnode hold a formal boolean value
|
||||||
bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source?
|
bool copyShadow(const Varnode *op2) const; ///< Are \b this and \b op2 copied from the same source?
|
||||||
|
bool findSubpieceShadow(int4 leastByte,const Varnode *whole,int4 recurse) const;
|
||||||
|
bool findPieceShadow(int4 leastByte,const Varnode *piece) const;
|
||||||
|
bool partialCopyShadow(const Varnode *op2,int4 relOff) const; ///< Is one of \b this or \b op2 a partial copy of the other?
|
||||||
void encode(Encoder &encoder) const; ///< Encode a description of \b this to a stream
|
void encode(Encoder &encoder) const; ///< Encode a description of \b this to a stream
|
||||||
static bool comparePointers(const Varnode *a,const Varnode *b) { return (*a < *b); } ///< Compare Varnodes as pointers
|
static bool comparePointers(const Varnode *a,const Varnode *b) { return (*a < *b); } ///< Compare Varnodes as pointers
|
||||||
static void printRaw(ostream &s,const Varnode *vn); ///< Print raw info about a Varnode to stream
|
static void printRaw(ostream &s,const Varnode *vn); ///< Print raw info about a Varnode to stream
|
||||||
|
@ -387,6 +390,7 @@ public:
|
||||||
VarnodeLocSet::const_iterator endLoc(int4 s,const Address &addr,uint4 fl) const;
|
VarnodeLocSet::const_iterator endLoc(int4 s,const Address &addr,uint4 fl) const;
|
||||||
VarnodeLocSet::const_iterator beginLoc(int4 s,const Address &addr,const Address &pc,uintm uniq) const;
|
VarnodeLocSet::const_iterator beginLoc(int4 s,const Address &addr,const Address &pc,uintm uniq) const;
|
||||||
VarnodeLocSet::const_iterator endLoc(int4 s,const Address &addr,const Address &pc,uintm uniq) const;
|
VarnodeLocSet::const_iterator endLoc(int4 s,const Address &addr,const Address &pc,uintm uniq) const;
|
||||||
|
uint4 overlapLoc(VarnodeLocSet::const_iterator iter,vector<VarnodeLocSet::const_iterator> &bounds) const;
|
||||||
VarnodeDefSet::const_iterator beginDef(void) const { return def_tree.begin(); } ///< Beginning of Varnodes sorted by definition
|
VarnodeDefSet::const_iterator beginDef(void) const { return def_tree.begin(); } ///< Beginning of Varnodes sorted by definition
|
||||||
VarnodeDefSet::const_iterator endDef(void) const { return def_tree.end(); } ///< End of Varnodes sorted by definition
|
VarnodeDefSet::const_iterator endDef(void) const { return def_tree.end(); } ///< End of Varnodes sorted by definition
|
||||||
VarnodeDefSet::const_iterator beginDef(uint4 fl) const;
|
VarnodeDefSet::const_iterator beginDef(uint4 fl) const;
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
<decompilertest>
|
||||||
|
<binaryimage arch="x86:LE:64:default:gcc">
|
||||||
|
<!--
|
||||||
|
Contrived examples of propagating a partial varnode (a structure field) when
|
||||||
|
the whole varnode (the whole structure) is also being manipulated.
|
||||||
|
-->
|
||||||
|
<bytechunk space="ram" offset="0x1006a7" readonly="true">
|
||||||
|
8b1dc3ffffff48893d
|
||||||
|
bcffffff83c30a89d8c300008b05aeff
|
||||||
|
ffff01f048893da5ffffff83c00ac3
|
||||||
|
</bytechunk>
|
||||||
|
<bytechunk space="ram" offset="0x1006e6" readonly="true">
|
||||||
|
4883ec104889e766e893
|
||||||
|
008b1c244889e766e8890089d8c30000
|
||||||
|
8b1d6affffff488b3d63ffffff66e873
|
||||||
|
0089d8c34883ec10488b0551ffffff48
|
||||||
|
8904244889e766e85a008b5c24044889
|
||||||
|
e766e84f0089d84883c410c348893d2d
|
||||||
|
ffffff83fe0a7f0c66e838008b051eff
|
||||||
|
ffffeb0a66e8b8fd8b0512ffffff83c0
|
||||||
|
07c3
|
||||||
|
</bytechunk>
|
||||||
|
<symbol space="ram" offset="0x1006a7" name="readpartial"/>
|
||||||
|
<symbol space="ram" offset="0x1006bc" name="read_expr_interfere"/>
|
||||||
|
<symbol space="ram" offset="0x100700" name="readpartial_callinterfere"/>
|
||||||
|
<symbol space="ram" offset="0x100714" name="readpartialstack_inbetween"/>
|
||||||
|
<symbol space="ram" offset="0x10073c" name="partial_restore"/>
|
||||||
|
</binaryimage>
|
||||||
|
<script>
|
||||||
|
<com>parse line struct highlow { int4 a; int4 b; };</com>
|
||||||
|
<com>map addr r0x100670 highlow glob1</com>
|
||||||
|
<com>lo fu readpartial</com>
|
||||||
|
<com>map hash r0x1006a7 3f9001cf6a int4 a_simple</com>
|
||||||
|
<com>decompile</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu read_expr_interfere</com>
|
||||||
|
<com>decompile</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu readpartial_callinterfere</com>
|
||||||
|
<com>map hash r0x100700 3fc348d857 int4 a_call</com>
|
||||||
|
<com>decompile</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu readpartialstack_inbetween</com>
|
||||||
|
<com>map addr s0xfffffffffffffff0 highlow hilo_stack</com>
|
||||||
|
<com>map hash r0x10072a 3ff1b7c944 int4 b_between</com>
|
||||||
|
<com>decompile</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>lo fu partial_restore</com>
|
||||||
|
<com>decompile</com>
|
||||||
|
<com>print C</com>
|
||||||
|
<com>quit</com>
|
||||||
|
</script>
|
||||||
|
<stringmatch name="Partial Merge #1" min="1" max="1">a_simple = glob1\.a;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #2" min="1" max="1">return a_simple \+ 10;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #3" min="0" max="0">return glob1\.a \+ 10;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #4" min="1" max="1">param_2 = glob1\.a \+ param_2;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #5" min="1" max="1">return param_2 \+ 10;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #6" min="1" max="1">a_call = glob1\.a;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #7" min="1" max="1">return a_call;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #8" min="1" max="1">return a_call;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #9" min="1" max="1">b_between = hilo_stack\.b;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #10" min="1" max="1">return b_between;</stringmatch>
|
||||||
|
<stringmatch name="Partial Merge #11" min="1" max="1">return glob1\.a \+ 7;</stringmatch>
|
||||||
|
</decompilertest>
|
Loading…
Add table
Add a link
Reference in a new issue