Refactor of RulePtrArith

This commit is contained in:
caheckman 2020-04-27 15:48:30 -04:00
parent e7bd8a6dba
commit 0a4d2d7ba1
2 changed files with 279 additions and 207 deletions

View file

@ -5653,14 +5653,28 @@ int4 RuleEqual2Constant::applyOp(PcodeOp *op,Funcdata &data)
return 1; return 1;
} }
/// \brief Accumulate details of given term and continue tree traversal AddTreeState::AddTreeState(PcodeOp *op,int4 slot)
///
{
baseOp = op;
ptr = op->getIn(slot);
ct = (const TypePointer *)ptr->getType();
ptrsize = ptr->getSize();
ptrmask = calc_mask(ptrsize);
size = AddrSpace::byteToAddressInt(ct->getPtrTo()->getSize(),ct->getWordSize());
multsum = 0; // Sums start out as zero
nonmultsum = 0;
correct = 0;
offset = 0;
valid = true; // Valid until proven otherwise
isSubtype = false;
}
/// If the given Varnode is a constant or multiplicative term, update /// If the given Varnode is a constant or multiplicative term, update
/// totals in the state object. If the Varnode is additive, traverse its sub-terms. /// totals. If the Varnode is additive, traverse its sub-terms.
/// \param vn is the given Varnode term /// \param vn is the given Varnode term
/// \param state is the state object
/// \return \b true if Varnode is a NON-multiple /// \return \b true if Varnode is a NON-multiple
bool RulePtrArith::checkTerm(Varnode *vn,AddTreeState *state) bool AddTreeState::checkTerm(Varnode *vn)
{ {
uintb val; uintb val;
@ -5668,29 +5682,29 @@ bool RulePtrArith::checkTerm(Varnode *vn,AddTreeState *state)
Varnode *vnconst,*vnterm; Varnode *vnconst,*vnterm;
PcodeOp *def; PcodeOp *def;
if (vn == state->ptr) return false; if (vn == ptr) return false;
if (vn->isConstant()) { if (vn->isConstant()) {
val = vn->getOffset(); val = vn->getOffset();
if (state->size == 0) if (size == 0)
rem = val; rem = val;
else { else {
intb sval = (intb)val; intb sval = (intb)val;
sign_extend(sval,vn->getSize()*8-1); sign_extend(sval,vn->getSize()*8-1);
rem = sval % state->size; rem = sval % size;
} }
if (rem!=0) { // constant is not multiple of size if (rem!=0) { // constant is not multiple of size
state->nonmultsum += val; nonmultsum += val;
return true; return true;
} }
state->multsum += val; // Add multiples of size into multsum multsum += val; // Add multiples of size into multsum
return false; return false;
} }
if (vn->isWritten()) { if (vn->isWritten()) {
def = vn->getDef(); def = vn->getDef();
if (def->code() == CPUI_INT_ADD) // Recurse if (def->code() == CPUI_INT_ADD) // Recurse
return spanAddTree(def,state); return spanAddTree(def);
if (def->code() == CPUI_COPY) { // Not finished reducing yet if (def->code() == CPUI_COPY) { // Not finished reducing yet
state->valid = false; valid = false;
return false; return false;
} }
if (def->code() == CPUI_INT_MULT) { // Check for constant coeff indicating size if (def->code() == CPUI_INT_MULT) { // Check for constant coeff indicating size
@ -5698,23 +5712,23 @@ bool RulePtrArith::checkTerm(Varnode *vn,AddTreeState *state)
vnterm = def->getIn(0); vnterm = def->getIn(0);
if (vnconst->isConstant()) { if (vnconst->isConstant()) {
val = vnconst->getOffset(); val = vnconst->getOffset();
if (state->size == 0) if (size == 0)
rem = val; rem = val;
else { else {
intb sval = (intb) val; intb sval = (intb) val;
sign_extend(sval, vn->getSize() * 8 - 1); sign_extend(sval, vn->getSize() * 8 - 1);
rem = sval % state->size; rem = sval % size;
} }
if (rem!=0) { if (rem!=0) {
if ((val > state->size)&&(state->size!=0)) { if ((val > size)&&(size!=0)) {
state->valid = false; // Size is too big: pointer type must be wrong valid = false; // Size is too big: pointer type must be wrong
return false; return false;
} }
return true; return true;
} }
if (rem==0) { if (rem==0) {
state->multiple.push_back(vnterm); multiple.push_back(vnterm);
state->coeff.push_back(val); coeff.push_back(val);
return false; return false;
} }
} }
@ -5723,192 +5737,253 @@ bool RulePtrArith::checkTerm(Varnode *vn,AddTreeState *state)
return true; return true;
} }
/// \brief Traverse the additive expression accumulating offset information. /// Recursively walk the sub-tree from the given root. This routine returns
/// /// \b true if no leaf nodes of the tree have been identified in the sub-tree.
/// In this case, this root may itself be a leaf (we don't know yet), otherwise
/// we know this root is \e not a leaf.
/// \param op is the root of the sub-expression to traverse /// \param op is the root of the sub-expression to traverse
/// \param state holds the offset information /// \return \b true if the given root might be a leaf
/// \return \b true if the sub-expression is invalid or a NON-multiple bool AddTreeState::spanAddTree(PcodeOp *op)
bool RulePtrArith::spanAddTree(PcodeOp *op,AddTreeState *state)
{ {
bool one_is_non,two_is_non; bool one_is_non,two_is_non;
one_is_non = checkTerm(op->getIn(0),state); one_is_non = checkTerm(op->getIn(0));
if (!state->valid) return false; if (!valid) return false;
two_is_non = checkTerm(op->getIn(1),state); two_is_non = checkTerm(op->getIn(1));
if (!state->valid) return false; if (!valid) return false;
if (one_is_non&&two_is_non) return true; if (one_is_non&&two_is_non) return true;
// Reaching here we know either, slot 0 or 1 is a leaf
if (one_is_non) if (one_is_non)
state->nonmult.push_back(op->getIn(0)); nonmult.push_back(op->getIn(0));
if (two_is_non) if (two_is_non)
state->nonmult.push_back(op->getIn(1)); nonmult.push_back(op->getIn(1));
return false; return false; // We are definitely not a leaf
} }
/// \brief Rewrite a pointer expression using PTRSUB and PTRADD /// Make final calcultions to determine if a pointer to a sub data-type of the base
/// /// data-type is being calculated, which will result in a CPUI_PTRSUB being generated.
/// Given a base pointer of known data-type and an additive expression involving void AddTreeState::calcSubtype(void)
/// the pointer, group the terms of the expression into:
/// - Constant multiple of the base data-type
/// - Non-constant multiples of the base data-type
/// - Multiples of an array element size: rewrite using PTRADD
/// - Drill down into sub-components of the base data-type: rewrite using PTRSUB
/// - Remaining offsets
///
/// \param bottom_op is the root Varnode of the expression
/// \param ptr_op is the PcodeOp taking the base pointer as input
/// \param slot is the input slot of the base pointer
/// \param data is the function being analyzed
/// \return 1 if modifications are made, 0 otherwise
int4 RulePtrArith::transformPtr(PcodeOp *bottom_op,PcodeOp *ptr_op,int4 slot,Funcdata &data)
{ {
AddTreeState state; nonmultsum &= ptrmask; // Make sure we are modulo ptr's space
const TypePointer *ct; multsum &= ptrmask;
bool yes_subtype,offset_corrected; if (size == 0)
int4 i,ptrsize; offset = nonmultsum;
uintb ptrmask,correct,coeff,offset,nonmultbytes,extra;
Varnode *ptrbump; // Will contain final result of PTR addition
Varnode *fullother; // Will contain anything else not part of PTR add
Varnode *newvn;
PcodeOp *newop = (PcodeOp *)0;
state.ptr = ptr_op->getIn(slot);
ct = (const TypePointer *) state.ptr->getType();
ptrsize = state.ptr->getSize();
state.size = AddrSpace::byteToAddressInt(ct->getPtrTo()->getSize(),ct->getWordSize());
state.multsum = 0; // Sums start out as zero
state.nonmultsum = 0;
state.valid = true; // Valid until proven otherwise
spanAddTree(bottom_op,&state); // Find multiples and non-multiples of ct->getSize()
if (!state.valid) return 0; // Were there any show stoppers
ptrmask = calc_mask(ptrsize);
state.nonmultsum &= ptrmask; // Make sure we are modulo ptr's space
state.multsum &= ptrmask;
if (state.size == 0)
offset = state.nonmultsum;
else { else {
intb snonmult = (intb)state.nonmultsum; intb snonmult = (intb)nonmultsum;
sign_extend(snonmult,ptrsize*8-1); sign_extend(snonmult,ptrsize*8-1);
snonmult = snonmult % state.size; snonmult = snonmult % size;
offset = (snonmult < 0) ? (uintb)(snonmult + state.size) : (uintb)snonmult; offset = (snonmult < 0) ? (uintb)(snonmult + size) : (uintb)snonmult;
} }
correct = state.nonmultsum - offset; correct = nonmultsum - offset;
state.nonmultsum = offset; nonmultsum = offset;
state.multsum = (state.multsum + correct) & ptrmask; // Some extra multiples of size multsum = (multsum + correct) & ptrmask; // Some extra multiples of size
if (nonmult.empty()) {
// Figure out if there is any subtype if ((multsum == 0) && multiple.empty()) { // Is there anything at all
if (state.nonmult.empty()) { valid = false;
if ((state.multsum==0)&&state.multiple.empty()) // Is there anything at all return;
return 0;
yes_subtype = false; // If there are no offsets INTO the pointer
offset = 0; // Do not check if there are sub structures
}
else if (ct->getPtrTo()->getMetatype()==TYPE_SPACEBASE) {
nonmultbytes = AddrSpace::addressToByte(state.nonmultsum,ct->getWordSize()); // Convert to bytes
// Get offset into mapped variable
if (ct->getPtrTo()->getSubType(nonmultbytes,&extra)==(Datatype *)0)
return 0; // Cannot find mapped variable but nonmult is non-empty
extra = AddrSpace::byteToAddress(extra,ct->getWordSize()); // Convert back to address units
offset = (state.nonmultsum - extra) & ptrmask;
yes_subtype = true;
}
else if (ct->getPtrTo()->getMetatype()==TYPE_STRUCT) {
nonmultbytes = AddrSpace::addressToByte(state.nonmultsum,ct->getWordSize()); // Convert to bytes
// Get offset into field in structure
if (ct->getPtrTo()->getSubType(nonmultbytes,&extra)==(Datatype *)0) {
if (nonmultbytes >= ct->getPtrTo()->getSize()) return 0; // Out of structure's bounds
extra = 0; // No field, but pretend there is something there
} }
extra = AddrSpace::byteToAddress(extra,ct->getWordSize()); // Convert back to address units isSubtype = false; // There are no offsets INTO the pointer
offset = (state.nonmultsum - extra) & ptrmask;
yes_subtype = true;
} }
else if (ct->getPtrTo()->getMetatype()==TYPE_ARRAY) { else if (ct->getPtrTo()->getMetatype() == TYPE_SPACEBASE) {
yes_subtype = true; uintb nonmultbytes = AddrSpace::addressToByte(nonmultsum,ct->getWordSize()); // Convert to bytes
uintb extra;
// Get offset into mapped variable
if (ct->getPtrTo()->getSubType(nonmultbytes, &extra) == (Datatype*)0) {
valid = false; // Cannot find mapped variable but nonmult is non-empty
return;
}
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units
offset = (nonmultsum - extra) & ptrmask;
isSubtype = true;
}
else if (ct->getPtrTo()->getMetatype() == TYPE_STRUCT) {
uintb nonmultbytes = AddrSpace::addressToByte(nonmultsum,ct->getWordSize()); // Convert to bytes
uintb extra;
// Get offset into field in structure
if (ct->getPtrTo()->getSubType(nonmultbytes, &extra) == (Datatype*) 0) {
if (nonmultbytes >= ct->getPtrTo()->getSize()) {
valid = false; // Out of structure's bounds
return;
}
extra = 0; // No field, but pretend there is something there
}
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units
offset = (nonmultsum - extra) & ptrmask;
isSubtype = true;
}
else if (ct->getPtrTo()->getMetatype() == TYPE_ARRAY) {
isSubtype = true;
offset = 0; offset = 0;
} }
else // No struct or array, but nonmult is non-empty else {
return 0; // There is substructure we don't know about // No struct or array, but nonmult is non-empty
valid = false; // There is substructure we don't know about
}
}
// Be sure to preserve sign in division below /// Construct part of the tree that sums to a multiple of the base data-type size.
// Calc size-relative constant PTR addition /// This value will be added to the base pointer as a CPUI_PTRADD. The final Varnode produced
intb smultsum = (intb)state.multsum; /// by the sum is returned. If there are no multiples, null is returned.
/// \param data is the function being operated on
/// \return the output Varnode of the multiple tree or null
Varnode *AddTreeState::buildMultiples(Funcdata &data)
{
Varnode *resNode;
// Be sure to preserve sign in division below
// Calc size-relative constant PTR addition
intb smultsum = (intb)multsum;
sign_extend(smultsum,ptrsize*8-1); sign_extend(smultsum,ptrsize*8-1);
coeff = (state.size==0) ? (uintb)0 : (smultsum / state.size) & ptrmask; uintb constCoeff = (size==0) ? (uintb)0 : (smultsum / size) & ptrmask;
if (coeff == 0) if (constCoeff == 0)
ptrbump = (Varnode *)0; resNode = (Varnode *)0;
else else
ptrbump = data.newConstant(ptrsize,coeff); resNode= data.newConstant(ptrsize,constCoeff);
for(i=0;i<state.multiple.size();++i) { for(int4 i=0;i<multiple.size();++i) {
coeff = (state.size==0) ? (uintb)0 : state.coeff[i] / state.size; uintb finalCoeff = (size==0) ? (uintb)0 : coeff[i] / size;
newvn = state.multiple[i]; Varnode *vn = multiple[i];
if (coeff != 1) { if (finalCoeff != 1) {
newop = data.newOpBefore(bottom_op,CPUI_INT_MULT,newvn,data.newConstant(ptrsize,coeff)); PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_MULT,vn,data.newConstant(ptrsize,finalCoeff));
newvn = newop->getOut(); vn = op->getOut();
} }
if (ptrbump == (Varnode *)0) if (resNode == (Varnode *)0)
ptrbump = newvn; resNode = vn;
else { else {
newop = data.newOpBefore(bottom_op,CPUI_INT_ADD, newvn, ptrbump); PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_ADD, vn, resNode);
ptrbump = newop->getOut(); resNode = op->getOut();
} }
} }
// Create PTRADD portion of operation return resNode;
if (ptrbump != (Varnode *)0) { }
newop = data.newOpBefore(bottom_op,CPUI_PTRADD,
state.ptr,ptrbump,data.newConstant(ptrsize,state.size)); /// Create a subtree summing all the elements that aren't multiples of the base data-type size.
ptrbump = newop->getOut(); /// Correct for any double counting of non-multiple constants.
} /// Return the final Varnode holding the sum or null if there are no terms.
else /// \param data is the function being operated on
ptrbump = state.ptr; /// \return the final Varnode or null
// Add up any remaining pieces Varnode *AddTreeState::buildExtra(Funcdata &data)
{
correct = (correct+offset) & ptrmask; // Total correction that needs to be made correct = (correct+offset) & ptrmask; // Total correction that needs to be made
offset_corrected= (correct==0); bool offset_corrected= (correct==0);
fullother = (Varnode *)0; Varnode *resNode = (Varnode *)0;
for(i=0;i<state.nonmult.size();++i) { for(int4 i=0;i<nonmult.size();++i) {
newvn = state.nonmult[i]; Varnode *vn = nonmult[i];
if ((!offset_corrected)&&(newvn->isConstant())) if ((!offset_corrected)&&(vn->isConstant()))
if (newvn->getOffset() == correct) { if (vn->getOffset() == correct) {
offset_corrected = true; offset_corrected = true;
continue; continue;
} }
if (fullother == (Varnode *)0) if (resNode == (Varnode *)0)
fullother = newvn; resNode = vn;
else { else {
newop = data.newOpBefore(bottom_op,CPUI_INT_ADD,newvn,fullother); PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_ADD,vn,resNode);
fullother = newop->getOut(); resNode = op->getOut();
} }
} }
if (!offset_corrected) { if (!offset_corrected) {
newvn = data.newConstant(ptrsize,uintb_negate(correct-1,ptrsize)); Varnode *vn = data.newConstant(ptrsize,uintb_negate(correct-1,ptrsize));
if (fullother == (Varnode *)0) if (resNode == (Varnode *)0)
fullother = newvn; resNode = vn;
else { else {
newop = data.newOpBefore(bottom_op,CPUI_INT_ADD,newvn,fullother); PcodeOp *op = data.newOpBefore(baseOp,CPUI_INT_ADD,vn,resNode);
fullother = newop->getOut(); resNode = op->getOut();
} }
} }
// Do PTRSUB portion of operation return resNode;
if (yes_subtype) { }
newop = data.newOpBefore(bottom_op,CPUI_PTRSUB,ptrbump,data.newConstant(ptrsize,offset));
ptrbump = newop->getOut(); void AddTreeState::walkTree(void)
{
spanAddTree(baseOp);
if (!valid) return; // Were there any show stoppers
calcSubtype();
}
/// The original ADD tree has been successfully spit into \e multiple and
/// \e non-multiple pieces. Rewrite the tree as a pointer expression, putting
/// any \e multiple pieces into a PTRADD operation, creating a PTRSUB if a sub
/// data-type offset has been calculated, and preserving and remaining terms.
void AddTreeState::buildTree(Funcdata &data)
{
Varnode *multNode = buildMultiples(data);
Varnode *extraNode = buildExtra(data);
PcodeOp *newop = (PcodeOp *)0;
// Create PTRADD portion of operation
if (multNode != (Varnode *)0) {
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
multNode = newop->getOut();
} }
else
if (fullother != (Varnode *)0) multNode = ptr; // Zero multiple terms
newop = data.newOpBefore(bottom_op,CPUI_INT_ADD,ptrbump,fullother);
// Create PTRSUB portion of operation
if (isSubtype) {
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
multNode = newop->getOut();
}
// Add back in any remaining terms
if (extraNode != (Varnode *)0)
newop = data.newOpBefore(baseOp,CPUI_INT_ADD,multNode,extraNode);
if (newop == (PcodeOp *)0) { if (newop == (PcodeOp *)0) {
// This shouldn't happen, but does because of negative offsets // This should never happen
// Should be fixed when we convert everything to signed calc data.warning("ptrarith problems",baseOp->getAddr());
data.warning("ptrarith problems",ptr_op->getAddr()); return;
return 0;
} }
data.opSetOutput(newop,bottom_op->getOut()); data.opSetOutput(newop,baseOp->getOut());
data.opDestroy(bottom_op); data.opDestroy(baseOp);
return 1; }
/// \brief Verify that given PcodeOp occurs at the bottom of the CPUI_INT_ADD tree
///
/// The main RulePtrArith algorithm assumes that the pointer Varnode is at the bottom
/// of the expression tree that is adding an offset to the pointer. This routine
/// verifies this condition.
/// \param op is the given PcodeOp which is the putative last operation in the tree
/// \param slot is the slot of the pointer Varnode within the given PcodeOp
/// \return \b true if the pointer is at the bottom of the tree, \b false otherwise
bool RulePtrArith::verifyAddTreeBottom(PcodeOp *op,int4 slot)
{
Varnode *vn = op->getOut();
Varnode *ptrbase = op->getIn(slot);
list<PcodeOp *>::const_iterator iter=vn->beginDescend();
OpCode opc;
if (iter == vn->endDescend()) return false; // Don't bother if no descendants
PcodeOp *lowerop = *iter++;
opc = lowerop->code();
if (vn->isSpacebase()) // For the RESULT to be a spacebase pointer
if (iter!=vn->endDescend()) // It must have only 1 descendant
return false;
if (opc == CPUI_INT_ADD) // Check for lone descendant which is an ADD
if (iter==vn->endDescend())
return false; // this is not bottom of add tree
if (ptrbase->isSpacebase() && (ptrbase->isInput()||(ptrbase->isConstant())) &&
(op->getIn(1-slot)->isConstant())) {
// Look for ANY descendant which LOADs or STOREs off of vn
if ((opc==CPUI_LOAD)||(opc==CPUI_STORE)) {
if (lowerop->getIn(1) == vn)
return false;
}
while(iter!=vn->endDescend()) {
opc = (*iter)->code();
if ((opc==CPUI_LOAD)||(opc==CPUI_STORE)) {
if ((*iter)->getIn(1) == vn)
return false;
}
++iter;
}
}
return true;
} }
/// \class RulePtrArith /// \class RulePtrArith
@ -5939,56 +6014,25 @@ void RulePtrArith::getOpList(vector<uint4> &oplist) const
int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data) int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
{ {
int4 i; int4 slot;
const Datatype *ct = (const Datatype *)0; // Unnecessary initialization const Datatype *ct = (const Datatype *)0; // Unnecessary initialization
const TypePointer *tp;
Varnode *vn,*ptrbase;
PcodeOp *lowerop;
if (!data.isTypeRecoveryOn()) return 0; if (!data.isTypeRecoveryOn()) return 0;
for(i=0;i<op->numInput();++i) { // Search for pointer type for(slot=0;slot<op->numInput();++slot) { // Search for pointer type
ct = op->getIn(i)->getType(); ct = op->getIn(slot)->getType();
if (ct->getMetatype() == TYPE_PTR) break; if (ct->getMetatype() == TYPE_PTR) break;
} }
if (i == op->numInput()) return 0; if (slot == op->numInput()) return 0;
if (!verifyAddTreeBottom(op, slot)) return 0;
vn = op->getOut(); const TypePointer *tp = (const TypePointer *) ct;
ptrbase = op->getIn(i);
list<PcodeOp *>::const_iterator iter=vn->beginDescend();
OpCode opc;
if (iter == vn->endDescend()) return 0; // Don't bother if no descendants
lowerop = *iter++;
opc = lowerop->code();
if (vn->isSpacebase()) // For the RESULT to be a spacebase pointer
if (iter!=vn->endDescend()) return 0; // It must have only 1 descendant
if (opc == CPUI_INT_ADD) // Check for lone descendant which is an ADD
if (iter==vn->endDescend()) return 0; // this is not bottom of add tree
if (ptrbase->isSpacebase() && (ptrbase->isInput()||(ptrbase->isConstant())) &&
(op->getIn(1-i)->isConstant())) {
// Look for ANY descendant which
// LOADs or STOREs off of vn
if ((opc==CPUI_LOAD)||(opc==CPUI_STORE)) {
if (lowerop->getIn(1) == vn)
return 0;
}
while(iter!=vn->endDescend()) {
opc = (*iter)->code();
if ((opc==CPUI_LOAD)||(opc==CPUI_STORE)) {
if ((*iter)->getIn(1) == vn)
return 0;
}
++iter;
}
}
tp = (const TypePointer *) ct;
ct = tp->getPtrTo(); // Type being pointed to ct = tp->getPtrTo(); // Type being pointed to
int4 unitsize = AddrSpace::addressToByteInt(1,tp->getWordSize()); int4 unitsize = AddrSpace::addressToByteInt(1,tp->getWordSize());
if (ct->getSize() == unitsize) { // Degenerate case if (ct->getSize() == unitsize) { // Degenerate case
vector<Varnode *> newparams; vector<Varnode *> newparams;
newparams.push_back( ptrbase ); newparams.push_back( op->getIn(slot) );
newparams.push_back( op->getIn(1-i) ); newparams.push_back( op->getIn(1-slot) );
newparams.push_back( data.newConstant(tp->getSize(),1)); newparams.push_back( data.newConstant(tp->getSize(),1));
data.opSetAllInput(op,newparams); data.opSetAllInput(op,newparams);
data.opSetOpcode(op,CPUI_PTRADD); data.opSetOpcode(op,CPUI_PTRADD);
@ -5999,7 +6043,13 @@ int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
// probably some sort of padding going on // probably some sort of padding going on
return 0; return 0;
return transformPtr(op,op,i,data); AddTreeState state(op,slot);
state.walkTree(); // Find multiples and non-multiples of base data-type size
if (!state.valid)
return 0;
state.buildTree(data);
return 1;
} }
/// \class RuleStructOffset0 /// \class RuleStructOffset0

View file

@ -28,16 +28,40 @@
#include "action.hh" #include "action.hh"
/// \brief Structure for sorting out pointer expression trees /// \brief Structure for sorting out pointer expression trees
///
/// Given a base pointer of known data-type and an additive expression involving
/// the pointer, group the terms of the expression into:
/// - Constant multiple of the base data-type
/// - Non-constant multiples of the base data-type
/// - Multiples of an array element size: rewrite using PTRADD
/// - Drill down into sub-components of the base data-type: rewrite using PTRSUB
/// - Remaining offsets
///
class AddTreeState { class AddTreeState {
public: PcodeOp *baseOp; ///< Base of the ADD tree
Varnode *ptr; ///< The pointer varnode Varnode *ptr; ///< The pointer varnode
int4 size; ///< Size of ptr type in question const TypePointer *ct; ///< The pointer data-type
int4 ptrsize; ///< Size of the pointer
int4 size; ///< Size of data-type being pointed to
uintb ptrmask; ///< Mask for modulo calculations in ptr space
uintb offset; ///< Number of bytes we dig into the base data-type
uintb correct; ///< Number of bytes being double counted
vector<Varnode *> multiple; ///< Varnodes which are multiples of size vector<Varnode *> multiple; ///< Varnodes which are multiples of size
vector<uintb> coeff; ///< Associated constant multiple vector<uintb> coeff; ///< Associated constant multiple
vector<Varnode *> nonmult; ///< Varnodes which are not multiples vector<Varnode *> nonmult; ///< Varnodes which are not multiples
uintb multsum; ///< Sum of multiple constants uintb multsum; ///< Sum of multiple constants
uintb nonmultsum; ///< Sum of non-multiple constants uintb nonmultsum; ///< Sum of non-multiple constants
bool isSubtype; ///< Is there a sub-type (using CPUI_PTRSUB)
bool checkTerm(Varnode *vn); ///< Accumulate details of given term and continue tree traversal
bool spanAddTree(PcodeOp *op); ///< Walk the given sub-tree
void calcSubtype(void); ///< Calculate final sub-type offset
Varnode *buildMultiples(Funcdata &data); ///< Build part of tree that is multiple of base size
Varnode *buildExtra(Funcdata &data); ///< Build part of tree not accounted for by multiples or \e offset
public:
bool valid; ///< Full tree search was performed bool valid; ///< Full tree search was performed
AddTreeState(PcodeOp *op,int4 slot); ///< Construct given root of ADD tree and pointer
void walkTree(void); ///< Traverse the entire ADD tree
void buildTree(Funcdata &data); ///< Build the transformed ADD tree
}; };
class RuleEarlyRemoval : public Rule { class RuleEarlyRemoval : public Rule {
@ -993,9 +1017,7 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data); virtual int4 applyOp(PcodeOp *op,Funcdata &data);
}; };
class RulePtrArith : public Rule { class RulePtrArith : public Rule {
static bool checkTerm(Varnode *vn,AddTreeState *state); static bool verifyAddTreeBottom(PcodeOp *op,int4 slot);
static bool spanAddTree(PcodeOp *op,AddTreeState *state);
static int4 transformPtr(PcodeOp *bottom_op,PcodeOp *ptr_op,int4 slot,Funcdata &data);
public: public:
RulePtrArith(const string &g) : Rule(g, 0, "ptrarith") {} ///< Constructor RulePtrArith(const string &g) : Rule(g, 0, "ptrarith") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const { virtual Rule *clone(const ActionGroupList &grouplist) const {