GP-4979 Better support for partial array optimizations

This commit is contained in:
caheckman 2024-10-28 19:34:30 +00:00
parent 43655ab76c
commit 784540f1c0
14 changed files with 317 additions and 134 deletions

View file

@ -459,7 +459,7 @@ bool StringSequence::transform(void)
return true;
}
/// From a starting pointer, backtrack through PTRADDs to a putative root Varnode pointer.
/// From a starting pointer, backtrack through PTRADDs and COPYs to a putative root Varnode pointer.
/// \param initPtr is pointer Varnode into the root STORE
void HeapSequence::findBasePointer(Varnode *initPtr)
@ -467,22 +467,84 @@ void HeapSequence::findBasePointer(Varnode *initPtr)
basePointer = initPtr;
while(basePointer->isWritten()) {
PcodeOp *op = basePointer->getDef();
if (op->code() != CPUI_PTRADD) break;
int8 sz = op->getIn(2)->getOffset();
if (sz != charType->getAlignSize()) break;
OpCode opc = op->code();
if (opc == CPUI_PTRADD) {
int8 sz = op->getIn(2)->getOffset();
if (sz != charType->getAlignSize()) break;
}
else if (opc != CPUI_COPY)
break;
basePointer = op->getIn(0);
}
}
/// Back-track from \b basePointer through PTRSUBs, PTRADDs, and INT_ADDs to an earlier root, keeping track
/// of any offsets. If an earlier root exists, trace forward, through ops trying to match the offsets.
/// For trace of ops whose offsets match exactly, the resulting Varnode is added to the list of duplicates.
/// \param duplist will hold the list of duplicate Varnodes (including \b basePointer)
void HeapSequence::findDuplicateBases(vector<Varnode *> &duplist)
{
if (!basePointer->isWritten()) {
duplist.push_back(basePointer);
return;
}
PcodeOp *op = basePointer->getDef();
OpCode opc = op->code();
if ((opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRADD) || !op->getIn(1)->isConstant()) {
duplist.push_back(basePointer);
return;
}
Varnode *copyRoot = basePointer;
vector<uintb> offset;
do {
uintb off = op->getIn(1)->getOffset();
if (opc == CPUI_PTRADD)
off *= op->getIn(2)->getOffset();
offset.push_back(off);
copyRoot = op->getIn(0);
if (!copyRoot->isWritten()) break;
op = copyRoot->getDef();
opc = op->code();
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRSUB)
break;
} while(op->getIn(1)->isConstant());
duplist.push_back(copyRoot);
vector<Varnode *> midlist;
for(int4 i=offset.size()-1;i>=0;--i) {
duplist.swap(midlist);
duplist.clear();
for(int4 j=0;j<midlist.size();++j) {
Varnode *vn = midlist[j];
list<PcodeOp *>::const_iterator iter = vn->beginDescend();
while(iter != vn->endDescend()) {
op = *iter;
++iter;
opc = op->code();
if (opc != CPUI_PTRSUB && opc != CPUI_INT_ADD && opc != CPUI_PTRSUB)
continue;
if (op->getIn(0) != vn || !op->getIn(1)->isConstant())
continue;
uintb off = op->getIn(1)->getOffset();
if (opc == CPUI_PTRADD)
off *= op->getIn(2)->getOffset();
if (off != offset[i])
continue;
duplist.push_back(op->getOut());
}
}
}
}
/// Find STOREs with pointers derived from the \b basePointer and that are in the same
/// basic block as the root STORE. The root STORE is \e not included in the resulting set.
/// \param stores holds the collected STOREs
void HeapSequence::findInitialStores(vector<PcodeOp *> &stores)
{
Datatype *ptrType = rootOp->getIn(1)->getTypeReadFacing(rootOp);
vector<Varnode *> ptradds;
ptradds.push_back(basePointer);
findDuplicateBases(ptradds);
int4 pos = 0;
int4 alignSize = charType->getAlignSize();
while(pos < ptradds.size()) {
@ -494,10 +556,14 @@ void HeapSequence::findInitialStores(vector<PcodeOp *> &stores)
OpCode opc = op->code();
if (opc == CPUI_PTRADD) {
if (op->getIn(0) != vn) continue;
if (op->getOut()->getTypeDefFacing() != ptrType) continue;
// We only check array element size here, if we checked the data-type, we would
// need to take into account different pointer styles to the same element data-type
if (op->getIn(2)->getOffset() != alignSize) continue;
ptradds.push_back(op->getOut());
}
else if (opc == CPUI_COPY) {
ptradds.push_back(op->getOut());
}
else if (opc == CPUI_STORE && op->getParent() == block && op != rootOp) {
if (op->getIn(1) != vn) continue;
stores.push_back(op);
@ -530,7 +596,7 @@ uint8 HeapSequence::calcAddElements(Varnode *vn,vector<Varnode *> &nonConst,int4
/// \brief Calculate the offset and any non-constant additive elements between the given Varnode and the \b basePointer
///
/// Walk backward from the given Varnode thru PTRADDs and ADDs, summing any offsets encountered.
/// Walk backward from the given Varnode thru PTRADDs and COPYs, summing any offsets encountered.
/// Any non-constant Varnodes encountered in the path, that are not themselves a pointer, are passed back in a list.
/// \param vn is the given Varnode to trace back to the \b basePointer
/// \param nonConst will hold the list of non-constant Varnodes being passed back
@ -539,12 +605,23 @@ uint8 HeapSequence::calcPtraddOffset(Varnode *vn,vector<Varnode *> &nonConst)
{
uint8 res = 0;
while(vn != basePointer) {
PcodeOp *ptradd = vn->getDef();
uint8 off = calcAddElements(ptradd->getIn(1),nonConst,3);
off *= (uint8)ptradd->getIn(2)->getOffset();
res += off;
vn = ptradd->getIn(0);
while(vn->isWritten()) {
PcodeOp *op = vn->getDef();
OpCode opc = op->code();
if (opc == CPUI_PTRADD) {
uint8 mult = op->getIn(2)->getOffset();
if (mult != charType->getAlignSize())
break;
uint8 off = calcAddElements(op->getIn(1),nonConst,3);
off *= mult;
res += off;
vn = op->getIn(0);
}
else if (opc == CPUI_COPY) {
vn = op->getIn(0);
}
else
break;
}
return res;
}