GP-4095 Check for primitive data-type when triggering double precision

This commit is contained in:
caheckman 2023-12-01 21:00:42 +00:00
parent 1b813ed33e
commit 60cf8311f1
8 changed files with 76 additions and 19 deletions

View file

@ -1667,8 +1667,8 @@ int4 ActionParamDouble::apply(Funcdata &data)
for(int4 i=0;i<numparams;++i) {
ProtoParameter *param = fp.getParam(i);
Datatype *tp = param->getType();
type_metatype mt = tp->getMetatype();
if ((mt==TYPE_ARRAY)||(mt==TYPE_STRUCT)) continue; // Not double precision objects
if (!tp->isPrimitiveWhole())
continue; // Not double precision objects
Varnode *vn = data.findVarnodeInput(tp->getSize(),param->getAddress());
if (vn == (Varnode *)0) continue;
if (vn->getSize() < minDoubleSize) continue;

View file

@ -693,6 +693,14 @@ PcodeOp *SplitVarnode::findOutExist(void)
return findEarliestSplitPoint();
}
/// If the logical whole is a constant and is too big to be represented internally return \b true.
/// \return \b true if \b this is a constant and too big
bool SplitVarnode::exceedsConstPrecision(void) const
{
return isConstant() && (wholesize > sizeof(uintb));
}
/// \brief Check if the values in the given Varnodes differ by the given size
///
/// Return \b true, if the (possibly dynamic) value represented by the given \b vn1 plus \b size1
@ -1543,6 +1551,8 @@ bool AddForm::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &data
return false;
indoub.initPartial(in.getSize(),lo2,hi2);
if (indoub.exceedsConstPrecision())
return false;
outdoub.initPartial(in.getSize(),reslo,reshi);
existop = SplitVarnode::prepareBinaryOp(outdoub,in,indoub);
if (existop == (PcodeOp *)0)
@ -1636,6 +1646,8 @@ bool SubForm::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &data
return false;
indoub.initPartial(in.getSize(),lo2,hi2);
if (indoub.exceedsConstPrecision())
return false;
outdoub.initPartial(in.getSize(),reslo,reshi);
existop = SplitVarnode::prepareBinaryOp(outdoub,in,indoub);
if (existop == (PcodeOp *)0)
@ -1757,6 +1769,8 @@ bool LogicalForm::applyRule(SplitVarnode &i,PcodeOp *lop,bool workishi,Funcdata
outdoub.initPartial(in.getSize(),loop->getOut(),hiop->getOut());
indoub.initPartial(in.getSize(),lo2,hi2);
if (indoub.exceedsConstPrecision())
return false;
existop = SplitVarnode::prepareBinaryOp(outdoub,in,indoub);
if (existop == (PcodeOp *)0)
return false;
@ -1817,6 +1831,8 @@ bool Equal1Form::applyRule(SplitVarnode &i,PcodeOp *hop,bool workishi,Funcdata &
++iter3;
in2.initPartial(in1.getSize(),lo2,hi2);
if (in2.exceedsConstPrecision())
continue;
if ((hibool->code() == CPUI_CBRANCH)&&(lobool->code()==CPUI_CBRANCH)) {
// Branching form of the equal operation
@ -1958,10 +1974,12 @@ bool Equal2Form::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &d
hixor = (PcodeOp *)0;
hi2 = (Varnode *)0;
if (fillOutFromOr(data)) {
if (!param2.exceedsConstPrecision()) {
SplitVarnode::replaceBoolOp(data,equalop,in,param2,equalop->code());
return true;
}
}
}
else { // We see an XOR
hixor = op;
xorhislot = hixor->getSlot(hi1);
@ -1976,11 +1994,13 @@ bool Equal2Form::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &d
if (orop->code() != CPUI_INT_OR) continue;
orhislot = orop->getSlot(vn);
if (fillOutFromOr(data)) {
if (!param2.exceedsConstPrecision()) {
SplitVarnode::replaceBoolOp(data,equalop,in,param2,equalop->code());
return true;
}
}
}
}
return false;
}
@ -2020,6 +2040,8 @@ bool Equal3Form::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata &d
return false;
SplitVarnode in2(in.getSize(),calc_mask(in.getSize())); // Create the -1 value
if (in2.exceedsConstPrecision())
return false;
if (!SplitVarnode::prepareBoolOp(in,in2,compareop)) return false;
SplitVarnode::replaceBoolOp(data,compareop,in,in2,compareop->code());
return true;
@ -2483,6 +2505,8 @@ bool LessThreeWay::applyRule(SplitVarnode &i,PcodeOp *loop,bool workishi,Funcdat
if (!mapFromLow(loop)) return false;
bool res = testReplace();
if (res) {
if (in2.exceedsConstPrecision())
return false;
if (hislot==0)
SplitVarnode::createBoolOp(data,hilessbool,in,in2,finalopc);
else
@ -2527,6 +2551,8 @@ bool LessConstForm::applyRule(SplitVarnode &i,PcodeOp *op,bool workishi,Funcdata
if (desc->code() != CPUI_CBRANCH) return false;
constin.initPartial(in.getSize(),val);
if (constin.exceedsConstPrecision())
return false;
if (inslot==0) {
if (SplitVarnode::prepareBoolOp(in,constin,op)) {
@ -2967,6 +2993,8 @@ bool MultForm::replace(Funcdata &data)
{ // We have matched a double precision multiply, now transform to logical variables
outdoub.initPartial(in.getSize(),reslo,reshi);
in2.initPartial(in.getSize(),lo2,hi2);
if (in2.exceedsConstPrecision())
return false;
existop = SplitVarnode::prepareBinaryOp(outdoub,in,in2);
if (existop == (PcodeOp *)0)
return false;
@ -3147,6 +3175,10 @@ int4 RuleDoubleIn::attemptMarking(Funcdata &data,Varnode *vn,PcodeOp *subpieceOp
{
Varnode *whole = subpieceOp->getIn(0);
if (whole->isTypeLock()) {
if (!whole->getType()->isPrimitiveWhole())
return 0; // Don't mark for double precision if not a primitive type
}
int4 offset = (int4)subpieceOp->getIn(1)->getOffset();
if (offset != vn->getSize()) return 0;
if (offset * 2 != whole->getSize()) return 0; // Truncate exactly half

View file

@ -70,6 +70,7 @@ public:
void buildHiFromWhole(Funcdata &data); ///< Rebuild the most significant piece as a CPUI_SUBPIECE of the \b whole
PcodeOp *findEarliestSplitPoint(void); ///< Find the earliest definition point of the \b lo and \b hi pieces
PcodeOp *findOutExist(void); ///< Find the point at which the output \b whole must exist
bool exceedsConstPrecision(void) const; ///< Check if \b this is a constant that exceeds precision limits
static bool adjacentOffsets(Varnode *vn1,Varnode *vn2,uintb size1);
static bool testContiguousPointers(PcodeOp *most,PcodeOp *least,PcodeOp *&first,PcodeOp *&second,AddrSpace *&spc);
static bool isAddrTiedContiguous(Varnode *lo,Varnode *hi,Address &res);

View file

@ -2065,11 +2065,9 @@ void Heritage::splitJoinRead(Varnode *vn,JoinRecord *joinrec)
{
PcodeOp *op = vn->loneDescend(); // vn isFree, so loneDescend must be non-null
bool preventConstCollapse = false;
bool isPrimitive = true;
if (vn->isTypeLock()) {
type_metatype meta = vn->getType()->getMetatype();
if (meta == TYPE_STRUCT || meta == TYPE_ARRAY)
preventConstCollapse = true;
isPrimitive = vn->getType()->isPrimitiveWhole();
}
vector<Varnode *> lastcombo;
@ -2090,10 +2088,13 @@ void Heritage::splitJoinRead(Varnode *vn,JoinRecord *joinrec)
fd->opSetInput(concat,mosthalf,0);
fd->opSetInput(concat,leasthalf,1);
fd->opInsertBefore(concat,op);
if (preventConstCollapse)
fd->opMarkNoCollapse(concat);
if (isPrimitive) {
mosthalf->setPrecisHi(); // Set precision flags to trigger "double precision" rules
leasthalf->setPrecisLo();
}
else {
fd->opMarkNoCollapse(concat);
}
op = concat; // Keep -op- as the earliest op in the concatenation construction
}
@ -2118,6 +2119,9 @@ void Heritage::splitJoinWrite(Varnode *vn,JoinRecord *joinrec)
{
PcodeOp *op = vn->getDef(); // vn cannot be free, either it has def, or it is input
BlockBasic *bb = (BlockBasic *)fd->getBasicBlocks().getBlock(0);
bool isPrimitive = true;
if (vn->isTypeLock())
isPrimitive = vn->getType()->isPrimitiveWhole();
vector<Varnode *> lastcombo;
vector<Varnode *> nextlev;
@ -2151,8 +2155,10 @@ void Heritage::splitJoinWrite(Varnode *vn,JoinRecord *joinrec)
fd->opSetInput(split,curvn,0);
fd->opSetInput(split,fd->newConstant(4,0),1);
fd->opInsertAfter(split,op);
if (isPrimitive) {
mosthalf->setPrecisHi(); // Make sure we set the precision flags to trigger "double precision" rules
leasthalf->setPrecisLo();
}
op = split; // Keep -op- as the latest op in the split construction
}

View file

@ -337,7 +337,7 @@ void DatatypeMatchFilter::decode(Decoder &decoder)
///
/// Allocate the action object corresponding to the element and configure it.
/// If the next element is not an action, throw an exception.
/// \param parser is the stream decoder
/// \param decoder is the stream decoder
/// \param res is the resource set for the new action
/// \return the new action
AssignAction *AssignAction::decodeAction(Decoder &decoder,const ParamListStandard *res)
@ -377,7 +377,7 @@ AssignAction *AssignAction::decodeAction(Decoder &decoder,const ParamListStandar
///
/// Allocate the sideeffect object corresponding to the element and configure it.
/// If the next element is not a sideeffect, throw an exception.
/// \param parser is the stream decoder
/// \param decoder is the stream decoder
/// \param res is the resource set for the new sideeffect
/// \return the new sideeffect
AssignAction *AssignAction::decodeSideeffect(Decoder &decoder,const ParamListStandard *res)

View file

@ -286,7 +286,7 @@ class MultiSlotAssign : public AssignAction {
void initializeEntries(void); ///< Cache specific ParamEntry needed by the action
public:
MultiSlotAssign(const ParamListStandard *res); ///< Constructor for use with decode
MultiSlotAssign(type_class store,bool stack,bool mostSig,bool align,bool justRight,const ParamListStandard *res);
MultiSlotAssign(type_class store,bool stack,bool mostSig,bool align,bool justRight,const ParamListStandard *res); ///< Constructor
virtual AssignAction *clone(const ParamListStandard *newResource) const {
return new MultiSlotAssign(resourceType,consumeFromStack,consumeMostSig,enforceAlignment,justifyRight,newResource); }
virtual uint4 assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,
@ -304,7 +304,7 @@ class MultiMemberAssign : public AssignAction {
bool consumeFromStack; ///< True if resources should be consumed from the stack
bool consumeMostSig; ///< True if resources are consumed starting with most significant bytes
public:
MultiMemberAssign(type_class store,bool stack,bool mostSig,const ParamListStandard *res);
MultiMemberAssign(type_class store,bool stack,bool mostSig,const ParamListStandard *res); ///< Constructor
virtual AssignAction *clone(const ParamListStandard *newResource) const {
return new MultiMemberAssign(resourceType,consumeFromStack,consumeMostSig,newResource); }
virtual uint4 assignAddress(Datatype *dt,const PrototypePieces &proto,int4 pos,TypeFactory &tlist,

View file

@ -476,6 +476,23 @@ void Datatype::encodeRef(Encoder &encoder) const
encode(encoder);
}
/// If \b this has no component data-types, return \b true.
/// If \b this has only a single primitive component filling the whole data-type, also return \b true.
/// \return \b true if \b this data-type is made up of a single primitive
bool Datatype::isPrimitiveWhole(void) const
{
if (!isPieceStructured()) return true;
if (metatype == TYPE_ARRAY || metatype == TYPE_STRUCT) {
if (numDepend() > 0) {
Datatype *component = getDepend(0);
if (component->getSize() == getSize())
return component->isPrimitiveWhole();
}
}
return false;
}
/// Called only if the \b typedefImm field is non-null. Encode the data-type to the
/// stream as a simple \<typedef> element including only the names and ids of \b this and
/// the data-type it typedefs.

View file

@ -278,6 +278,7 @@ public:
int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special
void encodeRef(Encoder &encoder) const; ///< Encode a reference of \b this to a stream
bool isPieceStructured(void) const; ///< Does \b this data-type consist of separate pieces?
bool isPrimitiveWhole(void) const; ///< Is \b this made up of a single primitive
static uint4 encodeIntegerFormat(const string &val);
static string decodeIntegerFormat(uint4 val);
};