mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 10:19:23 +02:00
progress towards dominant COPY model
This commit is contained in:
parent
ec9e31483a
commit
00bbc8516b
6 changed files with 150 additions and 20 deletions
|
@ -720,6 +720,39 @@ FlowBlock *FlowBlock::findCommonBlock(FlowBlock *bl1,FlowBlock *bl2)
|
||||||
return common;
|
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
|
/// 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
|
/// Update \b index so that it has the minimum over all components
|
||||||
/// \param bl is the given FlowBlock
|
/// \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 compareBlockIndex(const FlowBlock *bl1,const FlowBlock *bl2); ///< Compare FlowBlock by index
|
||||||
static bool compareFinalOrder(const FlowBlock *bl1,const FlowBlock *bl2); ///< Final FlowBlock comparison
|
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(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
|
/// \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)
|
int4 ActionCopyMarker::apply(Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
|
vector<HighVariable *> multiCopy;
|
||||||
list<PcodeOp *>::const_iterator iter;
|
list<PcodeOp *>::const_iterator iter;
|
||||||
PcodeOp *op;
|
PcodeOp *op;
|
||||||
HighVariable *h1,*h2,*h3;
|
HighVariable *h1,*h2,*h3;
|
||||||
|
@ -3597,8 +3598,10 @@ int4 ActionCopyMarker::apply(Funcdata &data)
|
||||||
}
|
}
|
||||||
else { // COPY between different HighVariables
|
else { // COPY between different HighVariables
|
||||||
if (h1->hasCopyIn()) { // If we've seen other COPYs into this high
|
if (h1->hasCopyIn()) { // If we've seen other COPYs into this high
|
||||||
if (!h1->isCopyProcessed()) // and we haven't searched before,
|
if (!h1->isCopyProcessed()) { // and we haven't searched before,
|
||||||
data.getMerge().markRedundantCopies(h1); // search for redundant COPYs
|
multiCopy.push_back(h1);
|
||||||
|
h1->setCopyProcessed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
h1->setCopyIn();
|
h1->setCopyIn();
|
||||||
|
@ -3641,6 +3644,8 @@ int4 ActionCopyMarker::apply(Funcdata &data)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for(int4 i=0;i<multiCopy.size();++i)
|
||||||
|
data.getMerge().processCopyTrims(multiCopy[i]);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -957,20 +957,119 @@ bool Merge::checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp)
|
||||||
return true;
|
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
|
/// \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
|
/// 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
|
/// 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.
|
/// for redundancy among COPY ops that assign to the given HighVariable.
|
||||||
/// \param high is the given HighVariable
|
/// \param high is the given HighVariable
|
||||||
/// \return \b true if any redundant COPYs were discovered
|
/// \param copy is the list of COPYs coming from the same source HighVariable
|
||||||
bool Merge::markRedundantCopies(HighVariable *high)
|
/// \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;
|
vector<PcodeOp *> copyIns;
|
||||||
|
|
||||||
high->setCopyProcessed();
|
|
||||||
// Find all the COPY ops into this HighVariable from a different HighVariable
|
// Find all the COPY ops into this HighVariable from a different HighVariable
|
||||||
for(int4 i=0;i<high->numInstances();++i) {
|
for(int4 i=0;i<high->numInstances();++i) {
|
||||||
Varnode *vn = high->getInstance(i);
|
Varnode *vn = high->getInstance(i);
|
||||||
|
@ -994,21 +1093,11 @@ bool Merge::markRedundantCopies(HighVariable *high)
|
||||||
sz += 1;
|
sz += 1;
|
||||||
}
|
}
|
||||||
if (sz > 1) { // If there is more than one COPY in a group
|
if (sz > 1) { // If there is more than one COPY in a group
|
||||||
for(int4 i=sz-1;i>0;--i) {
|
buildDominantCopy(high, copyIns, pos, sz);
|
||||||
PcodeOp *subOp = copyIns[pos+i];
|
markRedundantCopies(high, copyIns, pos, sz);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
pos += sz;
|
pos += sz;
|
||||||
}
|
}
|
||||||
return hasRedundant;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Perform low-level details of merging two HighVariables if possible
|
/// \brief Perform low-level details of merging two HighVariables if possible
|
||||||
|
|
|
@ -105,6 +105,8 @@ class Merge {
|
||||||
void mergeLinear(vector<HighVariable *> &highvec);
|
void mergeLinear(vector<HighVariable *> &highvec);
|
||||||
bool merge(HighVariable *high1,HighVariable *high2,bool isspeculative);
|
bool merge(HighVariable *high1,HighVariable *high2,bool isspeculative);
|
||||||
bool checkCopyPair(HighVariable *high,PcodeOp *domOp,PcodeOp *subOp);
|
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:
|
public:
|
||||||
Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function
|
Merge(Funcdata &fd) : data(fd) {} ///< Construct given a specific function
|
||||||
bool intersection(HighVariable *a,HighVariable *b);
|
bool intersection(HighVariable *a,HighVariable *b);
|
||||||
|
@ -118,7 +120,7 @@ public:
|
||||||
void mergeMarker(void);
|
void mergeMarker(void);
|
||||||
void mergeAdjacent(void);
|
void mergeAdjacent(void);
|
||||||
bool hideShadows(HighVariable *high);
|
bool hideShadows(HighVariable *high);
|
||||||
bool markRedundantCopies(HighVariable *high);
|
void processCopyTrims(HighVariable *high);
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Compare HighVariables by the blocks they cover
|
/// \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 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 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 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:
|
public:
|
||||||
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
HighVariable(Varnode *vn); ///< Construct a HighVariable with a single member Varnode
|
||||||
Datatype *getType(void) const { updateType(); return type; } ///< Get the data-type
|
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
|
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 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
|
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.
|
/// \brief Determine if \b this HighVariable has an associated cover.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue