GP-1518 Decompiler support for unions

This commit is contained in:
caheckman 2021-11-19 14:39:42 -05:00
parent 53e2c4dc4f
commit 3fdbbbb231
65 changed files with 5119 additions and 1068 deletions

View file

@ -82,7 +82,7 @@ CORE= xml space float address pcoderaw translate opcodes globalcontext
DECCORE=capability architecture options graph cover block cast typeop database cpool \
comment stringmanage fspec action loadimage grammar varnode op \
type variable varmap jumptable emulate emulateutil flow userop \
funcdata funcdata_block funcdata_op funcdata_varnode pcodeinject \
funcdata funcdata_block funcdata_op funcdata_varnode unionresolve pcodeinject \
heritage prefersplit rangeutil ruleaction subflow blockaction merge double \
transform coreaction condexe override dynamic crc32 prettyprint \
printlanguage printc printjava memstate opbehavior paramid $(COREEXT_NAMES)

View file

@ -3375,7 +3375,7 @@ const Datatype *BlockSwitch::getSwitchType(void) const
{
PcodeOp *op = jump->getIndirectOp();
return op->getIn(0)->getHigh()->getType();
return op->getIn(0)->getHighTypeReadFacing(op);
}
void BlockSwitch::markUnstructured(void)

View file

@ -58,10 +58,10 @@ bool CastStrategyC::checkIntPromotionForExtension(const PcodeOp *op) const
return true; // Otherwise we need a cast before we extend
}
int4 CastStrategyC::localExtensionType(const Varnode *vn) const
int4 CastStrategyC::localExtensionType(const Varnode *vn,const PcodeOp *op) const
{
type_metatype meta = vn->getHigh()->getType()->getMetatype();
type_metatype meta = vn->getHighTypeReadFacing(op)->getMetatype();
int4 natural; // 1= natural zero extension, 2= natural sign extension
if ((meta == TYPE_UINT)||(meta == TYPE_BOOL)||(meta == TYPE_UNKNOWN))
natural = UNSIGNED_EXTENSION;
@ -78,14 +78,14 @@ int4 CastStrategyC::localExtensionType(const Varnode *vn) const
return natural;
if (!vn->isWritten())
return UNKNOWN_PROMOTION;
const PcodeOp *op = vn->getDef();
if (op->isBoolOutput())
const PcodeOp *defOp = vn->getDef();
if (defOp->isBoolOutput())
return EITHER_EXTENSION;
OpCode opc = op->code();
if ((opc == CPUI_CAST)||(opc == CPUI_LOAD)||op->isCall())
OpCode opc = defOp->code();
if ((opc == CPUI_CAST)||(opc == CPUI_LOAD)||defOp->isCall())
return natural;
if (opc == CPUI_INT_AND) { // This is kind of recursing
const Varnode *tmpvn = op->getIn(1);
const Varnode *tmpvn = defOp->getIn(1);
if (tmpvn->isConstant()) {
if (!signbit_negative(tmpvn->getOffset(),tmpvn->getSize()))
return EITHER_EXTENSION;
@ -102,7 +102,7 @@ int4 CastStrategyC::intPromotionType(const Varnode *vn) const
if (vn->getSize() >= promoteSize)
return NO_PROMOTION;
if (vn->isConstant())
return localExtensionType(vn);
return localExtensionType(vn,vn->loneDescend());
if (vn->isExplicit())
return NO_PROMOTION;
if (!vn->isWritten()) return UNKNOWN_PROMOTION;
@ -111,21 +111,21 @@ int4 CastStrategyC::intPromotionType(const Varnode *vn) const
switch(op->code()) {
case CPUI_INT_AND:
othervn = op->getIn(1);
if ((localExtensionType(othervn) & UNSIGNED_EXTENSION) != 0)
if ((localExtensionType(othervn,op) & UNSIGNED_EXTENSION) != 0)
return UNSIGNED_EXTENSION;
othervn = op->getIn(0);
if ((localExtensionType(othervn) & UNSIGNED_EXTENSION) != 0)
if ((localExtensionType(othervn,op) & UNSIGNED_EXTENSION) != 0)
return UNSIGNED_EXTENSION; // If either side has zero extension, result has zero extension
break;
case CPUI_INT_RIGHT:
othervn = op->getIn(0);
val = localExtensionType(othervn);
val = localExtensionType(othervn,op);
if ((val & UNSIGNED_EXTENSION) != 0) // If the input provably zero extends
return val; // then the result is a zero extension (plus possibly a sign extension)
break;
case CPUI_INT_SRIGHT:
othervn = op->getIn(0);
val = localExtensionType(othervn);
val = localExtensionType(othervn,op);
if ((val & SIGNED_EXTENSION) != 0) // If input can be construed as a sign-extension
return val; // then the result is a sign extension (plus possibly a zero extension)
break;
@ -134,25 +134,25 @@ int4 CastStrategyC::intPromotionType(const Varnode *vn) const
case CPUI_INT_DIV:
case CPUI_INT_REM:
othervn = op->getIn(0);
if ((localExtensionType(othervn) & UNSIGNED_EXTENSION) == 0)
if ((localExtensionType(othervn,op) & UNSIGNED_EXTENSION) == 0)
return UNKNOWN_PROMOTION;
othervn = op->getIn(1);
if ((localExtensionType(othervn) & UNSIGNED_EXTENSION) == 0)
if ((localExtensionType(othervn,op) & UNSIGNED_EXTENSION) == 0)
return UNKNOWN_PROMOTION;
return UNSIGNED_EXTENSION; // If both sides have zero extension, result has zero extension
case CPUI_INT_SDIV:
case CPUI_INT_SREM:
othervn = op->getIn(0);
if ((localExtensionType(othervn) & SIGNED_EXTENSION) == 0)
if ((localExtensionType(othervn,op) & SIGNED_EXTENSION) == 0)
return UNKNOWN_PROMOTION;
othervn = op->getIn(1);
if ((localExtensionType(othervn) & SIGNED_EXTENSION) == 0)
if ((localExtensionType(othervn,op) & SIGNED_EXTENSION) == 0)
return UNKNOWN_PROMOTION;
return SIGNED_EXTENSION; // If both sides have sign extension, result has sign extension
case CPUI_INT_NEGATE:
case CPUI_INT_2COMP:
othervn = op->getIn(0);
if ((localExtensionType(othervn) & SIGNED_EXTENSION) != 0)
if ((localExtensionType(othervn,op) & SIGNED_EXTENSION) != 0)
return SIGNED_EXTENSION;
break;
case CPUI_INT_ADD:
@ -176,7 +176,7 @@ bool CastStrategyC::isExtensionCastImplied(const PcodeOp *op,const PcodeOp *read
else {
if (readOp == (PcodeOp *) 0)
return false;
type_metatype metatype = outVn->getHigh()->getType()->getMetatype();
type_metatype metatype = outVn->getHighTypeReadFacing(readOp)->getMetatype();
const Varnode *otherVn;
int4 slot;
switch (readOp->code()) {
@ -206,7 +206,7 @@ bool CastStrategyC::isExtensionCastImplied(const PcodeOp *op,const PcodeOp *read
}
else if (!otherVn->isExplicit())
return false;
if (otherVn->getHigh()->getType()->getMetatype() != metatype)
if (otherVn->getHighTypeReadFacing(readOp)->getMetatype() != metatype)
return false;
break;
default:
@ -298,13 +298,13 @@ Datatype *CastStrategyC::castStandard(Datatype *reqtype,Datatype *curtype,
Datatype *CastStrategyC::arithmeticOutputStandard(const PcodeOp *op)
{
Datatype *res1 = op->getIn(0)->getHigh()->getType();
Datatype *res1 = op->getIn(0)->getHighTypeReadFacing(op);
if (res1->getMetatype() == TYPE_BOOL) // Treat boolean as if it is cast to an integer
res1 = tlst->getBase(res1->getSize(),TYPE_INT);
Datatype *res2;
for(int4 i=1;i<op->numInput();++i) {
res2 = op->getIn(i)->getHigh()->getType();
res2 = op->getIn(i)->getHighTypeReadFacing(op);
if (res2->getMetatype() == TYPE_BOOL) continue;
if (0>res2->typeOrder(*res1))
res1 = res2;

View file

@ -61,8 +61,9 @@ public:
/// \brief Decide on integer promotion by examining just local properties of the given Varnode
///
/// \param vn is the given Varnode
/// \param op is the PcodeOp reading the Varnode
/// \return an IntPromotionCode (excluding NO_PROMOTION)
virtual int4 localExtensionType(const Varnode *vn) const=0;
virtual int4 localExtensionType(const Varnode *vn,const PcodeOp *op) const=0;
/// \brief Calculate the integer promotion code of a given Varnode
///
@ -157,7 +158,7 @@ public:
/// \brief Casting strategies that are specific to the C language
class CastStrategyC : public CastStrategy {
public:
virtual int4 localExtensionType(const Varnode *vn) const;
virtual int4 localExtensionType(const Varnode *vn,const PcodeOp *op) const;
virtual int4 intPromotionType(const Varnode *vn) const;
virtual bool checkIntPromotionForCompare(const PcodeOp *op,int4 slot) const;
virtual bool checkIntPromotionForExtension(const PcodeOp *op) const;

View file

@ -212,11 +212,17 @@ int main(int argc,char **argv)
status->registerCom(new IfcRestore(),"restore");
if (initscript != (const char *)0) {
status->pushScript(initscript,"init> ");
status->setErrorIsDone(true);
try {
status->setErrorIsDone(true);
status->pushScript(initscript,"init> ");
} catch(IfaceParseError &err) {
*status->optr << err.explain << endl;
status->done = true;
}
}
mainloop(status);
if (!status->done)
mainloop(status);
int4 retval = status->isInError() ? 1 : 0;
#ifdef CPUI_STATISTICS

View file

@ -1029,7 +1029,7 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
bool needexacthit;
Architecture *glb = data.getArch();
Varnode *outvn;
if (vn->getType()->getMetatype() == TYPE_PTR) { // Are we explicitly marked as a pointer
if (vn->getTypeReadFacing(op)->getMetatype() == TYPE_PTR) { // Are we explicitly marked as a pointer
rampoint = glb->resolveConstant(spc,vn->getOffset(),vn->getSize(),op->getAddr(),fullEncoding);
needexacthit = false;
}
@ -1057,9 +1057,9 @@ SymbolEntry *ActionConstantPtr::isPointer(AddrSpace *spc,Varnode *vn,PcodeOp *op
break;
case CPUI_INT_ADD:
outvn = op->getOut();
if (outvn->getType()->getMetatype()==TYPE_PTR) {
if (outvn->getTypeDefFacing()->getMetatype()==TYPE_PTR) {
// Is there another pointer base in this expression
if (op->getIn(1-slot)->getType()->getMetatype()==TYPE_PTR)
if (op->getIn(1-slot)->getTypeReadFacing(op)->getMetatype()==TYPE_PTR)
return (SymbolEntry *)0; // If so, we are not a pointer
// FIXME: need to fully explore additive tree
needexacthit = false;
@ -1197,7 +1197,7 @@ int4 ActionDeindirect::apply(Funcdata &data)
}
if (data.isTypeRecoveryOn()) {
// Check for a function pointer that has an attached prototype
Datatype *ct = op->getIn(0)->getType();
Datatype *ct = op->getIn(0)->getTypeReadFacing(op);
if ((ct->getMetatype()==TYPE_PTR)&&
(((TypePointer *)ct)->getPtrTo()->getMetatype()==TYPE_CODE)) {
TypeCode *tc = (TypeCode *)((TypePointer *)ct)->getPtrTo();
@ -2173,14 +2173,15 @@ int4 ActionDefaultParams::apply(Funcdata &data)
/// the data-type as a pointer to the structure's first field will get it to match the
/// desired data-type.
/// \param vn is the given Varnode
/// \param op is the PcodeOp reading the Varnode
/// \param ct is the desired data-type
/// \param castStrategy is used to determine if the data-types are compatible
/// \return \b true if a pointer to the first field makes sense
bool ActionSetCasts::testStructOffset0(Varnode *vn,Datatype *ct,CastStrategy *castStrategy)
bool ActionSetCasts::testStructOffset0(Varnode *vn,PcodeOp *op,Datatype *ct,CastStrategy *castStrategy)
{
if (ct->getMetatype() != TYPE_PTR) return false;
Datatype *highType = vn->getHigh()->getType();
Datatype *highType = vn->getHighTypeReadFacing(op);
if (highType->getMetatype() != TYPE_PTR) return false;
Datatype *highPtrTo = ((TypePointer *)highType)->getPtrTo();
if (highPtrTo->getMetatype() != TYPE_STRUCT) return false;
@ -2197,6 +2198,52 @@ bool ActionSetCasts::testStructOffset0(Varnode *vn,Datatype *ct,CastStrategy *ca
return (castStrategy->castStandard(reqtype, curtype, true, true) == (Datatype *)0);
}
/// \brief Try to adjust the input and output Varnodes to eliminate a CAST
///
/// If input/output data-types are different, it may be due to late merges. For
/// unions, the CAST can sometimes be eliminated by adjusting the data-type resolutions
/// of the Varnodes relative to the PcodeOp
/// \param op is the PcodeOp reading the input Varnode and writing the output Varnode
/// \param slot is the index of the input Varnode
/// \param data is the function
/// \return \b true if an adjustment is made so that a CAST is no longer needed
bool ActionSetCasts::tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &data)
{
Varnode *outvn = op->getOut();
if (outvn == (Varnode *)0)
return false;
Datatype *outType = outvn->getHigh()->getType();
Datatype *inType = op->getIn(slot)->getHigh()->getType();
if (!inType->needsResolution() && !outType->needsResolution()) return false;
int4 inResolve = -1;
int4 outResolve = -1;
if (inType->needsResolution()) {
inResolve = inType->findCompatibleResolve(outType);
if (inResolve < 0) return false;
}
if (outType->needsResolution()) {
if (inResolve >= 0)
outResolve = outType->findCompatibleResolve(inType->getDepend(inResolve));
else
outResolve = outType->findCompatibleResolve(inType);
if (outResolve < 0) return false;
}
TypeFactory *typegrp = data.getArch()->types;
if (inType->needsResolution()) {
ResolvedUnion resolve(inType,inResolve,*typegrp);
if (!data.setUnionField(inType, op, slot, resolve))
return false;
}
if (outType->needsResolution()) {
ResolvedUnion resolve(outType,outResolve,*typegrp);
if (!data.setUnionField(outType, op, -1, resolve))
return false;
}
return true;
}
/// \brief Test if two data-types are operation identical
///
/// If, at a source code level, a variable with data-type \b ct1 can be
@ -2219,6 +2266,42 @@ bool ActionSetCasts::isOpIdentical(Datatype *ct1,Datatype *ct2)
return (ct1 == ct2);
}
/// \brief If the given op reads a pointer to a union, insert the CPUI_PTRSUB that resolves the union
///
/// \param op is the given PcodeOp
/// \param slot is index of the input slot being read
/// \param data is the containing function
/// \return 1 if a PTRSUB is inserted, 0 otherwise
int4 ActionSetCasts::resolveUnion(PcodeOp *op,int4 slot,Funcdata &data)
{
Varnode *vn = op->getIn(slot);
if (vn->isAnnotation()) return 0;
Datatype *dt = vn->getHigh()->getType();
if (!dt->needsResolution())
return 0;
const ResolvedUnion *resUnion = data.getUnionField(dt, op,slot);
if (resUnion != (ResolvedUnion*)0 && resUnion->getFieldNum() >= 0) {
// Insert specific placeholder indicating which field is accessed
if (dt->getMetatype() == TYPE_PTR) {
PcodeOp *ptrsub = insertPtrsubZero(op,slot,resUnion->getDatatype(),data);
data.setUnionField(dt, ptrsub,-1,*resUnion); // Attach the resolution to the PTRSUB
}
else if (vn->isImplied()) {
if (vn->isWritten()) {
// If the writefacing and readfacing resolutions for vn (an implied variable) are the same,
// the resolutions are unnecessary and we treat the vn as if it had the field data-type
const ResolvedUnion *writeRes = data.getUnionField(dt, vn->getDef(), -1);
if (writeRes != (const ResolvedUnion *)0 && writeRes->getFieldNum() == resUnion->getFieldNum())
return 0; // Don't print implied fields for vn
}
vn->setImpliedField();
}
return 1;
}
return 0;
}
/// \brief Insert cast to output Varnode type after given PcodeOp if it is necessary
///
/// \param op is the given PcodeOp
@ -2231,12 +2314,23 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
Datatype *outct,*ct,*tokenct;
Varnode *vn,*outvn;
PcodeOp *newop;
HighVariable *outHigh;
Datatype *outHighType;
bool force=false;
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
outvn = op->getOut();
outHigh = outvn->getHigh();
outHighType = outvn->getHigh()->getType();
if (tokenct == outHighType) {
if (tokenct->needsResolution()) {
// operation copies directly to outvn AS a union
ResolvedUnion resolve(tokenct);
data.setUnionField(tokenct, op, -1, resolve);
}
// Short circuit more sophisticated casting tests. If they are the same type, there is no cast
return 0;
}
if (outHighType->needsResolution())
outHighType = outHighType->findResolve(op, -1); // Finish fetching DefFacing data-type
if (outvn->isImplied()) {
// implied varnode must have parse type
if (outvn->isTypeLock()) {
@ -2244,26 +2338,30 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
// The Varnode input to a CPUI_RETURN is marked as implied but
// casting should act as if it were explicit
if (outOp == (PcodeOp *)0 || outOp->code() != CPUI_RETURN) {
force = !isOpIdentical(outHigh->getType(), tokenct);
force = !isOpIdentical(outHighType, tokenct);
}
}
else if (outHigh->getType()->getMetatype() != TYPE_PTR) // If implied varnode has an atomic (non-pointer) type
else if (outHighType->getMetatype() != TYPE_PTR) { // If implied varnode has an atomic (non-pointer) type
outvn->updateType(tokenct,false,false); // Ignore it in favor of the token type
outHighType = outvn->getHighTypeDefFacing();
}
else if (tokenct->getMetatype() == TYPE_PTR) { // If the token is a pointer AND implied varnode is pointer
outct = ((TypePointer *)outHigh->getType())->getPtrTo();
outct = ((TypePointer *)outHighType)->getPtrTo();
type_metatype meta = outct->getMetatype();
// Preserve implied pointer if it points to a composite
if ((meta!=TYPE_ARRAY)&&(meta!=TYPE_STRUCT))
if ((meta!=TYPE_ARRAY)&&(meta!=TYPE_STRUCT)&&(meta!=TYPE_UNION)) {
outvn->updateType(tokenct,false,false); // Otherwise ignore it in favor of the token type
outHighType = outvn->getHighTypeDefFacing();
}
}
}
if (!force) {
outct = outHigh->getType(); // Type of result
outct = outHighType; // Type of result
ct = castStrategy->castStandard(outct,tokenct,false,true);
if (ct == (Datatype *)0) return 0;
}
// Generate the cast op
vn = data.newUnique(op->getOut()->getSize());
vn = data.newUnique(outvn->getSize());
vn->updateType(tokenct,false,false);
vn->setImplied();
newop = data.newOp(1,op->getAddr());
@ -2271,13 +2369,44 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
data.getArch()->stats->countCast();
#endif
data.opSetOpcode(newop,CPUI_CAST);
data.opSetOutput(newop,op->getOut());
data.opSetOutput(newop,outvn);
data.opSetInput(newop,vn,0);
data.opSetOutput(op,vn);
data.opInsertAfter(newop,op); // Cast comes AFTER this operation
if (outHighType->needsResolution())
data.forceFacingType(outHighType, -1, newop, -1);
return 1;
}
/// \brief Insert a PTRSUB with offset 0 that accesses a field of the given data-type
///
/// The data-type can be a structure, in which case the field at offset zero is being accessed.
/// The data-type can reference a union, in which case a specific field is being accessed
/// as indicated by Funcdata::getUnionField. The PTRSUB is inserted right before the given
/// PcodeOp. The indicated input Varnode becomes the PTRSUB input, and the PTRSUB output
/// replaces the Varnode in the PcodeOp.
/// \param op is the given PcodeOp where the PTRSUB is inserted
/// \param slot is the slot corresponding to the indicated Varnode
/// \param ct is the data-type produced by the PTRSUB
/// \param data is containing Function
/// \return the new PTRSUB op
PcodeOp *ActionSetCasts::insertPtrsubZero(PcodeOp *op,int4 slot,Datatype *ct,Funcdata &data)
{
Varnode *vn = op->getIn(slot);
PcodeOp *newop = data.newOp(2,op->getAddr());
Varnode *vnout = data.newUniqueOut(vn->getSize(), newop);
vnout->updateType(ct,false,false);
vnout->setImplied();
data.opSetOpcode(newop, CPUI_PTRSUB);
data.opSetInput(newop,vn,0);
data.opSetInput(newop,data.newConstant(4, 0),1);
data.opSetInput(op,vnout,slot);
data.opInsertBefore(newop,op);
return newop;
}
/// \brief Insert cast to produce the input Varnode to a given PcodeOp if necessary
///
/// This method can also mark a Varnode as an explicit integer constant.
@ -2315,17 +2444,12 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy
if (vn->getType() == ct)
return 1;
}
else if (testStructOffset0(vn, ct, castStrategy)) {
else if (testStructOffset0(vn, op, ct, castStrategy)) {
// Insert a PTRSUB(vn,#0) instead of a CAST
newop = data.newOp(2,op->getAddr());
vnout = data.newUniqueOut(vn->getSize(), newop);
vnout->updateType(ct,false,false);
vnout->setImplied();
data.opSetOpcode(newop, CPUI_PTRSUB);
data.opSetInput(newop,vn,0);
data.opSetInput(newop,data.newConstant(4, 0),1);
data.opSetInput(op,vnout,slot);
data.opInsertBefore(newop,op);
insertPtrsubZero(op, slot, ct, data);
return 1;
}
else if (tryResolutionAdjustment(op, slot, data)) {
return 1;
}
newop = data.newOp(1,op->getAddr());
@ -2339,6 +2463,12 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy
data.opSetInput(newop,vn,0);
data.opSetInput(op,vnout,slot);
data.opInsertBefore(newop,op); // Cast comes AFTER operation
if (ct->needsResolution()) {
data.forceFacingType(ct, -1, newop, -1);
}
if (vn->getHigh()->getType()->needsResolution()) {
data.inheritReadResolution(newop, 0, op, slot);
}
return 1;
}
@ -2362,12 +2492,12 @@ int4 ActionSetCasts::apply(Funcdata &data)
if (opc == CPUI_CAST) continue;
if (opc == CPUI_PTRADD) { // Check for PTRADD that no longer fits its pointer
int4 sz = (int4)op->getIn(2)->getOffset();
TypePointer *ct = (TypePointer *)op->getIn(0)->getHigh()->getType();
TypePointer *ct = (TypePointer *)op->getIn(0)->getHighTypeReadFacing(op);
if ((ct->getMetatype() != TYPE_PTR)||(ct->getPtrTo()->getSize() != AddrSpace::addressToByteInt(sz, ct->getWordSize())))
data.opUndoPtradd(op,true);
}
else if (opc == CPUI_PTRSUB) { // Check for PTRSUB that no longer fits pointer
if (!op->getIn(0)->getHigh()->getType()->isPtrsubMatching(op->getIn(1)->getOffset())) {
if (!op->getIn(0)->getHighTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset())) {
if (op->getIn(1)->getOffset() == 0) {
data.opRemoveInput(op, 1);
data.opSetOpcode(op, CPUI_COPY);
@ -2376,17 +2506,20 @@ int4 ActionSetCasts::apply(Funcdata &data)
data.opSetOpcode(op, CPUI_INT_ADD);
}
}
for(int4 i=0;i<op->numInput();++i) // Do input casts first, as output may depend on input
// Do input casts first, as output may depend on input
for(int4 i=0;i<op->numInput();++i) {
count += resolveUnion(op, i, data);
count += castInput(op,i,data,castStrategy);
}
if (opc == CPUI_LOAD) {
TypePointer *ptrtype = (TypePointer *)op->getIn(1)->getHigh()->getType();
TypePointer *ptrtype = (TypePointer *)op->getIn(1)->getHighTypeReadFacing(op);
int4 valsize = op->getOut()->getSize();
if ((ptrtype->getMetatype()!=TYPE_PTR)||
(ptrtype->getPtrTo()->getSize() != valsize))
data.warning("Load size is inaccurate",op->getAddr());
}
else if (opc == CPUI_STORE) {
TypePointer *ptrtype = (TypePointer *)op->getIn(1)->getHigh()->getType();
TypePointer *ptrtype = (TypePointer *)op->getIn(1)->getHighTypeReadFacing(op);
int4 valsize = op->getIn(2)->getSize();
if ((ptrtype->getMetatype()!=TYPE_PTR)||
(ptrtype->getPtrTo()->getSize() != valsize))
@ -4240,7 +4373,13 @@ void ActionInferTypes::buildLocaltypes(Funcdata &data)
if (vn->isAnnotation()) continue;
if ((!vn->isWritten())&&(vn->hasNoDescend())) continue;
bool needsBlock = false;
ct = vn->getLocalType(needsBlock);
if (vn->getSymbolEntry() != (SymbolEntry *)0) {
ct = data.checkSymbolType(vn);
if (ct == (Datatype *)0)
ct = vn->getLocalType(needsBlock);
}
else
ct = vn->getLocalType(needsBlock);
if (needsBlock)
vn->setStopUpPropagation();
#ifdef TYPEPROP_DEBUG
@ -4273,200 +4412,6 @@ bool ActionInferTypes::writeBack(Funcdata &data)
return change;
}
/// Determine if the given data-type edge looks like a pointer
/// propagating through an "add a constant" operation. We assume the input
/// to the edge has a pointer data-type. This routine returns one the commands:
/// - 0 indicates this is "add a constant" adding a zero (PTRSUB or PTRADD)
/// - 1 indicates this is "add a constant" and the constant is passed back
/// - 2 indicating the pointer does not propagate through
/// - 3 the input data-type propagates through untransformed
///
/// \param off passes back the constant offset if the command is '0' or '1'
/// \param op is the PcodeOp propagating the data-type
/// \param slot is the input edge being propagated
/// \param sz is the size of the data-type being pointed to
/// \return a command indicating how the op should be treated
int4 ActionInferTypes::propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4 sz)
{
if (op->code() == CPUI_PTRADD) {
if (slot != 0) return 2;
Varnode *constvn = op->getIn(1);
uintb mult = op->getIn(2)->getOffset();
if (constvn->isConstant()) {
off = (constvn->getOffset() * mult) & calc_mask(constvn->getSize()) ;
return (off == 0) ? 0 : 1;
}
if (sz != 0 && (mult % sz) != 0)
return 2;
return 3;
}
if (op->code() == CPUI_PTRSUB) {
if (slot != 0) return 2;
off = op->getIn(1)->getOffset();
return (off == 0) ? 0 : 1;
}
if (op->code() == CPUI_INT_ADD) {
Varnode *othervn = op->getIn(1-slot);
// Check if othervn is an offset
if (!othervn->isConstant()) {
if (othervn->isWritten()) {
PcodeOp *multop = othervn->getDef();
if (multop->code() == CPUI_INT_MULT) {
Varnode *constvn = multop->getIn(1);
if (constvn->isConstant()) {
uintb mult = constvn->getOffset();
if (mult == calc_mask(constvn->getSize())) // If multiplying by -1
return 2; // Assume this is a pointer difference and don't propagate
if (sz != 0 && (mult % sz) !=0)
return 2;
}
return 3;
}
}
if (sz == 1)
return 3;
return 2;
}
if (othervn->getTempType()->getMetatype() == TYPE_PTR) // Check if othervn marked as ptr
return 2;
off = othervn->getOffset();
return (off == 0) ? 0 : 1;
}
return 2;
}
/// \brief Propagate a pointer data-type through an ADD operation.
///
/// Assuming a pointer data-type from an ADD PcodeOp propagates from an input to
/// its output, calculate the transformed data-type of the output Varnode, which
/// will depend on details of the operation. If the edge doesn't make sense as
/// "an ADD to a pointer", prevent the propagation by returning the output Varnode's
/// current data-type.
/// \param typegrp is the TypeFactory for constructing the transformed Datatype
/// \param op is the ADD operation
/// \param inslot is the edge to propagate along
/// \return the transformed Datatype or the original output Datatype
Datatype *ActionInferTypes::propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,int4 inslot)
{
TypePointer *pointer = (TypePointer *)op->getIn(inslot)->getTempType(); // We know this is a pointer type
uintb uoffset;
int4 command = propagateAddPointer(uoffset,op,inslot,pointer->getPtrTo()->getSize());
if (command == 2) return op->getOut()->getTempType(); // Doesn't look like a good pointer add
TypePointer *parent = (TypePointer *)0;
uintb parentOff;
if (command != 3) {
uoffset = AddrSpace::addressToByte(uoffset,pointer->getWordSize());
bool allowWrap = (op->code() != CPUI_PTRSUB);
do {
pointer = pointer->downChain(uoffset,parent,parentOff,allowWrap,*typegrp);
if (pointer == (TypePointer *)0)
break;
} while(uoffset != 0);
}
if (parent != (TypePointer *)0) {
// If the innermost containing object is a TYPE_STRUCT or TYPE_ARRAY
// preserve info about this container
Datatype *pt;
if (pointer == (TypePointer *)0)
pt = typegrp->getBase(1,TYPE_UNKNOWN); // Offset does not point at a proper sub-type
else
pt = pointer->getPtrTo(); // The sub-type being directly pointed at
pointer = typegrp->getTypePointerRel(parent, pt, parentOff);
}
if (pointer == (TypePointer *)0) {
if (command == 0)
return op->getIn(inslot)->getTempType();
return op->getOut()->getTempType();
}
if (op->getIn(inslot)->isSpacebase()) {
if (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
pointer = typegrp->getTypePointer(pointer->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),pointer->getWordSize());
}
return pointer;
}
/// \brief Determine if propagation should happen along the given edge
///
/// This enforces a series of rules about how a data-type can propagate
/// between the input and output Varnodes of a single PcodeOp. An input to the
/// edge may either an input or output to the PcodeOp. A \e slot value of -1
/// indicates the PcodeOp output, a non-negative value indicates a PcodeOp input index.
/// \param op is the PcodeOp to test propagation through
/// \param inslot indicates the edge's input Varnode
/// \param outslot indicates the edge's output Varnode
/// \param invn is the input Varnode
/// \return \b false if edge cannot propagate type
bool ActionInferTypes::propagateGoodEdge(PcodeOp *op,int4 inslot,int4 outslot,Varnode *invn)
{
if (inslot == outslot) return false; // don't backtrack
type_metatype metain = invn->getTempType()->getMetatype();
switch(op->code()) {
case CPUI_NEW:
if ((inslot != 0)||(outslot != -1)) return false;
break;
case CPUI_INDIRECT:
if (op->isIndirectCreation()) return false;
if ((inslot==1)||(outslot==1)) return false;
if ((inslot!=-1)&&(outslot!=-1)) return false; // Must propagate input <-> output
break;
case CPUI_COPY:
if ((inslot!=-1)&&(outslot!=-1)) return false; // Must propagate input <-> output
break;
case CPUI_MULTIEQUAL:
if ((inslot!=-1)&&(outslot!=-1)) return false; // Must propagate input <-> output
break;
case CPUI_INT_SLESS:
case CPUI_INT_SLESSEQUAL:
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
if ((inslot==-1)||(outslot==-1)) return false; // Must propagate input <-> input
break;
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if ((inslot==-1)||(outslot==-1)) return false; // Must propagate input <-> input
break;
case CPUI_LOAD:
case CPUI_STORE:
if ((inslot==0)||(outslot==0)) return false; // Don't propagate along this edge
if (invn->isSpacebase()) return false;
break;
case CPUI_PTRADD:
if ((inslot==2)||(outslot==2)) return false; // Don't propagate along this edge
case CPUI_PTRSUB:
if ((inslot!=-1)&&(outslot!=-1)) return false; // Must propagate input <-> output
if (metain != TYPE_PTR) return false;
break;
case CPUI_INT_ADD:
if (metain != TYPE_PTR) {
if ((metain == TYPE_INT)||(metain == TYPE_UINT)) {
if ((outslot==1) && (op->getIn(1)->isConstant()))
return true;
}
return false;
}
if ((inslot!=-1)&&(outslot!=-1)) return false; // Must propagate input <-> output
break;
case CPUI_SEGMENTOP:
// Must propagate slot2 <-> output
if ((inslot==0)||(inslot==1)) return false;
if ((outslot==0)||(outslot==1)) return false;
if (invn->isSpacebase()) return false;
if (metain != TYPE_PTR) return false;
break;
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_XOR:
if (!invn->getTempType()->isPowerOfTwo()) return false; // Only propagate flag enums
break;
default:
return false;
}
return true;
}
/// \brief Attempt to propagate a data-type across a single PcodeOp edge
///
/// Given an \e input Varnode and an \e output Varnode defining a directed edge
@ -4483,126 +4428,31 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
{
Varnode *invn,*outvn;
Datatype *newtype;
if (inslot == outslot) return false; // don't backtrack
if (outslot < 0)
outvn = op->getOut();
else {
outvn = op->getIn(outslot);
if (outvn->stopsUpPropagation())
return false;
if (outvn->isAnnotation()) return false;
}
if (outvn->isAnnotation()) return false;
if (outvn->isTypeLock()) return false; // Can't propagate through typelock
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
if (!propagateGoodEdge(op,inslot,outslot,invn))
return false;
Datatype *alttype = invn->getTempType();
if (alttype->needsResolution()) {
alttype = alttype->resolveInFlow(op, inslot);
}
if (outvn->isTypeLock()) return false; // Can't propagate through typelock
if (outvn->stopsUpPropagation() && outslot >= 0) return false; // Propagation is blocked
if (alttype->getMetatype() == TYPE_BOOL) { // Only propagate boolean
if (outvn->getNZMask() > 1) // If we know output can only take boolean values
return false;
}
switch(op->code()) {
case CPUI_INT_LESS:
case CPUI_INT_LESSEQUAL:
case CPUI_INT_EQUAL:
case CPUI_INT_NOTEQUAL:
if (invn->isSpacebase()) {
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
newtype = typegrp->getTypePointer(alttype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else if (alttype->isPointerRel() && !outvn->isConstant()) {
TypePointerRel *relPtr = (TypePointerRel *)alttype;
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getPointerOffset() >= 0) {
// If we know the pointer is in the middle of a structure, don't propagate across comparison operators
// as the two sides of the operator are likely to be different types , and the other side can also
// get data-type information from the structure pointer
newtype = typegrp->getTypePointer(relPtr->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),relPtr->getWordSize());
}
else
newtype = alttype;
}
else
newtype = alttype;
break;
case CPUI_INDIRECT:
case CPUI_COPY:
case CPUI_MULTIEQUAL:
case CPUI_INT_AND:
case CPUI_INT_OR:
case CPUI_INT_XOR:
if (invn->isSpacebase()) {
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
newtype = typegrp->getTypePointer(alttype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
break;
case CPUI_INT_SLESS:
case CPUI_INT_SLESSEQUAL:
if (alttype->getMetatype() != TYPE_INT) return false; // Only propagate signed things
newtype = alttype;
break;
case CPUI_NEW:
{
Varnode *vn0 = op->getIn(0);
if (!vn0->isWritten()) return false; // Don't propagate
if (vn0->getDef()->code() != CPUI_CPOOLREF) return false;
newtype = alttype; // Propagate cpool result as result of new operator
}
break;
case CPUI_SEGMENTOP:
{
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
Datatype *btype = ((TypePointer *)alttype)->getPtrTo();
newtype = typegrp->getTypePointer(outvn->getSize(),btype,spc->getWordSize());
}
break;
case CPUI_LOAD:
if (inslot == -1) { // Propagating output to input (value to ptr)
AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
newtype = typegrp->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength()) // Size must be appropriate
newtype = outvn->getTempType();
}
else
newtype = outvn->getTempType(); // Don't propagate anything
break;
case CPUI_STORE:
if (inslot==2) { // Propagating value to ptr
AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
newtype = typegrp->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength())
newtype = outvn->getTempType();
}
else
newtype = outvn->getTempType(); // Don't propagate anything
break;
case CPUI_PTRADD:
case CPUI_PTRSUB:
if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction
else
newtype = propagateAddIn2Out(typegrp,op,inslot);
break;
case CPUI_INT_ADD:
if (outvn->isConstant() && (alttype->getMetatype() != TYPE_PTR))
newtype = alttype;
else if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction
else
newtype = propagateAddIn2Out(typegrp,op,inslot);
break;
default:
return false; // Don't propagate along this edge
}
Datatype *newtype = op->getOpcode()->propagateType(alttype, op, invn, outvn, inslot, outslot);
if (newtype == (Datatype *)0)
return false;
if (0>newtype->typeOrder(*outvn->getTempType())) {
#ifdef TYPEPROP_DEBUG
propagationDebug(typegrp->getArch(),outvn,newtype,op,inslot,(Varnode *)0);
@ -4939,11 +4789,11 @@ void TermOrder::collect(void)
for(int4 i=0;i<curop->numInput();++i) {
curvn = curop->getIn(i); // curvn is a node of the subtree IF
if (!curvn->isWritten()) { // curvn is not defined by another operation
terms.push_back(PcodeOpEdge(curop,i,multop));
terms.push_back(AdditiveEdge(curop,i,multop));
continue;
}
if (curvn->loneDescend() == (PcodeOp *)0) { // curvn has more then one use
terms.push_back(PcodeOpEdge(curop,i,multop));
terms.push_back(AdditiveEdge(curop,i,multop));
continue;
}
subop = curvn->getDef();
@ -4958,7 +4808,7 @@ void TermOrder::collect(void)
}
}
}
terms.push_back(PcodeOpEdge(curop,i,multop));
terms.push_back(AdditiveEdge(curop,i,multop));
continue;
}
opstack.push_back(subop);
@ -4970,7 +4820,7 @@ void TermOrder::collect(void)
void TermOrder::sortTerms(void)
{
for(vector<PcodeOpEdge>::iterator iter=terms.begin();iter!=terms.end();++iter)
for(vector<AdditiveEdge>::iterator iter=terms.begin();iter!=terms.end();++iter)
sorter.push_back( &(*iter) );
sort(sorter.begin(),sorter.end(),additiveCompare);

View file

@ -310,10 +310,13 @@ public:
/// input. In this case, it casts to the necessary pointer type
/// immediately.
class ActionSetCasts : public Action {
static bool testStructOffset0(Varnode *vn,Datatype *ct,CastStrategy *castStrategy);
static bool testStructOffset0(Varnode *vn,PcodeOp *op,Datatype *ct,CastStrategy *castStrategy);
static bool tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &data);
static bool isOpIdentical(Datatype *ct1,Datatype *ct2);
static int4 resolveUnion(PcodeOp *op,int4 slot,Funcdata &data);
static int4 castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStrategy);
static int4 castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy);
static PcodeOp *insertPtrsubZero(PcodeOp *op,int4 slot,Datatype *ct,Funcdata &data);
public:
ActionSetCasts(const string &g) : Action(rule_onceperfunc,"setcasts",g) {} ///< Constructor
virtual Action *clone(const ActionGroupList &grouplist) const {
@ -926,9 +929,6 @@ class ActionInferTypes : public Action {
int4 localcount; ///< Number of passes performed for this function
static void buildLocaltypes(Funcdata &data); ///< Assign initial data-type based on local info
static bool writeBack(Funcdata &data); ///< Commit the final propagated data-types to Varnodes
static int4 propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4 sz); ///< Test if edge is pointer plus a constant
static Datatype *propagateAddIn2Out(TypeFactory *typegrp,PcodeOp *op,int4 inslot);
static bool propagateGoodEdge(PcodeOp *op,int4 inslot,int4 outslot,Varnode *invn);
static bool propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 inslot,int4 outslot);
static void propagateOneType(TypeFactory *typegrp,Varnode *vn);
static void propagateRef(Funcdata &data,Varnode *vn,const Address &addr);
@ -1034,13 +1034,13 @@ public:
};
/// Class representing a \e term in an additive expression
class PcodeOpEdge {
class AdditiveEdge {
PcodeOp *op; ///< Lone descendant reading the term
int4 slot; ///< The input slot of the term
Varnode *vn; ///< The term Varnode
PcodeOp *mult; ///< The (optional) multiplier being applied to the term
public:
PcodeOpEdge(PcodeOp *o,int4 s,PcodeOp *m) { op = o; slot = s; vn = op->getIn(slot); mult=m; } ///< Constructor
AdditiveEdge(PcodeOp *o,int4 s,PcodeOp *m) { op = o; slot = s; vn = op->getIn(slot); mult=m; } ///< Constructor
PcodeOp *getMultiplier(void) const { return mult; } ///< Get the multiplier PcodeOp
PcodeOp *getOp(void) const { return op; } ///< Get the component PcodeOp adding in the term
int4 getSlot(void) const { return slot; } ///< Get the slot reading the term
@ -1054,15 +1054,15 @@ public:
/// sorting of the terms to facilitate constant collapse and factoring simplifications.
class TermOrder {
PcodeOp *root; ///< The final PcodeOp in the expression
vector<PcodeOpEdge> terms; ///< Collected terms
vector<PcodeOpEdge *> sorter; ///< An array of references to terms for quick sorting
static bool additiveCompare(const PcodeOpEdge *op1,const PcodeOpEdge *op2);
vector<AdditiveEdge> terms; ///< Collected terms
vector<AdditiveEdge *> sorter; ///< An array of references to terms for quick sorting
static bool additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2);
public:
TermOrder(PcodeOp *rt) { root = rt; } ///< Construct given root PcodeOp
int4 getSize(void) const { return terms.size(); } ///< Get the number of terms in the expression
void collect(void); ///< Collect all the terms in the expression
void sortTerms(void); ///< Sort the terms using additiveCompare()
const vector<PcodeOpEdge *> &getSort(void) { return sorter; } ///< Get the sorted list of references
const vector<AdditiveEdge *> &getSort(void) { return sorter; } ///< Get the sorted list of references
};
/// \brief A comparison operator for ordering terms in a sum
@ -1072,7 +1072,7 @@ public:
/// \param op1 is the first term to compare
/// \param op2 is the second term
/// \return \b true if the first term is less than the second
inline bool TermOrder::additiveCompare(const PcodeOpEdge *op1,const PcodeOpEdge *op2) {
inline bool TermOrder::additiveCompare(const AdditiveEdge *op1,const AdditiveEdge *op2) {
return (-1 == op1->getVarnode()->termOrder(op2->getVarnode())); }
#endif

View file

@ -127,20 +127,18 @@ bool SymbolEntry::updateType(Varnode *vn) const
Datatype *SymbolEntry::getSizedType(const Address &inaddr,int4 sz) const
{
Datatype *last,*cur;
uintb off;
if (isDynamic())
off = offset;
else
off = (inaddr.getOffset() - addr.getOffset()) + offset;
cur = symbol->getType();
Datatype *cur = symbol->getType();
do {
last = cur;
if (offset == 0 && cur->getSize() == sz)
return cur;
cur = cur->getSubType(off,&off);
} while(cur != (Datatype *)0);
if (last->getSize() == sz)
return last;
// else {
// This case occurs if the varnode is a "partial type" of some sort
// This PROBABLY means the varnode shouldn't be considered addrtied
@ -400,7 +398,7 @@ void Symbol::restoreXmlHeader(const Element *el)
{
name.clear();
category = -1;
category = no_category;
symbolId = 0;
for(int4 i=0;i<el->getNumAttributes();++i) {
const string &attName(el->getAttributeName(i));
@ -488,7 +486,7 @@ void Symbol::restoreXmlHeader(const Element *el)
break;
}
}
if (category == 0) {
if (category == function_parameter) {
istringstream s2(el->getAttributeValue("index"));
s2.unsetf(ios::dec | ios::hex | ios::oct);
s2 >> catindex;
@ -649,7 +647,7 @@ EquateSymbol::EquateSymbol(Scope *sc,const string &nm,uint4 format,uintb val)
: Symbol(sc, nm, (Datatype *)0)
{
value = val;
category = 1;
category = equate;
type = sc->getArch()->types->getBase(1,TYPE_UNKNOWN);
dispflags |= format;
}
@ -705,6 +703,49 @@ void EquateSymbol::restoreXml(const Element *el)
type = types->getBase(1,TYPE_UNKNOWN);
}
/// Create a symbol that forces a particular field of a union to propagate
///
/// \param sc is the scope owning the new symbol
/// \param nm is the name of the symbol
/// \param unionDt is the union data-type being forced
/// \param fldNum is the particular field to force (-1 indicates the whole union)
UnionFacetSymbol::UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum)
: Symbol(sc, nm, unionDt)
{
fieldNum = fldNum;
category = union_facet;
}
void UnionFacetSymbol::saveXml(ostream &s) const
{
s << "<facetsymbol";
saveXmlHeader(s);
a_v_i(s,"field",fieldNum);
s << ">\n";
saveXmlBody(s);
s << "</facetsymbol>\n";
}
void UnionFacetSymbol::restoreXml(const Element *el)
{
restoreXmlHeader(el);
istringstream s(el->getAttributeValue("field"));
s.unsetf(ios::dec | ios::hex | ios::oct);
s >> fieldNum;
const List &list(el->getChildren());
restoreXmlBody(list.begin());
Datatype *testType = type;
if (testType->getMetatype() == TYPE_PTR)
testType = ((TypePointer *)testType)->getPtrTo();
if (testType->getMetatype() != TYPE_UNION)
throw LowlevelError("<unionfacetsymbol> does not have a union type");
if (fieldNum < -1 || fieldNum >= testType->numDepend())
throw LowlevelError("<unionfacetsymbol> field attribute is out of bounds");
}
/// Label symbols don't really have a data-type, so we just put
/// a size 1 placeholder.
void LabSymbol::buildType(void)
@ -1556,6 +1597,8 @@ Symbol *Scope::addMapSym(const Element *el)
sym = new LabSymbol(owner);
else if (symname == "externrefsymbol")
sym = new ExternRefSymbol(owner);
else if (symname == "facetsymbol")
sym = new UnionFacetSymbol(owner);
else
throw LowlevelError("Unknown symbol type: "+symname);
try { // Protect against duplicate scope errors
@ -1711,9 +1754,9 @@ string Scope::buildDefaultName(Symbol *sym,int4 &base,Varnode *vn) const
if (!vn->isAddrTied() && fd != (Funcdata *)0)
usepoint = vn->getUsePoint(*fd);
HighVariable *high = vn->getHigh();
if (sym->getCategory() == 0 || high->isInput()) {
if (sym->getCategory() == Symbol::function_parameter || high->isInput()) {
int4 index = -1;
if (sym->getCategory()==0)
if (sym->getCategory()==Symbol::function_parameter)
index = sym->getCategoryIndex()+1;
return buildVariableName(vn->getAddr(),usepoint,sym->getType(),index,vn->getFlags() | Varnode::input);
}
@ -1724,7 +1767,7 @@ string Scope::buildDefaultName(Symbol *sym,int4 &base,Varnode *vn) const
Address addr = entry->getAddr();
Address usepoint = entry->getFirstUseAddress();
uint4 flags = usepoint.isInvalid() ? Varnode::addrtied : 0;
if (sym->getCategory() == 0) { // If this is a parameter
if (sym->getCategory() == Symbol::function_parameter) {
flags |= Varnode::input;
int4 index = sym->getCategoryIndex() + 1;
return buildVariableName(addr, usepoint, sym->getType(), index, flags);
@ -1958,7 +2001,7 @@ void ScopeInternal::categorySanity(void)
for(int4 j=0;j<list.size();++j) {
Symbol *sym = list[j];
if (sym == (Symbol *)0) continue;
setCategory(sym,-1,0); // Set symbol to have no category
setCategory(sym,Symbol::no_category,0);
}
}
}
@ -2004,7 +2047,7 @@ void ScopeInternal::clearUnlocked(void)
if (sym->isSizeTypeLocked())
resetSizeLockType(sym);
}
else if (sym->getCategory() == 1) {
else if (sym->getCategory() == Symbol::equate) {
// Note we treat EquateSymbols as locked for purposes of this method
// as a typelock (which traditionally prevents a symbol from being cleared)
// does not make sense for an equate
@ -2579,8 +2622,11 @@ void ScopeInternal::saveXml(ostream &s) const
int4 symbolType = 0;
if (!sym->mapentry.empty()) {
const SymbolEntry &entry( *sym->mapentry.front() );
if (entry.isDynamic())
symbolType = (sym->getCategory() == 1) ? 2 : 1;
if (entry.isDynamic()) {
if (sym->getCategory() == Symbol::union_facet)
continue; // Don't save override
symbolType = (sym->getCategory() == Symbol::equate) ? 2 : 1;
}
}
s << "<mapsym";
if (symbolType == 1)

View file

@ -144,11 +144,7 @@ typedef rangemap<SymbolEntry> EntryMap; ///< A rangemap of SymbolEntry
/// At its most basic, a Symbol is a \b name and a \b data-type.
/// Practically a Symbol knows what Scope its in, how it should be
/// displayed, and the symbols \e category. A category is a subset
/// of symbols that are stored together for quick access. The
/// \b category field can be:
/// - -1 for no category
/// - 0 indicates a function parameter
/// - 1 indicates an equate symbol
/// of symbols that are stored together for quick access.
class Symbol {
friend class Scope;
friend class ScopeInternal;
@ -162,7 +158,7 @@ protected:
// only typelock,namelock,readonly,externref
// addrtied, persist inherited from scope
uint4 dispflags; ///< Flags affecting the display of this symbol
int2 category; ///< Special category (-1==none 0=parameter 1=equate)
int2 category; ///< Special category (\b function_parameter, \b equate, etc.)
uint2 catindex; ///< Index within category
uint8 symbolId; ///< Unique id, 0=unassigned
vector<list<SymbolEntry>::iterator> mapentry; ///< List of storage locations labeled with \b this Symbol
@ -187,6 +183,14 @@ public:
is_this_ptr = 64 ///< We are the "this" symbol for a class method
};
/// \brief The possible specialize Symbol \e categories
enum {
no_category = -1, ///< Symbol is not in a special category
function_parameter = 0, ///< The Symbol is a parameter to a function
equate = 1, ///< The Symbol holds \e equate information about a constant
union_facet = 2 ///< Symbol holding read or write facing union field information
};
Symbol(Scope *sc,const string &nm,Datatype *ct); ///< Construct given a name and data-type
Symbol(Scope *sc); ///< Construct for use with restoreXml()
const string &getName(void) const { return name; } ///< Get the local name of the symbol
@ -271,13 +275,23 @@ class EquateSymbol : public Symbol {
uintb value; ///< Value of the constant being equated
public:
EquateSymbol(Scope *sc,const string &nm,uint4 format,uintb val); ///< Constructor
EquateSymbol(Scope *sc) : Symbol(sc) { value = 0; category = 1; } ///< Constructor for use with restoreXml
EquateSymbol(Scope *sc) : Symbol(sc) { value = 0; category = equate; } ///< Constructor for use with restoreXml
uintb getValue(void) const { return value; } ///< Get the constant value
bool isValueClose(uintb op2Value,int4 size) const; ///< Is the given value similar to \b this equate
virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el);
};
class UnionFacetSymbol : public Symbol {
int4 fieldNum; ///< Particular field to associate with Symbol access
public:
UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum); ///< Constructor from components
UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; } ///< Constructor for restoreXml
int4 getFieldNumber(void) const { return fieldNum; } ///< Get the particular field associate with \b this
virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el);
};
/// \brief A Symbol that labels code internal to a function
class LabSymbol : public Symbol {
void buildType(void); ///< Build placeholder data-type
@ -894,7 +908,7 @@ inline Symbol::Symbol(Scope *sc,const string &nm,Datatype *ct)
type=ct;
flags=0;
dispflags=0;
category=-1;
category=no_category;
catindex = 0;
symbolId=0;
wholeCount=0;
@ -911,7 +925,7 @@ inline Symbol::Symbol(Scope *sc)
type = (Datatype *)0;
flags=0;
dispflags=0;
category=-1;
category=no_category;
catindex = 0;
symbolId = 0;
wholeCount=0;

View file

@ -196,6 +196,38 @@ void DynamicHash::clear(void)
opedge.clear();
}
void DynamicHash::calcHash(const PcodeOp *op,int4 slot,uint4 method)
{
vnproc = 0;
opproc = 0;
opedgeproc = 0;
const Varnode *root = (slot < 0) ? op->getOut() : op->getIn(slot);
opedge.push_back(ToOpEdge(op,slot));
switch(method) {
case 4:
break;
case 5:
gatherUnmarkedOp();
for(;opproc < markop.size();++opproc) {
buildOpUp(markop[opproc]);
}
gatherUnmarkedVn();
break;
case 6:
gatherUnmarkedOp();
for(;opproc < markop.size();++opproc) {
buildOpDown(markop[opproc]);
}
gatherUnmarkedVn();
break;
default:
break;
}
pieceTogetherHash(root,method);
}
/// A sub-graph is formed extending from the given Varnode as the root. The
/// method specifies how the sub-graph is extended. In particular:
/// - Method 0 is extends to just immediate p-code ops reading or writing root
@ -254,7 +286,17 @@ void DynamicHash::calcHash(const Varnode *root,uint4 method)
default:
break;
}
pieceTogetherHash(root,method);
}
/// Assume all the elements of the hash have been calculated. Calculate the internal 32-bit hash
/// based on these elements. Construct the 64-bit hash by piecing together the 32-bit hash
/// together with the core opcode, slot, and method.
/// \param root is the Varnode to extract root characteristics from
/// \param method is the method used to compute the hash elements
void DynamicHash::pieceTogetherHash(const Varnode *root,uint4 method)
{
for(uint4 i=0;i<markvn.size();++i) // Clear our marks
markvn[i]->clearMark();
for(uint4 i=0;i<markop.size();++i)
@ -382,6 +424,65 @@ void DynamicHash::uniqueHash(const Varnode *root,Funcdata *fd)
addrresult = tmpaddr;
}
void DynamicHash::uniqueHash(const PcodeOp *op,int4 slot,Funcdata *fd)
{
vector<PcodeOp *> oplist;
vector<PcodeOp *> oplist2;
vector<PcodeOp *> champion;
uint4 method;
uint8 tmphash;
Address tmpaddr;
uint4 maxduplicates = 8;
gatherOpsAtAddress(oplist,fd,op->getAddr());
for(method=4;method<7;++method) {
clear();
calcHash(op,slot,method);
if (hash == 0) return; // Can't get a good hash
tmphash = hash;
tmpaddr = addrresult;
oplist.clear();
oplist2.clear();
for(uint4 i=0;i<oplist.size();++i) {
PcodeOp *tmpop = oplist[i];
if (slot >= tmpop->numInput()) continue;
clear();
calcHash(tmpop,slot,method);
if (hash == tmphash) { // Hash collision
oplist2.push_back(tmpop);
if (oplist2.size()>maxduplicates)
break;
}
}
if (oplist2.size() <= maxduplicates) {
if ((champion.size()==0)||(oplist2.size() < champion.size())) {
champion = oplist2;
if (champion.size()==1)
break; // Current hash is unique
}
}
}
if (champion.empty()) {
hash = (uint8)0;
addrresult = Address(); // Couldn't find a unique hash
return;
}
uint4 total = (uint4)champion.size() - 1; // total is in range [0,maxduplicates-1]
uint4 pos;
for(pos=0;pos<=total;++pos)
if (champion[pos] == op)
break;
if (pos > total) {
hash = (uint8)0;
addrresult = Address();
return;
}
hash = tmphash | ((uint8)pos << 49); // Store three bits for position with list of duplicate hashes
hash |= ((uint8)total << 52); // Store three bits for total number of duplicate hashes
addrresult = tmpaddr;
}
/// \brief Given an address and hash, find the unique matching Varnode
///
/// The method, number of collisions, and position are pulled out of the hash.
@ -414,6 +515,41 @@ Varnode *DynamicHash::findVarnode(const Funcdata *fd,const Address &addr,uint8 h
return vnlist2[pos];
}
/// \brief Given an address and hash, find the unique matching PcodeOp
///
/// The method, slot, number of collisions, and position are pulled out of the hash.
/// Hashes for the method are performed at PcodeOps linked to the given address,
/// and the PcodeOp which matches the hash (and the position) is returned.
/// If the number of collisions for the hash does not match, this method
/// will not return a PcodeOp, even if the position looks valid.
/// \param fd is the function containing the data-flow
/// \param addr is the given address
/// \param h is the hash
/// \return the matching PcodeOp or NULL
PcodeOp *DynamicHash::findOp(const Funcdata *fd,const Address &addr,uint8 h)
{
int method = getMethodFromHash(h);
int slot = getSlotFromHash(h);
int total = getTotalFromHash(h);
int pos = getPositionFromHash(h);
clearTotalPosition(h);
vector<PcodeOp *> oplist;
vector<PcodeOp *> oplist2;
gatherOpsAtAddress(oplist,fd,addr);
for(uint4 i=0;i<oplist.size();++i) {
PcodeOp *tmpop = oplist[i];
if (slot >= tmpop->numInput()) continue;
clear();
calcHash(tmpop,slot,method);
if (hash == h)
oplist2.push_back(tmpop);
}
if (total != oplist2.size())
return (PcodeOp *)0;
return oplist2[pos];
}
/// \brief Get the Varnodes immediately attached to PcodeOps at the given address
///
/// Varnodes can be either inputs or outputs to the PcodeOps. The op-code, slot, and
@ -463,6 +599,22 @@ void DynamicHash::gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata
}
}
/// \brief Place all PcodeOps at the given address in the provided container
///
/// \param opList is the container to hold the PcodeOps
/// \param fd is the function
/// \param addr is the given address
void DynamicHash::gatherOpsAtAddress(vector<PcodeOp *> &opList,const Funcdata *fd,const Address &addr)
{
PcodeOpTree::const_iterator iter,enditer;
enditer = fd->endOp(addr);
for(iter = fd->beginOp(addr); iter != enditer; ++iter) {
PcodeOp *op = (*iter).second;
opList.push_back(op);
}
}
/// The hash encodes the input \e slot the root Varnode was attached to in its PcodeOp.
/// \param h is the hash value
/// \return the slot index or -1 if the Varnode was attached as output

View file

@ -75,15 +75,20 @@ class DynamicHash {
void buildOpDown(const PcodeOp *op); ///< Move the output Varnode for the given PcodeOp into staging
void gatherUnmarkedVn(void); ///< Move staged Varnodes into the sub-graph and mark them
void gatherUnmarkedOp(void); ///< Mark any new PcodeOps in the sub-graph
void pieceTogetherHash(const Varnode *root,uint4 method); ///< Clean-up and piece together formal hash value
public:
void clear(void); ///< Called for each additional hash (after the first)
void calcHash(const Varnode *root,uint4 method); ///< Calculate the hash for given Varnode and method
void calcHash(const PcodeOp *op,int4 slot,uint4 method); ///< Calculate hash for given PcodeOp, slot, and method
void uniqueHash(const Varnode *root,Funcdata *fd); ///< Select a unique hash for the given Varnode
void uniqueHash(const PcodeOp *op,int4 slot,Funcdata *fd); ///< Select unique hash for given PcodeOp and slot
Varnode *findVarnode(const Funcdata *fd,const Address &addr,uint8 h);
PcodeOp *findOp(const Funcdata *fd,const Address &addr,uint8 h);
uint8 getHash(void) const { return hash; } ///< Get the (current) hash
const Address &getAddress(void) const { return addrresult; } ///< Get the (current) address
static void gatherFirstLevelVars(vector<Varnode *> &varlist,const Funcdata *fd,const Address &addr,uint8 h);
static void gatherOpsAtAddress(vector<PcodeOp *> &opList,const Funcdata *fd,const Address &addr);
static int4 getSlotFromHash(uint8 h); ///< Retrieve the encoded slot from a hash
static uint4 getMethodFromHash(uint8 h); ///< Retrieve the encoded method from a hash
static OpCode getOpCodeFromHash(uint8 h); ///< Retrieve the encoded op-code from a hash

View file

@ -2700,7 +2700,7 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
{
ParameterSymbol *res = getSymbolBacked(i);
res->sym = scope->getCategorySymbol(0,i);
res->sym = scope->getCategorySymbol(Symbol::function_parameter,i);
SymbolEntry *entry;
Address usepoint;
@ -2717,7 +2717,7 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
if (scope->discoverScope(pieces.addr,pieces.type->getSize(),usepoint) == (Scope *)0)
usepoint = restricted_usepoint;
res->sym = scope->addSymbol(nm,pieces.type,pieces.addr,usepoint)->getSymbol();
scope->setCategory(res->sym,0,i);
scope->setCategory(res->sym,Symbol::function_parameter,i);
if (isindirect || ishidden) {
uint4 mirror = 0;
if (isindirect)
@ -2750,17 +2750,17 @@ ProtoParameter *ProtoStoreSymbol::setInput(int4 i, const string &nm,const Parame
void ProtoStoreSymbol::clearInput(int4 i)
{
Symbol *sym = scope->getCategorySymbol(0,i);
Symbol *sym = scope->getCategorySymbol(Symbol::function_parameter,i);
if (sym != (Symbol *)0) {
scope->setCategory(sym,-1,0); // Remove it from category list
scope->setCategory(sym,Symbol::no_category,0); // Remove it from category list
scope->removeSymbol(sym); // Remove it altogether
}
// Renumber any category 0 symbol with index greater than i
int4 sz = scope->getCategorySize(0);
int4 sz = scope->getCategorySize(Symbol::function_parameter);
for(int4 j=i+1;j<sz;++j) {
sym = scope->getCategorySymbol(0,j);
sym = scope->getCategorySymbol(Symbol::function_parameter,j);
if (sym != (Symbol *)0)
scope->setCategory(sym,0,j-1);
scope->setCategory(sym,Symbol::function_parameter,j-1);
}
}
@ -2773,13 +2773,13 @@ void ProtoStoreSymbol::clearAllInputs(void)
int4 ProtoStoreSymbol::getNumInputs(void) const
{
return scope->getCategorySize(0);
return scope->getCategorySize(Symbol::function_parameter);
}
ProtoParameter *ProtoStoreSymbol::getInput(int4 i)
{
Symbol *sym = scope->getCategorySymbol(0,i);
Symbol *sym = scope->getCategorySymbol(Symbol::function_parameter,i);
if (sym == (Symbol *)0)
return (ProtoParameter *)0;
ParameterSymbol *res = getSymbolBacked(i);

View file

@ -85,6 +85,7 @@ void Funcdata::clear(void)
clearActiveOutput();
funcp.clearUnlockedOutput(); // Inputs are cleared by localmap
unionMap.clear();
clearBlocks();
obank.clear();
vbank.clear();
@ -852,6 +853,105 @@ void PcodeEmitFd::dump(const Address &addr,OpCode opc,VarnodeData *outvar,Varnod
}
}
/// \brief Get the resolved union field associated with the given edge
///
/// If there is no field associated with the edge, null is returned
/// \param parent is the data-type being resolved
/// \param op is the PcodeOp component of the given edge
/// \param slot is the slot component of the given edge
/// \return the associated field as a ResolvedUnion or null
const ResolvedUnion *Funcdata::getUnionField(const Datatype *parent,const PcodeOp *op,int4 slot) const
{
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
ResolveEdge edge(parent,op,slot);
iter = unionMap.find(edge);
if (iter != unionMap.end())
return &(*iter).second;
return (const ResolvedUnion *)0;
}
/// \brief Associate a union field with the given edge
///
/// If there was a previous association, it is overwritten unless it was \e locked.
/// The method returns \b true except in this case where a previous locked association exists.
/// \param parent is the parent union data-type
/// \param op is the PcodeOp component of the given edge
/// \param slot is the slot component of the given edge
/// \param resolve is the resolved union
/// \return \b true unless there was a locked association
bool Funcdata::setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve)
{
ResolveEdge edge(parent,op,slot);
pair<map<ResolveEdge,ResolvedUnion>::iterator,bool> res;
res = unionMap.emplace(edge,resolve);
if (!res.second) {
if ((*res.first).second.isLocked()) {
return false;
}
(*res.first).second = resolve;
}
return true;
}
/// \brief Force a specific union field resolution for the given edge
///
/// The \b parent data-type is taken directly from the given Varnode.
/// \param parent is the parent data-type
/// \param fieldNum is the index of the field to force
/// \param op is PcodeOp of the edge
/// \param slot is -1 for the write edge or >=0 indicating the particular read edge
void Funcdata::forceFacingType(Datatype *parent,int4 fieldNum,PcodeOp *op,int4 slot)
{
Datatype *baseType = parent;
if (baseType->getMetatype() == TYPE_PTR)
baseType = ((TypePointer *)baseType)->getPtrTo();
if (parent->isPointerRel()) {
// Don't associate a relative pointer with the resolution, but convert to a standard pointer
parent = glb->types->getTypePointer(parent->getSize(), baseType, ((TypePointer *)parent)->getWordSize());
}
ResolvedUnion resolve(parent,fieldNum,*glb->types);
setUnionField(parent, op, slot, resolve);
}
/// \brief Copy a Varnode's read facing resolve to another PcodeOp
///
/// \param op is the new PcodeOp reading the Varnode
/// \param slot is the new read slot
/// \param oldOp is the PcodeOp to inherit the resolve from
/// \param oldSlot is the old read slot
void Funcdata::inheritReadResolution(const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot)
{
Datatype *ct = op->getIn(slot)->getType();
if (!ct->needsResolution()) return;
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
ResolveEdge edge(ct,oldOp,oldSlot);
iter = unionMap.find(edge);
if (iter == unionMap.end()) return;
setUnionField(ct,op,slot,(*iter).second);
}
/// \brief Copy any write facing for a specific data-type from one PcodeOp to another
///
/// \param parent is the data-type that needs resolution
/// \param op is the destination PcodeOp
/// \param oldOp is the source PcodeOp
/// \return the resolution index that was copied or -1 if there was no resolution
int4 Funcdata::inheritWriteResolution(Datatype *parent,const PcodeOp *op,PcodeOp *oldOp)
{
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
ResolveEdge edge(parent,oldOp,-1);
iter = unionMap.find(edge);
if (iter == unionMap.end())
return -1;
setUnionField(parent,op,-1,(*iter).second);
return (*iter).second.getFieldNum();
}
#ifdef OPACTION_DEBUG
/// The current state of the op is recorded for later comparison after

View file

@ -24,6 +24,7 @@
#include "heritage.hh"
#include "merge.hh"
#include "dynamic.hh"
#include "unionresolve.hh"
class FlowInfo;
@ -88,6 +89,7 @@ class Funcdata {
ParamActive *activeoutput; ///< Data for assessing which parameters are passed to \b this function
Override localoverride; ///< Overrides of data-flow, prototypes, etc. that are local to \b this function
map<VarnodeData,const LanedRegister *> lanedMap; ///< Current storage locations which may be laned registers
map<ResolveEdge,ResolvedUnion> unionMap; ///< A map from data-flow edges to the resolved field of TypeUnion being accessed
// Low level Varnode functions
void setVarnodeProperties(Varnode *vn) const; ///< Look-up boolean properties and data-type information
@ -100,6 +102,7 @@ class Funcdata {
Varnode *cloneVarnode(const Varnode *vn); ///< Clone a Varnode (between copies of the function)
void destroyVarnode(Varnode *vn); ///< Delete the given Varnode from \b this function
void coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list);
bool applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash);
// Low level op functions
void opZeroMulti(PcodeOp *op); ///< Transform trivial CPUI_MULTIEQUAL to CPUI_COPY
// Low level block functions
@ -373,6 +376,7 @@ public:
bool onlyOpUse(const Varnode *invn,const PcodeOp *opmatch,const ParamTrial &trial,uint4 mainFlags) const;
bool ancestorOpUse(int4 maxlevel,const Varnode *invn,const PcodeOp *op,ParamTrial &trial,uint4 mainFlags) const;
bool syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes);
Datatype *checkSymbolType(Varnode *vn); ///< Check for any delayed symbol data-type information on the given Varnode
void transferVarnodeProperties(Varnode *vn,Varnode *newVn,int4 lsbOffset);
bool fillinReadOnly(Varnode *vn); ///< Replace the given Varnode with its (constant) value in the load image
bool replaceVolatile(Varnode *vn); ///< Replace accesses of the given Varnode with \e volatile operations
@ -489,6 +493,12 @@ public:
bool moveRespectingCover(PcodeOp *op,PcodeOp *lastOp); ///< Move given op past \e lastOp respecting covers if possible
const ResolvedUnion *getUnionField(const Datatype *parent,const PcodeOp *op,int4 slot) const;
bool setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve);
void forceFacingType(Datatype *parent,int4 fieldNum,PcodeOp *op,int4 slot);
void inheritReadResolution(const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
int4 inheritWriteResolution(Datatype *parent,const PcodeOp *op,PcodeOp *oldOp);
// Jumptable routines
JumpTable *linkJumpTable(PcodeOp *op); ///< Link jump-table with a given BRANCHIND
JumpTable *findJumpTable(const PcodeOp *op) const; ///< Find a jump-table associated with a given BRANCHIND

View file

@ -544,7 +544,7 @@ void Funcdata::opUndoPtradd(PcodeOp *op,bool finalize)
newVal &= calc_mask(offVn->getSize());
Varnode *newOffVn = newConstant(offVn->getSize(), newVal);
if (finalize)
newOffVn->updateType(offVn->getType(), false, false);
newOffVn->updateType(offVn->getTypeReadFacing(op), false, false);
opSetInput(op,newOffVn,1);
return;
}

View file

@ -828,13 +828,8 @@ bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes)
fl = entry->getAllFlags();
if (entry->getSize() >= vnexemplar->getSize()) {
if (typesyes) {
uintb off = (vnexemplar->getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
Datatype *cur = entry->getSymbol()->getType();
do {
ct = cur;
cur = cur->getSubType(off,&off);
} while(cur != (Datatype *)0);
if ((ct->getSize() != vnexemplar->getSize())||(ct->getMetatype() == TYPE_UNKNOWN))
ct = entry->getSizedType(vnexemplar->getAddr(), vnexemplar->getSize());
if (ct != (Datatype *)0 && ct->getMetatype() == TYPE_UNKNOWN)
ct = (Datatype *)0;
}
}
@ -863,6 +858,52 @@ bool Funcdata::syncVarnodesWithSymbols(const ScopeLocal *lm,bool typesyes)
return updateoccurred;
}
/// If the Varnode is a partial Symbol with \e union data-type, the best description of the Varnode's
/// data-type is delayed until data-type propagation is started.
/// We attempt to resolve this description and also lay down any facing resolutions for the Varnode
/// \param vn is the given Varnode
/// \return the best data-type or null
Datatype *Funcdata::checkSymbolType(Varnode *vn)
{
if (vn->isTypeLock()) return vn->getType();
SymbolEntry *entry = vn->getSymbolEntry();
Symbol *sym = entry->getSymbol();
if (sym->getType()->getMetatype() != TYPE_UNION)
return (Datatype *)0;
TypeUnion *unionType = (TypeUnion *)sym->getType();
int4 off = (int4)(vn->getOffset() - entry->getAddr().getOffset()) + entry->getOffset();
if (off == 0 && unionType->getSize() == vn->getSize())
return (Datatype *)0;
const TypeField *finalField = (const TypeField *)0;
uintb finalOff = 0;
list<PcodeOp *>::const_iterator iter;
for(iter=vn->beginDescend();iter!=vn->endDescend();++iter) {
PcodeOp *op = *iter;
const TypeField *field = unionType->resolveTruncation(off, op, op->getSlot(vn),off);
if (field != (const TypeField *)0) {
finalField = field;
finalOff = off;
}
}
if (vn->isWritten()) {
const TypeField *field = unionType->resolveTruncation(off, vn->getDef(), -1, off);
if (field != (const TypeField *)0) {
finalField = field;
finalOff = off;
}
}
if (finalField != (const TypeField *)0) { // If any use of the Varnode resolves to a specific field
// Try to truncate down to a final data-type to assign to the Varnode
Datatype *ct = finalField->type;
while(ct != (Datatype *)0 && (finalOff != 0 || ct->getSize() != vn->getSize())) {
ct = ct->getSubType(finalOff, &finalOff);
}
return ct;
}
return (Datatype *)0;
}
/// A Varnode overlaps the given SymbolEntry. Make sure the Varnode is part of the variable
/// underlying the Symbol. If not, remap things so that the Varnode maps to a distinct Symbol.
/// In either case, attach the appropriate Symbol to the Varnode
@ -1175,10 +1216,14 @@ bool Funcdata::attemptDynamicMapping(SymbolEntry *entry,DynamicHash &dhash)
if (sym->getScope() != localmap)
throw LowlevelError("Cannot currently have a dynamic symbol outside the local scope");
dhash.clear();
int4 category = sym->getCategory();
if (category == Symbol::union_facet) {
return applyUnionFacet(entry, dhash);
}
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
if (vn == (Varnode *)0) return false;
if (entry->getSymbol()->getCategory() == 1) { // Is this an equate symbol
if (vn->mapentry != entry) { // Check we haven't marked this before
if (category == Symbol::equate) { // Is this an equate symbol
if (vn->mapentry != entry) { // Check we haven't marked this before
vn->setSymbolEntry(entry);
return true;
}
@ -1202,12 +1247,15 @@ bool Funcdata::attemptDynamicMappingLate(SymbolEntry *entry,DynamicHash &dhash)
{
dhash.clear();
Symbol *sym = entry->getSymbol();
if (sym->getCategory() == Symbol::union_facet) {
return applyUnionFacet(entry, dhash);
}
Varnode *vn = dhash.findVarnode(this,entry->getFirstUseAddress(),entry->getHash());
if (vn == (Varnode *)0)
return false;
if (vn->getSymbolEntry() == entry) return false; // Already applied it
Symbol *sym = entry->getSymbol();
if (sym->getCategory() == 1) { // Equate symbol does not depend on size
if (sym->getCategory() == Symbol::equate) { // Equate symbol does not depend on size
vn->setSymbolEntry(entry);
return true;
}
@ -1406,6 +1454,28 @@ void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
}
}
/// \brief Cache information from a UnionFacetSymbol
///
/// The symbol forces a particular union field resolution for the associated PcodeOp and slot,
/// which are extracted from the given \e dynamic SymbolEntry. The resolution is cached
/// in the \b unionMap so that it will get picked up by resolveInFlow() methods etc.
/// \param entry is the given SymbolEntry
/// \param dhash is preallocated storage for calculating the dynamic hash
/// \return \b true if the UnionFacetSymbol is successfully cached
bool Funcdata::applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash)
{
Symbol *sym = entry->getSymbol();
PcodeOp *op = dhash.findOp(this, entry->getFirstUseAddress(), entry->getHash());
if (op == (PcodeOp *)0)
return false;
int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
int4 fldNum = ((UnionFacetSymbol *)sym)->getFieldNumber();
ResolvedUnion resolve(sym->getType(), fldNum, *glb->types);
resolve.setLock(true);
return setUnionField(sym->getType(),op,slot,resolve);
}
/// Search for \e addrtied Varnodes whose storage falls in the global Scope, then
/// build a new global Symbol if one didn't exist before.
void Funcdata::mapGlobals(void)

View file

@ -2814,7 +2814,7 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
{ // Build a new structure
TypeStruct *res = glb->types->getTypeStruct(ident); // Create stub (for recursion)
vector<TypeField> sublist;
for(uint4 i=0;i<declist->size();++i) {
TypeDeclarator *decl = (*declist)[i];
if (!decl->isValid()) {
@ -2822,12 +2822,10 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
glb->types->destroyType(res);
return (Datatype *)0;
}
sublist.push_back(TypeField());
sublist.back().type = decl->buildType(glb);
sublist.back().name = decl->getIdentifier();
sublist.back().offset = -1; // Let typegrp figure out offset
sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb));
}
TypeStruct::assignFieldOffsets(sublist,glb->types->getStructAlign());
if (!glb->types->setFields(sublist,res,-1,0)) {
setError("Bad structure definition");
glb->types->destroyType(res);
@ -2848,15 +2846,34 @@ Datatype *CParse::oldStruct(const string &ident)
Datatype *CParse::newUnion(const string &ident,vector<TypeDeclarator *> *declist)
{
setError("Unions are currently unsupported");
return (Datatype *)0;
TypeUnion *res = glb->types->getTypeUnion(ident); // Create stub (for recursion)
vector<TypeField> sublist;
for(uint4 i=0;i<declist->size();++i) {
TypeDeclarator *decl = (*declist)[i];
if (!decl->isValid()) {
setError("Invalid union declarator");
glb->types->destroyType(res);
return (Datatype *)0;
}
sublist.emplace_back(i,0,decl->getIdentifier(),decl->buildType(glb));
}
if (!glb->types->setFields(sublist,res,-1,0)) {
setError("Bad union definition");
glb->types->destroyType(res);
return (Datatype *)0;
}
return res;
}
Datatype *CParse::oldUnion(const string &ident)
{
setError("Unions are currently unsupported");
return (Datatype *)0;
Datatype *res = glb->types->findByName(ident);
if ((res==(Datatype *)0)||(res->getMetatype() != TYPE_UNION))
setError("Identifier does not represent a union as required");
return res;
}
Enumerator *CParse::newEnumerator(const string &ident)
@ -3179,6 +3196,9 @@ void parse_C(Architecture *glb,istream &s)
else if (decl->getBaseType()->getMetatype()==TYPE_STRUCT) {
// We parsed a struct, treat as a typedef
}
else if (decl->getBaseType()->getMetatype()==TYPE_UNION) {
// We parsed a union, treat as a typedef
}
else if (decl->getBaseType()->isEnumType()) {
// We parsed an enum, treat as a typedef
}

View file

@ -1029,7 +1029,7 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
{ // Build a new structure
TypeStruct *res = glb->types->getTypeStruct(ident); // Create stub (for recursion)
vector<TypeField> sublist;
for(uint4 i=0;i<declist->size();++i) {
TypeDeclarator *decl = (*declist)[i];
if (!decl->isValid()) {
@ -1037,12 +1037,10 @@ Datatype *CParse::newStruct(const string &ident,vector<TypeDeclarator *> *declis
glb->types->destroyType(res);
return (Datatype *)0;
}
sublist.push_back(TypeField());
sublist.back().type = decl->buildType(glb);
sublist.back().name = decl->getIdentifier();
sublist.back().offset = -1; // Let typegrp figure out offset
sublist.emplace_back(0,-1,decl->getIdentifier(),decl->buildType(glb));
}
TypeStruct::assignFieldOffsets(sublist,glb->types->getStructAlign());
if (!glb->types->setFields(sublist,res,-1,0)) {
setError("Bad structure definition");
glb->types->destroyType(res);
@ -1063,15 +1061,34 @@ Datatype *CParse::oldStruct(const string &ident)
Datatype *CParse::newUnion(const string &ident,vector<TypeDeclarator *> *declist)
{
setError("Unions are currently unsupported");
return (Datatype *)0;
TypeUnion *res = glb->types->getTypeUnion(ident); // Create stub (for recursion)
vector<TypeField> sublist;
for(uint4 i=0;i<declist->size();++i) {
TypeDeclarator *decl = (*declist)[i];
if (!decl->isValid()) {
setError("Invalid union declarator");
glb->types->destroyType(res);
return (Datatype *)0;
}
sublist.emplace_back(i,0,decl->getIdentifier(),decl->buildType(glb));
}
if (!glb->types->setFields(sublist,res,-1,0)) {
setError("Bad union definition");
glb->types->destroyType(res);
return (Datatype *)0;
}
return res;
}
Datatype *CParse::oldUnion(const string &ident)
{
setError("Unions are currently unsupported");
return (Datatype *)0;
Datatype *res = glb->types->findByName(ident);
if ((res==(Datatype *)0)||(res->getMetatype() != TYPE_UNION))
setError("Identifier does not represent a union as required");
return res;
}
Enumerator *CParse::newEnumerator(const string &ident)
@ -1394,6 +1411,9 @@ void parse_C(Architecture *glb,istream &s)
else if (decl->getBaseType()->getMetatype()==TYPE_STRUCT) {
// We parsed a struct, treat as a typedef
}
else if (decl->getBaseType()->getMetatype()==TYPE_UNION) {
// We parsed a union, treat as a typedef
}
else if (decl->getBaseType()->isEnumType()) {
// We parsed an enum, treat as a typedef
}

View file

@ -1266,7 +1266,7 @@ void IfcRename::execute(istream &s)
else
throw IfaceExecutionError("More than one symbol named: "+oldname);
if (sym->getCategory() == 0)
if (sym->getCategory() == Symbol::function_parameter)
dcp->fd->getFuncProto().setInputLock(true);
sym->getScope()->renameSymbol(sym,newname);
sym->getScope()->setAttribute(sym,Varnode::namelock|Varnode::typelock);
@ -1330,7 +1330,7 @@ void IfcRetype::execute(istream &s)
else
sym = symList[0];
if (sym->getCategory()==0)
if (sym->getCategory()==Symbol::function_parameter)
dcp->fd->getFuncProto().setInputLock(true);
sym->getScope()->retypeSymbol(sym,ct);
sym->getScope()->setAttribute(sym,Varnode::typelock);

View file

@ -144,7 +144,7 @@ void IfaceStatus::pushScript(const string &filename,const string &newprompt)
{
ifstream *s = new ifstream(filename.c_str());
if (!*s)
throw IfaceParseError("Unable to open script file");
throw IfaceParseError("Unable to open script file: "+filename);
pushScript(s,newprompt);
}

View file

@ -344,18 +344,24 @@ void Merge::mergeByDatatype(VarnodeLocSet::const_iterator startiter,VarnodeLocSe
/// A COPY is allocated with the given input and data-type. A \e unique space
/// output is created.
/// \param inVn is the given input Varnode for the new COPY
/// \param ct is the data-type to assign to the new unique output
/// \param addr is the address associated with the new COPY
/// \return the newly allocated COPY
PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,Datatype *ct,const Address &addr)
PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,const Address &addr)
{
PcodeOp *copyOp = data.newOp(1,addr);
data.opSetOpcode(copyOp,CPUI_COPY);
Datatype *ct = inVn->getType();
Varnode *outVn = data.newUnique(inVn->getSize(),ct);
data.opSetOutput(copyOp,outVn);
data.opSetInput(copyOp,inVn,0);
copyTrims.push_back(copyOp);
if (ct->needsResolution()) { // If the data-type needs resolution
if (inVn->isWritten()) {
int4 fieldNum = data.inheritWriteResolution(ct, copyOp, inVn->getDef());
data.forceFacingType(ct, fieldNum, copyOp, 0);
}
}
return copyOp;
}
@ -374,7 +380,6 @@ void Merge::snipReads(Varnode *vn,list<PcodeOp *> &markedop)
PcodeOp *copyop,*op;
BlockBasic *bl;
Address pc;
int4 slot;
PcodeOp *afterop;
// Figure out where copy is inserted
@ -392,7 +397,7 @@ void Merge::snipReads(Varnode *vn,list<PcodeOp *> &markedop)
else
afterop = vn->getDef();
}
copyop = allocateCopyTrim(vn, vn->getType(), pc);
copyop = allocateCopyTrim(vn, pc);
if (afterop == (PcodeOp *)0)
data.opInsertBegin(copyop,bl);
else
@ -401,8 +406,7 @@ void Merge::snipReads(Varnode *vn,list<PcodeOp *> &markedop)
list<PcodeOp *>::iterator iter;
for(iter=markedop.begin();iter!=markedop.end();++iter) {
op = *iter;
for(slot=0;slot<op->numInput();++slot)
if (op->getIn(slot)==vn) break; // Find the correct slot
int4 slot = op->getSlot(vn);
data.opSetInput(op,copyop->getOut(),slot);
}
}
@ -561,7 +565,7 @@ void Merge::trimOpOutput(PcodeOp *op)
else
afterop = op;
vn = op->getOut();
uniq = data.newUnique(vn->getSize(),vn->getType());
uniq = data.newUnique(vn->getSize(),vn->getTypeDefFacing());
copyop = data.newOp(1,op->getAddr());
data.opSetOutput(op,uniq); // Output of op is now stubby uniq
data.opSetOpcode(copyop,CPUI_COPY);
@ -592,7 +596,7 @@ void Merge::trimOpInput(PcodeOp *op,int4 slot)
else
pc = op->getAddr();
vn = op->getIn(slot);
copyop = allocateCopyTrim(vn, vn->getType(), pc);
copyop = allocateCopyTrim(vn, pc);
data.opSetInput(op,copyop->getOut(),slot);
if (op->code() == CPUI_MULTIEQUAL)
data.opInsertEnd(copyop,(BlockBasic *)op->getParent()->getIn(slot));
@ -748,7 +752,7 @@ void Merge::snipIndirect(PcodeOp *indop)
// an instance of the output high must
// all intersect so the varnodes must all be
// traceable via COPY to the same root
snipop = allocateCopyTrim(refvn, refvn->getType(), op->getAddr());
snipop = allocateCopyTrim(refvn, op->getAddr());
data.opInsertBefore(snipop,op);
list<PcodeOp *>::iterator oiter;
int4 i,slot;
@ -774,8 +778,10 @@ void Merge::mergeIndirect(PcodeOp *indop)
return;
}
if (mergeTestRequired(outvn->getHigh(),invn0->getHigh()))
if (merge(invn0->getHigh(),outvn->getHigh(),false)) return;
if (mergeTestRequired(outvn->getHigh(),invn0->getHigh())) {
if (merge(invn0->getHigh(),outvn->getHigh(),false))
return;
}
snipIndirect(indop); // If we cannot merge, the only thing that can go
// wrong with an input trim, is if the output of
// indop is involved in the input to the op causing
@ -783,7 +789,11 @@ void Merge::mergeIndirect(PcodeOp *indop)
PcodeOp *newop;
newop = allocateCopyTrim(invn0, outvn->getType(), indop->getAddr());
newop = allocateCopyTrim(invn0, indop->getAddr());
SymbolEntry *entry = outvn->getSymbolEntry();
if (entry != (SymbolEntry *)0 && entry->getSymbol()->getType()->needsResolution()) {
data.inheritWriteResolution(entry->getSymbol()->getType(), newop, indop);
}
data.opSetInput(indop,newop->getOut(),0);
data.opInsertBefore(newop,indop);
if (!mergeTestRequired(outvn->getHigh(),indop->getIn(0)->getHigh()) ||

View file

@ -96,7 +96,7 @@ class Merge {
void collectCovering(vector<Varnode *> &vlist,HighVariable *high,PcodeOp *op);
bool collectCorrectable(const vector<Varnode *> &vlist,list<PcodeOp *> &oplist,vector<int4> &slotlist,
PcodeOp *op);
PcodeOp *allocateCopyTrim(Varnode *inVn,Datatype *ct,const Address &addr);
PcodeOp *allocateCopyTrim(Varnode *inVn,const Address &addr);
void snipReads(Varnode *vn,list<PcodeOp *> &markedop);
void snipIndirect(PcodeOp *indop);
void eliminateIntersect(Varnode *vn,const vector<BlockVarnode> &blocksort);

View file

@ -233,7 +233,8 @@ void EmitXml::tagType(const char *ptr,syntax_highlight hl,const Datatype *ct) {
/// \param hl indicates how the identifier should be highlighted
/// \param ct is the data-type associated with the field
/// \param o is the (byte) offset of the field within its structured data-type
void EmitXml::tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 o) {
/// \param op is the PcodeOp associated with the field (usually PTRSUB or SUBPIECE)
void EmitXml::tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 o,const PcodeOp *op) {
*s << "<field " << highlight[(int4)hl];
if (ct != (const Datatype *)0) {
*s << " name=\"";
@ -243,6 +244,8 @@ void EmitXml::tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,in
}
*s << "\" off=\"" << dec << o << '\"';
if (op != (const PcodeOp *)0)
*s << " opref=\"0x" << hex << op->getTime() << "\"";
}
*s << '>';
xml_escape(*s,ptr);
@ -419,7 +422,7 @@ void TokenSplit::print(EmitXml *emit) const
emit->tagType(tok.c_str(),hl,ptr_second.ct);
break;
case field_t: // tagField
emit->tagField(tok.c_str(),hl,ptr_second.ct,(int4)off);
emit->tagField(tok.c_str(),hl,ptr_second.ct,(int4)off,op);
break;
case comm_t: // tagComment
emit->tagComment(tok.c_str(),hl,ptr_second.spc,off);
@ -1054,12 +1057,12 @@ void EmitPrettyPrint::tagType(const char *ptr,syntax_highlight hl,const Datatype
scan();
}
void EmitPrettyPrint::tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 o)
void EmitPrettyPrint::tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 o,const PcodeOp *op)
{
checkstring();
TokenSplit &tok( tokqueue.push() );
tok.tagField(ptr,hl,ct,o);
tok.tagField(ptr,hl,ct,o,op);
scan();
}

View file

@ -121,7 +121,7 @@ public:
virtual void tagOp(const char *ptr,syntax_highlight hl,const PcodeOp *op);
virtual void tagFuncName(const char *ptr,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op);
virtual void tagType(const char *ptr,syntax_highlight hl,const Datatype *ct);
virtual void tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 off);
virtual void tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op);
virtual void tagComment(const char *ptr,syntax_highlight hl,const AddrSpace *spc,uintb off);
virtual void tagLabel(const char *ptr,syntax_highlight hl,const AddrSpace *spc,uintb off);
virtual void print(const char *str,syntax_highlight hl=no_color);
@ -270,7 +270,7 @@ public:
*s << ptr; }
virtual void tagType(const char *ptr,syntax_highlight hl,const Datatype *ct) {
*s << ptr; }
virtual void tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 off) {
virtual void tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op) {
*s << ptr; }
virtual void tagComment(const char *ptr,syntax_highlight hl,
const AddrSpace *spc,uintb off) {
@ -504,9 +504,10 @@ public:
/// \param h indicates how the identifier should be highlighted
/// \param ct is the data-type associated with the field
/// \param o is the (byte) offset of the field within its structured data-type
void tagField(const char *ptr,EmitXml::syntax_highlight h,const Datatype *ct,int4 o) {
/// \param inOp is the PcodeOp associated with the field (usually PTRSUB or SUBPIECE)
void tagField(const char *ptr,EmitXml::syntax_highlight h,const Datatype *ct,int4 o,const PcodeOp *inOp) {
tok = ptr; size = tok.size();
tagtype=field_t; delimtype=tokenstring; hl=h; ptr_second.ct=ct; off=(uintb)o; }
tagtype=field_t; delimtype=tokenstring; hl=h; ptr_second.ct=ct; off=(uintb)o; op=inOp; }
/// \brief Create a comment string in the generated source code
///
@ -773,7 +774,7 @@ public:
virtual void tagOp(const char *ptr,syntax_highlight hl,const PcodeOp *op);
virtual void tagFuncName(const char *ptr,syntax_highlight hl,const Funcdata *fd,const PcodeOp *op);
virtual void tagType(const char *ptr,syntax_highlight hl,const Datatype *ct);
virtual void tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 off);
virtual void tagField(const char *ptr,syntax_highlight hl,const Datatype *ct,int4 off,const PcodeOp *op);
virtual void tagComment(const char *ptr,syntax_highlight hl,
const AddrSpace *spc,uintb off);
virtual void tagLabel(const char *ptr,syntax_highlight hl,

View file

@ -360,7 +360,7 @@ void PrintC::opFunc(const PcodeOp *op)
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=0;--i)
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
else // Push empty token for void
pushAtom(Atom("",blanktoken,EmitXml::no_color));
@ -375,9 +375,9 @@ void PrintC::opTypeCast(const PcodeOp *op)
{
if (!option_nocasts) {
pushOp(&typecast,op);
pushType(op->getOut()->getHigh()->getType());
pushType(op->getOut()->getHighTypeDefFacing());
}
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
/// The syntax represents the given op using a function with one input,
@ -392,13 +392,13 @@ void PrintC::opHiddenFunc(const PcodeOp *op)
{
pushOp(&hidden,op);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
void PrintC::opCopy(const PcodeOp *op)
{
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
void PrintC::opLoad(const PcodeOp *op)
@ -411,7 +411,7 @@ void PrintC::opLoad(const PcodeOp *op)
else {
pushOp(&dereference,op);
}
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(1),op,m);
}
void PrintC::opStore(const PcodeOp *op)
@ -430,8 +430,8 @@ void PrintC::opStore(const PcodeOp *op)
}
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVnImplied(op->getIn(2),op,mods);
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(2),op,mods);
pushVn(op->getIn(1),op,m);
}
void PrintC::opBranch(const PcodeOp *op)
@ -441,7 +441,7 @@ void PrintC::opBranch(const PcodeOp *op)
// Assume the BRANCH is a statement
emit->tagOp("goto",EmitXml::keyword_color,op);
emit->spaces(1);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
}
@ -480,7 +480,7 @@ void PrintC::opCbranch(const PcodeOp *op)
}
if (booleanflip)
pushOp(&boolean_not,op);
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(1),op,m);
// Make sure stack is clear before emitting more
recurse();
if (yesparen)
@ -492,7 +492,7 @@ void PrintC::opCbranch(const PcodeOp *op)
emit->spaces(1);
emit->print("goto",EmitXml::keyword_color);
emit->spaces(1);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
}
@ -502,7 +502,7 @@ void PrintC::opBranchind(const PcodeOp *op)
// FIXME: This routine shouldn't emit directly
emit->tagOp("switch",EmitXml::keyword_color,op); // Print header for switch
int4 id = emit->openParen('(');
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
recurse();
emit->closeParen(')',id);
}
@ -544,7 +544,7 @@ void PrintC::opCall(const PcodeOp *op)
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
}
else // Push empty token for void
@ -564,25 +564,25 @@ void PrintC::opCallind(const PcodeOp *op)
int4 count = op->numInput() - 1;
count -= (skip < 0) ? 0 : 1;
if (count > 1) { // Multiple parameters
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
for(int4 i=0;i<count-1;++i)
pushOp(&comma,op);
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
}
else if (count == 1) { // One parameter
if (skip == 1)
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
else
pushVnImplied(op->getIn(1),op,mods);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(1),op,mods);
pushVn(op->getIn(0),op,mods);
}
else { // A void function
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
pushAtom(Atom("",blanktoken,EmitXml::no_color));
}
}
@ -599,7 +599,7 @@ void PrintC::opCallother(const PcodeOp *op)
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i)
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
else // Push empty token for void
pushAtom(Atom("",blanktoken,EmitXml::no_color));
@ -614,7 +614,7 @@ void PrintC::opConstructor(const PcodeOp *op,bool withNew)
const Varnode *outvn = newop->getOut();
pushOp(&new_op,newop);
pushAtom(Atom("new",optoken,EmitXml::keyword_color,newop,outvn));
dt = outvn->getType();
dt = outvn->getTypeDefFacing();
}
else {
const Varnode *thisvn = op->getIn(1);
@ -632,10 +632,10 @@ void PrintC::opConstructor(const PcodeOp *op,bool withNew)
for(int4 i=2;i<op->numInput()-1;++i)
pushOp(&comma,op);
for(int4 i=op->numInput()-1;i>=2;--i)
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
else if (op->numInput()==3) { // One parameter
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
}
else { // A void function
pushAtom(Atom("",blanktoken,EmitXml::no_color));
@ -652,7 +652,7 @@ void PrintC::opReturn(const PcodeOp *op)
emit->tagOp("return",EmitXml::keyword_color,op);
if (op->numInput()>1) {
emit->spaces(1);
pushVnImplied(op->getIn(1),op,mods);
pushVn(op->getIn(1),op,mods);
}
return;
case PcodeOp::noreturn: // Previous instruction does not exit
@ -677,7 +677,7 @@ void PrintC::opReturn(const PcodeOp *op)
void PrintC::opIntZext(const PcodeOp *op,const PcodeOp *readOp)
{
if (castStrategy->isZextCast(op->getOut()->getHigh()->getType(),op->getIn(0)->getHigh()->getType())) {
if (castStrategy->isZextCast(op->getOut()->getHighTypeDefFacing(),op->getIn(0)->getHighTypeReadFacing(op))) {
if (option_hide_exts && castStrategy->isExtensionCastImplied(op,readOp))
opHiddenFunc(op);
else
@ -690,7 +690,7 @@ void PrintC::opIntZext(const PcodeOp *op,const PcodeOp *readOp)
void PrintC::opIntSext(const PcodeOp *op,const PcodeOp *readOp)
{
if (castStrategy->isSextCast(op->getOut()->getHigh()->getType(),op->getIn(0)->getHigh()->getType())) {
if (castStrategy->isSextCast(op->getOut()->getHighTypeDefFacing(),op->getIn(0)->getHighTypeReadFacing(op))) {
if (option_hide_exts && castStrategy->isExtensionCastImplied(op,readOp))
opHiddenFunc(op);
else
@ -707,22 +707,33 @@ void PrintC::opBoolNegate(const PcodeOp *op)
{
if (isSet(negatetoken)) { // Check if we are negated by a previous BOOL_NEGATE
unsetMod(negatetoken); // If so, mark that negatetoken is consumed
pushVnImplied(op->getIn(0),op,mods); // Don't print ourselves, but print our input unmodified
pushVn(op->getIn(0),op,mods); // Don't print ourselves, but print our input unmodified
}
else if (checkPrintNegation(op->getIn(0))) { // If the next operator can be flipped
pushVnImplied(op->getIn(0),op,mods|negatetoken); // Don't print ourselves, but print a modified input
pushVn(op->getIn(0),op,mods|negatetoken); // Don't print ourselves, but print a modified input
}
else {
pushOp(&boolean_not,op); // Otherwise print ourselves
pushVnImplied(op->getIn(0),op,mods); // And print our input
pushVn(op->getIn(0),op,mods); // And print our input
}
}
void PrintC::opSubpiece(const PcodeOp *op)
{
if (castStrategy->isSubpieceCast(op->getOut()->getHigh()->getType(),
op->getIn(0)->getHigh()->getType(),
if (op->doesSpecialPrinting()) { // Special printing means it is a field extraction
int4 offset;
Datatype *ct;
const TypeField *field = TypeOpSubpiece::testExtraction(true, op, ct, offset);
if (field != (const TypeField *)0 && offset == 0) {
pushOp(&object_member,op);
pushVn(op->getIn(0), op, mods);
pushAtom(Atom(field->name,fieldtoken,EmitXml::no_color,ct,field->ident,op));
return;
}
}
if (castStrategy->isSubpieceCast(op->getOut()->getHighTypeDefFacing(),
op->getIn(0)->getHighTypeReadFacing(op),
(uint4)op->getIn(1)->getOffset()))
opTypeCast(op);
else
@ -735,7 +746,7 @@ void PrintC::opPtradd(const PcodeOp *op)
bool printval = isSet(print_load_value|print_store_value);
uint4 m = mods & ~(print_load_value|print_store_value);
if (!printval) {
TypePointer *tp = (TypePointer *)op->getIn(0)->getHigh()->getType();
TypePointer *tp = (TypePointer *)op->getIn(0)->getHighTypeReadFacing(op);
if (tp->getMetatype() == TYPE_PTR) {
if (tp->getPtrTo()->getMetatype() == TYPE_ARRAY)
printval = true;
@ -747,8 +758,8 @@ void PrintC::opPtradd(const PcodeOp *op)
pushOp(&binary_plus,op);
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVnImplied(op->getIn(1),op,m);
pushVnImplied(op->getIn(0),op,m);
pushVn(op->getIn(1),op,m);
pushVn(op->getIn(0),op,m);
}
static bool isValueFlexible(const Varnode *vn)
@ -791,7 +802,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
in0 = op->getIn(0);
in1const = op->getIn(1)->getOffset();
ptype = (TypePointer *)in0->getHigh()->getType();
ptype = (TypePointer *)in0->getHighTypeReadFacing(op);
if (ptype->getMetatype() != TYPE_PTR) {
clear();
throw LowlevelError("PTRSUB off of non-pointer type");
@ -808,7 +819,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
valueon = (mods & (print_load_value|print_store_value)) != 0;
flex = isValueFlexible(in0);
if (ct->getMetatype() == TYPE_STRUCT) {
if (ct->getMetatype() == TYPE_STRUCT || ct->getMetatype() == TYPE_UNION) {
uintb suboff = in1const; // How far into container
if (ptrel != (TypePointerRel *)0) {
suboff += ptrel->getPointerOffset();
@ -817,34 +828,48 @@ void PrintC::opPtrsub(const PcodeOp *op)
// Special case where we do not print a field
pushTypePointerRel(op);
if (flex)
pushVnImplied(in0,op,m | print_load_value);
pushVn(in0,op,m | print_load_value);
else
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
return;
}
}
suboff = AddrSpace::addressToByte(suboff,ptype->getWordSize());
string fieldname;
Datatype *fieldtype;
int4 fieldoffset;
int4 fieldid;
int4 newoff;
const TypeField *fld = ((TypeStruct *)ct)->getField((int4)suboff,0,&newoff);
if (fld == (const TypeField *)0) {
if (ct->getSize() <= suboff) {
clear();
throw LowlevelError("PTRSUB out of bounds into struct");
}
// Try to match the Ghidra's default field name from DataTypeComponent.getDefaultFieldName
ostringstream s;
s << "field_0x" << hex << suboff;
fieldname = s.str();
fieldtype = (Datatype *)0;
fieldoffset = suboff;
}
else {
if (ct->getMetatype() == TYPE_UNION) {
if (suboff != 0)
throw LowlevelError("PTRSUB accesses union with non-zero offset");
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *resUnion = fd->getUnionField(ptype, op, -1);
if (resUnion == (const ResolvedUnion *)0 || resUnion->getFieldNum() < 0)
throw LowlevelError("PTRSUB for union that does not resolve to a field");
const TypeField *fld = ((TypeUnion *)ct)->getField(resUnion->getFieldNum());
fieldid = fld->ident;
fieldname = fld->name;
fieldtype = fld->type;
fieldoffset = fld->offset;
}
else { // TYPE_STRUCT
const TypeField *fld = ((TypeStruct*)ct)->resolveTruncation((int4)suboff,0,&newoff);
if (fld == (const TypeField*)0) {
if (ct->getSize() <= suboff) {
clear();
throw LowlevelError("PTRSUB out of bounds into struct");
}
// Try to match the Ghidra's default field name from DataTypeComponent.getDefaultFieldName
ostringstream s;
s << "field_0x" << hex << suboff;
fieldname = s.str();
fieldtype = (Datatype*)0;
fieldid = suboff;
}
else {
fieldname = fld->name;
fieldtype = fld->type;
fieldid = fld->ident;
}
}
arrayvalue = false;
// The '&' is dropped if the output type is an array
@ -859,16 +884,16 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&object_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
else { // EMIT &( )->name
pushOp(&addressof,op);
pushOp(&pointer_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
}
else { // Not printing an ampersand
@ -878,15 +903,15 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&object_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m | print_load_value);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
else { // EMIT ( )->name
pushOp(&pointer_member,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldoffset));
pushVn(in0,op,m);
pushAtom(Atom(fieldname,fieldtoken,EmitXml::no_color,ct,fieldid,op));
}
if (arrayvalue)
push_integer(0,4,false,(Varnode *)0,op);
@ -927,7 +952,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
// we can't use a cast in its description, so turn off
// casting when printing the partial symbol
// Datatype *exttype = ((mods & print_store_value)!=0) ? (Datatype *)0 : ct;
pushPartialSymbol(symbol,off,0,(Varnode *)0,op,(Datatype *)0);
pushPartialSymbol(symbol,off,0,(Varnode *)0,op,-1);
}
}
if (arrayvalue)
@ -947,13 +972,13 @@ void PrintC::opPtrsub(const PcodeOp *op)
// becomes struct->arrayfield[i]
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
}
else { // EMIT *( )
pushOp(&dereference,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
}
}
else {
@ -961,7 +986,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&subscript,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
push_integer(0,4,false,(Varnode *)0,op);
}
else { // EMIT (* )[0]
@ -969,7 +994,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
pushOp(&dereference,op);
if (ptrel != (TypePointerRel *)0)
pushTypePointerRel(op);
pushVnImplied(in0,op,m);
pushVn(in0,op,m);
push_integer(0,4,false,(Varnode *)0,op);
}
}
@ -988,7 +1013,7 @@ void PrintC::opPtrsub(const PcodeOp *op)
void PrintC::opSegmentOp(const PcodeOp *op)
{
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
}
void PrintC::opCpoolRefOp(const PcodeOp *op)
@ -1033,7 +1058,7 @@ void PrintC::opCpoolRefOp(const PcodeOp *op)
pushOp(&function_call,op);
pushAtom(Atom(rec->getToken(),functoken,EmitXml::funcname_color,op,outvn));
pushOp(&comma,(const PcodeOp *)0);
pushVnImplied(vn0,op,mods);
pushVn(vn0,op,mods);
pushAtom(Atom(dt->getName(),syntax,EmitXml::type_color,op,outvn));
break;
}
@ -1056,7 +1081,7 @@ void PrintC::opCpoolRefOp(const PcodeOp *op)
}
else {
pushOp(&pointer_member, op);
pushVnImplied(vn0, op, mods);
pushVn(vn0, op, mods);
pushAtom(Atom(rec->getToken(), syntax, color, op, outvn));
}
break;
@ -1081,7 +1106,7 @@ void PrintC::opNewOp(const PcodeOp *op)
nm = "<unused>";
}
else {
Datatype *dt = outvn->getType();
Datatype *dt = outvn->getTypeDefFacing();
while (dt->getMetatype() == TYPE_PTR) {
dt = ((TypePointer *)dt)->getPtrTo();
}
@ -1089,14 +1114,14 @@ void PrintC::opNewOp(const PcodeOp *op)
}
pushOp(&subscript,op);
pushAtom(Atom(nm,optoken,EmitXml::type_color,op));
pushVnImplied(vn1,op,mods);
pushVn(vn1,op,mods);
return;
}
}
// This printing is used only if the 'new' operator doesn't feed directly into a constructor
pushOp(&function_call,op);
pushAtom(Atom("new",optoken,EmitXml::keyword_color,op,outvn));
pushVnImplied(vn0,op,mods);
pushVn(vn0,op,mods);
}
void PrintC::opInsertOp(const PcodeOp *op)
@ -1133,7 +1158,7 @@ void PrintC::push_integer(uintb val,int4 sz,bool sign,
if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) {
Symbol *sym = vn->getHigh()->getSymbol();
if (sym != (Symbol *)0) {
if (sym->isNameLocked() && (sym->getCategory() == 1)) {
if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) {
if (pushEquate(val,sz,(EquateSymbol *)sym,vn,op))
return;
}
@ -1448,7 +1473,7 @@ void PrintC::pushCharConstant(uintb val,const Datatype *ct,const Varnode *vn,con
if ((vn != (const Varnode *)0)&&(!vn->isAnnotation())) {
Symbol *sym = vn->getHigh()->getSymbol();
if (sym != (Symbol *)0) {
if (sym->isNameLocked() && (sym->getCategory() == 1)) {
if (sym->isNameLocked() && (sym->getCategory() == Symbol::equate)) {
if (pushEquate(val,vn->getSize(),(EquateSymbol *)sym,vn,op))
return;
}
@ -1627,6 +1652,7 @@ void PrintC::pushConstant(uintb val,const Datatype *ct,
case TYPE_CODE:
case TYPE_ARRAY:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_PARTIALSTRUCT:
break;
}
@ -1723,7 +1749,7 @@ void PrintC::pushAnnotation(const Varnode *vn,const PcodeOp *op)
pushSymbol(entry->getSymbol(),vn,op);
else {
int4 symboloff = vn->getOffset() - entry->getFirst();
pushPartialSymbol(entry->getSymbol(),symboloff,size,vn,op,(Datatype *)0);
pushPartialSymbol(entry->getSymbol(),symboloff,size,vn,op,-1);
}
}
else {
@ -1743,7 +1769,7 @@ void PrintC::pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)
EmitXml::syntax_highlight tokenColor;
if (sym->getScope()->isGlobal())
tokenColor = EmitXml::global_color;
else if (sym->getCategory() == 0)
else if (sym->getCategory() == Symbol::function_parameter)
tokenColor = EmitXml::param_color;
else
tokenColor = EmitXml::var_color;
@ -1777,7 +1803,7 @@ void PrintC::pushUnnamedLocation(const Address &addr,
void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
const Varnode *vn,const PcodeOp *op,
Datatype *outtype)
int4 inslot)
{
// We need to print "bottom up" in order to get parentheses right
// I.e. we want to print globalstruct.arrayfield[0], rather than
@ -1788,12 +1814,19 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
Datatype *ct = sym->getType();
while(ct != (Datatype *)0) {
if (((sz==0)||(sz==ct->getSize()))&&(off==0))
break; // Found the full partial
if (off == 0) {
if (sz == 0 || (sz == ct->getSize() && (!ct->needsResolution() || ct->getMetatype()==TYPE_PTR)))
break;
}
bool succeeded = false;
if (ct->getMetatype()==TYPE_STRUCT) {
if (ct->needsResolution() && ct->getSize() == sz) {
Datatype *outtype = ct->findResolve(op, inslot);
if (outtype == ct)
break; // Turns out we don't resolve to the field
}
const TypeField *field;
field = ((TypeStruct *)ct)->getField(off,sz,&off);
field = ((TypeStruct *)ct)->resolveTruncation(off,sz,&off);
if (field != (const TypeField *)0) {
stack.emplace_back();
PartialSymbolEntry &entry( stack.back() );
@ -1822,13 +1855,32 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
succeeded = true;
}
}
else if ((outtype != (Datatype *)0)&&
castStrategy->isSubpieceCastEndian(outtype,ct,off,
sym->getFirstWholeMap()->getAddr().getSpace()->isBigEndian())) {
// Treat truncation as SUBPIECE style cast
finalcast = outtype;
ct = (Datatype *)0;
succeeded = true;
else if (ct->getMetatype() == TYPE_UNION) {
const TypeField *field;
field = ((TypeUnion *)ct)->findTruncation(off,op,inslot,off);
if (field != (const TypeField*)0) {
stack.emplace_back();
PartialSymbolEntry &entry(stack.back());
entry.token = &object_member;
entry.field = field;
entry.parent = ct;
entry.fieldname = entry.field->name;
entry.hilite = EmitXml::no_color;
ct = field->type;
succeeded = true;
}
else if (ct->getSize() == sz)
break; // Turns out we don't need to resolve the field
}
else if (inslot >= 0) {
Datatype *outtype = vn->getHigh()->getType();
if (castStrategy->isSubpieceCastEndian(outtype,ct,off,
sym->getFirstWholeMap()->getAddr().getSpace()->isBigEndian())) {
// Treat truncation as SUBPIECE style cast
finalcast = outtype;
ct = (Datatype*)0;
succeeded = true;
}
}
if (!succeeded) { // Subtype was not good
stack.emplace_back();
@ -1860,7 +1912,7 @@ void PrintC::pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
if (field == (const TypeField *)0)
pushAtom(Atom(stack[i].fieldname,syntax,stack[i].hilite,op));
else
pushAtom(Atom(stack[i].fieldname,fieldtoken,stack[i].hilite,stack[i].parent,field->offset));
pushAtom(Atom(stack[i].fieldname,fieldtoken,stack[i].hilite,stack[i].parent,field->ident,op));
}
}
@ -1882,6 +1934,39 @@ void PrintC::pushMismatchSymbol(const Symbol *sym,int4 off,int4 sz,
pushUnnamedLocation(vn->getAddr(),vn,op);
}
void PrintC::pushImpliedField(const Varnode *vn,const PcodeOp *op)
{
bool proceed = false;
Datatype *parent = vn->getHigh()->getType();
const TypeField *field;
if (parent->needsResolution() && parent->getMetatype() != TYPE_PTR) {
const Funcdata *fd = op->getParent()->getFuncdata();
int4 slot = op->getSlot(vn);
const ResolvedUnion *res = fd->getUnionField(parent, op, slot);
if (res != (const ResolvedUnion *)0 && res->getFieldNum() >= 0) {
if (parent->getMetatype() == TYPE_STRUCT && res->getFieldNum() == 0) {
field = &(*((TypeStruct *)parent)->beginField());
proceed = true;
}
else if (parent->getMetatype() == TYPE_UNION) {
field = ((TypeUnion *)parent)->getField(res->getFieldNum());
proceed = true;
}
}
}
const PcodeOp *defOp = vn->getDef();
if (!proceed) {
// Just push original op
defOp->getOpcode()->push(this,defOp,op);
return;
}
pushOp(&object_member,op);
defOp->getOpcode()->push(this,defOp,op);
pushAtom(Atom(field->name,fieldtoken,EmitXml::no_color,parent,field->ident,op));
}
/// Print all the components making up the data-type, using the \b struct keyword
/// \param ct is the structure data-type
void PrintC::emitStructDefinition(const TypeStruct *ct)
@ -2038,14 +2123,14 @@ void PrintC::emitLocalVarDecls(const Funcdata *fd)
{
bool notempty = false;
if (emitScopeVarDecls(fd->getScopeLocal(),-1))
if (emitScopeVarDecls(fd->getScopeLocal(),Symbol::no_category))
notempty = true;
ScopeMap::const_iterator iter,enditer;
iter = fd->getScopeLocal()->childrenBegin();
enditer = fd->getScopeLocal()->childrenEnd();
while(iter!=enditer) {
Scope *l1 = (*iter).second;
if (emitScopeVarDecls(l1,-1))
if (emitScopeVarDecls(l1,Symbol::no_category))
notempty = true;
++iter;
}
@ -2226,7 +2311,7 @@ bool PrintC::emitInplaceOp(const PcodeOp *op)
if (op->getOut()->getHigh() != vn->getHigh()) return false;
pushOp(tok,op);
pushVnExplicit(vn,op);
pushVnImplied(op->getIn(1),op,mods);
pushVn(op->getIn(1),op,mods);
recurse();
return true;
}
@ -2238,14 +2323,14 @@ void PrintC::emitExpression(const PcodeOp *op)
if (outvn != (Varnode *)0) {
if (option_inplace_ops && emitInplaceOp(op)) return;
pushOp(&assignment,op);
pushVnLHS(outvn,op);
pushSymbolDetail(outvn,op,false);
}
else if (op->doesSpecialPrinting()) {
// Printing of constructor syntax
const PcodeOp *newop = op->getIn(1)->getDef();
outvn = newop->getOut();
pushOp(&assignment,newop);
pushVnLHS(outvn,newop);
pushSymbolDetail(outvn,newop,false);
opConstructor(op,true);
recurse();
return;
@ -2377,7 +2462,7 @@ void PrintC::emitGlobalVarDeclsRecursive(Scope *symScope)
{
if (!symScope->isGlobal()) return;
emitScopeVarDecls(symScope,-1);
emitScopeVarDecls(symScope,Symbol::no_category);
ScopeMap::const_iterator iter,enditer;
iter = symScope->childrenBegin();
enditer = symScope->childrenEnd();

View file

@ -172,14 +172,14 @@ protected:
virtual bool pushEquate(uintb val,int4 sz,const EquateSymbol *sym,
const Varnode *vn,const PcodeOp *op);
virtual void pushAnnotation(const Varnode *vn,const PcodeOp *op);
virtual void pushSymbol(const Symbol *sym,const Varnode *vn,
const PcodeOp *op);
virtual void pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op);
virtual void pushUnnamedLocation(const Address &addr,
const Varnode *vn,const PcodeOp *op);
virtual void pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
const Varnode *vn,const PcodeOp *op,Datatype *outtype);
const Varnode *vn,const PcodeOp *op,int4 inslot);
virtual void pushMismatchSymbol(const Symbol *sym,int4 off,int4 sz,
const Varnode *vn,const PcodeOp *op);
virtual void pushImpliedField(const Varnode *vn,const PcodeOp *op);
virtual void push_integer(uintb val,int4 sz,bool sign,
const Varnode *vn,
const PcodeOp *op);

View file

@ -230,7 +230,7 @@ void PrintJava::opLoad(const PcodeOp *op)
bool printArrayRef = needZeroArray(op->getIn(1));
if (printArrayRef)
pushOp(&subscript,op);
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(1),op,m);
if (printArrayRef)
push_integer(0,4,false,(Varnode *)0,op);
}
@ -242,15 +242,15 @@ void PrintJava::opStore(const PcodeOp *op)
pushOp(&assignment,op); // This is an assignment
if (needZeroArray(op->getIn(1))) {
pushOp(&subscript,op);
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(1),op,m);
push_integer(0,4,false,(Varnode *)0,op);
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
}
else {
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVnImplied(op->getIn(2),op,mods);
pushVnImplied(op->getIn(1),op,m);
pushVn(op->getIn(2),op,mods);
pushVn(op->getIn(1),op,m);
}
}
@ -266,25 +266,25 @@ void PrintJava::opCallind(const PcodeOp *op)
int4 count = op->numInput() - 1;
count -= (skip < 0) ? 0 : 1;
if (count > 1) { // Multiple parameters
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
for(int4 i=0;i<count-1;++i)
pushOp(&comma,op);
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
for(int4 i=op->numInput()-1;i>=1;--i) {
if (i == skip) continue;
pushVnImplied(op->getIn(i),op,mods);
pushVn(op->getIn(i),op,mods);
}
}
else if (count == 1) { // One parameter
if (skip == 1)
pushVnImplied(op->getIn(2),op,mods);
pushVn(op->getIn(2),op,mods);
else
pushVnImplied(op->getIn(1),op,mods);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(1),op,mods);
pushVn(op->getIn(0),op,mods);
}
else { // A void function
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
pushAtom(Atom("",blanktoken,EmitXml::no_color));
}
}
@ -329,7 +329,7 @@ void PrintJava::opCpoolRefOp(const PcodeOp *op)
dt = ((TypePointer *)dt)->getPtrTo();
}
pushOp(&instanceof,op);
pushVnImplied(vn0,op,mods);
pushVn(vn0,op,mods);
pushAtom(Atom(dt->getName(),syntax,EmitXml::type_color,op,outvn));
break;
}
@ -352,7 +352,7 @@ void PrintJava::opCpoolRefOp(const PcodeOp *op)
}
else {
pushOp(&object_member,op);
pushVnImplied(vn0,op,mods);
pushVn(vn0,op,mods);
pushAtom(Atom(rec->getToken(),syntax,color,op,outvn));
}
}

View file

@ -189,7 +189,7 @@ void PrintLanguage::pushAtom(const Atom &atom)
/// \param vn is the given implied Varnode
/// \param op is PcodeOp taking the Varnode as input
/// \param m is the set of printing modifications to apply for this sub-expression
void PrintLanguage::pushVnImplied(const Varnode *vn,const PcodeOp *op,uint4 m)
void PrintLanguage::pushVn(const Varnode *vn,const PcodeOp *op,uint4 m)
{
// if (pending == nodepend.size())
@ -202,7 +202,7 @@ void PrintLanguage::pushVnImplied(const Varnode *vn,const PcodeOp *op,uint4 m)
// }
// But it is more efficient to just call them in reverse order
nodepend.push_back(NodePending(vn,op,m));
nodepend.emplace_back(vn,op,m);
}
/// This method pushes a given Varnode as a \b leaf of the current expression.
@ -217,35 +217,20 @@ void PrintLanguage::pushVnExplicit(const Varnode *vn,const PcodeOp *op)
pushAnnotation(vn,op);
return;
}
HighVariable *high = vn->getHigh();
if (vn->isConstant()) {
pushConstant(vn->getOffset(),high->getType(),vn,op);
pushConstant(vn->getOffset(),vn->getHighTypeReadFacing(op),vn,op);
return;
}
Symbol *sym = high->getSymbol();
if (sym == (Symbol *)0) {
pushUnnamedLocation(high->getNameRepresentative()->getAddr(),vn,op);
}
else {
int4 symboloff = high->getSymbolOffset();
if (symboloff == -1)
pushSymbol(sym,vn,op);
else {
if (symboloff + vn->getSize() <= sym->getType()->getSize())
pushPartialSymbol(sym,symboloff,vn->getSize(),vn,op,vn->getHigh()->getType());
else
pushMismatchSymbol(sym,symboloff,vn->getSize(),vn,op);
}
}
pushSymbolDetail(vn,op,true);
}
/// The given Varnode will ultimately be emitted as an explicit variable on
/// the left-hand side of an \e assignment statement. As with pushVnExplicit(),
/// this method decides how the Varnode will be emitted and pushes the resulting
/// Atom onto the RPN stack.
/// \param vn is the given LSH Varnode
/// \param op is the PcodeOp which produces the Varnode as an output
void PrintLanguage::pushVnLHS(const Varnode *vn,const PcodeOp *op)
/// We know that the given Varnode matches part of a single Symbol.
/// Push a set of tokens that represents the Varnode, which may require
/// extracting subfields or casting to get the correct value.
/// \param vn is the given Varnode
/// \param op is the PcodeOp involved in the expression with the Varnode
/// \param isRead is \b true if the PcodeOp reads the Varnode
void PrintLanguage::pushSymbolDetail(const Varnode *vn,const PcodeOp *op,bool isRead)
{
HighVariable *high = vn->getHigh();
@ -255,14 +240,19 @@ void PrintLanguage::pushVnLHS(const Varnode *vn,const PcodeOp *op)
}
else {
int4 symboloff = high->getSymbolOffset();
if (symboloff == -1)
pushSymbol(sym,vn,op);
else {
if (symboloff + vn->getSize() <= sym->getType()->getSize())
pushPartialSymbol(sym,symboloff,vn->getSize(),vn,op,(Datatype *)0);
else
pushMismatchSymbol(sym,symboloff,vn->getSize(),vn,op);
if (symboloff == -1) {
if (!sym->getType()->needsResolution()) {
pushSymbol(sym,vn,op);
return;
}
symboloff = 0;
}
if (symboloff + vn->getSize() <= sym->getType()->getSize()) {
int4 inslot = isRead ? op->getSlot(vn) : -1;
pushPartialSymbol(sym,symboloff,vn->getSize(),vn,op,inslot);
}
else
pushMismatchSymbol(sym,symboloff,vn->getSize(),vn,op);
}
}
@ -399,7 +389,7 @@ void PrintLanguage::emitAtom(const Atom &atom)
emit->tagType(atom.name.c_str(),atom.highlight,atom.ptr_second.ct);
break;
case fieldtoken:
emit->tagField(atom.name.c_str(),atom.highlight,atom.ptr_second.ct,atom.offset);
emit->tagField(atom.name.c_str(),atom.highlight,atom.ptr_second.ct,atom.offset,atom.op);
break;
case blanktoken:
break; // Print nothing
@ -519,17 +509,22 @@ void PrintLanguage::recurse(void)
{
uint4 modsave = mods;
int4 final = pending; // Already claimed
int4 lastPending = pending; // Already claimed
pending = nodepend.size(); // Lay claim to the rest
while(final < pending) {
while(lastPending < pending) {
const Varnode *vn = nodepend.back().vn;
const PcodeOp *op = nodepend.back().op;
mods = nodepend.back().vnmod;
nodepend.pop_back();
pending -= 1;
if (vn->isImplied()) {
const PcodeOp *defOp = vn->getDef();
defOp->getOpcode()->push(this,defOp,op);
if (vn->hasImpliedField()) {
pushImpliedField(vn, op);
}
else {
const PcodeOp *defOp = vn->getDef();
defOp->getOpcode()->push(this,defOp,op);
}
}
else
pushVnExplicit(vn,op);
@ -554,8 +549,8 @@ void PrintLanguage::opBinary(const OpToken *tok,const PcodeOp *op)
pushOp(tok,op); // Push on reverse polish notation
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVnImplied(op->getIn(1),op,mods);
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(1),op,mods);
pushVn(op->getIn(0),op,mods);
}
/// Push an operator onto the stack that has a normal unary format.
@ -568,7 +563,7 @@ void PrintLanguage::opUnary(const OpToken *tok,const PcodeOp *op)
pushOp(tok,op);
// implied vn's pushed on in reverse order for efficiency
// see PrintLanguage::pushVnImplied
pushVnImplied(op->getIn(0),op,mods);
pushVn(op->getIn(0),op,mods);
}
void PrintLanguage::resetDefaultsInternal(void)

View file

@ -24,6 +24,7 @@
#include "prettyprint.hh"
class PrintLanguage;
class ResolvedUnion;
/// \brief Base class for high-level language capabilities
///
@ -220,8 +221,8 @@ public:
: name(nm) { type = t; highlight = hl; ptr_second.ct = c; }
/// \brief Construct a token for a field name
Atom(const string &nm,tagtype t,EmitXml::syntax_highlight hl,const Datatype *c,int4 off)
: name(nm) { type = t; highlight = hl; ptr_second.ct = c; offset = off; }
Atom(const string &nm,tagtype t,EmitXml::syntax_highlight hl,const Datatype *c,int4 off,const PcodeOp *o)
: name(nm) { type = t; highlight = hl; ptr_second.ct = c; offset = off; op = o; }
/// \brief Construct a token with an associated PcodeOp
Atom(const string &nm,tagtype t,EmitXml::syntax_highlight hl,const PcodeOp *o)
@ -268,9 +269,9 @@ protected:
void unsetMod(uint4 m) { mods &= ~m; } ///< Deactivate the given printing modification
void pushOp(const OpToken *tok,const PcodeOp *op); ///< Push an operator token onto the RPN stack
void pushAtom(const Atom &atom); ///< Push a variable token onto the RPN stack
void pushVnImplied(const Varnode *vn,const PcodeOp *op,uint4 m); ///< Push an implied variable onto the RPN stack
void pushVn(const Varnode *vn,const PcodeOp *op,uint4 m); ///< Push an expression rooted at a Varnode onto the RPN stack
void pushVnExplicit(const Varnode *vn,const PcodeOp *op); ///< Push an explicit variable onto the RPN stack
void pushVnLHS(const Varnode *vn,const PcodeOp *op); ///< Push a variable as the left-hand side of an expression
void pushSymbolDetail(const Varnode *vn,const PcodeOp *op,bool isRead); ///< Push symbol name with adornments matching given Varnode
bool parentheses(const OpToken *op2); ///< Determine if the given token should be emitted in its own parenthetic expression
void emitOp(const ReversePolish &entry); ///< Send an operator token from the RPN to the emitter
@ -328,8 +329,7 @@ protected:
/// \param sym is the given Symbol
/// \param vn is the Varnode holding the Symbol value
/// \param op is a PcodeOp associated with the Varnode
virtual void pushSymbol(const Symbol *sym,const Varnode *vn,
const PcodeOp *op)=0;
virtual void pushSymbol(const Symbol *sym,const Varnode *vn,const PcodeOp *op)=0;
/// \brief Push an address as a substitute for a Symbol onto the RPN stack
///
@ -338,8 +338,7 @@ protected:
/// \param addr is the storage address
/// \param vn is the Varnode representing the variable (if present)
/// \param op is a PcodeOp associated with the variable
virtual void pushUnnamedLocation(const Address &addr,
const Varnode *vn,const PcodeOp *op)=0;
virtual void pushUnnamedLocation(const Address &addr,const Varnode *vn,const PcodeOp *op)=0;
/// \brief Push a variable that represents only part of a symbol onto the RPN stack
///
@ -349,9 +348,9 @@ protected:
/// \param sz is the number of bytes in the partial variable
/// \param vn is the Varnode holding the partial value
/// \param op is a PcodeOp associate with the Varnode
/// \param outtype is the data-type expected by expression using the partial variable
/// \param inslot is the input slot of \b vn with \b op, or -1 if \b op writes \b vn
virtual void pushPartialSymbol(const Symbol *sym,int4 off,int4 sz,
const Varnode *vn,const PcodeOp *op,Datatype *outtype)=0;
const Varnode *vn,const PcodeOp *op,int4 inslot)=0;
/// \brief Push an identifier for a variable that mismatches with its Symbol
///
@ -365,6 +364,15 @@ protected:
virtual void pushMismatchSymbol(const Symbol *sym,int4 off,int4 sz,
const Varnode *vn,const PcodeOp *op)=0;
/// \brief Push the implied field of a given Varnode as an object member extraction operation
///
/// If a Varnode is \e implied and has a \e union data-type, the particular read of the varnode
/// may correspond to a particular field that needs to get printed as a token, even though the
/// Varnode itself is printed directly. This method pushes the field name token.
/// \param vn is the given Varnode
/// \param op is the particular PcodeOp reading the Varnode
virtual void pushImpliedField(const Varnode *vn,const PcodeOp *op)=0;
virtual void emitLineComment(int4 indent,const Comment *comm); ///< Emit a comment line
/// \brief Emit a variable declaration

View file

@ -114,7 +114,7 @@ int4 RuleCollectTerms::applyOp(PcodeOp *op,Funcdata &data)
termorder.sortTerms(); // Sort them based on termorder
Varnode *vn1,*vn2;
uintb coef1,coef2;
const vector<PcodeOpEdge *> &order( termorder.getSort() );
const vector<AdditiveEdge *> &order( termorder.getSort() );
int4 i=0;
if (!order[0]->getVarnode()->isConstant()) {
@ -5661,8 +5661,9 @@ AddTreeState::AddTreeState(Funcdata &d,PcodeOp *op,int4 slot)
: data(d)
{
baseOp = op;
baseSlot = slot;
ptr = op->getIn(slot);
ct = (const TypePointer *)ptr->getType();
ct = (const TypePointer *)ptr->getTypeReadFacing(op);
ptrsize = ptr->getSize();
ptrmask = calc_mask(ptrsize);
baseType = ct->getPtrTo();
@ -6038,16 +6039,14 @@ Varnode *AddTreeState::buildMultiples(void)
Varnode *AddTreeState::buildExtra(void)
{
correct = (correct+offset) & ptrmask; // Total correction that needs to be made
bool offset_corrected= (correct==0);
correct = correct+offset; // Total correction that needs to be made
Varnode *resNode = (Varnode *)0;
for(int4 i=0;i<nonmult.size();++i) {
Varnode *vn = nonmult[i];
if ((!offset_corrected)&&(vn->isConstant()))
if (vn->getOffset() == correct) {
offset_corrected = true;
continue;
}
if (vn->isConstant()) {
correct -= vn->getOffset();
continue;
}
if (resNode == (Varnode *)0)
resNode = vn;
else {
@ -6055,7 +6054,8 @@ Varnode *AddTreeState::buildExtra(void)
resNode = op->getOut();
}
}
if (!offset_corrected) {
correct &= ptrmask;
if (correct != 0) {
Varnode *vn = data.newConstant(ptrsize,uintb_negate(correct-1,ptrsize));
if (resNode == (Varnode *)0)
resNode = vn;
@ -6077,7 +6077,7 @@ bool AddTreeState::buildDegenerate(void)
// If the size is really less than scale, there is
// probably some sort of padding going on
return false; // Don't transform at all
if (baseOp->getOut()->getType()->getMetatype() != TYPE_PTR) // Make sure pointer propagates thru INT_ADD
if (baseOp->getOut()->getTypeDefFacing()->getMetatype() != TYPE_PTR) // Make sure pointer propagates thru INT_ADD
return false;
vector<Varnode *> newparams;
int4 slot = baseOp->getSlot(ptr);
@ -6152,6 +6152,7 @@ void AddTreeState::buildTree(void)
// Create PTRADD portion of operation
if (multNode != (Varnode *)0) {
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
data.inheritReadResolution(newop, 0, baseOp, baseSlot);
multNode = newop->getOut();
}
else
@ -6160,6 +6161,7 @@ void AddTreeState::buildTree(void)
// Create PTRSUB portion of operation
if (isSubtype) {
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
data.inheritReadResolution(newop, 0, baseOp, baseSlot);
if (size != 0)
newop->setStopPropagation();
multNode = newop->getOut();
@ -6192,9 +6194,9 @@ bool RulePtrArith::verifyPreferredPointer(PcodeOp *op,int4 slot)
PcodeOp *preOp = vn->getDef();
if (preOp->code() != CPUI_INT_ADD) return true;
int preslot = 0;
if (preOp->getIn(preslot)->getType()->getMetatype() != TYPE_PTR) {
if (preOp->getIn(preslot)->getTypeReadFacing(preOp)->getMetatype() != TYPE_PTR) {
preslot = 1;
if (preOp->getIn(preslot)->getType()->getMetatype() != TYPE_PTR)
if (preOp->getIn(preslot)->getTypeReadFacing(preOp)->getMetatype() != TYPE_PTR)
return true;
}
return (1 != evaluatePointerExpression(preOp, preslot)); // Does earlier varnode look like the base pointer
@ -6220,7 +6222,7 @@ int4 RulePtrArith::evaluatePointerExpression(PcodeOp *op,int4 slot)
Varnode *ptrBase = op->getIn(slot);
if (ptrBase->isFree() && !ptrBase->isConstant())
return 0;
if (op->getIn(1 - slot)->getType()->getMetatype() == TYPE_PTR)
if (op->getIn(1 - slot)->getTypeReadFacing(op)->getMetatype() == TYPE_PTR)
res = 2;
Varnode *outVn = op->getOut();
list<PcodeOp *>::const_iterator iter;
@ -6232,7 +6234,7 @@ int4 RulePtrArith::evaluatePointerExpression(PcodeOp *op,int4 slot)
Varnode *otherVn = decOp->getIn(1 - decOp->getSlot(outVn));
if (otherVn->isFree() && !otherVn->isConstant())
return 0; // No action if the data-flow isn't fully linked
if (otherVn->getType()->getMetatype() == TYPE_PTR)
if (otherVn->getTypeReadFacing(decOp)->getMetatype() == TYPE_PTR)
res = 2; // Do not push in the presence of other pointers
}
else if ((opc == CPUI_LOAD || opc == CPUI_STORE) && decOp->getIn(1) == outVn) { // If use is as pointer for LOAD or STORE
@ -6289,7 +6291,7 @@ int4 RulePtrArith::applyOp(PcodeOp *op,Funcdata &data)
if (!data.isTypeRecoveryOn()) return 0;
for(slot=0;slot<op->numInput();++slot) { // Search for pointer type
ct = op->getIn(slot)->getType();
ct = op->getIn(slot)->getTypeReadFacing(op);
if (ct->getMetatype() == TYPE_PTR) break;
}
if (slot == op->numInput()) return 0;
@ -6334,7 +6336,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
else
return 0;
Datatype *ct = op->getIn(1)->getType();
Datatype *ct = op->getIn(1)->getTypeReadFacing(op);
if (ct->getMetatype() != TYPE_PTR) return 0;
Datatype *baseType = ((TypePointer *)ct)->getPtrTo();
uintb offset = 0;
@ -6373,6 +6375,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
return 0;
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,op->getIn(1),data.newConstant(op->getIn(1)->getSize(),0));
data.inheritReadResolution(newop, 0, op, 1);
newop->setStopPropagation();
data.opSetInput(op,newop->getOut(),1);
return 1;
@ -6474,7 +6477,7 @@ int4 RulePushPtr::applyOp(PcodeOp *op,Funcdata &data)
if (!data.isTypeRecoveryOn()) return 0;
for(slot=0;slot<op->numInput();++slot) { // Search for pointer type
vni = op->getIn(slot);
if (vni->getType()->getMetatype() == TYPE_PTR) break;
if (vni->getTypeReadFacing(op)->getMetatype() == TYPE_PTR) break;
}
if (slot == op->numInput()) return 0;
@ -6538,7 +6541,7 @@ int4 RulePtraddUndo::applyOp(PcodeOp *op,Funcdata &data)
if (!data.isTypeRecoveryOn()) return 0;
int4 size = (int4)op->getIn(2)->getOffset(); // Size the PTRADD thinks we are pointing
basevn = op->getIn(0);
tp = (TypePointer *)basevn->getType();
tp = (TypePointer *)basevn->getTypeReadFacing(op);
if (tp->getMetatype() == TYPE_PTR) // Make sure we are still a pointer
if (tp->getPtrTo()->getSize()==AddrSpace::addressToByteInt(size,tp->getWordSize())) { // of the correct size
Varnode *indVn = op->getIn(1);
@ -6568,7 +6571,7 @@ int4 RulePtrsubUndo::applyOp(PcodeOp *op,Funcdata &data)
if (!data.isTypeRecoveryOn()) return 0;
Varnode *basevn = op->getIn(0);
if (basevn->getType()->isPtrsubMatching(op->getIn(1)->getOffset()))
if (basevn->getTypeReadFacing(op)->isPtrsubMatching(op->getIn(1)->getOffset()))
return 0;
data.opSetOpcode(op,CPUI_INT_ADD);
@ -6613,7 +6616,7 @@ int4 RuleAddUnsigned::applyOp(PcodeOp *op,Funcdata &data)
Varnode *constvn = op->getIn(1);
if (!constvn->isConstant()) return 0;
Datatype *dt = constvn->getType();
Datatype *dt = constvn->getTypeReadFacing(op);
if (dt->getMetatype() != TYPE_UINT) return 0;
if (dt->isCharPrint()) return 0; // Only change integer forms
if (dt->isEnumType()) return 0;
@ -6661,6 +6664,8 @@ int4 Rule2Comp2Sub::applyOp(PcodeOp *op,Funcdata &data)
/// \class RuleSubRight
/// \brief Cleanup: Convert truncation to cast: `sub(V,c) => sub(V>>c*8,0)`
///
/// Before attempting the transform, check if the SUBPIECE is really extracting a field
/// from a structure. If so, mark the op as requiring special printing and return.
/// If the lone descendant of the SUBPIECE is a INT_RIGHT or INT_SRIGHT,
/// we lump that into the shift as well.
void RuleSubRight::getOpList(vector<uint4> &oplist) const
@ -6672,6 +6677,16 @@ void RuleSubRight::getOpList(vector<uint4> &oplist) const
int4 RuleSubRight::applyOp(PcodeOp *op,Funcdata &data)
{
Datatype *parent;
int4 offset;
if (op->doesSpecialPrinting())
return 0;
if (TypeOpSubpiece::testExtraction(false, op, parent, offset) != (const TypeField *)0) {
data.opMarkSpecialPrint(op); // Print this as a field extraction
return 0;
}
int4 c = op->getIn(1)->getOffset();
if (c==0) return 0; // SUBPIECE is not least sig
Varnode *a = op->getIn(0);
@ -6764,13 +6779,14 @@ int4 RulePtrsubCharConstant::applyOp(PcodeOp *op,Funcdata &data)
{
Varnode *sb = op->getIn(0);
if (sb->getType()->getMetatype() != TYPE_PTR) return 0;
TypeSpacebase *sbtype = (TypeSpacebase *)((TypePointer *)sb->getType())->getPtrTo();
Datatype *sbType = sb->getTypeReadFacing(op);
if (sbType->getMetatype() != TYPE_PTR) return 0;
TypeSpacebase *sbtype = (TypeSpacebase *)((TypePointer *)sbType)->getPtrTo();
if (sbtype->getMetatype() != TYPE_SPACEBASE) return 0;
Varnode *vn1 = op->getIn(1);
if (!vn1->isConstant()) return 0;
Varnode *outvn = op->getOut();
TypePointer *outtype = (TypePointer *)outvn->getType();
TypePointer *outtype = (TypePointer *)outvn->getTypeDefFacing();
if (outtype->getMetatype() != TYPE_PTR) return 0;
Datatype *basetype = outtype->getPtrTo();
if (!basetype->isCharPrint()) return 0;

View file

@ -48,6 +48,7 @@ class AddTreeState {
const TypePointerRel *pRelType; ///< A copy of \b ct, if it is a relative pointer
int4 ptrsize; ///< Size of the pointer
int4 size; ///< Size of data-type being pointed to (in address units) or 0 for open ended pointer
int4 baseSlot; ///< Slot of the ADD tree base that is holding the pointer
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

View file

@ -178,8 +178,8 @@ public:
virtual void printRaw(ostream &s,uintb offset) const;
virtual void saveXml(ostream &s) const;
virtual void restoreXml(const Element *el);
static const string NAME; // Reserved name for the address space
static const int4 INDEX; // Reserved index for constant space
static const string NAME; ///< Reserved name for the address space
static const int4 INDEX; ///< Reserved index for constant space
};
/// \brief Special AddrSpace for special/user-defined address spaces
@ -189,8 +189,8 @@ public:
OtherSpace(AddrSpaceManager *m, const Translate *t); ///< For use with restoreXml
virtual void printRaw(ostream &s, uintb offset) const;
virtual void saveXml(ostream &s) const;
static const string NAME; // Reserved name for the address space
static const int4 INDEX; // Reserved index for the other space
static const string NAME; ///< Reserved name for the address space
static const int4 INDEX; ///< Reserved index for the other space
};
/// \brief The pool of temporary storage registers

View file

@ -18,8 +18,8 @@
/// The base propagation ordering associated with each meta-type.
/// The array elements correspond to the ordering of #type_metatype.
sub_metatype Datatype::base2sub[13] = {
SUB_STRUCT, SUB_PARTIALSTRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL,
sub_metatype Datatype::base2sub[14] = {
SUB_UNION, SUB_STRUCT, SUB_PARTIALSTRUCT, SUB_ARRAY, SUB_PTRREL, SUB_PTR, SUB_FLOAT, SUB_CODE, SUB_BOOL,
SUB_UINT_PLAIN, SUB_INT_PLAIN, SUB_UNKNOWN, SUB_SPACEBASE, SUB_VOID
};
@ -190,6 +190,9 @@ void metatype2string(type_metatype metatype,string &res)
case TYPE_STRUCT:
res = "struct";
break;
case TYPE_UNION:
res = "union";
break;
case TYPE_SPACEBASE:
res = "spacebase";
break;
@ -246,6 +249,8 @@ type_metatype string2metatype(const string &metastring)
return TYPE_UNKNOWN;
else if (metastring=="uint")
return TYPE_UINT;
else if (metastring=="union")
return TYPE_UNION;
break;
case 'i':
if (metastring == "int")
@ -370,6 +375,41 @@ Datatype *Datatype::getStripped(void) const
return (Datatype *)0;
}
/// For certain data-types, particularly \e union, variables of that data-type are transformed into a subtype
/// depending on the particular use. Each read or write of the variable may use a different subtype.
/// This method returns the particular subtype required based on a specific PcodeOp. A slot index >=0
/// indicates which operand \e reads the variable, or if the index is -1, the variable is \e written.
/// \param op is the specific PcodeOp
/// \param slot indicates the input operand, or the output
/// \return the resolved sub-type
Datatype *Datatype::resolveInFlow(PcodeOp *op,int4 slot)
{
return this;
}
/// This is the constant version of resolveInFlow. If a resulting subtype has already been calculated,
/// for the particular read (\b slot >= 0) or write (\b slot == -1), then return it.
/// Otherwise return the original data-type.
/// \param op is the PcodeOp using the Varnode assigned with \b this data-type
/// \param slot is the slot reading or writing the Varnode
/// \return the resolved subtype or the original data-type
Datatype* Datatype::findResolve(const PcodeOp *op,int4 slot)
{
return this;
}
/// If \b this data-type has an alternate data-type form that matches the given data-type,
/// return an index indicating this form, otherwise return -1.
/// \param ct is the given data-type
/// \return the index of the matching form or -1
int4 Datatype::findCompatibleResolve(Datatype *ct) const
{
return -1;
}
/// Restore the basic properties (name,size,id) of a data-type from an XML element
/// Properties are read from the attributes of the element
/// \param el is the XML element
@ -449,6 +489,53 @@ uint8 Datatype::hashSize(uint8 id,int4 size)
return id;
}
/// Contruct from the given \<field> element.
/// \param el is the element
/// \param typegrp is the TypeFactory for parsing data-type info
TypeField::TypeField(const Element *el,TypeFactory &typegrp)
{
ident = -1;
offset = -1;
for(int4 i=0;i<el->getNumAttributes();++i) {
const string &attribName(el->getAttributeName(i));
if (attribName == "name")
name = el->getAttributeValue(i);
else if (attribName == "offset") {
istringstream j(el->getAttributeValue(i));
j.unsetf(ios::dec | ios::hex | ios::oct);
j >> offset;
}
else if (attribName == "id") {
istringstream j(el->getAttributeValue(i));
j.unsetf(ios::dec | ios::hex | ios::oct);
j >> ident;
}
}
type = typegrp.restoreXmlType( *el->getChildren().begin() );
if (name.size()==0)
throw LowlevelError("name attribute must not be empty in <field> tag");
if (offset < 0)
throw LowlevelError("offset attribute invalid for <field> tag");
if (ident < 0)
ident = offset; // By default the id is the offset
}
/// Write out a formal description of \b this as an XML \<field> tag.
/// \param s is the stream to write to
void TypeField::saveXml(ostream &s) const
{
s << "<field";
a_v(s,"name",name);
a_v_i(s,"offset",offset);
if (ident != offset)
a_v_i(s,"id",ident);
s << '>';
type->saveXmlRef(s);
s << "</field>\n";
}
/// Parse a \<type> tag for attributes of the character data-type
/// \param el is the root XML element
/// \param typegrp is the factory owning \b this data-type
@ -591,20 +678,26 @@ void TypePointer::restoreXml(const Element *el,TypeFactory &typegrp)
}
ptrto = typegrp.restoreXmlType( *el->getChildren().begin() );
calcSubmeta();
if (name.size() == 0) // Inherit only coretype only if no name
flags = ptrto->getInheritable();
if (name.size() == 0) // Inherit only if no name
flags |= ptrto->getInheritable();
}
/// Pointers to structures may require a specific \b submeta
void TypePointer::calcSubmeta(void)
{
if (ptrto->getMetatype() == TYPE_STRUCT) {
type_metatype ptrtoMeta = ptrto->getMetatype();
if (ptrtoMeta == TYPE_STRUCT) {
if (ptrto->numDepend() > 1 || ptrto->isIncomplete())
submeta = SUB_PTR_STRUCT;
else
submeta = SUB_PTR;
}
else if (ptrtoMeta == TYPE_UNION) {
submeta = SUB_PTR_STRUCT;
}
if (ptrto->needsResolution() && ptrtoMeta != TYPE_PTR)
flags |= needs_resolution; // Inherit needs_resolution, but only if not a pointer
}
/// \brief Find a sub-type pointer given an offset into \b this
@ -665,17 +758,49 @@ bool TypePointer::isPtrsubMatching(uintb off) const
if (newoff != 0)
return false;
}
else {
else if (ptrto->getMetatype() == TYPE_ARRAY || ptrto->getMetatype() == TYPE_STRUCT) {
int4 sz = off;
int4 typesize = ptrto->getSize();
if ((ptrto->getMetatype() != TYPE_ARRAY)&&(ptrto->getMetatype() != TYPE_STRUCT))
return false; // Not a pointer to a structured type
else if ((typesize <= AddrSpace::addressToByteInt(sz,wordsize))&&(typesize!=0))
if ((typesize <= AddrSpace::addressToByteInt(sz,wordsize))&&(typesize!=0))
return false;
}
else if (ptrto->getMetatype() == TYPE_UNION) {
// A PTRSUB reaching here cannot be used for a union field resolution
// These are created by ActionSetCasts::resolveUnion
return false; // So we always return false
}
else
return false; // Not a pointer to a structured data-type
return true;
}
Datatype *TypePointer::resolveInFlow(PcodeOp *op,int4 slot)
{
if (ptrto->getMetatype() == TYPE_UNION) {
Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this,op,slot);
if (res != (ResolvedUnion*)0)
return res->getDatatype();
ScoreUnionFields scoreFields(*fd->getArch()->types,this,op,slot);
fd->setUnionField(this,op,slot,scoreFields.getResult());
return scoreFields.getResult().getDatatype();
}
return this;
}
Datatype* TypePointer::findResolve(const PcodeOp *op,int4 slot)
{
if (ptrto->getMetatype() == TYPE_UNION) {
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this,op,slot);
if (res != (ResolvedUnion*)0)
return res->getDatatype();
}
return this;
}
void TypeArray::printRaw(ostream &s) const
{
@ -747,6 +872,34 @@ void TypeArray::saveXml(ostream &s) const
s << "</type>";
}
Datatype *TypeArray::resolveInFlow(PcodeOp *op,int4 slot)
{
// This is currently only called if the array size is 1
// in which case this should always resolve to the element data-type
return arrayof;
}
Datatype* TypeArray::findResolve(const PcodeOp *op,int4 slot)
{
// This is currently only called if the array size is 1
// in which case this should always resolve to the element data-type
return arrayof;
}
int4 TypeArray::findCompatibleResolve(Datatype *ct) const
{
if (ct->needsResolution() && !arrayof->needsResolution()) {
if (ct->findCompatibleResolve(arrayof) >= 0)
return 0;
}
if (arrayof == ct)
return 0;
return -1;
}
/// Parse a \<type> tag with a child describing the array element data-type.
/// \param el is the root XML element
/// \param typegrp is the factory owning \b this data-type
@ -761,6 +914,8 @@ void TypeArray::restoreXml(const Element *el,TypeFactory &typegrp)
arrayof = typegrp.restoreXmlType(*el->getChildren().begin());
if ((arraysize<=0)||(arraysize*arrayof->getSize()!=size))
throw LowlevelError("Bad size for array of type "+arrayof->getName());
if (arraysize == 1)
flags |= needs_resolution; // Array of size 1 needs special treatment
}
TypeEnum::TypeEnum(const TypeEnum &op) : TypeBase(op)
@ -978,6 +1133,10 @@ void TypeStruct::setFields(const vector<TypeField> &fd)
if (end > size)
size = end;
}
if (field.size() == 1) { // A single field
if (field[0].type->getSize() == size) // that fills the whole structure
flags |= needs_resolution; // needs special attention
}
}
/// Find the proper subfield given an offset. Return the index of that field
@ -1034,7 +1193,7 @@ int4 TypeStruct::getLowerBoundField(int4 off) const
/// \param sz is the size of the byte range
/// \param newoff points to the renormalized offset to pass back
/// \return the containing field or NULL if the range is not contained
const TypeField *TypeStruct::getField(int4 off,int4 sz,int4 *newoff) const
const TypeField *TypeStruct::resolveTruncation(int4 off,int4 sz,int4 *newoff) const
{
int4 i;
@ -1196,12 +1355,7 @@ void TypeStruct::saveXml(ostream &s) const
s << ">\n";
vector<TypeField>::const_iterator iter;
for(iter=field.begin();iter!=field.end();++iter) {
s << "<field";
a_v(s,"name",(*iter).name);
a_v_i(s,"offset",(*iter).offset);
s << '>';
(*iter).type->saveXmlRef(s);
s << "</field>\n";
(*iter).saveXml(s);
}
s << "</type>";
}
@ -1216,27 +1370,365 @@ void TypeStruct::restoreFields(const Element *el,TypeFactory &typegrp)
List::const_iterator iter;
int4 maxoffset = 0;
for(iter=list.begin();iter!=list.end();++iter) {
field.push_back( TypeField() );
field.back().name = (*iter)->getAttributeValue("name");
istringstream j((*iter)->getAttributeValue("offset"));
j.unsetf(ios::dec | ios::hex | ios::oct);
j >> field.back().offset;
field.back().type = typegrp.restoreXmlType( *(*iter)->getChildren().begin() );
field.emplace_back(*iter,typegrp);
int4 trialmax = field.back().offset + field.back().type->getSize();
if (trialmax > maxoffset)
maxoffset = trialmax;
if (field.back().name.size()==0) {
if (maxoffset > size) {
ostringstream s;
s << "unlabelled" << dec << field.back().offset;
field.back().name = s.str();
s << "Field " << field.back().name << " does not fit in structure " + name;
throw LowlevelError(s.str());
}
}
if (maxoffset > size)
throw LowlevelError("Size too small for fields of structure "+name);
if (size == 0) // We can restore an incomplete structure, indicated by 0 size
flags |= type_incomplete;
else
markComplete(); // Otherwise the structure is complete
if (field.size() == 1) { // A single field
if (field[0].type->getSize() == size) // that fills the whole structure
flags |= needs_resolution; // needs special resolution
}
}
/// We know if this method is called that \b this structure has a single field that fills the entire
/// structure. The indicated Varnode can either be referred either by naming the struture or naming
/// the field. This method returns an indication of the best fit: either 0 for the field or
/// -1 for the structure.
/// \param op is the given PcodeOp using the Varnode
/// \param slot is -1 if the Varnode is an output or >=0 indicating the input slot
/// \return either 0 to indicate the field or -1 to indicate the structure
int4 TypeStruct::scoreFill(PcodeOp *op,int4 slot) const
{
if (op->code() == CPUI_COPY || op->code() == CPUI_INDIRECT) {
Varnode *vn;
if (slot == 0)
vn = op->getOut();
else
vn = op->getIn(0);
if (vn->isTypeLock() && vn->getType() == this)
return -1; // COPY of the structure directly, use whole structure
}
else if ((op->code() == CPUI_LOAD && slot == -1)||(op->code() == CPUI_STORE && slot == 2)) {
Varnode *vn = op->getIn(1);
if (vn->isTypeLock()) {
Datatype *ct = vn->getTypeReadFacing(op);
if (ct->getMetatype() == TYPE_PTR && ((TypePointer *)ct)->getPtrTo() == this)
return -1; // LOAD or STORE of the structure directly, use whole structure
}
}
else if (op->isCall()) {
Funcdata *fd = op->getParent()->getFuncdata();
FuncCallSpecs *fc = fd->getCallSpecs(op);
if (fc != (FuncCallSpecs *)0) {
ProtoParameter *param = (ProtoParameter *)0;
if (slot >= 1 && fc->isInputLocked())
param = fc->getParam(slot-1);
else if (slot < 0 && fc->isOutputLocked())
param = fc->getOutput();
if (param != (ProtoParameter *)0 && param->getType() == this)
return -1; // Function signature refers to structure directly, use whole structure
}
}
return 0; // In all other cases refer to the field
}
Datatype *TypeStruct::resolveInFlow(PcodeOp *op,int4 slot)
{
Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0)
return res->getDatatype();
int4 fieldNum = scoreFill(op,slot);
ResolvedUnion compFill(this,fieldNum,*fd->getArch()->types);
fd->setUnionField(this, op, slot, compFill);
return compFill.getDatatype();
}
Datatype *TypeStruct::findResolve(const PcodeOp *op,int4 slot)
{
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0)
return res->getDatatype();
return field[0].type; // If not calculated before, assume referring to field
}
int4 TypeStruct::findCompatibleResolve(Datatype *ct) const
{
Datatype *fieldType = field[0].type;
if (ct->needsResolution() && !fieldType->needsResolution()) {
if (ct->findCompatibleResolve(fieldType) >= 0)
return 0;
}
if (fieldType == ct)
return 0;
return -1;
}
/// Assign an offset to fields in order so that each field starts at an aligned offset within the structure
/// \param list is the list of fields
/// \param align is the given alignment
void TypeStruct::assignFieldOffsets(vector<TypeField> &list,int4 align)
{
int4 offset = 0;
vector<TypeField>::iterator iter;
for(iter=list.begin();iter!=list.end();++iter) {
if ((*iter).offset != -1) continue;
int4 cursize = (*iter).type->getSize();
int4 curalign = 0;
if (align > 1) {
curalign = align;
while((curalign>>1) >= cursize)
curalign >>= 1;
curalign -= 1;
}
if ((offset & curalign)!=0)
offset = (offset-(offset & curalign) + (curalign+1));
(*iter).offset = offset;
(*iter).ident = offset;
offset += cursize;
}
}
/// Copy a list of fields into this union, establishing its size.
/// Should only be called once when constructing the type. TypeField \b offset is assumed to be 0.
/// \param fd is the list of fields to copy in
void TypeUnion::setFields(const vector<TypeField> &fd)
{
vector<TypeField>::const_iterator iter;
// Need to calculate size
size = 0;
for(iter=fd.begin();iter!=fd.end();++iter) {
field.push_back(*iter);
int4 end = field.back().type->getSize();
if (end > size)
size = end;
}
}
/// Children of the XML element describe each field.
/// \param el is the root union element
/// \param typegrp is the factory owning the new union
void TypeUnion::restoreFields(const Element *el,TypeFactory &typegrp)
{
const List &list(el->getChildren());
List::const_iterator iter;
for(iter=list.begin();iter!=list.end();++iter) {
field.emplace_back(*iter,typegrp);
if (field.back().offset + field.back().type->getSize() > size) {
ostringstream s;
s << "Field " << field.back().name << " does not fit in union " << name;
throw LowlevelError(s.str());
}
}
if (size == 0) // We can restore an incomplete structure, indicated by 0 size
flags |= type_incomplete;
else
markComplete(); // Otherwise the union is complete
}
TypeUnion::TypeUnion(const TypeUnion &op)
: Datatype(op)
{
setFields(op.field);
size = op.size; // setFields might have changed the size
}
int4 TypeUnion::compare(const Datatype &op,int4 level) const
{
int4 res = Datatype::compare(op,level);
if (res != 0) return res;
const TypeUnion *tu = (const TypeUnion *)&op;
vector<TypeField>::const_iterator iter1,iter2;
if (field.size() != tu->field.size()) return (tu->field.size()-field.size());
iter1 = field.begin();
iter2 = tu->field.begin();
// Test only the name and first level metatype first
while(iter1 != field.end()) {
if ((*iter1).name != (*iter2).name)
return ((*iter1).name < (*iter2).name) ? -1:1;
if ((*iter1).type->getMetatype() != (*iter2).type->getMetatype())
return ((*iter1).type->getMetatype() < (*iter2).type->getMetatype()) ? -1 : 1;
++iter1;
++iter2;
}
level -= 1;
if (level < 0) {
if (id == op.getId()) return 0;
return (id < op.getId()) ? -1 : 1;
}
// If we are still equal, now go down deep into each field type
iter1 = field.begin();
iter2 = tu->field.begin();
while(iter1 != field.end()) {
if ((*iter1).type != (*iter2).type) { // Short circuit recursive loops
int4 c = (*iter1).type->compare( *(*iter2).type, level );
if (c != 0) return c;
}
++iter1;
++iter2;
}
return 0;
}
int4 TypeUnion::compareDependency(const Datatype &op) const
{
int4 res = Datatype::compareDependency(op);
if (res != 0) return res;
const TypeUnion *tu = (const TypeUnion *)&op;
vector<TypeField>::const_iterator iter1,iter2;
if (field.size() != tu->field.size()) return (tu->field.size()-field.size());
iter1 = field.begin();
iter2 = tu->field.begin();
// Test only the name and first level metatype first
while(iter1 != field.end()) {
if ((*iter1).name != (*iter2).name)
return ((*iter1).name < (*iter2).name) ? -1:1;
Datatype *fld1 = (*iter1).type;
Datatype *fld2 = (*iter2).type;
if (fld1 != fld2)
return (fld1 < fld2) ? -1 : 1; // compare the pointers directly
++iter1;
++iter2;
}
return 0;
}
void TypeUnion::saveXml(ostream &s) const
{
if (typedefImm != (Datatype *)0) {
saveXmlTypedef(s);
return;
}
s << "<type";
saveXmlBasic(metatype,s);
s << ">\n";
vector<TypeField>::const_iterator iter;
for(iter=field.begin();iter!=field.end();++iter) {
(*iter).saveXml(s);
}
s << "</type>";
}
Datatype *TypeUnion::resolveInFlow(PcodeOp *op,int4 slot)
{
Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0)
return res->getDatatype();
ScoreUnionFields scoreFields(*fd->getArch()->types,this,op,slot);
fd->setUnionField(this, op, slot, scoreFields.getResult());
return scoreFields.getResult().getDatatype();
}
Datatype* TypeUnion::findResolve(const PcodeOp *op,int4 slot)
{
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0)
return res->getDatatype();
return this;
}
/// \brief Resolve which union field is being used for a given PcodeOp when a truncation is involved
///
/// This is used either when a Varnode is backed by a larger Symbol with a union data-type,
/// or if the Varnode is produced by a CPUI_SUBPIECE where the input Varnode has a union data-type.
/// Scoring is done to compute the best field and the result is cached with the function.
/// The record of the best field is returned or null if there is no appropriate field
/// \param offset is the byte offset into the union we are truncating to
/// \param op is either the PcodeOp reading the truncated Varnode or the CPUI_SUBPIECE doing the truncation
/// \param slot is either the input slot of the reading PcodeOp or the artificial SUBPIECE slot: 1
/// \param newoff is used to pass back how much offset is left to resolve
/// \return the field of the union best associated with the truncation or null
const TypeField *TypeUnion::resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff)
{
Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0 && res->getFieldNum() >= 0) {
const TypeField *field = getField(res->getFieldNum());
newoff = offset - field->offset;
return field;
}
if (op->code() == CPUI_SUBPIECE && slot == 1) { // The slot is artificial in this case
ScoreUnionFields scoreFields(*fd->getArch()->types,this,offset,op);
fd->setUnionField(this, op, slot, scoreFields.getResult());
if (scoreFields.getResult().getFieldNum() >= 0) {
newoff = 0;
return getField(scoreFields.getResult().getFieldNum());
}
}
else {
ScoreUnionFields scoreFields(*fd->getArch()->types,this,offset,op,slot);
fd->setUnionField(this, op, slot, scoreFields.getResult());
if (scoreFields.getResult().getFieldNum() >= 0) {
const TypeField *field = getField(scoreFields.getResult().getFieldNum());
newoff = offset - field->offset;
return field;
}
}
return (const TypeField *)0;
}
/// \brief Return a precalculated field associated with a truncation
///
/// This is the \e const version of resolveTruncation(). No new scoring is done, but if a cached result
/// is available, return it.
/// \param offset is the byte offset of the truncation
/// \param op is the PcodeOp reading the truncated value
/// \param slot is the input slot being read
/// \param newoff is used to pass back any remaining offset into the field which still must be resolved
/// \return the field to use with truncation or null if there is no appropriate field
const TypeField *TypeUnion::findTruncation(int4 offset,const PcodeOp *op,int4 slot,int4 &newoff) const
{
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0 && res->getFieldNum() >= 0) {
const TypeField *field = getField(res->getFieldNum());
newoff = offset - field->offset;
return field;
}
return (const TypeField *)0;
}
int4 TypeUnion::findCompatibleResolve(Datatype *ct) const
{
if (!ct->needsResolution()) {
for(int4 i=0;i<field.size();++i) {
if (field[i].type == ct && field[i].offset == 0)
return i;
}
}
else {
for(int4 i=0;i<field.size();++i) {
if (field[i].offset != 0) continue;
Datatype *fieldType = field[i].type;
if (fieldType->getSize() != ct->getSize()) continue;
if (fieldType->needsResolution()) continue;
if (ct->findCompatibleResolve(fieldType) >= 0)
return i;
}
}
return -1;
}
/// Parse a \<type> tag with children describing the data-type being pointed to and the parent data-type.
@ -1271,9 +1763,9 @@ void TypePointerRel::restoreXml(const Element *el,TypeFactory &typegrp)
cacheStrippedType(typegrp); // it is considered ephemeral
}
/// For a variable that is a relative pointer, constant offsets off of the variable can be
/// For a variable that is a relative pointer, constant offsets relative to the variable can be
/// displayed either as coming from the variable itself or from the parent object.
/// \param byteOff is the given offset off of the variable
/// \param addrOff is the given offset in address units
/// \return \b true if the variable should be displayed as coming from the parent
bool TypePointerRel::evaluateThruParent(uintb addrOff) const
@ -2090,11 +2582,9 @@ Datatype *TypeFactory::setName(Datatype *ct,const string &n)
bool TypeFactory::setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,uint4 flags)
{
int4 offset,cursize,curalign;
if (!ot->isIncomplete())
throw LowlevelError("Can only set fields on an incomplete structure");
offset = 0;
int4 offset = 0;
vector<TypeField>::iterator iter;
// Find the maximum offset, from the explicitly set offsets
@ -2111,23 +2601,6 @@ bool TypeFactory::setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,
}
}
// Assign offsets, respecting alignment, where not explicitly set
for(iter=fd.begin();iter!=fd.end();++iter) {
if ((*iter).offset != -1) continue;
cursize = (*iter).type->getSize();
curalign = 0;
if (align > 1) {
curalign = align;
while((curalign>>1) >= cursize)
curalign >>= 1;
curalign -= 1;
}
if ((offset & curalign)!=0)
offset = (offset-(offset & curalign) + (curalign+1));
(*iter).offset = offset;
offset += cursize;
}
sort(fd.begin(),fd.end()); // Sort fields by offset
// We could check field overlapping here
@ -2148,6 +2621,42 @@ bool TypeFactory::setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,
return true;
}
/// If \b fixedsize is greater than 0, force the final structure to have that size.
/// This method should only be used on an incomplete union. It will mark the union as complete.
/// \param fd is the list of fields to set
/// \param ot is the TypeUnion object to modify
/// \param fixedsize is 0 or the forced size of the union
/// \param flags are other flags to set on the union
/// \return true if modification was successful
bool TypeFactory::setFields(vector<TypeField> &fd,TypeUnion *ot,int4 fixedsize,uint4 flags)
{
if (!ot->isIncomplete())
throw LowlevelError("Can only set fields on an incomplete union");
vector<TypeField>::iterator iter;
for(iter=fd.begin();iter!=fd.end();++iter) {
Datatype *ct = (*iter).type;
// Do some sanity checks on the field
if (ct->getMetatype() == TYPE_VOID) return false;
if ((*iter).offset != 0) return false;
if ((*iter).name.size() == 0) return false;
}
tree.erase(ot);
ot->setFields(fd);
ot->flags &= ~(uint4)Datatype::type_incomplete;
ot->flags |= (flags & (Datatype::variable_length | Datatype::type_incomplete));
if (fixedsize > 0) { // If the caller is trying to force a size
if (fixedsize > ot->size) // If the forced size is bigger than the size required for fields
ot->size = fixedsize; // Force the bigger size
else if (fixedsize < ot->size) // If the forced size is smaller, this is an error
throw LowlevelError("Trying to force too small a size on "+ot->getName());
}
tree.insert(ot);
return true;
}
/// The given prototype is copied into the given code data-type
/// This method should only be used on an incomplete TypeCode. It will mark the TypeCode as complete.
/// \param fp is the given prototype to copy
@ -2519,14 +3028,24 @@ TypeArray *TypeFactory::getTypeArray(int4 as,Datatype *ao)
TypeStruct *TypeFactory::getTypeStruct(const string &n)
{
// We should probably strip offsets here
// But I am currently choosing not to
TypeStruct tmp;
tmp.name = n;
tmp.id = Datatype::hashName(n);
return (TypeStruct *) findAdd(tmp);
}
/// The created union will be incomplete and have no fields. They must be added later.
/// \param n is the name of the union
/// \return the TypeUnion object
TypeUnion *TypeFactory::getTypeUnion(const string &n)
{
TypeUnion tmp;
tmp.name = n;
tmp.id = Datatype::hashName(n);
return (TypeUnion *) findAdd(tmp);
}
/// The created enumeration will have no named values and a default configuration
/// Named values must be added later.
/// \param n is the name of the enumeration
@ -2711,7 +3230,7 @@ void TypeFactory::saveXml(ostream &s) const
if ((*iter)->isCoreType()) { // If this would be saved as a coretype
type_metatype meta = (*iter)->getMetatype();
if ((meta != TYPE_PTR)&&(meta != TYPE_ARRAY)&&
(meta != TYPE_STRUCT))
(meta != TYPE_STRUCT)&&(meta != TYPE_UNION))
continue; // Don't save it here
}
s << ' ';
@ -2736,7 +3255,7 @@ void TypeFactory::saveXmlCoreTypes(ostream &s) const
if (!ct->isCoreType()) continue;
type_metatype meta = ct->getMetatype();
if ((meta==TYPE_PTR)||(meta==TYPE_ARRAY)||
(meta==TYPE_STRUCT))
(meta==TYPE_STRUCT)||(meta==TYPE_UNION))
continue;
s << ' ';
ct->saveXml(s);
@ -2752,24 +3271,44 @@ void TypeFactory::saveXmlCoreTypes(ostream &s) const
Datatype *TypeFactory::restoreTypedef(const Element *el)
{
uint8 id;
istringstream s1(el->getAttributeValue("id"));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> id;
string nm = el->getAttributeValue("name");
uint8 id = 0;
string nm;
for(int4 i=0;i<el->getNumAttributes();++i) {
const string &attribName(el->getAttributeName(i));
if (attribName == "id") {
istringstream s1(el->getAttributeValue("id"));
s1.unsetf(ios::dec | ios::hex | ios::oct);
s1 >> id;
}
else if (attribName == "name") {
nm = el->getAttributeValue("name");
}
}
if (id == 0) { // Its possible the typedef is a builtin
id = Datatype::hashName(nm); // There must be some kind of id
}
Datatype *defedType = restoreXmlType( *el->getChildren().begin() );
if (defedType->isVariableLength())
id = Datatype::hashSize(id, defedType->size);
if (defedType->getMetatype() == TYPE_STRUCT) {
// Its possible that a typedef of a struct is recursively defined, in which case
if (defedType->getMetatype() == TYPE_STRUCT || defedType->getMetatype() == TYPE_UNION) {
// Its possible that a typedef of a struct/union is recursively defined, in which case
// an incomplete version may already be in the container
TypeStruct *prev = (TypeStruct *)findByIdLocal(nm, id);
Datatype *prev = findByIdLocal(nm, id);
if (prev != (Datatype *)0) {
if (defedType != prev->getTypedef())
throw LowlevelError("Trying to create typedef of existing type: " + prev->name);
TypeStruct *defedStruct = (TypeStruct *)defedType;
if (prev->field.size() != defedStruct->field.size())
prev->field = defedStruct->field;
if (prev->getMetatype() == TYPE_STRUCT) {
TypeStruct *prevStruct = (TypeStruct *)prev;
TypeStruct *defedStruct = (TypeStruct *)defedType;
if (prevStruct->field.size() != defedStruct->field.size())
setFields(defedStruct->field,prevStruct,defedStruct->size,defedStruct->flags);
}
else {
TypeUnion *prevUnion = (TypeUnion *)prev;
TypeUnion *defedUnion = (TypeUnion *)defedType;
if (prevUnion->field.size() != defedUnion->field.size())
setFields(defedUnion->field,prevUnion,defedUnion->size,defedUnion->flags);
}
return prev;
}
}
@ -2805,6 +3344,35 @@ Datatype* TypeFactory::restoreStruct(const Element *el,bool forcecore)
return ct;
}
/// If necessary create a stub object before parsing the field descriptions, to deal with recursive definitions
/// \param el is the XML element describing the union
/// \param forcecore is \b true if the data-type is considered core
/// \return the newly minted union data-type
Datatype* TypeFactory::restoreUnion(const Element *el,bool forcecore)
{
TypeUnion tu;
tu.restoreXmlBasic(el);
if (forcecore)
tu.flags |= Datatype::coretype;
Datatype *ct = findByIdLocal(tu.name,tu.id);
if (ct == (Datatype*)0) {
ct = findAdd(tu); // Create stub to allow recursive definitions
}
else if (ct->getMetatype() != TYPE_UNION)
throw LowlevelError("Trying to redefine type: " + tu.name);
tu.restoreFields(el,*this);
if (!ct->isIncomplete()) { // Structure of this name was already present
if (0 != ct->compareDependency(tu))
throw LowlevelError("Redefinition of union: " + tu.name);
}
else { // If structure is a placeholder stub
if (!setFields(tu.field,(TypeUnion*)ct,tu.size,tu.flags)) // Define structure now by copying fields
throw LowlevelError("Bad union definition");
}
return ct;
}
/// If necessary create a stub object before parsing the prototype description, to deal with recursive definitions
/// \param el is the XML element describing the code object
/// \param isConstructor is \b true if any prototype should be treated as a constructor
@ -2886,6 +3454,9 @@ Datatype *TypeFactory::restoreXmlTypeNoRef(const Element *el,bool forcecore)
case TYPE_STRUCT:
ct = restoreStruct(el,forcecore);
break;
case TYPE_UNION:
ct = restoreUnion(el,forcecore);
break;
case TYPE_SPACEBASE:
{
TypeSpacebase tsb((AddrSpace *)0,Address(),glb);

View file

@ -29,46 +29,48 @@ extern void print_data(ostream &s,uint1 *buffer,int4 size,const Address &baseadd
/// The core meta-types supported by the decompiler. These are sizeless templates
/// for the elements making up the type algebra.
enum type_metatype {
TYPE_VOID = 12, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 11, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 10, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 9, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 8, ///< Unsigned integer
TYPE_BOOL = 7, ///< Boolean
TYPE_CODE = 6, ///< Data is actual executable code
TYPE_FLOAT = 5, ///< Floating-point
TYPE_VOID = 13, ///< Standard "void" type, absence of type
TYPE_SPACEBASE = 12, ///< Placeholder for symbol/type look-up calculations
TYPE_UNKNOWN = 11, ///< An unknown low-level type. Treated as an unsigned integer.
TYPE_INT = 10, ///< Signed integer. Signed is considered less specific than unsigned in C
TYPE_UINT = 9, ///< Unsigned integer
TYPE_BOOL = 8, ///< Boolean
TYPE_CODE = 7, ///< Data is actual executable code
TYPE_FLOAT = 6, ///< Floating-point
TYPE_PTR = 4, ///< Pointer data-type
TYPE_PTRREL = 3, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 2, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_PARTIALSTRUCT = 1, ///< Part of a structure, stored separately from the whole
TYPE_STRUCT = 0 ///< Structure data-type, made up of component datatypes
TYPE_PTR = 5, ///< Pointer data-type
TYPE_PTRREL = 4, ///< Pointer relative to another data-type (specialization of TYPE_PTR)
TYPE_ARRAY = 3, ///< Array data-type, made up of a sequence of "element" datatype
TYPE_PARTIALSTRUCT = 2, ///< Part of a structure, stored separately from the whole
TYPE_STRUCT = 1, ///< Structure data-type, made up of component datatypes
TYPE_UNION = 0 ///< An overlapping union of multiple datatypes
};
/// Specializations of the core meta-types. Each enumeration is associated with a specific #type_metatype.
/// Ordering is important: The lower the number, the more \b specific the data-type, affecting propagation.
enum sub_metatype {
SUB_VOID = 20, ///< Compare as a TYPE_VOID
SUB_SPACEBASE = 19, ///< Compare as a TYPE_SPACEBASE
SUB_UNKNOWN = 18, ///< Compare as a TYPE_UNKNOWN
SUB_INT_CHAR = 17, ///< Signed 1-byte character, sub-type of TYPE_INT
SUB_UINT_CHAR = 16, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
SUB_INT_PLAIN = 15, ///< Compare as a plain TYPE_INT
SUB_UINT_PLAIN = 14, ///< Compare as a plain TYPE_UINT
SUB_INT_ENUM = 13, ///< Signed enum, sub-type of TYPE_INT
SUB_UINT_ENUM = 12, ///< Unsigned enum, sub-type of TYPE_UINT
SUB_INT_UNICODE = 11, ///< Signed wide character, sub-type of TYPE_INT
SUB_UINT_UNICODE = 10, ///< Unsigned wide character, sub-type of TYPE_UINT
SUB_BOOL = 9, ///< Compare as TYPE_BOOL
SUB_CODE = 8, ///< Compare as TYPE_CODE
SUB_FLOAT = 7, ///< Compare as TYPE_FLOAT
SUB_PTRREL_UNK = 6, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
SUB_PTR = 5, ///< Compare as TYPE_PTR
SUB_PTRREL = 4, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
SUB_PTR_STRUCT = 3, ///< Pointer into struct, sub-type of TYPE_PTR
SUB_ARRAY = 2, ///< Compare as TYPE_ARRAY
SUB_PARTIALSTRUCT = 1, ///< Compare as TYPE_PARTIALSTRUCT
SUB_STRUCT = 0 ///< Compare as TYPE_STRUCT
SUB_VOID = 21, ///< Compare as a TYPE_VOID
SUB_SPACEBASE = 20, ///< Compare as a TYPE_SPACEBASE
SUB_UNKNOWN = 19, ///< Compare as a TYPE_UNKNOWN
SUB_INT_CHAR = 18, ///< Signed 1-byte character, sub-type of TYPE_INT
SUB_UINT_CHAR = 17, ///< Unsigned 1-byte character, sub-type of TYPE_UINT
SUB_INT_PLAIN = 16, ///< Compare as a plain TYPE_INT
SUB_UINT_PLAIN = 15, ///< Compare as a plain TYPE_UINT
SUB_INT_ENUM = 14, ///< Signed enum, sub-type of TYPE_INT
SUB_UINT_ENUM = 13, ///< Unsigned enum, sub-type of TYPE_UINT
SUB_INT_UNICODE = 12, ///< Signed wide character, sub-type of TYPE_INT
SUB_UINT_UNICODE = 11, ///< Unsigned wide character, sub-type of TYPE_UINT
SUB_BOOL = 10, ///< Compare as TYPE_BOOL
SUB_CODE = 9, ///< Compare as TYPE_CODE
SUB_FLOAT = 8, ///< Compare as TYPE_FLOAT
SUB_PTRREL_UNK = 7, ///< Pointer to unknown field of struct, sub-type of TYPE_PTR
SUB_PTR = 6, ///< Compare as TYPE_PTR
SUB_PTRREL = 5, ///< Pointer relative to another data-type, sub-type of TYPE_PTR
SUB_PTR_STRUCT = 4, ///< Pointer into struct, sub-type of TYPE_PTR
SUB_ARRAY = 3, ///< Compare as TYPE_ARRAY
SUB_PARTIALSTRUCT = 2, ///< Compare as TYPE_PARTIALSTRUCT
SUB_STRUCT = 1, ///< Compare as TYPE_STRUCT
SUB_UNION = 0 ///< Compare as TYPE_UNION
};
/// Convert type \b meta-type to name
extern void metatype2string(type_metatype metatype,string &res);
@ -77,6 +79,7 @@ extern void metatype2string(type_metatype metatype,string &res);
extern type_metatype string2metatype(const string &metastring);
class Architecture; // Forward declarations
class PcodeOp;
class Scope;
class TypeFactory;
struct DatatypeCompare;
@ -86,7 +89,7 @@ struct DatatypeCompare;
/// Used for symbols, function prototypes, type propagation etc.
class Datatype {
protected:
static sub_metatype base2sub[13];
static sub_metatype base2sub[14];
/// Boolean properties of datatypes
enum {
coretype = 1, ///< This is a basic type which will never be redefined
@ -105,6 +108,7 @@ protected:
has_stripped = 0x100, ///< Datatype has a stripped form for formal declarations
is_ptrrel = 0x200, ///< Datatype is a TypePointerRel
type_incomplete = 0x400, ///< Set if \b this (recursive) data-type has not been fully defined yet
needs_resolution = 0x800 ///< Datatype (union, pointer to union) needs resolution before propagation
};
friend class TypeFactory;
friend struct DatatypeCompare;
@ -143,6 +147,7 @@ public:
bool isFormalPointerRel(void) const { return (flags & (is_ptrrel | has_stripped))==is_ptrrel; } ///< Is \b this a non-ephemeral TypePointerRel
bool hasStripped(void) const { return (flags & has_stripped)!=0; } ///< Return \b true if \b this has a stripped form
bool isIncomplete(void) const { return (flags & type_incomplete)!=0; } ///< Is \b this an incompletely defined data-type
bool needsResolution(void) const { return (flags & needs_resolution)!=0; } ///< Is \b this a union or a pointer to union
uint4 getInheritable(void) const { return (flags & coretype); } ///< Get properties pointers inherit
type_metatype getMetatype(void) const { return metatype; } ///< Get the type \b meta-type
sub_metatype getSubMeta(void) const { return submeta; } ///< Get the \b sub-metatype
@ -162,17 +167,25 @@ public:
virtual void saveXml(ostream &s) const; ///< Serialize the data-type to XML
virtual bool isPtrsubMatching(uintb off) 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 *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 int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type
int4 typeOrder(const Datatype &op) const { if (this==&op) return 0; return compare(op,10); } ///< Order this with -op- datatype
int4 typeOrderBool(const Datatype &op) const; ///< Order \b this with -op-, treating \e bool data-type as special
void saveXmlRef(ostream &s) const; ///< Write an XML reference of \b this to stream
};
/// \brief Specifies subfields of a structure or what a pointer points to
struct TypeField {
int4 offset; ///< Offset (into containing struct) of subfield
/// \brief A field within a structure or union
class TypeField {
public:
int4 ident; ///< Id for identifying \b this within its containing structure or union
int4 offset; ///< Offset (into containing structure or union) of subfield
string name; ///< Name of subfield
Datatype *type; ///< type of subfield
Datatype *type; ///< Data-type of subfield
TypeField(const Element *el,TypeFactory &typegrp); ///< Restore \b this field from an XML stream
TypeField(int4 id,int4 off,const string &nm,Datatype *ct) { ident=id; offset=off; name=nm; type=ct; } ///< Construct from components
bool operator<(const TypeField &op2) const { return (offset < op2.offset); } ///< Compare based on offset
void saveXml(ostream &s) const; ///< Save \b this field as XML
};
/// Compare two Datatype pointers for equivalence of their description
@ -291,6 +304,8 @@ public:
virtual void saveXml(ostream &s) const;
virtual TypePointer *downChain(uintb &off,TypePointer *&par,uintb &parOff,bool allowArrayWrap,TypeFactory &typegrp);
virtual bool isPtrsubMatching(uintb off) const;
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
};
/// \brief Datatype object representing an array of elements
@ -306,8 +321,7 @@ public:
/// Construct from another TypeArray
TypeArray(const TypeArray &op) : Datatype(op) { arrayof = op.arrayof; arraysize = op.arraysize; }
/// Construct given an array size and element data-type
TypeArray(int4 n,Datatype *ao) : Datatype(n*ao->getSize(),TYPE_ARRAY) {
arraysize = n; arrayof = ao; }
TypeArray(int4 n,Datatype *ao);
Datatype *getBase(void) const { return arrayof; } ///< Get the element data-type
int4 numElements(void) const { return arraysize; } ///< Get the number of elements
Datatype *getSubEntry(int4 off,int4 sz,int4 *newoff,int4 *el) const; ///< Figure out what a byte range overlaps
@ -320,6 +334,9 @@ public:
virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypeArray(*this); }
virtual void saveXml(ostream &s) const;
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const;
};
/// \brief An enumerated Datatype object: an integer with named values.
@ -351,7 +368,7 @@ public:
virtual void saveXml(ostream &s) const;
};
/// \brief A composite Datatype object: A "structure" with component "fields"
/// \brief A composite Datatype object: A \b structure with component \b fields
class TypeStruct : public Datatype {
protected:
friend class TypeFactory;
@ -360,12 +377,13 @@ protected:
int4 getFieldIter(int4 off) const; ///< Get index into field list
int4 getLowerBoundField(int4 off) const; ///< Get index of last field before or equal to given offset
void restoreFields(const Element *el,TypeFactory &typegrp); ///< Restore fields from XML description
int4 scoreFill(PcodeOp *op,int4 slot) const; ///< Determine best type fit for given PcodeOp use
public:
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
TypeStruct(void) : Datatype(0,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct
vector<TypeField>::const_iterator beginField(void) const { return field.begin(); } ///< Beginning of fields
vector<TypeField>::const_iterator endField(void) const { return field.end(); } ///< End of fields
const TypeField *getField(int4 off,int4 sz,int4 *newoff) const; ///< Get field based on offset
const TypeField *resolveTruncation(int4 off,int4 sz,int4 *newoff) const; ///< Get field based on offset
virtual Datatype *getSubType(uintb off,uintb *newoff) const;
virtual Datatype *nearestArrayedComponentForward(uintb off,uintb *newoff,int4 *elSize) const;
virtual Datatype *nearestArrayedComponentBackward(uintb off,uintb *newoff,int4 *elSize) const;
@ -375,10 +393,40 @@ public:
virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypeStruct(*this); }
virtual void saveXml(ostream &s) const;
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const;
static void assignFieldOffsets(vector<TypeField> &list,int4 align); ///< Assign field offsets given a byte alignment
};
/// \brief A pointer data-type that knows it is offset relative to another data-type
/// \brief A collection of overlapping Datatype objects: A \b union of component \b fields
///
/// The individual components have \b field names, as with a structure, but for a union, the components all
/// share the same memory.
class TypeUnion : public Datatype {
protected:
friend class TypeFactory;
vector<TypeField> field; ///< The list of fields
void setFields(const vector<TypeField> &fd); ///< Establish fields for \b this
void restoreFields(const Element *el,TypeFactory &typegrp); ///< Restore fields from XML description
public:
TypeUnion(const TypeUnion &op); ///< Construct from another TypeUnion
TypeUnion(void) : Datatype(0,TYPE_UNION) { flags |= (type_incomplete | needs_resolution); } ///< Construct incomplete TypeUnion
const TypeField *getField(int4 i) const { return &field[i]; } ///< Get the i-th field of the union
// virtual Datatype *getSubType(uintb off,uintb *newoff) const;
virtual int4 numDepend(void) const { return field.size(); }
virtual Datatype *getDepend(int4 index) const { return field[index].type; }
virtual int4 compare(const Datatype &op,int4 level) const; // For tree structure
virtual int4 compareDependency(const Datatype &op) const; // For tree structure
virtual Datatype *clone(void) const { return new TypeUnion(*this); }
virtual void saveXml(ostream &s) const;
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const;
const TypeField *resolveTruncation(int4 offset,PcodeOp *op,int4 slot,int4 &newoff);
const TypeField *findTruncation(int4 offset,const PcodeOp *op,int4 slot,int4 &newoff) const;
};
/// The other data, the \b container, is typically a TypeStruct or TypeArray. Even though \b this pointer
/// does not point directly to the start of the container, it is possible to access the container through \b this,
/// as the distance (the \b offset) to the start of the container is explicitly known.
@ -496,6 +544,7 @@ class TypeFactory {
void orderRecurse(vector<Datatype *> &deporder,DatatypeSet &mark,Datatype *ct) const; ///< Write out dependency list
Datatype *restoreTypedef(const Element *el); ///< Restore a \<def> XML tag describing a typedef
Datatype *restoreStruct(const Element *el,bool forcecore); ///< Restore a \<type> XML tag describing a structure
Datatype *restoreUnion(const Element *el,bool forcecore); ///< Restore a \<type> XML tag describing a union
Datatype *restoreCode(const Element *el,bool isConstructor,bool isDestructor,bool forcecore); ///< Restore XML tag describing a code object
Datatype *restoreXmlTypeNoRef(const Element *el,bool forcecore); ///< Restore from an XML tag
void clearCache(void); ///< Clear the common type cache
@ -520,6 +569,7 @@ public:
Datatype *findByName(const string &n); ///< Return type of given name
Datatype *setName(Datatype *ct,const string &n); ///< Set the given types name
bool setFields(vector<TypeField> &fd,TypeStruct *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeStruct
bool setFields(vector<TypeField> &fd,TypeUnion *ot,int4 fixedsize,uint4 flags); ///< Set fields on a TypeUnion
void setPrototype(const FuncProto *fp,TypeCode *newCode,uint4 flags); ///< Set the prototype on a TypeCode
bool setEnumValues(const vector<string> &namelist,
const vector<uintb> &vallist,
@ -538,6 +588,7 @@ public:
TypePointer *getTypePointerNoDepth(int4 s,Datatype *pt,uint4 ws); ///< Construct a depth limited pointer data-type
TypeArray *getTypeArray(int4 as,Datatype *ao); ///< Construct an array data-type
TypeStruct *getTypeStruct(const string &n); ///< Create an (empty) structure
TypeUnion *getTypeUnion(const string &n); ///< Create an (empty) union
TypeEnum *getTypeEnum(const string &n); ///< Create an (empty) enumeration
TypeSpacebase *getTypeSpacebase(AddrSpace *id,const Address &addr); ///< Create a "spacebase" type
TypeCode *getTypeCode(ProtoModel *model,Datatype *outtype,
@ -574,6 +625,17 @@ inline int4 Datatype::typeOrderBool(const Datatype &op) const
return compare(op,10);
}
inline TypeArray::TypeArray(int4 n,Datatype *ao) : Datatype(n*ao->getSize(),TYPE_ARRAY)
{
arraysize = n;
arrayof = ao;
// A varnode which is an array of size 1, should generally always be treated
// as the element data-type
if (n == 1)
flags |= needs_resolution;
}
/// \brief Set up the base pointer data-type \b this is modeling
///
/// This base data-type is used for formal variable declarations in source code output.

View file

@ -215,10 +215,28 @@ Datatype *TypeOp::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *c
const Varnode *vn = op->getIn(slot);
if (vn->isAnnotation()) return (Datatype *)0;
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHigh()->getType();
Datatype *curtype = vn->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,false,true);
}
/// The data-type can propagate between any two Varnodes attached to the PcodeOp, either in or out.
/// The pair \b invn and \b inslot indicate the Varnode holding the \e incoming data-type.
/// The pair \b outvn and \b outslot indicate the Varnode that will hold the \e outgoing data-type.
/// The data-type for the outgoing Varnode is returned, which may be different then the incoming data-type
/// as the PcodeOp can transform the data-type as it propagates.
/// \param alttype is the incoming data-type
/// \param op is the PcodeOp to propagate across
/// \param invn is the Varnode holding the incoming data-type
/// \param outvn is the Varnode that will hold the outgoing data-type
/// \param inslot indicates how the incoming Varnode is attached to the PcodeOp (-1 indicates output >= indicates input)
/// \param outslot indicates how the outgoing Varnode is attached to the PcodeOp
/// \return the outgoing data-type or null (to indicate no propagation)
Datatype *TypeOp::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
return (Datatype *)0; // Don't propagate by default
}
/// Many languages can mark an integer constant as explicitly \e unsigned. When
/// the decompiler is deciding on \e cast operations, this is one of the checks
/// it performs. This method checks if the indicated input is an
@ -234,14 +252,14 @@ bool TypeOp::markExplicitUnsigned(PcodeOp *op,int4 slot) const
if ((slot==1) && ((addlflags & inherits_sign_zero)!=0)) return false;
Varnode *vn = op->getIn(slot);
if (!vn->isConstant()) return false;
Datatype *dt = vn->getHigh()->getType();
Datatype *dt = vn->getHighTypeReadFacing(op);
type_metatype meta = dt->getMetatype();
if ((meta != TYPE_UINT)&&(meta != TYPE_UNKNOWN)) return false;
if (dt->isCharPrint()) return false;
if (dt->isEnumType()) return false;
if ((op->numInput() == 2) && ((addlflags & inherits_sign_zero)==0)) {
Varnode *firstvn = op->getIn(1-slot);
meta = firstvn->getHigh()->getType()->getMetatype();
meta = firstvn->getHighTypeReadFacing(op)->getMetatype();
if ((meta == TYPE_UINT)||(meta == TYPE_UNKNOWN))
return false; // Other side of the operation will force the unsigned
}
@ -336,15 +354,29 @@ TypeOpCopy::TypeOpCopy(TypeFactory *t) : TypeOp(t,CPUI_COPY,"copy")
Datatype *TypeOpCopy::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
{
Datatype *reqtype = op->getOut()->getHigh()->getType(); // Require input to be same type as output
Datatype *curtype = op->getIn(0)->getHigh()->getType();
Datatype *reqtype = op->getOut()->getHighTypeDefFacing(); // Require input to be same type as output
Datatype *curtype = op->getIn(0)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,false,true);
}
Datatype *TypeOpCopy::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
return op->getIn(0)->getHigh()->getType();
return op->getIn(0)->getHighTypeReadFacing(op);
}
Datatype *TypeOpCopy::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot!=-1)&&(outslot!=-1)) return (Datatype *)0; // Must propagate input <-> output
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
newtype = tlst->getTypePointer(alttype->getSize(),tlst->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
return newtype;
}
void TypeOpCopy::printRaw(ostream &s,const PcodeOp *op)
@ -366,9 +398,9 @@ Datatype *TypeOpLoad::getInputCast(const PcodeOp *op,int4 slot,const CastStrateg
{
if (slot!=1) return (Datatype *)0;
Datatype *reqtype = op->getOut()->getHigh()->getType(); // Cast load pointer to match output
Datatype *reqtype = op->getOut()->getHighTypeDefFacing(); // Cast load pointer to match output
const Varnode *invn = op->getIn(1);
Datatype *curtype = invn->getHigh()->getType();
Datatype *curtype = invn->getHighTypeReadFacing(op);
AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
// Its possible that the input type is not a pointer to the output type
// (or even a pointer) due to cycle trimming in the type propagation algorithms
@ -380,7 +412,7 @@ Datatype *TypeOpLoad::getInputCast(const PcodeOp *op,int4 slot,const CastStrateg
// If we have a non-standard in = ptr a out = b (a!=b)
// We may want to postpone casting BEFORE the load in favor of casting AFTER the load
type_metatype curmeta = curtype->getMetatype();
if ((curmeta!=TYPE_STRUCT)&&(curmeta!=TYPE_ARRAY)&&(curmeta!=TYPE_SPACEBASE)) {
if ((curmeta!=TYPE_STRUCT)&&(curmeta!=TYPE_ARRAY)&&(curmeta!=TYPE_SPACEBASE)&&(curmeta!=TYPE_UNION)) {
// if the input is a pointer to a primitive type
if ((!invn->isImplied())||(!invn->isWritten())||(invn->getDef()->code() != CPUI_CAST))
return (Datatype *)0; // Postpone cast to output
@ -397,7 +429,7 @@ Datatype *TypeOpLoad::getInputCast(const PcodeOp *op,int4 slot,const CastStrateg
Datatype *TypeOpLoad::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
Datatype *ct = op->getIn(1)->getHigh()->getType();
Datatype *ct = op->getIn(1)->getHighTypeReadFacing(op);
if ((ct->getMetatype() == TYPE_PTR)&&(((TypePointer *)ct)->getPtrTo()->getSize() == op->getOut()->getSize()))
return ((TypePointer *)ct)->getPtrTo();
// return TypeOp::getOutputToken(op);
@ -406,7 +438,27 @@ Datatype *TypeOpLoad::getOutputToken(const PcodeOp *op,CastStrategy *castStrateg
// In this case, there will have to be a cast, so we assume
// the cast will cause the load to produce the type matching
// its output
return op->getOut()->getHigh()->getType();
return op->getOut()->getHighTypeDefFacing();
}
Datatype *TypeOpLoad::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot==0)||(outslot==0)) return (Datatype *)0; // Don't propagate along this edge
if (invn->isSpacebase()) return (Datatype *)0;
Datatype *newtype;
if (inslot == -1) { // Propagating output to input (value to ptr)
AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
newtype = tlst->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength()) // Size must be appropriate
newtype = outvn->getTempType();
}
else
newtype = outvn->getTempType(); // Don't propagate anything
return newtype;
}
void TypeOpLoad::printRaw(ostream &s,const PcodeOp *op)
@ -432,13 +484,14 @@ Datatype *TypeOpStore::getInputCast(const PcodeOp *op,int4 slot,const CastStrate
{
if (slot==0) return (Datatype *)0;
const Varnode *pointerVn = op->getIn(1);
Datatype *pointerType = pointerVn->getHigh()->getType();
Datatype *valueType = op->getIn(2)->getHigh()->getType();
Datatype *pointerType = pointerVn->getHighTypeReadFacing(op);
Datatype *pointedToType = pointerType;
Datatype *valueType = op->getIn(2)->getHighTypeReadFacing(op);
AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
int4 destSize;
if (pointerType->getMetatype() == TYPE_PTR) {
pointerType = ((TypePointer *)pointerType)->getPtrTo();
destSize = pointerType->getSize();
pointedToType = ((TypePointer *)pointerType)->getPtrTo();
destSize = pointedToType->getSize();
}
else
destSize = -1;
@ -453,14 +506,34 @@ Datatype *TypeOpStore::getInputCast(const PcodeOp *op,int4 slot,const CastStrate
if (pointerVn->isImplied() && pointerVn->loneDescend() == op) {
// CAST is already in place, test if it is casting to the right type
Datatype *newType = tlst->getTypePointer(pointerVn->getSize(), valueType, spc->getWordSize());
if (pointerVn->getHigh()->getType() != newType)
if (pointerType != newType)
return newType;
}
}
return (Datatype *)0;
}
// If we reach here, cast the value, not the pointer
return castStrategy->castStandard(pointerType,valueType,false,true);
return castStrategy->castStandard(pointedToType,valueType,false,true);
}
Datatype *TypeOpStore::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot==0)||(outslot==0)) return (Datatype *)0; // Don't propagate along this edge
if (invn->isSpacebase()) return (Datatype *)0;
Datatype *newtype;
if (inslot==2) { // Propagating value to ptr
AddrSpace *spc = Address::getSpaceFromConst(op->getIn(0)->getAddr());
newtype = tlst->getTypePointerNoDepth(outvn->getTempType()->getSize(),alttype,spc->getWordSize());
}
else if (alttype->getMetatype()==TYPE_PTR) {
newtype = ((TypePointer *)alttype)->getPtrTo();
if (newtype->getSize() != outvn->getTempType()->getSize() || newtype->isVariableLength())
newtype = outvn->getTempType();
}
else
newtype = outvn->getTempType(); // Don't propagate anything
return newtype;
}
void TypeOpStore::printRaw(ostream &s,const PcodeOp *op)
@ -831,16 +904,59 @@ TypeOpEqual::TypeOpEqual(TypeFactory *t)
Datatype *TypeOpEqual::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
{
Datatype *reqtype = op->getIn(0)->getHigh()->getType(); // Input arguments should be the same type
Datatype *othertype = op->getIn(1)->getHigh()->getType();
Datatype *reqtype = op->getIn(0)->getHighTypeReadFacing(op); // Input arguments should be the same type
Datatype *othertype = op->getIn(1)->getHighTypeReadFacing(op);
if (0>othertype->typeOrder(*reqtype))
reqtype = othertype;
if (castStrategy->checkIntPromotionForCompare(op,slot))
return reqtype;
othertype = op->getIn(slot)->getHigh()->getType();
othertype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,othertype,false,false);
}
Datatype *TypeOpEqual::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
return TypeOpEqual::propagateAcrossCompare(alttype, tlst, invn, outvn, inslot, outslot);
}
/// \brief Propagate a given data-type across a \e comparison PcodeOp
///
/// This implements the propagateType() method for multiple p-code operators:
/// CPUI_INT_EQUAL, CPUI_INT_NOTEQUAL, CPUI_INT_LESS, etc.
/// The propagation must be across the input Varnodes of the comparison.
/// \param alttype is the incoming data-type to propagate
/// \param typegrp is the TypeFactory used for constructing transformed data-types
/// \param invn is the Varnode holding the incoming data-type
/// \param outvn is the Varnode that will hold the outgoing data-type
/// \param inslot indicates how the incoming Varnode is attached to the PcodeOp (-1 indicates output >= indicates input)
/// \param outslot indicates how the outgoing Varnode is attached to the PcodeOp
/// \return the outgoing data-type or null (to indicate no propagation)
Datatype *TypeOpEqual::propagateAcrossCompare(Datatype *alttype,TypeFactory *typegrp,Varnode *invn,
Varnode *outvn,int4 inslot,int4 outslot)
{
if (inslot == -1 || outslot == -1) return (Datatype *)0;
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = typegrp->getArch()->getDefaultDataSpace();
newtype = typegrp->getTypePointer(alttype->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else if (alttype->isPointerRel() && !outvn->isConstant()) {
TypePointerRel *relPtr = (TypePointerRel *)alttype;
if (relPtr->getParent()->getMetatype() == TYPE_STRUCT && relPtr->getPointerOffset() >= 0) {
// If we know the pointer is in the middle of a structure, don't propagate across comparison operators
// as the two sides of the operator are likely to be different types , and the other side can also
// get data-type information from the structure pointer
newtype = typegrp->getTypePointer(relPtr->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),relPtr->getWordSize());
}
else
newtype = alttype;
}
else
newtype = alttype;
return newtype;
}
TypeOpNotEqual::TypeOpNotEqual(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_NOTEQUAL,"!=",TYPE_BOOL,TYPE_INT)
{
@ -852,16 +968,22 @@ TypeOpNotEqual::TypeOpNotEqual(TypeFactory *t)
Datatype *TypeOpNotEqual::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
{
Datatype *reqtype = op->getIn(0)->getHigh()->getType(); // Input arguments should be the same type
Datatype *othertype = op->getIn(1)->getHigh()->getType();
Datatype *reqtype = op->getIn(0)->getHighTypeReadFacing(op); // Input arguments should be the same type
Datatype *othertype = op->getIn(1)->getHighTypeReadFacing(op);
if (0>othertype->typeOrder(*reqtype))
reqtype = othertype;
if (castStrategy->checkIntPromotionForCompare(op,slot))
return reqtype;
othertype = op->getIn(slot)->getHigh()->getType();
othertype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,othertype,false,false);
}
Datatype *TypeOpNotEqual::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
return TypeOpEqual::propagateAcrossCompare(alttype, tlst, invn, outvn, inslot, outslot);
}
TypeOpIntSless::TypeOpIntSless(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_SLESS,"<",TYPE_BOOL,TYPE_INT)
{
@ -876,10 +998,18 @@ Datatype *TypeOpIntSless::getInputCast(const PcodeOp *op,int4 slot,const CastStr
Datatype *reqtype = op->inputTypeLocal(slot);
if (castStrategy->checkIntPromotionForCompare(op,slot))
return reqtype;
Datatype *curtype = op->getIn(slot)->getHigh()->getType();
Datatype *curtype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,true,true);
}
Datatype *TypeOpIntSless::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot==-1)||(outslot==-1)) return (Datatype *)0; // Must propagate input <-> input
if (alttype->getMetatype() != TYPE_INT) return (Datatype *)0; // Only propagate signed things
return alttype;
}
TypeOpIntSlessEqual::TypeOpIntSlessEqual(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_SLESSEQUAL,"<=",TYPE_BOOL,TYPE_INT)
{
@ -894,10 +1024,18 @@ Datatype *TypeOpIntSlessEqual::getInputCast(const PcodeOp *op,int4 slot,const Ca
Datatype *reqtype = op->inputTypeLocal(slot);
if (castStrategy->checkIntPromotionForCompare(op,slot))
return reqtype;
Datatype *curtype = op->getIn(slot)->getHigh()->getType();
Datatype *curtype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,true,true);
}
Datatype *TypeOpIntSlessEqual::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot==-1)||(outslot==-1)) return (Datatype *)0; // Must propagate input <-> input
if (alttype->getMetatype() != TYPE_INT) return (Datatype *)0; // Only propagate signed things
return alttype;
}
TypeOpIntLess::TypeOpIntLess(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_LESS,"<",TYPE_BOOL,TYPE_UINT)
{
@ -912,10 +1050,16 @@ Datatype *TypeOpIntLess::getInputCast(const PcodeOp *op,int4 slot,const CastStra
Datatype *reqtype = op->inputTypeLocal(slot);
if (castStrategy->checkIntPromotionForCompare(op,slot))
return reqtype;
Datatype *curtype = op->getIn(slot)->getHigh()->getType();
Datatype *curtype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,true,false);
}
Datatype *TypeOpIntLess::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
return TypeOpEqual::propagateAcrossCompare(alttype, tlst, invn, outvn, inslot, outslot);
}
TypeOpIntLessEqual::TypeOpIntLessEqual(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_LESSEQUAL,"<=",TYPE_BOOL,TYPE_UINT)
{
@ -930,10 +1074,16 @@ Datatype *TypeOpIntLessEqual::getInputCast(const PcodeOp *op,int4 slot,const Cas
Datatype *reqtype = op->inputTypeLocal(slot);
if (castStrategy->checkIntPromotionForCompare(op,slot))
return reqtype;
Datatype *curtype = op->getIn(slot)->getHigh()->getType();
Datatype *curtype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,true,false);
}
Datatype *TypeOpIntLessEqual::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
return TypeOpEqual::propagateAcrossCompare(alttype, tlst, invn, outvn, inslot, outslot);
}
TypeOpIntZext::TypeOpIntZext(TypeFactory *t)
: TypeOpFunc(t,CPUI_INT_ZEXT,"ZEXT",TYPE_UINT,TYPE_UINT)
{
@ -956,7 +1106,7 @@ Datatype *TypeOpIntZext::getInputCast(const PcodeOp *op,int4 slot,const CastStra
Datatype *reqtype = op->inputTypeLocal(slot);
if (castStrategy->checkIntPromotionForExtension(op))
return reqtype;
Datatype *curtype = op->getIn(slot)->getHigh()->getType();
Datatype *curtype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,true,false);
}
@ -982,7 +1132,7 @@ Datatype *TypeOpIntSext::getInputCast(const PcodeOp *op,int4 slot,const CastStra
Datatype *reqtype = op->inputTypeLocal(slot);
if (castStrategy->checkIntPromotionForExtension(op))
return reqtype;
Datatype *curtype = op->getIn(slot)->getHigh()->getType();
Datatype *curtype = op->getIn(slot)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,true,false);
}
@ -1000,6 +1150,143 @@ Datatype *TypeOpIntAdd::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
return castStrategy->arithmeticOutputStandard(op); // Use arithmetic typing rules
}
Datatype *TypeOpIntAdd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
type_metatype invnMeta = alttype->getMetatype();
if (invnMeta != TYPE_PTR) {
if (invnMeta != TYPE_INT && invnMeta != TYPE_UINT)
return (Datatype *)0;
if (outslot != 1 || !op->getIn(1)->isConstant())
return (Datatype *)0;
}
else if ((inslot!=-1)&&(outslot!=-1))
return (Datatype *)0; // Must propagate input <-> output for pointers
Datatype *newtype;
if (outvn->isConstant() && (alttype->getMetatype() != TYPE_PTR))
newtype = alttype;
else if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction
else
newtype = propagateAddIn2Out(alttype,tlst,op,inslot);
return newtype;
}
/// \brief Propagate a pointer data-type through an ADD operation.
///
/// Assuming a pointer data-type from an ADD PcodeOp propagates from an input to
/// its output, calculate the transformed data-type of the output Varnode, which
/// will depend on details of the operation. If the edge doesn't make sense as
/// "an ADD to a pointer", prevent the propagation by returning the output Varnode's
/// current data-type.
/// \param alttype is the resolved input pointer data-type
/// \param typegrp is the TypeFactory for constructing the transformed Datatype
/// \param op is the ADD operation
/// \param inslot is the edge to propagate along
/// \return the transformed Datatype or the original output Datatype
Datatype *TypeOpIntAdd::propagateAddIn2Out(Datatype *alttype,TypeFactory *typegrp,PcodeOp *op,int4 inslot)
{
TypePointer *pointer = (TypePointer *)alttype;
uintb uoffset;
int4 command = propagateAddPointer(uoffset,op,inslot,pointer->getPtrTo()->getSize());
if (command == 2) return op->getOut()->getTempType(); // Doesn't look like a good pointer add
TypePointer *parent = (TypePointer *)0;
uintb parentOff;
if (command != 3) {
uoffset = AddrSpace::addressToByte(uoffset,pointer->getWordSize());
bool allowWrap = (op->code() != CPUI_PTRSUB);
do {
pointer = pointer->downChain(uoffset,parent,parentOff,allowWrap,*typegrp);
if (pointer == (TypePointer *)0)
break;
} while(uoffset != 0);
}
if (parent != (TypePointer *)0) {
// If the innermost containing object is a TYPE_STRUCT or TYPE_ARRAY
// preserve info about this container
Datatype *pt;
if (pointer == (TypePointer *)0)
pt = typegrp->getBase(1,TYPE_UNKNOWN); // Offset does not point at a proper sub-type
else
pt = pointer->getPtrTo(); // The sub-type being directly pointed at
pointer = typegrp->getTypePointerRel(parent, pt, parentOff);
}
if (pointer == (TypePointer *)0) {
if (command == 0)
return alttype;
return op->getOut()->getTempType();
}
if (op->getIn(inslot)->isSpacebase()) {
if (pointer->getPtrTo()->getMetatype() == TYPE_SPACEBASE)
pointer = typegrp->getTypePointer(pointer->getSize(),typegrp->getBase(1,TYPE_UNKNOWN),pointer->getWordSize());
}
return pointer;
}
/// Determine if the given data-type edge looks like a pointer
/// propagating through an "add a constant" operation. We assume the input
/// to the edge has a pointer data-type. This routine returns one the commands:
/// - 0 indicates this is "add a constant" adding a zero (PTRSUB or PTRADD)
/// - 1 indicates this is "add a constant" and the constant is passed back
/// - 2 indicating the pointer does not propagate through
/// - 3 the input data-type propagates through untransformed
///
/// \param off passes back the constant offset if the command is '0' or '1'
/// \param op is the PcodeOp propagating the data-type
/// \param slot is the input edge being propagated
/// \param sz is the size of the data-type being pointed to
/// \return a command indicating how the op should be treated
int4 TypeOpIntAdd::propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4 sz)
{
if (op->code() == CPUI_PTRADD) {
if (slot != 0) return 2;
Varnode *constvn = op->getIn(1);
uintb mult = op->getIn(2)->getOffset();
if (constvn->isConstant()) {
off = (constvn->getOffset() * mult) & calc_mask(constvn->getSize()) ;
return (off == 0) ? 0 : 1;
}
if (sz != 0 && (mult % sz) != 0)
return 2;
return 3;
}
if (op->code() == CPUI_PTRSUB) {
if (slot != 0) return 2;
off = op->getIn(1)->getOffset();
return (off == 0) ? 0 : 1;
}
if (op->code() == CPUI_INT_ADD) {
Varnode *othervn = op->getIn(1-slot);
// Check if othervn is an offset
if (!othervn->isConstant()) {
if (othervn->isWritten()) {
PcodeOp *multop = othervn->getDef();
if (multop->code() == CPUI_INT_MULT) {
Varnode *constvn = multop->getIn(1);
if (constvn->isConstant()) {
uintb mult = constvn->getOffset();
if (mult == calc_mask(constvn->getSize())) // If multiplying by -1
return 2; // Assume this is a pointer difference and don't propagate
if (sz != 0 && (mult % sz) !=0)
return 2;
}
return 3;
}
}
if (sz == 1)
return 3;
return 2;
}
if (othervn->getTempType()->getMetatype() == TYPE_PTR) // Check if othervn marked as ptr
return 2;
off = othervn->getOffset();
return (off == 0) ? 0 : 1;
}
return 2;
}
TypeOpIntSub::TypeOpIntSub(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_SUB,"-",TYPE_INT,TYPE_INT)
{
@ -1101,6 +1388,20 @@ Datatype *TypeOpIntXor::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
return castStrategy->arithmeticOutputStandard(op);
}
Datatype *TypeOpIntXor::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) return (Datatype *)0; // Only propagate flag enums
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
newtype = tlst->getTypePointer(alttype->getSize(),tlst->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
return newtype;
}
TypeOpIntAnd::TypeOpIntAnd(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_AND,"&",TYPE_UINT,TYPE_UINT)
{
@ -1115,6 +1416,20 @@ Datatype *TypeOpIntAnd::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
return castStrategy->arithmeticOutputStandard(op);
}
Datatype *TypeOpIntAnd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) return (Datatype *)0; // Only propagate flag enums
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
newtype = tlst->getTypePointer(alttype->getSize(),tlst->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
return newtype;
}
TypeOpIntOr::TypeOpIntOr(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_OR,"|",TYPE_UINT,TYPE_UINT)
{
@ -1129,6 +1444,20 @@ Datatype *TypeOpIntOr::getOutputToken(const PcodeOp *op,CastStrategy *castStrate
return castStrategy->arithmeticOutputStandard(op);
}
Datatype *TypeOpIntOr::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (!alttype->isPowerOfTwo()) return (Datatype *)0; // Only propagate flag enums
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
newtype = tlst->getTypePointer(alttype->getSize(),tlst->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
return newtype;
}
TypeOpIntLeft::TypeOpIntLeft(TypeFactory *t)
: TypeOpBinary(t,CPUI_INT_LEFT,"<<",TYPE_INT,TYPE_INT)
{
@ -1148,7 +1477,7 @@ Datatype *TypeOpIntLeft::getInputLocal(const PcodeOp *op,int4 slot) const
Datatype *TypeOpIntLeft::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
Datatype *res1 = op->getIn(0)->getHigh()->getType();
Datatype *res1 = op->getIn(0)->getHighTypeReadFacing(op);
if (res1->getMetatype() == TYPE_BOOL)
res1 = tlst->getBase(res1->getSize(),TYPE_INT);
return res1;
@ -1176,7 +1505,7 @@ Datatype *TypeOpIntRight::getInputCast(const PcodeOp *op,int4 slot,const CastStr
if (slot == 0) {
const Varnode *vn = op->getIn(0);
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHigh()->getType();
Datatype *curtype = vn->getHighTypeReadFacing(op);
int4 promoType = castStrategy->intPromotionType(vn);
if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::UNSIGNED_EXTENSION)==0))
return reqtype;
@ -1188,7 +1517,7 @@ Datatype *TypeOpIntRight::getInputCast(const PcodeOp *op,int4 slot,const CastStr
Datatype *TypeOpIntRight::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
Datatype *res1 = op->getIn(0)->getHigh()->getType();
Datatype *res1 = op->getIn(0)->getHighTypeReadFacing(op);
if (res1->getMetatype() == TYPE_BOOL)
res1 = tlst->getBase(res1->getSize(),TYPE_INT);
return res1;
@ -1218,7 +1547,7 @@ Datatype *TypeOpIntSright::getInputCast(const PcodeOp *op,int4 slot,const CastSt
if (slot == 0) {
const Varnode *vn = op->getIn(0);
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHigh()->getType();
Datatype *curtype = vn->getHighTypeReadFacing(op);
int4 promoType = castStrategy->intPromotionType(vn);
if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::SIGNED_EXTENSION)==0))
return reqtype;
@ -1238,7 +1567,7 @@ Datatype *TypeOpIntSright::getInputLocal(const PcodeOp *op,int4 slot) const
Datatype *TypeOpIntSright::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
Datatype *res1 = op->getIn(0)->getHigh()->getType();
Datatype *res1 = op->getIn(0)->getHighTypeReadFacing(op);
if (res1->getMetatype() == TYPE_BOOL)
res1 = tlst->getBase(res1->getSize(),TYPE_INT);
return res1;
@ -1271,7 +1600,7 @@ Datatype *TypeOpIntDiv::getInputCast(const PcodeOp *op,int4 slot,const CastStrat
{
const Varnode *vn = op->getIn(slot);
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHigh()->getType();
Datatype *curtype = vn->getHighTypeReadFacing(op);
int4 promoType = castStrategy->intPromotionType(vn);
if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::UNSIGNED_EXTENSION)==0))
return reqtype;
@ -1291,7 +1620,7 @@ Datatype *TypeOpIntSdiv::getInputCast(const PcodeOp *op,int4 slot,const CastStra
{
const Varnode *vn = op->getIn(slot);
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHigh()->getType();
Datatype *curtype = vn->getHighTypeReadFacing(op);
int4 promoType = castStrategy->intPromotionType(vn);
if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::SIGNED_EXTENSION)==0))
return reqtype;
@ -1311,7 +1640,7 @@ Datatype *TypeOpIntRem::getInputCast(const PcodeOp *op,int4 slot,const CastStrat
{
const Varnode *vn = op->getIn(slot);
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHigh()->getType();
Datatype *curtype = vn->getHighTypeReadFacing(op);
int4 promoType = castStrategy->intPromotionType(vn);
if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::UNSIGNED_EXTENSION)==0))
return reqtype;
@ -1331,7 +1660,7 @@ Datatype *TypeOpIntSrem::getInputCast(const PcodeOp *op,int4 slot,const CastStra
{
const Varnode *vn = op->getIn(slot);
Datatype *reqtype = op->inputTypeLocal(slot);
Datatype *curtype = vn->getHigh()->getType();
Datatype *curtype = vn->getHighTypeReadFacing(op);
int4 promoType = castStrategy->intPromotionType(vn);
if (promoType != CastStrategy::NO_PROMOTION && ((promoType & CastStrategy::SIGNED_EXTENSION)==0))
return reqtype;
@ -1499,6 +1828,20 @@ TypeOpMulti::TypeOpMulti(TypeFactory *t) : TypeOp(t,CPUI_MULTIEQUAL,"?")
behave = new OpBehavior(CPUI_MULTIEQUAL,false,true); // Dummy behavior
}
Datatype *TypeOpMulti::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot!=-1)&&(outslot!=-1)) return (Datatype *)0; // Must propagate input <-> output
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
newtype = tlst->getTypePointer(alttype->getSize(),tlst->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
return newtype;
}
void TypeOpMulti::printRaw(ostream &s,const PcodeOp *op)
{
@ -1537,6 +1880,23 @@ Datatype *TypeOpIndirect::getInputLocal(const PcodeOp *op,int4 slot) const
return tlst->getTypePointer(op->getIn(0)->getSize(),ct,spc->getWordSize()); // Second parameter is code pointer
}
Datatype *TypeOpIndirect::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (op->isIndirectCreation()) return (Datatype *)0;
if ((inslot==1)||(outslot==1)) return (Datatype *)0;
if ((inslot!=-1)&&(outslot!=-1)) return (Datatype *)0; // Must propagate input <-> output
Datatype *newtype;
if (invn->isSpacebase()) {
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
newtype = tlst->getTypePointer(alttype->getSize(),tlst->getBase(1,TYPE_UNKNOWN),spc->getWordSize());
}
else
newtype = alttype;
return newtype;
}
void TypeOpIndirect::printRaw(ostream &s,const PcodeOp *op)
{
@ -1572,7 +1932,7 @@ Datatype *TypeOpPiece::getOutputToken(const PcodeOp *op,CastStrategy *castStrate
{
const Varnode *vn = op->getOut();
Datatype *dt = vn->getHigh()->getType();
Datatype *dt = vn->getHighTypeDefFacing();
type_metatype meta = dt->getMetatype();
if ((meta == TYPE_INT)||(meta == TYPE_UINT)) // PIECE casts to uint or int, based on output
return dt;
@ -1598,13 +1958,99 @@ string TypeOpSubpiece::getOperatorName(const PcodeOp *op) const
Datatype *TypeOpSubpiece::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
int4 offset;
Datatype *parent;
const Varnode *vn = op->getOut();
Datatype *dt = vn->getHigh()->getType(); // SUBPIECE prints as cast to whatever its output is
const TypeField *field = testExtraction(true, op, parent, offset);
if (field != (const TypeField *)0) {
if (vn->getSize() == field->type->getSize())
return field->type;
}
Datatype *dt = vn->getHighTypeDefFacing(); // SUBPIECE prints as cast to whatever its output is
if (dt->getMetatype() != TYPE_UNKNOWN)
return dt;
return tlst->getBase(vn->getSize(),TYPE_INT); // If output is unknown, treat as cast to int
}
Datatype *TypeOpSubpiece::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if (inslot != 0 || outslot != -1) return (Datatype *)0; // Propagation must be from in0 to out
int4 byteOff;
int4 newoff;
const TypeField *field;
if (alttype->getMetatype() == TYPE_UNION) {
// NOTE: We use an artificial slot here to store the field being truncated to
// as the facing data-type for slot 0 is already to the parent (this TYPE_UNION)
byteOff = computeByteOffsetForComposite(op);
field = ((TypeUnion *)alttype)->resolveTruncation(byteOff,op,1,newoff);
}
else if (alttype->getMetatype() == TYPE_STRUCT) {
int4 byteOff = computeByteOffsetForComposite(op);
field = ((TypeStruct *)alttype)->resolveTruncation(byteOff, outvn->getSize(), &newoff);
}
else
return (Datatype *)0;
if (field != (const TypeField *)0 && newoff == 0 && field->type->getSize() == outvn->getSize()) {
return field->type;
}
return (Datatype *)0;
}
/// \brief Test if the given SUBPIECE PcodeOp is acting as a field extraction operator
///
/// For packed structures with small fields, SUBPIECE may be used to extract the field.
/// Test if the HighVariable being truncated is a structure and if the truncation produces
/// part of a \e single field. If so return the TypeField descriptor, and pass back the parent
/// structure and the number of least significant bytes that have been truncated from the field.
/// \param useHigh is \b true if the HighVariable data-type is checked, otherwise the Varnode data-type is used
/// \param op is the given SUBPIECE PcodeOp
/// \param parent holds the parent Datatype being passed back
/// \param offset holds the LSB offset being passed back
/// \return the TypeField if a field is being extracted or null otherwise
const TypeField *TypeOpSubpiece::testExtraction(bool useHigh,const PcodeOp *op,Datatype *&parent,int4 &offset)
{
const Varnode *vn = op->getIn(0);
Datatype *ct = useHigh ? vn->getHigh()->getType() : vn->getType();
if (ct->getMetatype() == TYPE_STRUCT) {
parent = ct;
int4 byteOff = computeByteOffsetForComposite(op);
return ((TypeStruct *)ct)->resolveTruncation(byteOff,op->getOut()->getSize(),&offset);
}
else if (ct->getMetatype() == TYPE_UNION) {
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(ct, op, 1); // Use artificial slot
if (res != (const ResolvedUnion *)0 && res->getFieldNum() >= 0) {
parent = ct;
offset = 0;
return ((TypeUnion *)ct)->getField(res->getFieldNum());
}
}
return (const TypeField *)0;
}
/// \brief Compute the byte offset into an assumed composite data-type produced by the given CPUI_SUBPIECE
///
/// If the input Varnode is a composite data-type, the extracted result of the SUBPIECE represent a
/// range of bytes starting at a particular offset within the data-type. Return this offset, which
/// depends on endianness of the input.
/// \param op is the given CPUI_SUBPIECE
/// \return the byte offset into the composite represented by the output of the SUBPIECE
int4 TypeOpSubpiece::computeByteOffsetForComposite(const PcodeOp *op)
{
int4 outSize = op->getOut()->getSize();
int4 lsb = (int4)op->getIn(1)->getOffset();
const Varnode *vn = op->getIn(0);
int byteOff;
if (vn->getSpace()->isBigEndian())
byteOff = vn->getSize() - outSize - lsb;
else
byteOff = lsb;
return byteOff;
}
TypeOpCast::TypeOpCast(TypeFactory *t) : TypeOp(t,CPUI_CAST,"(cast)")
{
@ -1642,7 +2088,7 @@ Datatype *TypeOpPtradd::getOutputLocal(const PcodeOp *op) const
Datatype *TypeOpPtradd::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
return op->getIn(0)->getHigh()->getType(); // Cast to the input data-type
return op->getIn(0)->getHighTypeReadFacing(op); // Cast to the input data-type
}
Datatype *TypeOpPtradd::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
@ -1650,13 +2096,28 @@ Datatype *TypeOpPtradd::getInputCast(const PcodeOp *op,int4 slot,const CastStrat
{
if (slot==0) { // The operation expects the type of the VARNODE
// not the (possibly different) type of the HIGH
Datatype *reqtype = op->getIn(0)->getType();
Datatype *curtype = op->getIn(0)->getHigh()->getType();
Datatype *reqtype = op->getIn(0)->getTypeReadFacing(op);
Datatype *curtype = op->getIn(0)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,false,false);
}
return TypeOp::getInputCast(op,slot,castStrategy);
}
Datatype *TypeOpPtradd::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot == 2) || (outslot == 2)) return (Datatype *)0; // Don't propagate along this edge
if ((inslot != -1) && (outslot != -1)) return (Datatype *)0; // Must propagate input <-> output
type_metatype metain = alttype->getMetatype();
if (metain != TYPE_PTR) return (Datatype *)0;
Datatype *newtype;
if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction
else
newtype = TypeOpIntAdd::propagateAddIn2Out(alttype,tlst,op,inslot);
return newtype;
}
void TypeOpPtradd::printRaw(ostream &s,const PcodeOp *op)
{
@ -1698,8 +2159,8 @@ Datatype *TypeOpPtrsub::getInputCast(const PcodeOp *op,int4 slot,const CastStrat
{
if (slot==0) { // The operation expects the type of the VARNODE
// not the (possibly different) type of the HIGH
Datatype *reqtype = op->getIn(0)->getType();
Datatype *curtype = op->getIn(0)->getHigh()->getType();
Datatype *reqtype = op->getIn(0)->getTypeReadFacing(op);
Datatype *curtype = op->getIn(0)->getHighTypeReadFacing(op);
return castStrategy->castStandard(reqtype,curtype,false,false);
}
return TypeOp::getInputCast(op,slot,castStrategy);
@ -1708,7 +2169,7 @@ Datatype *TypeOpPtrsub::getInputCast(const PcodeOp *op,int4 slot,const CastStrat
Datatype *TypeOpPtrsub::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
TypePointer *ptype = (TypePointer *)op->getIn(0)->getHigh()->getType();
TypePointer *ptype = (TypePointer *)op->getIn(0)->getHighTypeReadFacing(op);
if (ptype->getMetatype() == TYPE_PTR) {
uintb offset = AddrSpace::addressToByte(op->getIn(1)->getOffset(),ptype->getWordSize());
uintb unusedOffset;
@ -1722,6 +2183,20 @@ Datatype *TypeOpPtrsub::getOutputToken(const PcodeOp *op,CastStrategy *castStrat
return TypeOp::getOutputToken(op,castStrategy);
}
Datatype *TypeOpPtrsub::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot!=-1)&&(outslot!=-1)) return (Datatype *)0; // Must propagate input <-> output
type_metatype metain= alttype->getMetatype();
if (metain != TYPE_PTR) return (Datatype *)0;
Datatype *newtype;
if (inslot == -1) // Propagating output to input
newtype = op->getIn(outslot)->getTempType(); // Don't propagate pointer types this direction
else
newtype = TypeOpIntAdd::propagateAddIn2Out(alttype,tlst,op,inslot);
return newtype;
}
void TypeOpPtrsub::printRaw(ostream &s,const PcodeOp *op)
{
@ -1759,7 +2234,7 @@ void TypeOpSegment::printRaw(ostream &s,const PcodeOp *op)
Datatype *TypeOpSegment::getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const
{
return op->getIn(2)->getHigh()->getType(); // Assume type of ptr portion
return op->getIn(2)->getHighTypeReadFacing(op); // Assume type of ptr portion
}
Datatype *TypeOpSegment::getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const
@ -1773,6 +2248,20 @@ Datatype *TypeOpSegment::getInputCast(const PcodeOp *op,int4 slot,const CastStra
// {
// }
Datatype *TypeOpSegment::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
// Must propagate slot2 <-> output
if ((inslot==0)||(inslot==1)) return (Datatype *)0;
if ((outslot==0)||(outslot==1)) return (Datatype *)0;
if (invn->isSpacebase()) return (Datatype *)0;
type_metatype metain = alttype->getMetatype();
if (metain != TYPE_PTR) return (Datatype *)0;
AddrSpace *spc = tlst->getArch()->getDefaultDataSpace();
Datatype *btype = ((TypePointer *)alttype)->getPtrTo();
return tlst->getTypePointer(outvn->getSize(),btype,spc->getWordSize());
}
TypeOpCpoolref::TypeOpCpoolref(TypeFactory *t) : TypeOp(t,CPUI_CPOOLREF,"cpoolref")
{
@ -1831,6 +2320,16 @@ TypeOpNew::TypeOpNew(TypeFactory *t) : TypeOp(t,CPUI_NEW,"new")
behave = new OpBehavior(CPUI_NEW,false,true); // Dummy behavior
}
Datatype *TypeOpNew::propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot)
{
if ((inslot != 0)||(outslot != -1)) return (Datatype *)0;
Varnode *vn0 = op->getIn(0);
if (!vn0->isWritten()) return (Datatype *)0; // Don't propagate
if (vn0->getDef()->code() != CPUI_CPOOLREF) return (Datatype *)0;
return alttype; // Propagate cpool result as result of new operator
}
void TypeOpNew::printRaw(ostream &s,const PcodeOp *op)
{

View file

@ -118,6 +118,10 @@ public:
/// \brief Find the data-type of the input to a specific PcodeOp
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
/// \brief Propagate an incoming data-type across a specific PcodeOp
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
/// \brief Push the specific PcodeOp to the emitter's RPN stack
///
/// Given a specific language and PcodeOp, emit the expression rooted at the operation.
@ -208,6 +212,8 @@ public:
TypeOpCopy(TypeFactory *t); ///< Constructor
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opCopy(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -219,6 +225,8 @@ public:
// virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opLoad(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -229,6 +237,8 @@ public:
TypeOpStore(TypeFactory *t); ///< Constructor
// virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opStore(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -304,6 +314,10 @@ public:
TypeOpEqual(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntEqual(op); }
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
static Datatype *propagateAcrossCompare(Datatype *alttype,TypeFactory *typegrp,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
};
/// \brief Information about the INT_NOTEQUAL op-code
@ -312,22 +326,28 @@ public:
TypeOpNotEqual(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntNotEqual(op); }
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
};
/// \brief Information about the INT_SLESS op-code
class TypeOpIntSless : public TypeOpBinary {
public:
TypeOpIntSless(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntSless(op); }
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntSless(op); }
};
/// \brief Information about the INT_SLESSEQUAL op-code
class TypeOpIntSlessEqual : public TypeOpBinary {
public:
TypeOpIntSlessEqual(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntSlessEqual(op); }
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntSlessEqual(op); }
};
/// \brief Information about the INT_LESS op-code
@ -336,6 +356,8 @@ public:
TypeOpIntLess(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntLess(op); }
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
};
/// \brief Information about the INT_LESSEQUAL op-code
@ -344,6 +366,8 @@ public:
TypeOpIntLessEqual(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntLessEqual(op); }
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
};
/// \brief Information about the INT_ZEXT op-code
@ -370,6 +394,10 @@ public:
TypeOpIntAdd(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntAdd(op); }
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
static Datatype *propagateAddIn2Out(Datatype *alttype,TypeFactory *typegrp,PcodeOp *op,int4 inslot);
static int4 propagateAddPointer(uintb &off,PcodeOp *op,int4 slot,int4 sz);
};
/// \brief Information about the INT_SUB op-code
@ -424,24 +452,30 @@ public:
class TypeOpIntXor : public TypeOpBinary {
public:
TypeOpIntXor(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntXor(op); }
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntXor(op); }
};
/// \brief Information about the INT_AND op-code
class TypeOpIntAnd : public TypeOpBinary {
public:
TypeOpIntAnd(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntAnd(op); }
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntAnd(op); }
};
/// \brief Information about the INT_OR op-code
class TypeOpIntOr : public TypeOpBinary {
public:
TypeOpIntOr(TypeFactory *t); ///< Constructor
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntOr(op); }
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIntOr(op); }
};
/// \brief Information about the INT_LEFT op-code
@ -672,6 +706,8 @@ public:
class TypeOpMulti : public TypeOp {
public:
TypeOpMulti(TypeFactory *t); ///< Constructor
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opMultiequal(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -681,6 +717,8 @@ class TypeOpIndirect : public TypeOp {
public:
TypeOpIndirect(TypeFactory *t); ///< Constructor
virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opIndirect(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -701,8 +739,12 @@ public:
// virtual Datatype *getOutputLocal(const PcodeOp *op) const;
// virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual string getOperatorName(const PcodeOp *op) const;
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opSubpiece(op); }
static const TypeField *testExtraction(bool useHigh,const PcodeOp *op,Datatype *&parent,int4 &offset);
static int4 computeByteOffsetForComposite(const PcodeOp *op);
};
/// \brief Information about the CAST op-code
@ -723,6 +765,8 @@ public:
virtual Datatype *getOutputLocal(const PcodeOp *op) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opPtradd(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -735,6 +779,8 @@ public:
virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opPtrsub(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -754,6 +800,8 @@ public:
// virtual Datatype *getInputLocal(const PcodeOp *op,int4 slot) const;
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const;
virtual Datatype *getOutputToken(const PcodeOp *op,CastStrategy *castStrategy) const;
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opSegmentOp(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};
@ -775,6 +823,8 @@ class TypeOpNew : public TypeOp {
public:
TypeOpNew(TypeFactory *t); ///< Constructor
virtual Datatype *getInputCast(const PcodeOp *op,int4 slot,const CastStrategy *castStrategy) const { return (Datatype *)0; } // Never needs casting
virtual Datatype *propagateType(Datatype *alttype,PcodeOp *op,Varnode *invn,Varnode *outvn,
int4 inslot,int4 outslot);
virtual void push(PrintLanguage *lng,const PcodeOp *op,const PcodeOp *readOp) const { lng->opNewOp(op); }
virtual void printRaw(ostream &s,const PcodeOp *op);
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,180 @@
/* ###
* IP: GHIDRA
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __UNION_RESOLVE__
#define __UNION_RESOLVE__
#include "op.hh"
/// \brief A data-type \e resolved from an associated TypeUnion or TypeStruct
///
/// A \b parent refers to either:
/// 1) A union
/// 2) A structure that is an effective union (1 field filling the entire structure) OR
/// 3) A pointer to a union/structure
///
/// This object represents a data-type that is resolved via analysis from the \b parent data-type.
/// The resolved data-type can be either:
/// 1) A specific field of the parent (if the parent is not a pointer)
/// 2) A pointer to a specific field of the underlying union/structure (if the parent is a pointer)
/// 3) The parent data-type itself (either a pointer or not)
/// The \b fieldNum (if non-negative) selects a particular field of the underlying union/structure.
/// If the parent is a pointer, the resolution is a pointer to the field.
/// If the parent is not a pointer, the resolution is the field itself.
/// A \b fieldNum of -1 indicates that the parent data-type itself is the resolution.
class ResolvedUnion {
friend class ScoreUnionFields;
Datatype *resolve; ///< The resolved data-type
Datatype *baseType; ///< Union or Structure being resolved
int4 fieldNum; ///< Index of field referenced by \b resolve
bool lock; ///< If \b true, resolution cannot be overridden
public:
ResolvedUnion(Datatype *parent); ///< Construct a data-type that resolves to itself
ResolvedUnion(Datatype *parent,int4 fldNum,TypeFactory &typegrp); ///< Construct a reference to a field
Datatype *getDatatype(void) const { return resolve; } ///< Get the resolved data-type
Datatype *getBase(void) const { return baseType; } ///< Get the union or structure being referenced
int4 getFieldNum(void) const { return fieldNum; } ///< Get the index of the resolved field or -1
bool isLocked(void) const { return lock; } ///< Is \b this locked against overrides
void setLock(bool val) { lock = val; } ///< Set whether \b this resolution is locked against overrides
};
/// \brief A data-flow edge to which a resolved data-type can be assigned
///
/// The edge is associated with the specific data-type that needs to be resolved,
/// which is typically a union or a pointer to a union. The edge collapses different
/// kinds of pointers to the same base union.
class ResolveEdge {
uint8 typeId; ///< Id of base data-type being resolved
uintm opTime; ///< Id of PcodeOp edge
int4 encoding; ///< Encoding of the slot and pointer-ness
public:
ResolveEdge(const Datatype *parent,const PcodeOp *op,int4 slot); ///< Construct from components
bool operator<(const ResolveEdge &op2) const; ///< Compare two edges
};
/// \brief Analyze data-flow to resolve which field of a union data-type is being accessed
///
/// A Varnode with a data-type that is either a union, a pointer to union, or a part of a union, can
/// be accessed in multiple ways. Each individual read (or write) of the Varnode may be accessing either
/// a specific field of the union or accessing the union as a whole. The particular access may not be
/// explicitly known but can sometimes be inferred from data-flow near the Varnode. This class scores
/// all the possible fields of a data-type involving a union for a specific Varnode.
///
/// Because the answer may be different for different accesses, the Varnode must be specified as an
/// access \e edge, a PcodeOp and a \b slot. A slot >= 0 indicates the index of a Varnode that is being read
/// by the PcodeOp, a slot == -1 indicates the output Varnode being written by the PcodeOp.
///
/// The result of scoring is returned as a ResolvedUnion record.
class ScoreUnionFields {
/// \brief A trial data-type fitted to a specific place in the data-flow
class Trial {
friend class ScoreUnionFields;
/// \brief An enumerator to distinguish how an individual trial follows data-flow
enum dir_type {
fit_down, ///< Only push the fit down \e with the data-flow
fit_up ///< Only push the fit up \e against the data-flow
};
Varnode *vn; ///< The Varnode we are testing for data-type fit
PcodeOp *op; ///< The PcodeOp reading the Varnode (or null)
int4 inslot; ///< The slot reading the Varnode (or -1)
dir_type direction; ///< Direction to push fit. 0=down 1=up
bool array; ///< Field can be accessed as an array
Datatype *fitType; ///< The putative data-type of the Varnode
int4 scoreIndex; ///< The original field being scored by \b this trial
public:
/// \brief Construct a downward trial for a Varnode
///
/// \param o is the PcodeOp reading the Varnode
/// \param slot is the input slot being read
/// \param ct is the trial data-type to fit
/// \param index is the scoring index
/// \param isArray is \b true if the data-type to fit is a pointer to an array
Trial(PcodeOp *o,int4 slot,Datatype *ct,int4 index,bool isArray) {
op = o; inslot = slot; direction = fit_down; fitType = ct; scoreIndex = index; vn = o->getIn(slot); array=isArray; }
/// \brief Construct an upward trial for a Varnode
///
/// \param v is the Varnode to fit
/// \param ct is the trial data-type to fit
/// \param index is the scoring index
/// \param isArray is \b true if the data-type to fit is a pointer to an array
Trial(Varnode *v,Datatype *ct,int4 index,bool isArray) {
vn = v; op = (PcodeOp *)0; inslot=-1; direction = fit_up; fitType = ct; scoreIndex = index; array=isArray; }
};
/// \brief A mark accumulated when a given Varnode is visited with a specific field index
class VisitMark {
Varnode *vn; ///< Varnode reached by trial field
int4 index; ///< Index of the trial field
public:
VisitMark(Varnode *v,int4 i) { vn = v; index = i; } ///< Constructor
/// \brief Compare two VisitMarks for use in a set container
///
/// \param op2 is the other VisitMark being compared with \b this
/// \return \b true if \b this should be ordered before \b op2
bool operator<(const VisitMark &op2) const {
if (vn != op2.vn)
return (vn < op2.vn);
return (index < op2.index);
}
};
TypeFactory &typegrp; ///< The factory containing data-types
vector<int4> scores; ///< Score for each field, indexed by fieldNum + 1 (whole union is index=0)
vector<Datatype *> fields; ///< Field corresponding to each score
set<VisitMark> visited; ///< Places that have already been visited
list<Trial> trialCurrent; ///< Current trials being pushed
list<Trial> trialNext; ///< Next set of trials
ResolvedUnion result; ///< The best result
int4 trialCount; ///< Number of trials evaluated so far
static const int4 maxPasses; ///< Maximum number of levels to score through
static const int4 threshold; ///< Threshold of trials over which to cancel additional passes
static const int4 maxTrials; ///< Maximum number of trials to evaluate
bool testArrayArithmetic(PcodeOp *op,int4 inslot); ///< Check if given PcodeOp is operating on array with union elements
bool testSimpleCases(PcodeOp *op,int4 inslot,Datatype *parent); ///< Preliminary checks before doing full scoring
int4 scoreLockedType(Datatype *ct,Datatype *lockType); ///< Score trial data-type against a locked data-type
int4 scoreParameter(Datatype *ct,const PcodeOp *callOp,int4 paramSlot); ///< Score trial data-type against a parameter
int4 scoreReturnType(Datatype *ct,const PcodeOp *callOp); ///< Score trial data-type against return data-type of function
Datatype *derefPointer(Datatype *ct,Varnode *vn,int4 &score); ///< Score trial data-type as a pointer to LOAD/STORE
void newTrialsDown(Varnode *vn,Datatype *ct,int4 scoreIndex,bool isArray); ///< Create new trials based an reads of given Varnode
void newTrials(PcodeOp *op,int4 slot,Datatype *ct,int4 scoreIndex,bool isArray); ///< Create new trials based on given input slot
void scoreTrialDown(const Trial &trial,bool lastLevel); ///< Try to fit the given trial following data-flow down
void scoreTrialUp(const Trial &trial,bool lastLevel); ///< Try to fit the given trial following data-flow up
Datatype *scoreTruncation(Datatype *ct,Varnode *vn,int4 offset,int4 scoreIndex); ///< Score a truncation in the data-flow
void scoreConstantFit(const Trial &trial); ///< Score trial data-type against a constant
void runOneLevel(bool lastPass); ///< Score all the current trials
void computeBestIndex(void); ///< Assuming scoring is complete, compute the best index
void run(void); ///< Calculate best fitting field
public:
ScoreUnionFields(TypeFactory &tgrp,Datatype *parentType,PcodeOp *op,int4 slot);
ScoreUnionFields(TypeFactory &tgrp,TypeUnion *unionType,int4 offset,PcodeOp *op);
ScoreUnionFields(TypeFactory &tgrp,TypeUnion *unionType,int4 offset,PcodeOp *op,int4 slot);
const ResolvedUnion &getResult(void) const { return result; } ///< Get the resulting best field resolution
};
/// Compare based on the data-type, the \b slot, and the PcodeOp's unique id.
/// \param op2 is the other edge to compare with \b this
/// \return \b true if \b this should be ordered before the other edge
inline bool ResolveEdge::operator<(const ResolveEdge &op2) const
{
if (typeId != op2.typeId)
return (typeId < op2.typeId);
if (encoding != op2.encoding)
return (encoding < op2.encoding);
return (opTime < op2.opTime);
}
#endif

View file

@ -51,7 +51,7 @@ void HighVariable::setSymbol(Varnode *vn) const
symbol = entry->getSymbol();
if (entry->isDynamic()) // Dynamic symbols match whole variable
symboloffset = -1;
else if (symbol->getCategory() == 1)
else if (symbol->getCategory() == Symbol::equate)
symboloffset = -1; // For equates, we don't care about size
else if (symbol->getType()->getSize() == vn->getSize() &&
entry->getAddr() == vn->getAddr() && !entry->isPiece())
@ -466,7 +466,7 @@ void HighVariable::saveXml(ostream &s) const
else if (isConstant())
a_v(s,"class",string("constant"));
else if (!isPersist() && (symbol != (Symbol *)0)) {
if (symbol->getCategory() == 0)
if (symbol->getCategory() == Symbol::function_parameter)
a_v(s,"class",string("param"));
else
a_v(s,"class",string("local"));

View file

@ -395,7 +395,7 @@ void ScopeLocal::markNotMapped(AddrSpace *spc,uintb first,int4 sz,bool parameter
// If the symbol and the use are both as parameters
// this is likely the special case of a shared return call sharing the parameter location
// of the original function in which case we don't print a warning
if ((!parameter) || (sym->getCategory() != 0))
if ((!parameter) || (sym->getCategory() != Symbol::function_parameter))
fd->warningHeader("Variable defined which should be unmapped: "+sym->getName());
return;
}
@ -814,7 +814,7 @@ void MapState::reconcileDatatypes(void)
maplist.swap(newList);
}
/// The given LoadGuard, which may be a LOAD or STORE is converted into an appropriate
/// The given LoadGuard, which may be a LOAD or STORE, is converted into an appropriate
/// RangeHint, attempting to make use of any data-type or index information.
/// \param guard is the given LoadGuard
/// \param opc is the expected op-code (CPUI_LOAD or CPUI_STORE)
@ -825,7 +825,7 @@ void MapState::addGuard(const LoadGuard &guard,OpCode opc,TypeFactory *typeFacto
if (!guard.isValid(opc)) return;
int4 step = guard.getStep();
if (step == 0) return; // No definitive sign of array access
Datatype *ct = guard.getOp()->getIn(1)->getType();
Datatype *ct = guard.getOp()->getIn(1)->getTypeReadFacing(guard.getOp());
if (ct->getMetatype() == TYPE_PTR) {
ct = ((TypePointer *) ct)->getPtrTo();
while (ct->getMetatype() == TYPE_ARRAY)
@ -1157,7 +1157,7 @@ void ScopeLocal::markUnaliased(const vector<uintb> &alias)
void ScopeLocal::fakeInputSymbols(void)
{
int4 lockedinputs = getCategorySize(0);
int4 lockedinputs = getCategorySize(Symbol::function_parameter);
VarnodeDefSet::const_iterator iter,enditer;
iter = fd->beginDef(Varnode::input);
@ -1194,7 +1194,7 @@ void ScopeLocal::fakeInputSymbols(void)
uint4 vflags = 0;
SymbolEntry *entry = queryProperties(vn->getAddr(),vn->getSize(),usepoint,vflags);
if (entry != (SymbolEntry *)0) {
if (entry->getSymbol()->getCategory()==0)
if (entry->getSymbol()->getCategory()==Symbol::function_parameter)
continue; // Found a matching symbol
}
}

View file

@ -564,6 +564,58 @@ Varnode::~Varnode(void)
}
}
/// This generally just returns the data-type of the Varnode itself unless it is a \e union data-type.
/// In this case, the data-type of the resolved field of the \e union, associated with writing to the Varnode,
/// is returned. The Varnode \b must be written to, to call this method.
/// \return the resolved data-type
Datatype *Varnode::getTypeDefFacing(void) const
{
if (!type->needsResolution())
return type;
return type->findResolve(def,-1);
}
/// This generally just returns the data-type of the Varnode itself unless it is a \e union data-type.
/// In this case, the data-type of the resolved field of the \e union, associated with reading the Varnode,
/// is returned.
/// \param op is the PcodeOp reading \b this Varnode
/// \return the resolved data-type
Datatype *Varnode::getTypeReadFacing(const PcodeOp *op) const
{
if (!type->needsResolution())
return type;
return type->findResolve(op, op->getSlot(this));
}
/// This generally just returns the data-type of the HighVariable associated with \b this, unless it is a
/// \e union data-type. In this case, the data-type of the resolved field of the \e union, associated with
/// writing to the Varnode, is returned.
/// \return the resolved data-type
Datatype *Varnode::getHighTypeDefFacing(void) const
{
Datatype *ct = high->getType();
if (!ct->needsResolution())
return ct;
return ct->findResolve(def,-1);
}
/// This generally just returns the data-type of the HighVariable associated with \b this, unless it is a
/// \e union data-type. In this case, the data-type of the resolved field of the \e union, associated with
/// reading the Varnode, is returned.
/// \param op is the PcodeOp reading \b this Varnode
/// \return the resolved data-type
Datatype *Varnode::getHighTypeReadFacing(const PcodeOp *op) const
{
Datatype *ct = high->getType();
if (!ct->needsResolution())
return ct;
return ct->findResolve(op, op->getSlot(this));
}
/// This is a convenience method for quickly finding the unique PcodeOp that reads this Varnode
/// \return only descendant (if there is 1 and ONLY 1) or \b null otherwise
PcodeOp *Varnode::loneDescend(void) const

View file

@ -118,7 +118,8 @@ public:
locked_input = 0x100, ///< Input that exists even if its unused
spacebase_placeholder = 0x200, ///< This varnode is inserted artificially to track a register
///< value at a specific point in the code
stop_uppropagation = 0x400 ///< Data-types do not propagate from an output into \b this
stop_uppropagation = 0x400, ///< Data-types do not propagate from an output into \b this
has_implied_field = 0x800 ///< The varnode is implied but also has a data-type that needs resolution
};
private:
mutable uint4 flags; ///< The collection of boolean attributes for this Varnode
@ -176,6 +177,10 @@ public:
SymbolEntry *getSymbolEntry(void) const { return mapentry; } ///< Get symbol and scope information associated with this Varnode
uint4 getFlags(void) const { return flags; } ///< Get all the boolean attributes
Datatype *getType(void) const { return type; } ///< Get the Datatype associated with this Varnode
Datatype *getTypeDefFacing(void) const; ///< Return the data-type of \b this when it is written to
Datatype *getTypeReadFacing(const PcodeOp *op) const; ///< Get the data-type of \b this when it is read by the given PcodeOp
Datatype *getHighTypeDefFacing(void) const; ///< Return the data-type of the HighVariable when \b this is written to
Datatype *getHighTypeReadFacing(const PcodeOp *op) const; ///< Return data-type of the HighVariable when read by the given PcodeOp
void setTempType(Datatype *t) const { temp.dataType = t; } ///< Set the temporary Datatype
Datatype *getTempType(void) const { return temp.dataType; } ///< Get the temporary Datatype (used during type propagation)
void setValueSet(ValueSet *v) const { temp.valueSet = v; } ///< Set the temporary ValueSet record
@ -245,6 +250,7 @@ public:
bool isStackStore(void) const { return ((addlflags&Varnode::stack_store)!=0); } ///< Was this originally produced by an explicit STORE
bool isLockedInput(void) const { return ((addlflags&Varnode::locked_input)!=0); } ///< Is always an input, even if unused
bool stopsUpPropagation(void) const { return ((addlflags&Varnode::stop_uppropagation)!=0); } ///< Is data-type propagation stopped
bool hasImpliedField(void) const { return ((addlflags&Varnode::has_implied_field)!=0); } ///< Does \b this have an implied field
/// Is \b this just a special placeholder representing INDIRECT creation?
bool isIndirectZero(void) const { return ((flags&(Varnode::indirect_creation|Varnode::constant))==(Varnode::indirect_creation|Varnode::constant)); }
@ -305,6 +311,7 @@ public:
void setUnsignedPrint(void) { addlflags |= Varnode::unsignedprint; } ///< Force \b this to be printed as unsigned
void setStopUpPropagation(void) { addlflags |= Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this
void clearStopUpPropagation(void) { addlflags &= ~Varnode::stop_uppropagation; } ///< Stop up-propagation thru \b this
void setImpliedField(void) { addlflags |= Varnode::has_implied_field; } ///< Mark \this as having an implied field
bool updateType(Datatype *ct,bool lock,bool override); ///< (Possibly) set the Datatype given various restrictions
void setStackStore(void) { addlflags |= Varnode::stack_store; } ///< Mark as produced by explicit CPUI_STORE
void setLockedInput(void) { addlflags |= Varnode::locked_input; } ///< Mark as existing input, even if unused