GP-4782 Refactor RulePtrsubUndo

This commit is contained in:
caheckman 2024-07-12 15:21:07 +00:00
parent be305db930
commit 34adcff830
7 changed files with 355 additions and 80 deletions

View file

@ -2723,7 +2723,7 @@ int4 ActionSetCasts::apply(Funcdata &data)
data.opUndoPtradd(op,true); data.opUndoPtradd(op,true);
} }
else if (opc == CPUI_PTRSUB) { // Check for PTRSUB that no longer fits pointer else if (opc == CPUI_PTRSUB) { // Check for PTRSUB that no longer fits pointer
if (!op->getIn(0)->getHighTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset())) { if (!op->getIn(0)->getTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset(),0,1)) {
if (op->getIn(1)->getOffset() == 0) { if (op->getIn(1)->getOffset() == 0) {
data.opRemoveInput(op, 1); data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY); data.opSetOpcode(op, CPUI_COPY);
@ -5232,6 +5232,7 @@ int4 ActionInferTypes::apply(Funcdata &data)
if (localcount >= 7) { // This constant arrived at empirically if (localcount >= 7) { // This constant arrived at empirically
if (localcount == 7) { if (localcount == 7) {
data.warningHeader("Type propagation algorithm not settling"); data.warningHeader("Type propagation algorithm not settling");
data.setTypeRecoveryExceeded();
localcount += 1; localcount += 1;
} }
return 0; return 0;

View file

@ -68,7 +68,8 @@ class Funcdata {
restart_pending = 0x400, ///< Analysis must be restarted (because of new override info) restart_pending = 0x400, ///< Analysis must be restarted (because of new override info)
unimplemented_present = 0x800, ///< Set if function contains unimplemented instructions unimplemented_present = 0x800, ///< Set if function contains unimplemented instructions
baddata_present = 0x1000, ///< Set if function flowed into bad data baddata_present = 0x1000, ///< Set if function flowed into bad data
double_precis_on = 0x2000 ///< Set if we are performing double precision recovery double_precis_on = 0x2000, ///< Set if we are performing double precision recovery
typerecovery_exceeded= 0x4000 ///< Set if data-type propagation passes reached maximum
}; };
uint4 flags; ///< Boolean properties associated with \b this function uint4 flags; ///< Boolean properties associated with \b this function
uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup uint4 clean_up_index; ///< Creation index of first Varnode created after start of cleanup
@ -151,6 +152,7 @@ public:
bool hasUnreachableBlocks(void) const { return ((flags&blocks_unreachable)!=0); } ///< Did this function exhibit unreachable code bool hasUnreachableBlocks(void) const { return ((flags&blocks_unreachable)!=0); } ///< Did this function exhibit unreachable code
bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Will data-type analysis be performed bool isTypeRecoveryOn(void) const { return ((flags&typerecovery_on)!=0); } ///< Will data-type analysis be performed
bool hasTypeRecoveryStarted(void) const { return ((flags&typerecovery_start)!=0); } ///< Has data-type recovery processes started bool hasTypeRecoveryStarted(void) const { return ((flags&typerecovery_start)!=0); } ///< Has data-type recovery processes started
bool isTypeRecoveryExceeded(void) const { return ((flags&typerecovery_exceeded)!=0); } ///< Has maximum propagation passes been reached
bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body bool hasNoCode(void) const { return ((flags & no_code)!=0); } ///< Return \b true if \b this function has no code body
void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body void setNoCode(bool val) { if (val) flags |= no_code; else flags &= ~no_code; } ///< Toggle whether \b this has a body
void setLanedRegGenerated(void) { minLanedSize = 1000000; } ///< Mark that laned registers have been collected void setLanedRegGenerated(void) { minLanedSize = 1000000; } ///< Mark that laned registers have been collected
@ -180,6 +182,7 @@ public:
/// ///
/// \param val is \b true if data-type analysis is enabled /// \param val is \b true if data-type analysis is enabled
void setTypeRecovery(bool val) { flags = val ? (flags | typerecovery_on) : (flags & ~typerecovery_on); } void setTypeRecovery(bool val) { flags = val ? (flags | typerecovery_on) : (flags & ~typerecovery_on); }
void setTypeRecoveryExceeded(void) { flags |= typerecovery_exceeded; } ///< Mark propagation passes have reached maximum
void startCastPhase(void) { cast_phase_index = vbank.getCreateIndex(); } ///< Start the \b cast insertion phase void startCastPhase(void) { cast_phase_index = vbank.getCreateIndex(); } ///< Start the \b cast insertion phase
uint4 getCastPhaseIndex(void) const { return cast_phase_index; } ///< Get creation index at the start of \b cast insertion uint4 getCastPhaseIndex(void) const { return cast_phase_index; } ///< Get creation index at the start of \b cast insertion
uint4 getHighLevelIndex(void) const { return high_level_index; } ///< Get creation index at the start of HighVariable creation uint4 getHighLevelIndex(void) const { return high_level_index; } ///< Get creation index at the start of HighVariable creation

View file

@ -5920,30 +5920,30 @@ bool AddTreeState::spanAddTree(PcodeOp *op,uint8 treeCoeff)
void AddTreeState::calcSubtype(void) void AddTreeState::calcSubtype(void)
{ {
if (size == 0 || nonmultsum < size) uint8 tmpoff = (multsum + nonmultsum) & ptrmask;
offset = nonmultsum; if (size == 0 || tmpoff < size)
offset = tmpoff;
else { else {
// For a sum that falls completely outside the data-type, there is presumably some // For a sum that falls completely outside the data-type, there is presumably some
// type of constant term added to an array index either at the current level or lower. // type of constant term added to an array index either at the current level or lower.
// If we knew here whether an array of the baseType was possible we could make a slightly // If we knew here whether an array of the baseType was possible we could make a slightly
// better decision. // better decision.
intb snonmult = sign_extend(nonmultsum,ptrsize*8-1); intb stmpoff = sign_extend(tmpoff,ptrsize*8-1);
snonmult = snonmult % size; stmpoff = stmpoff % size;
if (snonmult >= 0) if (stmpoff >= 0)
// We assume the sum is big enough it represents an array index at this level // We assume the sum is big enough it represents an array index at this level
offset = (uint8)snonmult; offset = (uint8)stmpoff;
else { else {
// For a negative sum, if the baseType is a structure and there is array hints, // For a negative sum, if the baseType is a structure and there is array hints,
// we assume the sum is an array index at a lower level // we assume the sum is an array index at a lower level
if (baseType->getMetatype() == TYPE_STRUCT && biggestNonMultCoeff != 0) if (baseType->getMetatype() == TYPE_STRUCT && biggestNonMultCoeff != 0 && multsum == 0)
offset = nonmultsum; offset = tmpoff;
else else
offset = (uint8)(snonmult + size); offset = (uint8)(stmpoff + size);
} }
} }
correct = nonmultsum - offset; correct = nonmultsum; // Non-multiple constants are double counted, correct in final sum
nonmultsum = offset; multsum = (tmpoff - offset) & ptrmask; // Some extra multiples of size
multsum = (multsum + correct) & ptrmask; // Some extra multiples of size
if (nonmult.empty()) { if (nonmult.empty()) {
if ((multsum == 0) && multiple.empty()) { // Is there anything at all if ((multsum == 0) && multiple.empty()) { // Is there anything at all
valid = false; valid = false;
@ -5952,31 +5952,33 @@ void AddTreeState::calcSubtype(void)
isSubtype = false; // There are no offsets INTO the pointer isSubtype = false; // There are no offsets INTO the pointer
} }
else if (baseType->getMetatype() == TYPE_SPACEBASE) { else if (baseType->getMetatype() == TYPE_SPACEBASE) {
int8 nonmultbytes = AddrSpace::addressToByteInt(nonmultsum,ct->getWordSize()); // Convert to bytes int8 offsetbytes = AddrSpace::addressToByteInt(offset,ct->getWordSize()); // Convert to bytes
int8 extra; int8 extra;
// Get offset into mapped variable // Get offset into mapped variable
if (!hasMatchingSubType(nonmultbytes, biggestNonMultCoeff, &extra)) { if (!hasMatchingSubType(offsetbytes, biggestNonMultCoeff, &extra)) {
valid = false; // Cannot find mapped variable but nonmult is non-empty valid = false; // Cannot find mapped variable but nonmult is non-empty
return; return;
} }
extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units extra = AddrSpace::byteToAddress(extra, ct->getWordSize()); // Convert back to address units
offset = (nonmultsum - extra) & ptrmask; offset = (offset - extra) & ptrmask;
correct = (correct - extra) & ptrmask;
isSubtype = true; isSubtype = true;
} }
else if (baseType->getMetatype() == TYPE_STRUCT) { else if (baseType->getMetatype() == TYPE_STRUCT) {
intb snonmult = sign_extend(nonmultsum,ptrsize*8-1); intb soffset = sign_extend(offset,ptrsize*8-1);
int8 nonmultbytes = AddrSpace::addressToByteInt(snonmult,ct->getWordSize()); // Convert to bytes int8 offsetbytes = AddrSpace::addressToByteInt(soffset,ct->getWordSize()); // Convert to bytes
int8 extra; int8 extra;
// Get offset into field in structure // Get offset into field in structure
if (!hasMatchingSubType(nonmultbytes, biggestNonMultCoeff, &extra)) { if (!hasMatchingSubType(offsetbytes, biggestNonMultCoeff, &extra)) {
if (nonmultbytes < 0 || nonmultbytes >= baseType->getSize()) { // Compare as bytes! not address units if (offsetbytes < 0 || offsetbytes >= baseType->getSize()) { // Compare as bytes! not address units
valid = false; // Out of structure's bounds valid = false; // Out of structure's bounds
return; return;
} }
extra = 0; // No field, but pretend there is something there extra = 0; // No field, but pretend there is something there
} }
extra = AddrSpace::byteToAddressInt(extra, ct->getWordSize()); // Convert back to address units extra = AddrSpace::byteToAddressInt(extra, ct->getWordSize()); // Convert back to address units
offset = (nonmultsum - extra) & ptrmask; offset = (offset - extra) & ptrmask;
correct = (correct - extra) & ptrmask;
if (pRelType != (TypePointerRel *)0 && offset == pRelType->getPointerOffset()) { if (pRelType != (TypePointerRel *)0 && offset == pRelType->getPointerOffset()) {
// offset falls within basic ptrto // offset falls within basic ptrto
if (!pRelType->evaluateThruParent(0)) { // If we are not representing offset 0 through parent if (!pRelType->evaluateThruParent(0)) { // If we are not representing offset 0 through parent
@ -5988,12 +5990,31 @@ void AddTreeState::calcSubtype(void)
} }
else if (baseType->getMetatype() == TYPE_ARRAY) { else if (baseType->getMetatype() == TYPE_ARRAY) {
isSubtype = true; isSubtype = true;
correct = (correct - offset) & ptrmask;
offset = 0; offset = 0;
} }
else { else {
// No struct or array, but nonmult is non-empty // No struct or array, but nonmult is non-empty
valid = false; // There is substructure we don't know about valid = false; // There is substructure we don't know about
} }
if (pRelType != (const TypePointerRel *)0) {
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
offset = (offset - ptrOff) & ptrmask;
correct = (correct - ptrOff) & ptrmask;
}
}
/// The data-type from the pointer input (of either a PTRSUB or PTRADD) is propagated to the
/// output of the PcodeOp.
/// \param op is the given PcodeOp
void AddTreeState::assignPropagatedType(PcodeOp *op)
{
Varnode *vn = op->getIn(0);
Datatype *inType = vn->getTypeReadFacing(op);
Datatype *newType = op->getOpcode()->propagateType(inType, op, vn, op->getOut(), 0, -1);
if (newType != (Datatype *)0)
op->getOut()->updateType(newType, false, false);
} }
/// Construct part of the tree that sums to a multiple of the base data-type size. /// Construct part of the tree that sums to a multiple of the base data-type size.
@ -6037,7 +6058,6 @@ Varnode *AddTreeState::buildMultiples(void)
Varnode *AddTreeState::buildExtra(void) Varnode *AddTreeState::buildExtra(void)
{ {
correct = correct+offset; // Total correction that needs to be made
Varnode *resNode = (Varnode *)0; Varnode *resNode = (Varnode *)0;
for(int4 i=0;i<nonmult.size();++i) { for(int4 i=0;i<nonmult.size();++i) {
Varnode *vn = nonmult[i]; Varnode *vn = nonmult[i];
@ -6138,11 +6158,6 @@ bool AddTreeState::apply(void)
void AddTreeState::buildTree(void) void AddTreeState::buildTree(void)
{ {
if (pRelType != (const TypePointerRel *)0) {
int4 ptrOff = ((TypePointerRel *)ct)->getPointerOffset();
offset -= ptrOff;
offset &= ptrmask;
}
Varnode *multNode = buildMultiples(); Varnode *multNode = buildMultiples();
Varnode *extraNode = buildExtra(); Varnode *extraNode = buildExtra();
PcodeOp *newop = (PcodeOp *)0; PcodeOp *newop = (PcodeOp *)0;
@ -6152,6 +6167,8 @@ void AddTreeState::buildTree(void)
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size)); newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
if (ptr->getType()->needsResolution()) if (ptr->getType()->needsResolution())
data.inheritResolution(ptr->getType(),newop, 0, baseOp, baseSlot); data.inheritResolution(ptr->getType(),newop, 0, baseOp, baseSlot);
if (data.isTypeRecoveryExceeded())
assignPropagatedType(newop);
multNode = newop->getOut(); multNode = newop->getOut();
} }
else else
@ -6162,6 +6179,8 @@ void AddTreeState::buildTree(void)
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset)); newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
if (multNode->getType()->needsResolution()) if (multNode->getType()->needsResolution())
data.inheritResolution(multNode->getType(),newop, 0, baseOp, baseSlot); data.inheritResolution(multNode->getType(),newop, 0, baseOp, baseSlot);
if (data.isTypeRecoveryExceeded())
assignPropagatedType(newop);
if (size != 0) if (size != 0)
newop->setStopTypePropagation(); newop->setStopTypePropagation();
multNode = newop->getOut(); multNode = newop->getOut();
@ -6555,6 +6574,8 @@ int4 RulePtraddUndo::applyOp(PcodeOp *op,Funcdata &data)
return 1; return 1;
} }
const int4 RulePtrsubUndo::DEPTH_LIMIT = 8;
/// \class RulePtrsubUndo /// \class RulePtrsubUndo
/// \brief Remove PTRSUB operations with mismatched data-type information /// \brief Remove PTRSUB operations with mismatched data-type information
/// ///
@ -6567,17 +6588,204 @@ void RulePtrsubUndo::getOpList(vector<uint4> &oplist) const
oplist.push_back(CPUI_PTRSUB); oplist.push_back(CPUI_PTRSUB);
} }
/// \brief Recursively search for additive constants and multiplicative constants
///
/// Walking backward from the given Varnode, search for constants being added in and return
/// the sum of all the constants. Additionally pass back the biggest constant coefficient, for any term
/// formed with INT_MULT.
/// \param vn is the given root Varnode of the additive tree
/// \param multiplier will hold the biggest constant coefficient
/// \param maxLevel is the maximum depth to search in the tree
/// \return the sum of all constants in the additive expression
int8 RulePtrsubUndo::getConstOffsetBack(Varnode *vn,int8 &multiplier,int4 maxLevel)
{
multiplier = 1;
int8 submultiplier;
if (vn->isConstant())
return vn->getOffset();
if (!vn->isWritten())
return 0;
maxLevel -= 1;
if (maxLevel < 0)
return 0;
PcodeOp *op = vn->getDef();
OpCode opc = op->code();
int8 retval = 0;
if (opc == CPUI_INT_ADD) {
retval += getConstOffsetBack(op->getIn(0),submultiplier,maxLevel);
if (submultiplier > multiplier)
multiplier = submultiplier;
retval += getConstOffsetBack(op->getIn(1), submultiplier, maxLevel);
if (submultiplier > multiplier)
multiplier = submultiplier;
}
else if (opc == CPUI_INT_MULT) {
Varnode *cvn = op->getIn(1);
if (!cvn->isConstant()) return 0;
multiplier = cvn->getOffset();
getConstOffsetBack(op->getIn(0), submultiplier, maxLevel);
multiplier *= submultiplier; // Only contribute to the multiplier
}
return retval;
}
/// \brief Collect constants and the biggest multiplier in the given PTRSUB expression.
///
/// Walking the additive expression (INT_ADD, PTRADD, and other PTRSUBs) and calculate any additional
/// constant value being added to the PTRSUB. Additionally pass back the biggest constant coefficient of any
/// multiplicative term in the expression.
/// \param op is the given PTRSUB
/// \param multiplier will hold the biggest multiplicative coefficient
int8 RulePtrsubUndo::getExtraOffset(PcodeOp *op,int8 &multiplier)
{
int8 extra = 0;
multiplier = 1;
int8 submultiplier;
Varnode *outvn = op->getOut();
op = outvn->loneDescend();
while(op != (PcodeOp *)0) {
OpCode opc = op->code();
if (opc == CPUI_INT_ADD) {
int4 slot = op->getSlot(outvn);
extra += getConstOffsetBack(op->getIn(1-slot),submultiplier,DEPTH_LIMIT); // Get any constants from other input
if (submultiplier > multiplier)
multiplier = submultiplier;
}
else if (opc == CPUI_PTRSUB) {
extra += op->getIn(1)->getOffset();
}
else if (opc == CPUI_PTRADD) {
if (op->getIn(0) != outvn) break;
int8 ptraddmult = op->getIn(2)->getOffset();
Varnode *invn = op->getIn(1);
if (invn->isConstant()) // Only contribute to the extra
extra += ptraddmult * (int8)invn->getOffset(); // if the index is constant
getConstOffsetBack(invn,submultiplier,DEPTH_LIMIT); // otherwise just contribute to multiplier
submultiplier *= ptraddmult;
if (submultiplier > multiplier)
multiplier = submultiplier;
}
else {
break;
}
outvn = op->getOut();
op = outvn->loneDescend();
}
extra = sign_extend(extra, 8*outvn->getSize()-1);
extra &= calc_mask(outvn->getSize());
return extra;
}
/// \brief Remove any constants in the additive expression rooted at the given PcodeOp
///
/// Walking recursively through the expression, any INT_ADD with a constant input is converted to
/// a COPY. The INT_ADD must only contribute to the root expression.
/// \param op is the given root PcodeOp
/// \param slot is the input slot to walk back from
/// \param maxLevel is the maximum depth to recurse
/// \param data is the function containing the expression
/// \return the sum of all constants that are removed
int8 RulePtrsubUndo::removeLocalAddRecurse(PcodeOp *op,int4 slot,int4 maxLevel,Funcdata &data)
{
Varnode *vn = op->getIn(slot);
if (!vn->isWritten())
return 0;
if (vn->loneDescend() != op)
return 0; // Varnode must not be used anywhere else
maxLevel -= 1;
if (maxLevel < 0)
return 0;
op = vn->getDef();
int8 retval = 0;
if (op->code() == CPUI_INT_ADD) {
if (op->getIn(1)->isConstant()) {
retval += (int8)op->getIn(1)->getOffset();
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
}
else {
retval += removeLocalAddRecurse(op, 0, maxLevel, data);
retval += removeLocalAddRecurse(op, 1, maxLevel, data);
}
}
return retval;
}
/// \brief Remove constants in the additive expression involving the given Varnode
///
/// Any additional PTRADD, PTRSUB, or INT_ADD that uses the Varnode and adds a constant is converted
/// to a COPY. Additionally any other INT_ADD involved in the expression that adds a constant is
/// also converted to COPY.
/// \param vn is the given Varnode
/// \param data is the function containing the expression
/// \return the sum of all constants that are removed
int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
{
int8 extra = 0;
PcodeOp *op = vn->loneDescend();
while(op != (PcodeOp *)0) {
OpCode opc = op->code();
if (opc == CPUI_INT_ADD) {
int4 slot = op->getSlot(vn);
if (slot == 0 && op->getIn(1)->isConstant()) {
extra += (int8)op->getIn(1)->getOffset();
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
}
else {
extra += removeLocalAddRecurse(op,1-slot,DEPTH_LIMIT, data); // Get any constants from other input
}
}
else if (opc == CPUI_PTRSUB) {
extra += op->getIn(1)->getOffset();
op->clearStopTypePropagation();
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
}
else if (opc == CPUI_PTRADD) {
if (op->getIn(0) != vn) break;
int8 ptraddmult = op->getIn(2)->getOffset();
Varnode *invn = op->getIn(1);
if (invn->isConstant()) {
extra += ptraddmult * (int8)invn->getOffset();
data.opRemoveInput(op,2);
data.opRemoveInput(op,1);
data.opSetOpcode(op, CPUI_COPY);
}
}
else {
break;
}
vn = op->getOut();
op = vn->loneDescend();
}
return extra;
}
int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data) int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
{ {
if (!data.hasTypeRecoveryStarted()) return 0; if (!data.hasTypeRecoveryStarted()) return 0;
Varnode *basevn = op->getIn(0); Varnode *basevn = op->getIn(0);
if (basevn->getTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset())) Varnode *cvn = op->getIn(1);
int8 val = cvn->getOffset();
int8 multiplier;
int8 extra = getExtraOffset(op,multiplier);
if (basevn->getTypeReadFacing(op)->isPtrsubMatching(val,extra,multiplier))
return 0; return 0;
data.opSetOpcode(op,CPUI_INT_ADD); data.opSetOpcode(op,CPUI_INT_ADD);
op->clearStopTypePropagation(); op->clearStopTypePropagation();
extra = removeLocalAdds(op->getOut(),data);
if (extra != 0) {
val = val + extra; // Lump extra into additive offset
data.opSetInput(op,data.newConstant(cvn->getSize(), val & calc_mask(cvn->getSize())),1);
}
return 1; return 1;
} }

View file

@ -71,6 +71,7 @@ class AddTreeState {
bool checkTerm(Varnode *vn,uint8 treeCoeff); ///< Accumulate details of given term and continue tree traversal bool checkTerm(Varnode *vn,uint8 treeCoeff); ///< Accumulate details of given term and continue tree traversal
bool spanAddTree(PcodeOp *op,uint8 treeCoeff); ///< Walk the given sub-tree accumulating details bool spanAddTree(PcodeOp *op,uint8 treeCoeff); ///< Walk the given sub-tree accumulating details
void calcSubtype(void); ///< Calculate final sub-type offset void calcSubtype(void); ///< Calculate final sub-type offset
void assignPropagatedType(PcodeOp *op); ///< Assign a data-type propagated through the given PcodeOp
Varnode *buildMultiples(void); ///< Build part of tree that is multiple of base size Varnode *buildMultiples(void); ///< Build part of tree that is multiple of base size
Varnode *buildExtra(void); ///< Build part of tree not accounted for by multiples or \e offset Varnode *buildExtra(void); ///< Build part of tree not accounted for by multiples or \e offset
bool buildDegenerate(void); ///< Transform ADD into degenerate PTRADD bool buildDegenerate(void); ///< Transform ADD into degenerate PTRADD
@ -1079,6 +1080,11 @@ public:
virtual int4 applyOp(PcodeOp *op,Funcdata &data); virtual int4 applyOp(PcodeOp *op,Funcdata &data);
}; };
class RulePtrsubUndo : public Rule { class RulePtrsubUndo : public Rule {
static const int4 DEPTH_LIMIT; ///< The maximum depth of the additive expression to check
static int8 getConstOffsetBack(Varnode *vn,int8 &multiplier,int4 maxLevel);
static int8 getExtraOffset(PcodeOp *op,int8 &multiplier);
static int8 removeLocalAdds(Varnode *vn,Funcdata &data);
static int8 removeLocalAddRecurse(PcodeOp *op,int4 slot,int4 maxLevel,Funcdata &data);
public: public:
RulePtrsubUndo(const string &g) : Rule(g, 0, "ptrsubundo") {} ///< Constructor RulePtrsubUndo(const string &g) : Rule(g, 0, "ptrsubundo") {} ///< Constructor
virtual Rule *clone(const ActionGroupList &grouplist) const { virtual Rule *clone(const ActionGroupList &grouplist) const {

View file

@ -528,8 +528,10 @@ void Datatype::calcAlignSize(void)
/// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component. /// A CPUI_PTRSUB must act on a pointer data-type where the given offset addresses a component.
/// Perform this check. /// Perform this check.
/// \param off is the given offset /// \param off is the given offset
/// \param extra is any additional constant being added to the pointer
/// \param multiplier is the size of any index multiplier being added to the pointer
/// \return \b true if \b this is a suitable PTRSUB data-type /// \return \b true if \b this is a suitable PTRSUB data-type
bool Datatype::isPtrsubMatching(uintb off) const bool Datatype::isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const
{ {
return false; return false;
@ -897,14 +899,14 @@ void TypePointer::printRaw(ostream &s) const
Datatype *TypePointer::getSubType(int8 off,int8 *newoff) const Datatype *TypePointer::getSubType(int8 off,int8 *newoff) const
{ {
if (truncate == (TypePointer *)0) if (truncate != (TypePointer *)0) {
return truncate;
int8 min = ((flags & truncate_bigendian) != 0) ? size - truncate->getSize() : 0; int8 min = ((flags & truncate_bigendian) != 0) ? size - truncate->getSize() : 0;
if (off >= min && off < min + truncate->getSize()) { if (off >= min && off < min + truncate->getSize()) {
*newoff = off - min; *newoff = off - min;
return truncate; return truncate;
} }
return (Datatype *)0; }
return Datatype::getSubType(off, newoff);
} }
int4 TypePointer::compare(const Datatype &op,int4 level) const int4 TypePointer::compare(const Datatype &op,int4 level) const
@ -960,6 +962,27 @@ void TypePointer::encode(Encoder &encoder) const
encoder.closeElement(ELEM_TYPE); encoder.closeElement(ELEM_TYPE);
} }
/// If the given data-type is an array, or has an arrayed component, return \b true.
/// \param dt is the given data-type to check
/// \param off is the out-of-bounds offset
/// \return \b true is an array is present
bool TypePointer::testForArraySlack(Datatype *dt,int8 off)
{
int8 newoff;
int8 elSize;
if (dt->getMetatype() == TYPE_ARRAY)
return true;
Datatype *compType;
if (off < 0) {
compType = dt->nearestArrayedComponentForward(off, &newoff, &elSize);
}
else {
compType = dt->nearestArrayedComponentBackward(off, &newoff, &elSize);
}
return (compType != (Datatype *)0);
}
/// Parse a \<type> element with a child describing the data-type being pointed to /// Parse a \<type> element with a child describing the data-type being pointed to
/// \param decoder is the stream decoder /// \param decoder is the stream decoder
/// \param typegrp is the factory owning \b this data-type /// \param typegrp is the factory owning \b this data-type
@ -1070,19 +1093,49 @@ TypePointer *TypePointer::downChain(int8 &off,TypePointer *&par,int8 &parOff,boo
return typegrp.getTypePointer(size,pt,wordsize); return typegrp.getTypePointer(size,pt,wordsize);
} }
bool TypePointer::isPtrsubMatching(uintb off) const bool TypePointer::isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const
{ {
if (ptrto->getMetatype()==TYPE_SPACEBASE) { type_metatype meta = ptrto->getMetatype();
if (meta==TYPE_SPACEBASE) {
int8 newoff = AddrSpace::addressToByteInt(off,wordsize); int8 newoff = AddrSpace::addressToByteInt(off,wordsize);
ptrto->getSubType(newoff,&newoff); Datatype *subType = ptrto->getSubType(newoff,&newoff);
if (newoff != 0) if (subType == (Datatype *)0 || newoff != 0)
return false;
extra = AddrSpace::addressToByteInt(extra,wordsize);
if (extra < 0 || extra >= subType->getSize()) {
if (!testForArraySlack(subType, extra))
return false; return false;
} }
else if (ptrto->getMetatype() == TYPE_ARRAY || ptrto->getMetatype() == TYPE_STRUCT) { }
int4 typesize = ptrto->getSize(); else if (meta == TYPE_ARRAY) {
if ((typesize <= AddrSpace::addressToByteInt(off,wordsize))&&(typesize!=0)) if (off != 0)
return false; return false;
multiplier = AddrSpace::addressToByteInt(multiplier,wordsize);
if (multiplier >= ptrto->getAlignSize())
return false;
}
else if (meta == TYPE_STRUCT) {
int4 typesize = ptrto->getSize();
multiplier = AddrSpace::addressToByteInt(multiplier,wordsize);
if (multiplier >= ptrto->getAlignSize())
return false;
int8 newoff = AddrSpace::addressToByteInt(off,wordsize);
extra = AddrSpace::addressToByteInt(extra, wordsize);
Datatype *subType = ptrto->getSubType(newoff,&newoff);
if (subType != (Datatype *)0) {
if (newoff != 0)
return false;
if (extra < 0 || extra >= subType->getSize()) {
if (!testForArraySlack(subType, extra))
return false;
}
}
else {
extra += newoff;
if ((extra < 0 || extra >= typesize)&&(typesize!=0))
return false;
}
} }
else if (ptrto->getMetatype() == TYPE_UNION) { else if (ptrto->getMetatype() == TYPE_UNION) {
// A PTRSUB reaching here cannot be used for a union field resolution // A PTRSUB reaching here cannot be used for a union field resolution
@ -1154,6 +1207,8 @@ int4 TypeArray::compareDependency(const Datatype &op) const
Datatype *TypeArray::getSubType(int8 off,int8 *newoff) const Datatype *TypeArray::getSubType(int8 off,int8 *newoff) const
{ // Go down exactly one level, to type of element { // Go down exactly one level, to type of element
if (off >= size)
return Datatype::getSubType(off, newoff);
*newoff = off % arrayof->getAlignSize(); *newoff = off % arrayof->getAlignSize();
return arrayof; return arrayof;
} }
@ -2465,13 +2520,14 @@ TypePointer *TypePointerRel::downChain(int8 &off,TypePointer *&par,int8 &parOff,
return origPointer->downChain(off,par,parOff,allowArrayWrap,typegrp); return origPointer->downChain(off,par,parOff,allowArrayWrap,typegrp);
} }
bool TypePointerRel::isPtrsubMatching(uintb off) const bool TypePointerRel::isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const
{ {
if (stripped != (TypePointer *)0) if (stripped != (TypePointer *)0)
return TypePointer::isPtrsubMatching(off); return TypePointer::isPtrsubMatching(off,extra,multiplier);
int4 iOff = AddrSpace::addressToByteInt(off,wordsize); int4 iOff = AddrSpace::addressToByteInt(off,wordsize);
iOff += offset; extra = AddrSpace::addressToByteInt(extra, wordsize);
iOff += offset + extra;
return (iOff >= 0 && iOff <= parent->getSize()); return (iOff >= 0 && iOff <= parent->getSize());
} }
@ -3874,27 +3930,27 @@ TypePointer *TypeFactory::resizePointer(TypePointer *ptr,int4 newSize)
Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size) Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
{ {
if (offset + size > ct->getSize())
return (Datatype *)0;
Datatype *lastType = (Datatype *)0; Datatype *lastType = (Datatype *)0;
int8 lastOff = 0; int8 lastOff = 0;
int8 curOff = offset; int8 curOff = offset;
do { do {
if (ct->getSize() <= size) { if (ct->getSize() < size + curOff) { // Range is beyond end of current data-type
break; // Construct partial around last data-type
}
if (ct->getSize() == size) if (ct->getSize() == size)
return ct; // Perfect size match return ct; // Perfect size match
break; if (ct->getMetatype() == TYPE_UNION) {
}
else if (ct->getMetatype() == TYPE_UNION) {
return getTypePartialUnion((TypeUnion *)ct, curOff, size); return getTypePartialUnion((TypeUnion *)ct, curOff, size);
} }
lastType = ct; lastType = ct;
lastOff = curOff; lastOff = curOff;
ct = ct->getSubType(curOff,&curOff); ct = ct->getSubType(curOff,&curOff);
} while(ct != (Datatype *)0); } while(ct != (Datatype *)0);
if (lastType != (Datatype *)0) {
// If we reach here, lastType is bigger than size // If we reach here, lastType is bigger than size
if (lastType->getMetatype() == TYPE_STRUCT || lastType->getMetatype() == TYPE_ARRAY) if (lastType->getMetatype() == TYPE_STRUCT || lastType->getMetatype() == TYPE_ARRAY)
return getTypePartialStruct(lastType, lastOff, size); return getTypePartialStruct(lastType, lastOff, size);
}
return (Datatype *)0; return (Datatype *)0;
} }

View file

@ -268,7 +268,7 @@ public:
virtual int4 compare(const Datatype &op,int4 level) const; ///< Order types for propagation virtual int4 compare(const Datatype &op,int4 level) const; ///< Order types for propagation
virtual int4 compareDependency(const Datatype &op) const; ///< Compare for storage in tree structure virtual int4 compareDependency(const Datatype &op) const; ///< Compare for storage in tree structure
virtual void encode(Encoder &encoder) const; ///< Encode the data-type to a stream virtual void encode(Encoder &encoder) const; ///< Encode the data-type to a stream
virtual bool isPtrsubMatching(uintb off) const; ///< Is this data-type suitable as input to a CPUI_PTRSUB op virtual bool isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const; ///< Is this data-type suitable as input to a CPUI_PTRSUB op
virtual Datatype *getStripped(void) const; ///< Get a stripped version of \b this for formal use in formal declarations virtual Datatype *getStripped(void) const; ///< Get a stripped version of \b this for formal use in formal declarations
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); ///< Tailor data-type propagation based on Varnode use virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); ///< Tailor data-type propagation based on Varnode use
virtual Datatype* findResolve(const PcodeOp *op,int4 slot); ///< Find a previously resolved sub-type virtual Datatype* findResolve(const PcodeOp *op,int4 slot); ///< Find a previously resolved sub-type
@ -393,6 +393,7 @@ protected:
AddrSpace *spaceid; ///< If non-null, the address space \b this is intented to point into AddrSpace *spaceid; ///< If non-null, the address space \b this is intented to point into
TypePointer *truncate; ///< Truncated form of the pointer (if not null) TypePointer *truncate; ///< Truncated form of the pointer (if not null)
uint4 wordsize; ///< What size unit does the pointer address uint4 wordsize; ///< What size unit does the pointer address
static bool testForArraySlack(Datatype *dt,int8 off); ///< Test if an \e out-of-bounds offset makes sense as array slack
void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this pointer data-type from a stream void decode(Decoder &decoder,TypeFactory &typegrp); ///< Restore \b this pointer data-type from a stream
void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer void calcSubmeta(void); ///< Calculate specific submeta for \b this pointer
void calcTruncate(TypeFactory &typegrp); // Assign a truncated pointer subcomponent if necessary void calcTruncate(TypeFactory &typegrp); // Assign a truncated pointer subcomponent if necessary
@ -420,7 +421,7 @@ public:
virtual Datatype *clone(void) const { return new TypePointer(*this); } virtual Datatype *clone(void) const { return new TypePointer(*this); }
virtual void encode(Encoder &encoder) const; virtual void encode(Encoder &encoder) const;
virtual TypePointer *downChain(int8 &off,TypePointer *&par,int8 &parOff,bool allowArrayWrap,TypeFactory &typegrp); virtual TypePointer *downChain(int8 &off,TypePointer *&par,int8 &parOff,bool allowArrayWrap,TypeFactory &typegrp);
virtual bool isPtrsubMatching(uintb off) const; virtual bool isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const;
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot); virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot); virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
}; };
@ -633,7 +634,7 @@ public:
virtual Datatype *clone(void) const { return new TypePointerRel(*this); } virtual Datatype *clone(void) const { return new TypePointerRel(*this); }
virtual void encode(Encoder &encoder) const; virtual void encode(Encoder &encoder) const;
virtual TypePointer *downChain(int8 &off,TypePointer *&par,int8 &parOff,bool allowArrayWrap,TypeFactory &typegrp); virtual TypePointer *downChain(int8 &off,TypePointer *&par,int8 &parOff,bool allowArrayWrap,TypeFactory &typegrp);
virtual bool isPtrsubMatching(uintb off) const; virtual bool isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const;
virtual Datatype *getStripped(void) const { return stripped; } ///< Get the plain form of the pointer virtual Datatype *getStripped(void) const { return stripped; } ///< Get the plain form of the pointer
static Datatype *getPtrToFromParent(Datatype *base,int4 off,TypeFactory &typegrp); static Datatype *getPtrToFromParent(Datatype *base,int4 off,TypeFactory &typegrp);
}; };

View file

@ -411,15 +411,15 @@ Datatype *TypeOpLoad::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,
Datatype *newtype; Datatype *newtype;
if (inslot == -1) { // Propagating output to input (value to ptr) if (inslot == -1) { // Propagating output to input (value to ptr)
AddrSpace *spc = op->getIn(0)->getSpaceFromConst(); AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
newtype = tlst->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize()); newtype = tlst->getTypePointerNoDepth(outvn->getSize(),alttype,spc->getWordSize());
} }
else if (alttype->getMetatype()==TYPE_PTR) { else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo(); newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength()) // Size must be appropriate if (newtype->getSize() != outvn->getSize() || newtype->isVariableLength()) // Size must be appropriate
newtype = outvn->getTempType(); newtype = (Datatype *)0;
} }
else else
newtype = outvn->getTempType(); // Don't propagate anything newtype = (Datatype *)0; // Don't propagate anything
return newtype; return newtype;
} }
@ -486,15 +486,15 @@ Datatype *TypeOpStore::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn
Datatype *newtype; Datatype *newtype;
if (inslot==2) { // Propagating value to ptr if (inslot==2) { // Propagating value to ptr
AddrSpace *spc = op->getIn(0)->getSpaceFromConst(); AddrSpace *spc = op->getIn(0)->getSpaceFromConst();
newtype = tlst->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize()); newtype = tlst->getTypePointerNoDepth(outvn->getSize(),alttype,spc->getWordSize());
} }
else if (alttype->getMetatype()==TYPE_PTR) { else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo(); newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength()) if (newtype->getSize() != outvn->getSize() || newtype->isVariableLength())
newtype = outvn->getTempType(); newtype = (Datatype *)0;
} }
else else
newtype = outvn->getTempType(); // Don't propagate anything newtype = (Datatype *)0; // Don't propagate anything
return newtype; return newtype;
} }
@ -1106,7 +1106,7 @@ Datatype *TypeOpIntAdd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *inv
if (outvn->isConstant() && (alttype->getMetatype() != TYPE_PTR)) if (outvn->isConstant() && (alttype->getMetatype() != TYPE_PTR))
newtype = alttype; newtype = alttype;
else if (inslot == -1) // Propagating output to input else if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction newtype = (Datatype *)0; // Don't propagate pointer types this direction
else else
newtype = propagateAddIn2Out(alttype,tlst,op,inslot); newtype = propagateAddIn2Out(alttype,tlst,op,inslot);
return newtype; return newtype;
@ -1130,7 +1130,7 @@ Datatype *TypeOpIntAdd::propagateAddIn2Out(Datatype *alttype,TypeFactory *typegr
TypePointer *pointer = (TypePointer *)alttype; TypePointer *pointer = (TypePointer *)alttype;
uintb offset; uintb offset;
int4 command = propagateAddPointer(offset,op,inslot,pointer->getPtrTo()->getAlignSize()); int4 command = propagateAddPointer(offset,op,inslot,pointer->getPtrTo()->getAlignSize());
if (command == 2) return op->getOut()->getTempType(); // Doesn't look like a good pointer add if (command == 2) return (Datatype *)0; // Doesn't look like a good pointer add
TypePointer *parent = (TypePointer *)0; TypePointer *parent = (TypePointer *)0;
int8 parentOff; int8 parentOff;
if (command != 3) { if (command != 3) {
@ -1155,7 +1155,7 @@ Datatype *TypeOpIntAdd::propagateAddIn2Out(Datatype *alttype,TypeFactory *typegr
if (pointer == (TypePointer *)0) { if (pointer == (TypePointer *)0) {
if (command == 0) if (command == 0)
return alttype; return alttype;
return op->getOut()->getTempType(); return (Datatype *)0;
} }
if (op->getIn(inslot)->isSpacebase()) { if (op->getIn(inslot)->isSpacebase()) {
if (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE) if (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
@ -2112,7 +2112,7 @@ Datatype *TypeOpPtradd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *inv
if (metain != TYPE_PTR) return (Datatype *)0; if (metain != TYPE_PTR) return (Datatype *)0;
Datatype *newtype; Datatype *newtype;
if (inslot == -1) // Propagating output to input if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction newtype = (Datatype *)0; // Don't propagate pointer types this direction
else else
newtype = TypeOpIntAdd::propagateAddIn2Out(alttype,tlst,op,inslot); newtype = TypeOpIntAdd::propagateAddIn2Out(alttype,tlst,op,inslot);
return newtype; return newtype;
@ -2192,7 +2192,7 @@ Datatype *TypeOpPtrsub::propagateType(Datatype *alttype,PcodeOp *op,Varnode *inv
if (metain != TYPE_PTR) return (Datatype *)0; if (metain != TYPE_PTR) return (Datatype *)0;
Datatype *newtype; Datatype *newtype;
if (inslot == -1) // Propagating output to input if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction newtype = (Datatype *)0; // Don't propagate pointer types this direction
else else
newtype = TypeOpIntAdd::propagateAddIn2Out(alttype,tlst,op,inslot); newtype = TypeOpIntAdd::propagateAddIn2Out(alttype,tlst,op,inslot);
return newtype; return newtype;