mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-04 18:29:37 +02:00
Refactor of RulePtrArith
This commit is contained in:
parent
e7bd8a6dba
commit
0a4d2d7ba1
2 changed files with 279 additions and 207 deletions
|
@ -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) {
|
isSubtype = false; // There are no offsets INTO the pointer
|
||||||
nonmultbytes = AddrSpace::addressToByte(state.nonmultsum,ct->getWordSize()); // Convert to bytes
|
}
|
||||||
|
else if (ct->getPtrTo()->getMetatype() == TYPE_SPACEBASE) {
|
||||||
|
uintb nonmultbytes = AddrSpace::addressToByte(nonmultsum,ct->getWordSize()); // Convert to bytes
|
||||||
|
uintb extra;
|
||||||
// Get offset into mapped variable
|
// Get offset into mapped variable
|
||||||
if (ct->getPtrTo()->getSubType(nonmultbytes,&extra)==(Datatype *)0)
|
if (ct->getPtrTo()->getSubType(nonmultbytes, &extra) == (Datatype*)0) {
|
||||||
return 0; // Cannot find mapped variable but nonmult is non-empty
|
valid = false; // Cannot find mapped variable but nonmult is non-empty
|
||||||
extra = AddrSpace::byteToAddress(extra,ct->getWordSize()); // Convert back to address units
|
return;
|
||||||
offset = (state.nonmultsum - extra) & ptrmask;
|
|
||||||
yes_subtype = true;
|
|
||||||
}
|
}
|
||||||
else if (ct->getPtrTo()->getMetatype()==TYPE_STRUCT) {
|
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units
|
||||||
nonmultbytes = AddrSpace::addressToByte(state.nonmultsum,ct->getWordSize()); // Convert to bytes
|
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
|
// Get offset into field in structure
|
||||||
if (ct->getPtrTo()->getSubType(nonmultbytes,&extra)==(Datatype *)0) {
|
if (ct->getPtrTo()->getSubType(nonmultbytes, &extra) == (Datatype*) 0) {
|
||||||
if (nonmultbytes >= ct->getPtrTo()->getSize()) return 0; // Out of structure's bounds
|
if (nonmultbytes >= ct->getPtrTo()->getSize()) {
|
||||||
|
valid = false; // Out of structure's bounds
|
||||||
|
return;
|
||||||
|
}
|
||||||
extra = 0; // No field, but pretend there is something there
|
extra = 0; // No field, but pretend there is something there
|
||||||
}
|
}
|
||||||
extra = AddrSpace::byteToAddress(extra,ct->getWordSize()); // Convert back to address units
|
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units
|
||||||
offset = (state.nonmultsum - extra) & ptrmask;
|
offset = (nonmultsum - extra) & ptrmask;
|
||||||
yes_subtype = true;
|
isSubtype = true;
|
||||||
}
|
}
|
||||||
else if (ct->getPtrTo()->getMetatype()==TYPE_ARRAY) {
|
else if (ct->getPtrTo()->getMetatype() == TYPE_ARRAY) {
|
||||||
yes_subtype = true;
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Construct part of the tree that sums to a multiple of the base data-type size.
|
||||||
|
/// This value will be added to the base pointer as a CPUI_PTRADD. The final Varnode produced
|
||||||
|
/// 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
|
// Be sure to preserve sign in division below
|
||||||
// Calc size-relative constant PTR addition
|
// Calc size-relative constant PTR addition
|
||||||
intb smultsum = (intb)state.multsum;
|
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
|
||||||
|
multNode = ptr; // Zero multiple terms
|
||||||
|
|
||||||
|
// Create PTRSUB portion of operation
|
||||||
|
if (isSubtype) {
|
||||||
|
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
|
||||||
|
multNode = newop->getOut();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fullother != (Varnode *)0)
|
// Add back in any remaining terms
|
||||||
newop = data.newOpBefore(bottom_op,CPUI_INT_ADD,ptrbump,fullother);
|
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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue