mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2024-11-22 04:05:39 +00:00
progress towards dominant COPY model
This commit is contained in:
parent
ec9e31483a
commit
00bbc8516b
@ -720,6 +720,39 @@ FlowBlock *FlowBlock::findCommonBlock(FlowBlock *bl1,FlowBlock *bl2)
|
||||
return common;
|
||||
}
|
||||
|
||||
/// Find the most immediate dominating FlowBlock of all blocks in the given set.
|
||||
/// The container must not be empty.
|
||||
/// \param blockSet is the given set of blocks
|
||||
/// \return the most immediate dominating FlowBlock
|
||||
FlowBlock *FlowBlock::findCommonBlock(const vector<FlowBlock *> &blockSet)
|
||||
|
||||
{
|
||||
vector<FlowBlock *> markedSet;
|
||||
FlowBlock *res = blockSet[0];
|
||||
int4 bestIndex = res->getIndex();
|
||||
res->setMark();
|
||||
markedSet.push_back(res);
|
||||
for(int4 i=0;i<blockSet.size();++i) {
|
||||
if (bestIndex == 0)
|
||||
break;
|
||||
FlowBlock *bl = blockSet[i];
|
||||
while(bl->getIndex() > bestIndex) {
|
||||
if (bl->isMark()) break;
|
||||
bl->setMark();
|
||||
markedSet.push_back(bl);
|
||||
bl = bl->getImmedDom();
|
||||
}
|
||||
if (bl->isMark()) continue;
|
||||
res = bl;
|
||||
bestIndex = res->getIndex();
|
||||
res->setMark();
|
||||
markedSet.push_back(res);
|
||||
}
|
||||
for(int4 i=0;i<markedSet.size();++i)
|
||||
markedSet[i]->clearMark();
|
||||
return res;
|
||||
}
|
||||
|
||||
/// Add the given FlowBlock to the list and make \b this the parent
|
||||
/// Update \b index so that it has the minimum over all components
|
||||
/// \param bl is the given FlowBlock
|
||||
|
@ -257,6 +257,7 @@ public:
|
||||
static bool compareBlockIndex(const FlowBlock *bl1,const FlowBlock *bl2); ///< Compare FlowBlock by index
|
||||
static bool compareFinalOrder(const FlowBlock *bl1,const FlowBlock *bl2); ///< Final FlowBlock comparison
|
||||
static FlowBlock *findCommonBlock(FlowBlock *bl1,FlowBlock *bl2); ///< Find the common dominator of two FlowBlocks
|
||||
static FlowBlock *findCommonBlock(const vector<FlowBlock *> &blockSet); ///< Find common dominator of multiple FlowBlocks
|
||||
};
|
||||
|
||||
/// \brief A control-flow block built out of sub-components
|
||||
|
@ -3579,6 +3579,7 @@ bool ActionCopyMarker::shadowedVarnode(const Varnode *vn)
|
||||
int4 ActionCopyMarker::apply(Funcdata &data)
|
||||
|
||||
{
|
||||
vector<HighVariable *> multiCopy;
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
PcodeOp *op;
|
||||
HighVariable *h1,*h2,*h3;
|
||||
@ -3597,8 +3598,10 @@ int4 ActionCopyMarker::apply(Funcdata &data)
|
||||
}
|
||||
else { // COPY between different HighVariables
|
||||
if (h1->hasCopyIn()) { // If we've seen other COPYs into this high
|
||||
if (!h1->isCopyProcessed()) // and we haven't searched before,
|
||||
data.getMerge().markRedundantCopies(h1); // search for redundant COPYs
|
||||
if (!h1->isCopyProcessed()) { // and we haven't searched before,
|
||||
multiCopy.push_back(h1);
|
||||
h1->setCopyProcessed();
|
||||
}
|
||||
}
|
||||
else
|
||||
h1->setCopyIn();
|
||||
@ -3641,6 +3644,8 @@ int4 ActionCopyMarker::apply(Funcdata &data)
|
||||
break;
|
||||
}
|
||||
}
|
||||
for(int4 i=0;i<multiCopy.size();++i)
|
||||
data.getMerge().processCopyTrims(multiCopy[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -957,20 +957,119 @@ bool Merge::checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp)
|
||||
return true;
|
||||
}
|
||||
|
||||
void Merge::buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 pos,int4 size)
|
||||
|
||||
{
|
||||
vector<FlowBlock *> blockSet;
|
||||
for(int4 i=0;i<size;++i)
|
||||
blockSet.push_back(copy[pos+i]->getParent());
|
||||
BlockBasic *domBl = (BlockBasic *)FlowBlock::findCommonBlock(blockSet);
|
||||
Varnode *rootVn = copy[pos]->getIn(0);
|
||||
bool domCopyIsNew;
|
||||
PcodeOp *domCopy;
|
||||
Varnode *domVn;
|
||||
if (domBl == copy[pos]->getParent()) {
|
||||
domCopyIsNew = false;
|
||||
domCopy = copy[pos];
|
||||
domVn = domCopy->getOut();
|
||||
}
|
||||
else {
|
||||
domCopyIsNew = true;
|
||||
domCopy = data.newOp(1,domBl->getStop());
|
||||
data.opSetOpcode(domCopy, CPUI_COPY);
|
||||
domVn = data.newUnique(rootVn->getSize(), rootVn->getType());
|
||||
data.opSetOutput(domCopy,domVn);
|
||||
data.opSetInput(domCopy,rootVn,0);
|
||||
data.opInsertEnd(domCopy, domBl);
|
||||
}
|
||||
// Cover created by removing all the COPYs from rootVn
|
||||
Cover bCover;
|
||||
for(int4 i=0;i<high->numInstances();++i) {
|
||||
Varnode *vn = high->getInstance(i);
|
||||
if (vn->isWritten()) {
|
||||
PcodeOp *op = vn->getDef();
|
||||
if (op->code() == CPUI_COPY) {
|
||||
if (op->getIn(0)->copyShadow(rootVn)) continue;
|
||||
}
|
||||
}
|
||||
bCover.merge(*vn->getCover());
|
||||
}
|
||||
|
||||
int4 count = size;
|
||||
for(int4 i=0;i<size;++i) {
|
||||
PcodeOp *op = copy[pos+i];
|
||||
if (op == domCopy) continue; // No intersections from domVn already proven
|
||||
Varnode *outVn = op->getOut();
|
||||
list<PcodeOp *>::const_iterator iter;
|
||||
Cover aCover;
|
||||
aCover.addDefPoint(domVn);
|
||||
for(iter=outVn->beginDescend();iter!=outVn->endDescend();++iter)
|
||||
aCover.addRefPoint(*iter, outVn);
|
||||
if (bCover.intersect(aCover)>1) {
|
||||
count -= 1;
|
||||
op->setMark();
|
||||
}
|
||||
}
|
||||
|
||||
if (count <= 1) { // Don't bother if we only replace one COPY with another
|
||||
for (int4 i = 0; i < size; ++i)
|
||||
copy[pos + i]->setMark();
|
||||
count = 0;
|
||||
if (domCopyIsNew) {
|
||||
data.opDestroy(domCopy);
|
||||
}
|
||||
}
|
||||
// Replace all non-intersecting COPYs with read of dominating Varnode
|
||||
for(int4 i=0;i<size;++i) {
|
||||
PcodeOp *op = copy[pos+i];
|
||||
if (op->isMark())
|
||||
op->clearMark();
|
||||
else {
|
||||
Varnode *outVn = op->getOut();
|
||||
if (outVn != domVn) {
|
||||
outVn->getHigh()->remove(outVn);
|
||||
data.totalReplace(outVn, domVn);
|
||||
data.opDestroy(op);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count > 0 && domCopyIsNew) {
|
||||
high->merge(domVn->getHigh(),false);
|
||||
}
|
||||
}
|
||||
|
||||
/// \brief Search for and mark redundant COPY ops into the given high as \e non-printing
|
||||
///
|
||||
/// Trimming during the merge process can insert multiple COPYs from the same source. In some
|
||||
/// cases, one or more COPYs may be redundant and shouldn't be printed. This method searches
|
||||
/// for redundancy among COPY ops that assign to the given HighVariable.
|
||||
/// \param high is the given HighVariable
|
||||
/// \return \b true if any redundant COPYs were discovered
|
||||
bool Merge::markRedundantCopies(HighVariable *high)
|
||||
/// \param copy is the list of COPYs coming from the same source HighVariable
|
||||
/// \param pos is the starting index of a set of COPYs coming from the same Varnode
|
||||
/// \param size is the number of Varnodes in the set coming from the same Varnode
|
||||
void Merge::markRedundantCopies(HighVariable *high,vector<PcodeOp *> ©,int4 pos,int4 size)
|
||||
|
||||
{
|
||||
for (int4 i = size - 1; i > 0; --i) {
|
||||
PcodeOp *subOp = copy[pos + i];
|
||||
if (subOp->isDead()) continue;
|
||||
for (int4 j = i - 1; j >= 0; --j) {
|
||||
// Make sure earlier index provides dominant op
|
||||
PcodeOp *domOp = copy[pos + j];
|
||||
if (domOp->isDead()) continue;
|
||||
if (checkCopyPair(high, domOp, subOp)) {
|
||||
data.opSetFlag(subOp, PcodeOp::nonprinting);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Merge::processCopyTrims(HighVariable *high)
|
||||
|
||||
{
|
||||
bool hasRedundant = false;
|
||||
vector<PcodeOp *> copyIns;
|
||||
|
||||
high->setCopyProcessed();
|
||||
// Find all the COPY ops into this HighVariable from a different HighVariable
|
||||
for(int4 i=0;i<high->numInstances();++i) {
|
||||
Varnode *vn = high->getInstance(i);
|
||||
@ -994,21 +1093,11 @@ bool Merge::markRedundantCopies(HighVariable *high)
|
||||
sz += 1;
|
||||
}
|
||||
if (sz > 1) { // If there is more than one COPY in a group
|
||||
for(int4 i=sz-1;i>0;--i) {
|
||||
PcodeOp *subOp = copyIns[pos+i];
|
||||
for(int4 j=i-1;j>=0;--j) {
|
||||
// Make sure earlier index provides dominant op
|
||||
if (checkCopyPair(high,copyIns[pos+j],subOp)) {
|
||||
data.opSetFlag(subOp, PcodeOp::nonprinting);
|
||||
hasRedundant = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
buildDominantCopy(high, copyIns, pos, sz);
|
||||
markRedundantCopies(high, copyIns, pos, sz);
|
||||
}
|
||||
pos += sz;
|
||||
}
|
||||
return hasRedundant;
|
||||
}
|
||||
|
||||
/// \brief Perform low-level details of merging two HighVariables if possible
|
||||
|
@ -105,6 +105,8 @@ class Merge {
|
||||
void mergeLinear(vector<HighVariable *> &highvec);
|
||||
bool merge(HighVariable *high1,HighVariable *high2,bool isspeculative);
|
||||
bool checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp);
|
||||
void buildDominantCopy(HighVariable *high,vector<PcodeOp *> ©,int4 pos,int4 size);
|
||||
void markRedundantCopies(HighVariable *high,vector<PcodeOp *> ©,int4 pos,int4 size);
|
||||
public:
|
||||
Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function
|
||||
bool intersection(HighVariable *a,HighVariable *b);
|
||||
@ -118,7 +120,7 @@ public:
|
||||
void mergeMarker(void);
|
||||
void mergeAdjacent(void);
|
||||
bool hideShadows(HighVariable *high);
|
||||
bool markRedundantCopies(HighVariable *high);
|
||||
void processCopyTrims(HighVariable *high);
|
||||
};
|
||||
|
||||
/// \brief Compare HighVariables by the blocks they cover
|
||||
|
@ -63,7 +63,6 @@ private:
|
||||
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 updateType(void) const; ///< (Re)derive the data-type for \b this from the member Varnodes
|
||||
void setCopyProcessed(void) const { highflags |= copy_processed; } ///< Mark that \b this has had its COPY ins processed
|
||||
public:
|
||||
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
||||
Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type
|
||||
@ -114,6 +113,7 @@ public:
|
||||
void setCopyIn(void) const { highflags |= copy_in; } ///< Mark the existence of COPY ops into \b this
|
||||
bool hasCopyIn(void) const { return ((highflags©_in)!=0); } ///< Are there COPY ops into \b this
|
||||
bool isCopyProcessed(void) const { return ((highflags©_processed)!=0); } ///< Have COPY ops into \b this been processed
|
||||
void setCopyProcessed(void) const { highflags |= copy_processed; } ///< Mark that \b this has had its COPY ins processed
|
||||
|
||||
/// \brief Determine if \b this HighVariable has an associated cover.
|
||||
///
|
||||
|
Loading…
Reference in New Issue
Block a user