mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
GP-2845 Merging overlapping variables
This commit is contained in:
parent
1cdb59e1bb
commit
722c17f9f2
9 changed files with 818 additions and 77 deletions
|
@ -112,6 +112,10 @@ bool Merge::mergeTestRequired(HighVariable *high_out,HighVariable *high_in)
|
|||
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;
|
||||
}
|
||||
|
||||
|
@ -433,6 +437,7 @@ void Merge::eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort
|
|||
map<int4,CoverBlock>::const_iterator iter,enditer;
|
||||
Varnode *vn2;
|
||||
int4 boundtype;
|
||||
int4 overlaptype;
|
||||
bool insertop;
|
||||
|
||||
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;
|
||||
boundtype = single.containVarnodeDef(vn2);
|
||||
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 (vn2->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;
|
||||
// The vn2 INDIRECT must be linked to the read op
|
||||
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;
|
||||
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
|
||||
/// 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 enditer is the end of the range
|
||||
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) {
|
||||
vn = *iter;
|
||||
if (vn->isFree()) continue;
|
||||
isectlist.push_back(vn);
|
||||
}
|
||||
blocksort.resize(isectlist.size());
|
||||
for(int4 i=0;i<isectlist.size();++i)
|
||||
blocksort[i].set(isectlist[i]);
|
||||
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)
|
||||
eliminateIntersect(isectlist[i],blocksort);
|
||||
}
|
||||
|
@ -534,23 +552,41 @@ void Merge::unifyAddress(VarnodeLocSet::const_iterator startiter,VarnodeLocSet::
|
|||
void Merge::mergeAddrTied(void)
|
||||
|
||||
{
|
||||
bool addrtied;
|
||||
VarnodeLocSet::const_iterator startiter,enditer,iter;
|
||||
VarnodeLocSet::const_iterator startiter;
|
||||
vector<VarnodeLocSet::const_iterator> bounds;
|
||||
for(startiter=data.beginLoc();startiter!=data.endLoc();) {
|
||||
addrtied = false;
|
||||
enditer = data.endLoc((*startiter)->getSize(),(*startiter)->getAddr(),Varnode::written);
|
||||
for(iter=startiter;iter!=enditer;++iter) {
|
||||
if ((*iter)->isAddrTied()) {
|
||||
addrtied = true;
|
||||
break;
|
||||
AddrSpace *spc = (*startiter)->getSpace();
|
||||
spacetype type = spc->getType();
|
||||
if (type != IPTR_PROCESSOR && type != IPTR_SPACEBASE) {
|
||||
startiter = data.endLoc(spc); // Skip over the whole space
|
||||
continue;
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
/// \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. Otherwise, all the Varnode instances from the second HighVariable
|
||||
/// are merged into the first and its Cover is updated. 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)
|
||||
/// 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)
|
||||
|
||||
{
|
||||
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 *> nointer; // Highs that high2 does not intersect
|
||||
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;
|
||||
|
||||
for(iter=iterfirst;iter!=iterlast;++iter) {
|
||||
HighVariable *b = (*iter).first.b;
|
||||
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
|
||||
|
@ -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) );
|
||||
++iterlast; // Restore original range (with possibly new open endpoint)
|
||||
|
||||
|
||||
highedgemap.erase(iterfirst,iterlast);
|
||||
}
|
||||
|
||||
|
@ -1454,13 +1482,33 @@ bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
|||
vector<HighVariable *>::iterator titer;
|
||||
for(titer=nointer.begin();titer!=nointer.end();++titer)
|
||||
(*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) {
|
||||
highedgemap[ HighEdge(high1,*titer) ] = true;
|
||||
highedgemap[ HighEdge(*titer,high1) ] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Perform low-level details of merging two HighVariables if possible
|
||||
///
|
||||
/// This routine only fails (returning \b false) if there is a Cover intersection between
|
||||
/// 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->updateCover();
|
||||
high1->updateCover(); // Update cover now so that updateHigh won't purge cached tests
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1473,10 +1521,8 @@ bool Merge::merge(HighVariable *high1,HighVariable *high2,bool isspeculative)
|
|||
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();
|
||||
purgeHigh(a);
|
||||
return false;
|
||||
|
@ -1525,7 +1571,7 @@ bool Merge::intersection(HighVariable *a,HighVariable *b)
|
|||
bool res = false;
|
||||
int4 blk;
|
||||
vector<int4> blockisect;
|
||||
a->wholecover.intersectList(blockisect,b->wholecover,2);
|
||||
a->getCover().intersectList(blockisect,b->getCover(),2);
|
||||
for(blk=0;blk<blockisect.size();++blk) {
|
||||
if (blockIntersection(a,b,blockisect[blk])) {
|
||||
res = true;
|
||||
|
@ -1537,6 +1583,56 @@ bool Merge::intersection(HighVariable *a,HighVariable *b)
|
|||
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.
|
||||
|
@ -1549,19 +1645,40 @@ bool Merge::blockIntersection(HighVariable *a,HighVariable *b,int4 blk)
|
|||
{
|
||||
vector<Varnode *> blist;
|
||||
|
||||
for(int4 i=0;i<b->numInstances();++i) {
|
||||
Varnode *vn = b->getInstance(i);
|
||||
if (1<vn->getCover()->intersectByBlock(blk,a->wholecover))
|
||||
blist.push_back(vn);
|
||||
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;
|
||||
}
|
||||
}
|
||||
for(int4 i=0;i<a->numInstances();++i) {
|
||||
Varnode *vn = a->getInstance(i);
|
||||
if (2>vn->getCover()->intersectByBlock(blk,b->wholecover)) continue;
|
||||
for(int4 j=0;j<blist.size();++j) {
|
||||
Varnode *vn2 = blist[j];
|
||||
if (1<vn2->getCover()->intersectByBlock(blk,*vn->getCover()))
|
||||
if (!vn->copyShadow(vn2))
|
||||
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;
|
||||
|
@ -1595,24 +1712,38 @@ void Merge::inflate(Varnode *a,HighVariable *high)
|
|||
/// Varnode is not part of the HighVariable.
|
||||
/// \param a is the given Varnode to inflate
|
||||
/// \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)
|
||||
|
||||
{
|
||||
HighVariable *ahigh = a->getHigh();
|
||||
bool res = false;
|
||||
|
||||
updateHigh(high);
|
||||
const Cover &highCover( high->internalCover ); // Only check for intersections with cover contributing to inflate
|
||||
|
||||
for(int4 i=0;i<ahigh->numInstances();++i) {
|
||||
Varnode *b = ahigh->getInstance(i);
|
||||
if (b->copyShadow(a)) continue;
|
||||
if (2==b->getCover()->intersect( high->wholecover )) {
|
||||
res = true;
|
||||
break;
|
||||
if (b->copyShadow(a)) continue; // Intersection with a or shadows of a is allowed
|
||||
if (2==b->getCover()->intersect( highCover )) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue