mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-27 21:26:02 +08:00
GP-6492 Adjustments to union scoring
This commit is contained in:
@@ -205,7 +205,13 @@ StringSequence::StringSequence(Funcdata &fdata,Datatype *ct,SymbolEntry *ent,Pco
|
|||||||
break;
|
break;
|
||||||
arrayType = parentType;
|
arrayType = parentType;
|
||||||
lastOff = off;
|
lastOff = off;
|
||||||
parentType = parentType->getSubType(off, &off);
|
if (parentType->needsResolution()) {
|
||||||
|
const TypeField *field = parentType->resolveTruncation(off, root, -1, off); // Resolve thru the specific COPY
|
||||||
|
if (field == (const TypeField *)0) break;
|
||||||
|
parentType = field->type;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
parentType = parentType->getSubType(off, &off);
|
||||||
} while(parentType != (Datatype *)0);
|
} while(parentType != (Datatype *)0);
|
||||||
if (parentType != ct || arrayType == (Datatype *)0 || arrayType->getMetatype() != TYPE_ARRAY)
|
if (parentType != ct || arrayType == (Datatype *)0 || arrayType->getMetatype() != TYPE_ARRAY)
|
||||||
return;
|
return;
|
||||||
@@ -296,8 +302,20 @@ Varnode *StringSequence::constructTypedPointer(PcodeOp *insertPoint)
|
|||||||
if (baseType->getMetatype() == TYPE_ARRAY)
|
if (baseType->getMetatype() == TYPE_ARRAY)
|
||||||
elSize = ((TypeArray *)baseType)->getBase()->getAlignSize();
|
elSize = ((TypeArray *)baseType)->getBase()->getAlignSize();
|
||||||
int8 newOff;
|
int8 newOff;
|
||||||
baseType = baseType->getSubType(curOff, &newOff );
|
if (baseType->needsResolution()) {
|
||||||
if (baseType == (Datatype *)0) break;
|
const TypeField *field = baseType->resolveTruncation(curOff, insertPoint, -1, newOff);
|
||||||
|
if (field != (const TypeField *)0) {
|
||||||
|
baseType = field->type;
|
||||||
|
curOff = newOff;
|
||||||
|
continue; // Do not create PTRSUB for union resolution here
|
||||||
|
}
|
||||||
|
else
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
baseType = baseType->getSubType(curOff, &newOff );
|
||||||
|
if (baseType == (Datatype *)0) break;
|
||||||
|
}
|
||||||
curOff -= newOff;
|
curOff -= newOff;
|
||||||
baseOff = AddrSpace::byteToAddress(curOff, spc->getWordSize());
|
baseOff = AddrSpace::byteToAddress(curOff, spc->getWordSize());
|
||||||
if (elSize >= 0) {
|
if (elSize >= 0) {
|
||||||
@@ -318,6 +336,8 @@ Varnode *StringSequence::constructTypedPointer(PcodeOp *insertPoint)
|
|||||||
data.opSetInput(ptrsub,data.newConstant(spacePtr->getSize(), baseOff), 1);
|
data.opSetInput(ptrsub,data.newConstant(spacePtr->getSize(), baseOff), 1);
|
||||||
}
|
}
|
||||||
data.opSetInput(ptrsub,spacePtr,0);
|
data.opSetInput(ptrsub,spacePtr,0);
|
||||||
|
if (curType->needsResolution())
|
||||||
|
data.inheritUnionFieldPtr(curType, ptrsub, 0, insertPoint, -1);
|
||||||
spacePtr = data.newUniqueOut(spacePtr->getSize(), ptrsub);
|
spacePtr = data.newUniqueOut(spacePtr->getSize(), ptrsub);
|
||||||
data.opInsertBefore(ptrsub, insertPoint);
|
data.opInsertBefore(ptrsub, insertPoint);
|
||||||
curType = types->getTypePointerStripArray(spacePtr->getSize(), baseType, spc->getWordSize());
|
curType = types->getTypePointerStripArray(spacePtr->getSize(), baseType, spc->getWordSize());
|
||||||
@@ -364,6 +384,8 @@ PcodeOp *StringSequence::buildStringCopy(void)
|
|||||||
Varnode *destPtr = constructTypedPointer(insertPoint);
|
Varnode *destPtr = constructTypedPointer(insertPoint);
|
||||||
data.opSetInput(copyOp, destPtr, 1);
|
data.opSetInput(copyOp, destPtr, 1);
|
||||||
data.opSetInput(copyOp, srcPtr, 2);
|
data.opSetInput(copyOp, srcPtr, 2);
|
||||||
|
if (destPtr->getType()->needsResolution())
|
||||||
|
data.inheritUnionFieldPtr(destPtr->getType(), copyOp, 1, insertPoint, -1);
|
||||||
Varnode *lenVn = data.newConstant(4,index);
|
Varnode *lenVn = data.newConstant(4,index);
|
||||||
lenVn->updateType(copyOp->inputTypeLocal(3));
|
lenVn->updateType(copyOp->inputTypeLocal(3));
|
||||||
data.opSetInput(copyOp, lenVn, 3);
|
data.opSetInput(copyOp, lenVn, 3);
|
||||||
@@ -460,12 +482,12 @@ bool StringSequence::transform(void)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// From a starting pointer, backtrack through PTRADDs and COPYs to a putative root Varnode pointer.
|
/// From a starting pointer to \b rootOp, backtrack through PTRADDs and COPYs to a putative root Varnode pointer.
|
||||||
/// \param initPtr is pointer Varnode into the root STORE
|
void HeapSequence::findBasePointer(void)
|
||||||
void HeapSequence::findBasePointer(Varnode *initPtr)
|
|
||||||
|
|
||||||
{
|
{
|
||||||
basePointer = initPtr;
|
basePointer = rootOp->getIn(1);
|
||||||
|
immedRead = rootOp;
|
||||||
while(basePointer->isWritten()) {
|
while(basePointer->isWritten()) {
|
||||||
PcodeOp *op = basePointer->getDef();
|
PcodeOp *op = basePointer->getDef();
|
||||||
OpCode opc = op->code();
|
OpCode opc = op->code();
|
||||||
@@ -476,6 +498,7 @@ void HeapSequence::findBasePointer(Varnode *initPtr)
|
|||||||
else if (opc != CPUI_COPY)
|
else if (opc != CPUI_COPY)
|
||||||
break;
|
break;
|
||||||
basePointer = op->getIn(0);
|
basePointer = op->getIn(0);
|
||||||
|
immedRead = op;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -745,6 +768,8 @@ PcodeOp *HeapSequence::buildStringCopy(void)
|
|||||||
data.opSetInput(ptrAdd,data.newConstant(basePointer->getSize(), charType->getAlignSize()),2);
|
data.opSetInput(ptrAdd,data.newConstant(basePointer->getSize(), charType->getAlignSize()),2);
|
||||||
destPtr->updateType(charPtrType);
|
destPtr->updateType(charPtrType);
|
||||||
data.opInsertBefore(ptrAdd, insertPoint);
|
data.opInsertBefore(ptrAdd, insertPoint);
|
||||||
|
if (basePointer->getType()->needsResolution())
|
||||||
|
data.inheritUnionField(basePointer->getType(), ptrAdd, 0, immedRead, immedRead->getSlot(basePointer));
|
||||||
}
|
}
|
||||||
int4 index;
|
int4 index;
|
||||||
uint4 builtInId = selectStringCopyFunction(index);
|
uint4 builtInId = selectStringCopyFunction(index);
|
||||||
@@ -758,6 +783,8 @@ PcodeOp *HeapSequence::buildStringCopy(void)
|
|||||||
lenVn->updateType(copyOp->inputTypeLocal(3));
|
lenVn->updateType(copyOp->inputTypeLocal(3));
|
||||||
data.opSetInput(copyOp, lenVn, 3);
|
data.opSetInput(copyOp, lenVn, 3);
|
||||||
data.opInsertBefore(copyOp, insertPoint);
|
data.opInsertBefore(copyOp, insertPoint);
|
||||||
|
if (destPtr->getType()->needsResolution())
|
||||||
|
data.inheritUnionField(destPtr->getType(), copyOp, 1, immedRead, immedRead->getSlot(destPtr));
|
||||||
return copyOp;
|
return copyOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,7 +937,7 @@ HeapSequence::HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root)
|
|||||||
baseOffset = 0;
|
baseOffset = 0;
|
||||||
storeSpace = root->getIn(0)->getSpaceFromConst();
|
storeSpace = root->getIn(0)->getSpaceFromConst();
|
||||||
ptrAddMult = AddrSpace::byteToAddressInt(charType->getAlignSize(), storeSpace->getWordSize());
|
ptrAddMult = AddrSpace::byteToAddressInt(charType->getAlignSize(), storeSpace->getWordSize());
|
||||||
findBasePointer(rootOp->getIn(1));
|
findBasePointer();
|
||||||
if (!collectStoreOps())
|
if (!collectStoreOps())
|
||||||
return;
|
return;
|
||||||
if (!checkInterference())
|
if (!checkInterference())
|
||||||
@@ -956,7 +983,7 @@ int4 RuleStringCopy::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
{
|
{
|
||||||
if (!op->getIn(0)->isConstant()) return 0; // Constant
|
if (!op->getIn(0)->isConstant()) return 0; // Constant
|
||||||
Varnode *outvn = op->getOut();
|
Varnode *outvn = op->getOut();
|
||||||
Datatype *ct = outvn->getType();
|
Datatype *ct = outvn->getTypeDefFacing();
|
||||||
if (!ct->isCharPrint()) return 0; // Copied to a "char" data-type Varnode
|
if (!ct->isCharPrint()) return 0; // Copied to a "char" data-type Varnode
|
||||||
if (ct->isOpaqueString()) return 0;
|
if (ct->isOpaqueString()) return 0;
|
||||||
if (!outvn->isAddrTied()) return 0;
|
if (!outvn->isAddrTied()) return 0;
|
||||||
|
|||||||
@@ -95,11 +95,12 @@ class HeapSequence : public ArraySequence {
|
|||||||
static bool compareOutput(const IndirectPair *a,const IndirectPair *b); ///< Compare pairs by output storage
|
static bool compareOutput(const IndirectPair *a,const IndirectPair *b); ///< Compare pairs by output storage
|
||||||
};
|
};
|
||||||
Varnode *basePointer; ///< Pointer that sequence is stored to
|
Varnode *basePointer; ///< Pointer that sequence is stored to
|
||||||
|
PcodeOp *immedRead; ///< Op immediately reading basePointer
|
||||||
uint8 baseOffset; ///< Offset relative to pointer to root STORE
|
uint8 baseOffset; ///< Offset relative to pointer to root STORE
|
||||||
AddrSpace *storeSpace; ///< Address space being STOREed to
|
AddrSpace *storeSpace; ///< Address space being STOREed to
|
||||||
int4 ptrAddMult; ///< Required multiplier for PTRADD ops
|
int4 ptrAddMult; ///< Required multiplier for PTRADD ops
|
||||||
vector<Varnode *> nonConstAdds; ///< non-constant Varnodes being added into pointer calculation
|
vector<Varnode *> nonConstAdds; ///< non-constant Varnodes being added into pointer calculation
|
||||||
void findBasePointer(Varnode *initPtr); ///< Find the base pointer for the sequence
|
void findBasePointer(void); ///< Find the base pointer for the sequence
|
||||||
void findDuplicateBases(vector<Varnode *> &duplist); ///< Find any duplicates of \b basePointer
|
void findDuplicateBases(vector<Varnode *> &duplist); ///< Find any duplicates of \b basePointer
|
||||||
void findInitialStores(vector<PcodeOp *> &stores);
|
void findInitialStores(vector<PcodeOp *> &stores);
|
||||||
static uint8 calcAddElements(Varnode *vn,vector<Varnode *> &nonConst,int4 maxDepth);
|
static uint8 calcAddElements(Varnode *vn,vector<Varnode *> &nonConst,int4 maxDepth);
|
||||||
|
|||||||
@@ -2454,23 +2454,54 @@ bool ActionSetCasts::testStructOffset0(Datatype *reqtype,Datatype *curtype,CastS
|
|||||||
return (castStrategy->castStandard(reqtype, curtype, true, true) == (Datatype *)0);
|
return (castStrategy->castStandard(reqtype, curtype, true, true) == (Datatype *)0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Try to adjust the input and output Varnodes to eliminate a CAST
|
/// \brief Try to eliminate a CAST for a data-type needing resolution by matching the data-type needed by the p-code op
|
||||||
|
///
|
||||||
|
/// Merging can cause the high data-type to become unresolved even though the underlying data-type requires a specific
|
||||||
|
/// resolution. This forces the resolution onto the high, if possible, in the context of the specific read or write.
|
||||||
|
/// \param dt is the data-type needed by the p-code op
|
||||||
|
/// \param op is the p-code op
|
||||||
|
/// \param slot is the index of the slot to test for resolution (-1 for output, >= 0 for input)
|
||||||
|
/// \return \b true if the resolution was successfully changed and a CAST is not needed
|
||||||
|
bool ActionSetCasts::tryResolutionAdjustment(Datatype *dt,PcodeOp *op,int4 slot,Funcdata &data)
|
||||||
|
|
||||||
|
{
|
||||||
|
if (dt->needsResolution()) return false;
|
||||||
|
Varnode *vn = (slot < 0) ? op->getOut() : op->getIn(slot);
|
||||||
|
Datatype *curType = vn->getHigh()->getType();
|
||||||
|
if (!curType->needsResolution()) return false;
|
||||||
|
if (slot < 0 && curType->getMetatype() == TYPE_PTR) return false; // Cannot take field of pointer during assignment
|
||||||
|
int4 fieldNum = curType->findCompatibleResolve(dt);
|
||||||
|
if (fieldNum < 0) return false;
|
||||||
|
TypeFactory *typegrp = data.getArch()->types;
|
||||||
|
ResolvedUnion resolve(curType,fieldNum,*typegrp);
|
||||||
|
if (!data.setUnionField(curType, op, slot, resolve))
|
||||||
|
return false;
|
||||||
|
if (slot >=0 && curType->getMetatype() == TYPE_PTR) {
|
||||||
|
if (vn->isWritten() && (vn->getDef()->code() != CPUI_PTRSUB || vn->getDef()->getIn(0)->getType() != curType)) {
|
||||||
|
// For pointers, if not already inserted, insert a PTRSUB representing the field access
|
||||||
|
PcodeOp *ptrsub = insertPtrsubZero(op,slot,resolve.getDatatype(),data);
|
||||||
|
data.setUnionField(curType, ptrsub,-1,resolve); // Attach the resolution to the PTRSUB
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Try to adjust the input and output Varnodes to a COPY, in order to eliminate a CAST
|
||||||
///
|
///
|
||||||
/// If input/output data-types are different, it may be due to late merges. For
|
/// 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
|
/// unions, the CAST can sometimes be eliminated by adjusting the data-type resolutions
|
||||||
/// of the Varnodes relative to the PcodeOp
|
/// of the Varnodes relative to the PcodeOp
|
||||||
/// \param op is the PcodeOp reading the input Varnode and writing the output Varnode
|
/// \param op is the COPY
|
||||||
/// \param slot is the index of the input Varnode
|
|
||||||
/// \param data is the function
|
/// \param data is the function
|
||||||
/// \return \b true if an adjustment is made so that a CAST is no longer needed
|
/// \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)
|
bool ActionSetCasts::tryResolutionCopy(PcodeOp *op,Funcdata &data)
|
||||||
|
|
||||||
{
|
{
|
||||||
Varnode *outvn = op->getOut();
|
Varnode *outvn = op->getOut();
|
||||||
if (outvn == (Varnode *)0)
|
if (outvn == (Varnode *)0)
|
||||||
return false;
|
return false;
|
||||||
Datatype *outType = outvn->getHigh()->getType();
|
Datatype *outType = outvn->getHigh()->getType();
|
||||||
Datatype *inType = op->getIn(slot)->getHigh()->getType();
|
Datatype *inType = op->getIn(0)->getHigh()->getType();
|
||||||
if (!inType->needsResolution() && !outType->needsResolution()) return false;
|
if (!inType->needsResolution() && !outType->needsResolution()) return false;
|
||||||
int4 inResolve = -1;
|
int4 inResolve = -1;
|
||||||
int4 outResolve = -1;
|
int4 outResolve = -1;
|
||||||
@@ -2478,7 +2509,7 @@ bool ActionSetCasts::tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &dat
|
|||||||
inResolve = inType->findCompatibleResolve(outType);
|
inResolve = inType->findCompatibleResolve(outType);
|
||||||
if (inResolve < 0) return false;
|
if (inResolve < 0) return false;
|
||||||
}
|
}
|
||||||
if (outType->needsResolution()) {
|
if (outType->needsResolution() && outType->getMetatype() != TYPE_PTR) {
|
||||||
if (inResolve >= 0)
|
if (inResolve >= 0)
|
||||||
outResolve = outType->findCompatibleResolve(inType->getDepend(inResolve));
|
outResolve = outType->findCompatibleResolve(inType->getDepend(inResolve));
|
||||||
else
|
else
|
||||||
@@ -2487,12 +2518,12 @@ bool ActionSetCasts::tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
TypeFactory *typegrp = data.getArch()->types;
|
TypeFactory *typegrp = data.getArch()->types;
|
||||||
if (inType->needsResolution()) {
|
if (inResolve >= 0) {
|
||||||
ResolvedUnion resolve(inType,inResolve,*typegrp);
|
ResolvedUnion resolve(inType,inResolve,*typegrp);
|
||||||
if (!data.setUnionField(inType, op, slot, resolve))
|
if (!data.setUnionField(inType, op, 0, resolve))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (outType->needsResolution()) {
|
if (outResolve >= 0) {
|
||||||
ResolvedUnion resolve(outType,outResolve,*typegrp);
|
ResolvedUnion resolve(outType,outResolve,*typegrp);
|
||||||
if (!data.setUnionField(outType, op, -1, resolve))
|
if (!data.setUnionField(outType, op, -1, resolve))
|
||||||
return false;
|
return false;
|
||||||
@@ -2537,10 +2568,12 @@ int4 ActionSetCasts::resolveUnion(PcodeOp *op,int4 slot,Funcdata &data,CastStrat
|
|||||||
Datatype *dt = vn->getHigh()->getType();
|
Datatype *dt = vn->getHigh()->getType();
|
||||||
if (!dt->needsResolution())
|
if (!dt->needsResolution())
|
||||||
return 0;
|
return 0;
|
||||||
if (dt != vn->getType())
|
const ResolvedUnion *resUnion = data.getUnionField(dt, op, slot);
|
||||||
|
if (resUnion == (ResolvedUnion *)0) {
|
||||||
dt->resolveInFlow(op, slot); // Last chance to resolve data-type based on flow
|
dt->resolveInFlow(op, slot); // Last chance to resolve data-type based on flow
|
||||||
const ResolvedUnion *resUnion = data.getUnionField(dt, op,slot);
|
resUnion = data.getUnionField(dt, op, slot);
|
||||||
if (resUnion != (ResolvedUnion*)0 && resUnion->getFieldNum() >= 0) {
|
}
|
||||||
|
if (resUnion != (ResolvedUnion *)0 && resUnion->getFieldNum() >= 0) {
|
||||||
if (dt->getMetatype() == TYPE_PTR) {
|
if (dt->getMetatype() == TYPE_PTR) {
|
||||||
// Test if a cast is still needed even after resolution
|
// Test if a cast is still needed even after resolution
|
||||||
Datatype *reqtype = vn->getTypeReadFacing(op);
|
Datatype *reqtype = vn->getTypeReadFacing(op);
|
||||||
@@ -2577,12 +2610,11 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
|||||||
Datatype *outct,*ct,*tokenct;
|
Datatype *outct,*ct,*tokenct;
|
||||||
Varnode *vn,*outvn;
|
Varnode *vn,*outvn;
|
||||||
PcodeOp *newop;
|
PcodeOp *newop;
|
||||||
Datatype *outHighType;
|
|
||||||
bool force=false;
|
bool force=false;
|
||||||
|
|
||||||
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
|
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
|
||||||
outvn = op->getOut();
|
outvn = op->getOut();
|
||||||
outHighType = outvn->getHigh()->getType();
|
Datatype *outHighType = outvn->getHigh()->getType();
|
||||||
if (tokenct == outHighType) {
|
if (tokenct == outHighType) {
|
||||||
if (tokenct->needsResolution()) {
|
if (tokenct->needsResolution()) {
|
||||||
// operation copies directly to outvn AS a union
|
// operation copies directly to outvn AS a union
|
||||||
@@ -2592,12 +2624,7 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
|||||||
// Short circuit more sophisticated casting tests. If they are the same type, there is no cast
|
// Short circuit more sophisticated casting tests. If they are the same type, there is no cast
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
Datatype *outHighResolve = outHighType;
|
Datatype *outHighResolve = outvn->getHighTypeDefFacing();
|
||||||
if (outHighType->needsResolution()) {
|
|
||||||
if (outHighType != outvn->getType())
|
|
||||||
outHighType->resolveInFlow(op, -1); // Last chance to resolve data-type based on flow
|
|
||||||
outHighResolve = outHighType->findResolve(op, -1); // Finish fetching DefFacing data-type
|
|
||||||
}
|
|
||||||
if (outvn->isImplied()) {
|
if (outvn->isImplied()) {
|
||||||
// implied varnode must have parse type
|
// implied varnode must have parse type
|
||||||
if (outvn->isTypeLock()) {
|
if (outvn->isTypeLock()) {
|
||||||
@@ -2632,6 +2659,8 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
|||||||
ct = castStrategy->castStandard(outct,tokenct,false,true);
|
ct = castStrategy->castStandard(outct,tokenct,false,true);
|
||||||
if (ct == (Datatype *)0) return 0;
|
if (ct == (Datatype *)0) return 0;
|
||||||
}
|
}
|
||||||
|
if (tryResolutionAdjustment(tokenct, op, -1, data))
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
// Generate the cast op
|
// Generate the cast op
|
||||||
vn = data.newUnique(outvn->getSize());
|
vn = data.newUnique(outvn->getSize());
|
||||||
@@ -2652,7 +2681,7 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
|||||||
if (tokenct->needsResolution())
|
if (tokenct->needsResolution())
|
||||||
data.forceFacingType(tokenct, -1, newop, 0);
|
data.forceFacingType(tokenct, -1, newop, 0);
|
||||||
if (outHighType->needsResolution())
|
if (outHighType->needsResolution())
|
||||||
data.inheritResolution(outHighType, newop, -1, op, -1); // Inherit write resolution
|
data.inheritUnionField(outHighType, newop, -1, op, -1); // Inherit write resolution
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -2735,10 +2764,12 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy
|
|||||||
// Insert a PTRSUB(vn,#0) instead of a CAST
|
// Insert a PTRSUB(vn,#0) instead of a CAST
|
||||||
newop = insertPtrsubZero(op, slot, ct, data);
|
newop = insertPtrsubZero(op, slot, ct, data);
|
||||||
if (vn->getHigh()->getType()->needsResolution())
|
if (vn->getHigh()->getType()->needsResolution())
|
||||||
data.inheritResolution(vn->getHigh()->getType(),newop, 0, op, slot);
|
data.inheritUnionField(vn->getHigh()->getType(),newop, 0, op, slot);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else if (tryResolutionAdjustment(op, slot, data)) {
|
else if (op->code() != CPUI_COPY && tryResolutionAdjustment(ct, op, slot, data))
|
||||||
|
return 1;
|
||||||
|
else if (op->code() == CPUI_COPY && tryResolutionCopy(op, data)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
newop = data.newOp(1,op->getAddr());
|
newop = data.newOp(1,op->getAddr());
|
||||||
@@ -2756,7 +2787,7 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy
|
|||||||
data.forceFacingType(ct, -1, newop, -1);
|
data.forceFacingType(ct, -1, newop, -1);
|
||||||
}
|
}
|
||||||
if (vn->getHigh()->getType()->needsResolution()) {
|
if (vn->getHigh()->getType()->needsResolution()) {
|
||||||
data.inheritResolution(vn->getHigh()->getType(),newop, 0, op, slot);
|
data.inheritUnionField(vn->getHigh()->getType(),newop, 0, op, slot);
|
||||||
}
|
}
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -2796,9 +2827,18 @@ int4 ActionSetCasts::apply(Funcdata &data)
|
|||||||
data.opSetOpcode(op, CPUI_INT_ADD);
|
data.opSetOpcode(op, CPUI_INT_ADD);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Do input casts first, as output may depend on input
|
// Allow unresolved high data-types to resolve
|
||||||
for(int4 i=0;i<op->numInput();++i) {
|
for(int4 i=0;i<op->numInput();++i) {
|
||||||
count += resolveUnion(op, i, data, castStrategy);
|
count += resolveUnion(op, i, data, castStrategy);
|
||||||
|
}
|
||||||
|
Varnode *vn = op->getOut();
|
||||||
|
if (vn != (Varnode *)0) {
|
||||||
|
Datatype *outHighType = vn->getHigh()->getType();
|
||||||
|
if (outHighType->needsResolution())
|
||||||
|
outHighType->resolveInFlow(op, -1); // Last chance to resolve data-type based on flow
|
||||||
|
}
|
||||||
|
// Do input casts first, as output may depend on input
|
||||||
|
for(int4 i=0;i<op->numInput();++i) {
|
||||||
count += castInput(op,i,data,castStrategy);
|
count += castInput(op,i,data,castStrategy);
|
||||||
}
|
}
|
||||||
if (opc == CPUI_LOAD) {
|
if (opc == CPUI_LOAD) {
|
||||||
@@ -2807,9 +2847,8 @@ int4 ActionSetCasts::apply(Funcdata &data)
|
|||||||
else if (opc == CPUI_STORE) {
|
else if (opc == CPUI_STORE) {
|
||||||
checkPointerIssues(op, op->getIn(2), data);
|
checkPointerIssues(op, op->getIn(2), data);
|
||||||
}
|
}
|
||||||
Varnode *vn = op->getOut();
|
if (vn != (Varnode *)0)
|
||||||
if (vn == (Varnode *)0) continue;
|
count += castOutput(op,data,castStrategy);
|
||||||
count += castOutput(op,data,castStrategy);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return 0; // Indicate full completion
|
return 0; // Indicate full completion
|
||||||
@@ -5127,13 +5166,15 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
|
|||||||
{
|
{
|
||||||
Varnode *invn,*outvn;
|
Varnode *invn,*outvn;
|
||||||
|
|
||||||
|
if (inslot == outslot) return false; // don't backtrack
|
||||||
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
|
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
|
||||||
Datatype *alttype = invn->getTempType();
|
Datatype *alttype = invn->getTempType();
|
||||||
if (alttype->needsResolution()) {
|
if (alttype->needsResolution()) {
|
||||||
// Always give incoming data-type a chance to resolve, even if it would not otherwise propagate
|
// Always give incoming data-type a chance to resolve, even if it would not otherwise propagate
|
||||||
alttype = alttype->resolveInFlow(op, inslot);
|
Datatype *resType = alttype->resolveInFlow(op, inslot);
|
||||||
|
if (!op->isMarker())
|
||||||
|
alttype = resType;
|
||||||
}
|
}
|
||||||
if (inslot == outslot) return false; // don't backtrack
|
|
||||||
if (outslot < 0)
|
if (outslot < 0)
|
||||||
outvn = op->getOut();
|
outvn = op->getOut();
|
||||||
else {
|
else {
|
||||||
|
|||||||
@@ -320,7 +320,8 @@ public:
|
|||||||
class ActionSetCasts : public Action {
|
class ActionSetCasts : public Action {
|
||||||
static void checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data);
|
static void checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data);
|
||||||
static bool testStructOffset0(Datatype *reqtype,Datatype *curtype,CastStrategy *castStrategy);
|
static bool testStructOffset0(Datatype *reqtype,Datatype *curtype,CastStrategy *castStrategy);
|
||||||
static bool tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &data);
|
static bool tryResolutionAdjustment(Datatype *dt,PcodeOp *op,int4 slot,Funcdata &data);
|
||||||
|
static bool tryResolutionCopy(PcodeOp *op,Funcdata &data);
|
||||||
static bool isOpIdentical(Datatype *ct1,Datatype *ct2);
|
static bool isOpIdentical(Datatype *ct1,Datatype *ct2);
|
||||||
static int4 resolveUnion(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy);
|
static int4 resolveUnion(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy *castStrategy);
|
||||||
static int4 castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStrategy);
|
static int4 castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStrategy);
|
||||||
|
|||||||
@@ -688,11 +688,13 @@ void EquateSymbol::decode(Decoder &decoder)
|
|||||||
/// \param nm is the name of the symbol
|
/// \param nm is the name of the symbol
|
||||||
/// \param unionDt is the union data-type being forced
|
/// \param unionDt is the union data-type being forced
|
||||||
/// \param fldNum is the particular field to force (-1 indicates the whole union)
|
/// \param fldNum is the particular field to force (-1 indicates the whole union)
|
||||||
UnionFacetSymbol::UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum)
|
/// \param isAddr is \b true for facets that apply to all ops at the address
|
||||||
|
UnionFacetSymbol::UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum,bool isAddr)
|
||||||
: Symbol(sc, nm, unionDt)
|
: Symbol(sc, nm, unionDt)
|
||||||
{
|
{
|
||||||
fieldNum = fldNum;
|
fieldNum = fldNum;
|
||||||
category = union_facet;
|
category = union_facet;
|
||||||
|
addrBased = isAddr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnionFacetSymbol::encode(Encoder &encoder) const
|
void UnionFacetSymbol::encode(Encoder &encoder) const
|
||||||
@@ -701,6 +703,7 @@ void UnionFacetSymbol::encode(Encoder &encoder) const
|
|||||||
encoder.openElement(ELEM_FACETSYMBOL);
|
encoder.openElement(ELEM_FACETSYMBOL);
|
||||||
encodeHeader(encoder);
|
encodeHeader(encoder);
|
||||||
encoder.writeSignedInteger(ATTRIB_FIELD, fieldNum);
|
encoder.writeSignedInteger(ATTRIB_FIELD, fieldNum);
|
||||||
|
encoder.writeBool(ATTRIB_ADDRTIED, true);
|
||||||
encodeBody(encoder);
|
encodeBody(encoder);
|
||||||
encoder.closeElement(ELEM_FACETSYMBOL);
|
encoder.closeElement(ELEM_FACETSYMBOL);
|
||||||
}
|
}
|
||||||
@@ -711,6 +714,7 @@ void UnionFacetSymbol::decode(Decoder &decoder)
|
|||||||
uint4 elemId = decoder.openElement(ELEM_FACETSYMBOL);
|
uint4 elemId = decoder.openElement(ELEM_FACETSYMBOL);
|
||||||
decodeHeader(decoder);
|
decodeHeader(decoder);
|
||||||
fieldNum = decoder.readSignedInteger(ATTRIB_FIELD);
|
fieldNum = decoder.readSignedInteger(ATTRIB_FIELD);
|
||||||
|
addrBased = decoder.readBool(ATTRIB_ADDRTIED);
|
||||||
|
|
||||||
decodeBody(decoder);
|
decodeBody(decoder);
|
||||||
decoder.closeElement(elemId);
|
decoder.closeElement(elemId);
|
||||||
|
|||||||
@@ -318,10 +318,12 @@ public:
|
|||||||
/// different symbols attached. The Symbol's associated data-type will be the desired \e union to force.
|
/// different symbols attached. The Symbol's associated data-type will be the desired \e union to force.
|
||||||
class UnionFacetSymbol : public Symbol {
|
class UnionFacetSymbol : public Symbol {
|
||||||
int4 fieldNum; ///< Particular field to associate with Symbol access
|
int4 fieldNum; ///< Particular field to associate with Symbol access
|
||||||
|
bool addrBased; ///< Set to \b true if facet matches any PcodeOp at the address
|
||||||
public:
|
public:
|
||||||
UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum); ///< Constructor from components
|
UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum,bool isAddr=false); ///< Constructor from components
|
||||||
UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; } ///< Constructor for decode
|
UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; addrBased = false; } ///< Constructor for decode
|
||||||
int4 getFieldNumber(void) const { return fieldNum; } ///< Get the particular field associate with \b this
|
int4 getFieldNumber(void) const { return fieldNum; } ///< Get the particular field associate with \b this
|
||||||
|
bool isAddrBased(void) const { return addrBased; } ///< Return \b true if facet matches any PcodeOp at the address
|
||||||
virtual void encode(Encoder &encoder) const;
|
virtual void encode(Encoder &encoder) const;
|
||||||
virtual void decode(Decoder &decoder);
|
virtual void decode(Decoder &decoder);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -222,6 +222,25 @@ void FloatFormat::calcPrecision(void)
|
|||||||
decimalMaxPrecision = (int4)ceil((frac_size + 1) * 0.30103) + 1;
|
decimalMaxPrecision = (int4)ceil((frac_size + 1) * 0.30103) + 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// \param encoding is the encoded floating-point value
|
||||||
|
/// \return either \e zero, \e infinity, \e denormalized, \e nan, or \e normalized
|
||||||
|
FloatFormat::floatclass FloatFormat::getClass(uintb encoding) const
|
||||||
|
|
||||||
|
{
|
||||||
|
int4 exp = extractExponentCode(encoding);
|
||||||
|
if (exp == 0) {
|
||||||
|
if ( extractFractionalCode(encoding) == 0 )
|
||||||
|
return zero;
|
||||||
|
return denormalized;
|
||||||
|
}
|
||||||
|
if (exp == maxexponent) {
|
||||||
|
if ( extractFractionalCode(encoding) == 0 )
|
||||||
|
return infinity;
|
||||||
|
return nan;
|
||||||
|
}
|
||||||
|
return normalized;
|
||||||
|
}
|
||||||
|
|
||||||
/// \param encoding is the encoding value
|
/// \param encoding is the encoding value
|
||||||
/// \param type points to the floating-point class, which is passed back
|
/// \param type points to the floating-point class, which is passed back
|
||||||
/// \return the equivalent double value
|
/// \return the equivalent double value
|
||||||
|
|||||||
@@ -64,6 +64,7 @@ private:
|
|||||||
public:
|
public:
|
||||||
FloatFormat(int4 sz); ///< Construct default IEEE 754 standard settings
|
FloatFormat(int4 sz); ///< Construct default IEEE 754 standard settings
|
||||||
int4 getSize(void) const { return size; } ///< Get the size of the encoding in bytes
|
int4 getSize(void) const { return size; } ///< Get the size of the encoding in bytes
|
||||||
|
floatclass getClass(uintb encoding) const; ///< Get the class of an encoding
|
||||||
double getHostFloat(uintb encoding,floatclass *type) const; ///< Convert an encoding into host's double
|
double getHostFloat(uintb encoding,floatclass *type) const; ///< Convert an encoding into host's double
|
||||||
uintb getEncoding(double host) const; ///< Convert host's double into \b this encoding
|
uintb getEncoding(double host) const; ///< Convert host's double into \b this encoding
|
||||||
uintb convertEncoding(uintb encoding,const FloatFormat *formin) const; ///< Convert between two different formats
|
uintb convertEncoding(uintb encoding,const FloatFormat *formin) const; ///< Convert between two different formats
|
||||||
@@ -71,6 +72,7 @@ public:
|
|||||||
uintb extractFractionalCode(uintb x) const; ///< Extract the fractional part of the encoding
|
uintb extractFractionalCode(uintb x) const; ///< Extract the fractional part of the encoding
|
||||||
bool extractSign(uintb x) const; ///< Extract the sign bit from the encoding
|
bool extractSign(uintb x) const; ///< Extract the sign bit from the encoding
|
||||||
int4 extractExponentCode(uintb x) const; ///< Extract the exponent from the encoding
|
int4 extractExponentCode(uintb x) const; ///< Extract the exponent from the encoding
|
||||||
|
int4 getExponent(uintb x) const { return extractExponentCode(x) - bias; } ///< Get the exponent of an encoding
|
||||||
|
|
||||||
string printDecimal(double host,bool forcesci) const; ///< Print given value as a decimal string
|
string printDecimal(double host,bool forcesci) const; ///< Print given value as a decimal string
|
||||||
|
|
||||||
|
|||||||
@@ -907,44 +907,87 @@ void PcodeEmitFd::dump(const Address &addr,OpCode opc,VarnodeData *outvar,Varnod
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Get the resolved union field associated with the given edge
|
/// \brief Get the resolution (union field) associated with an unresolved data-type and the given edge
|
||||||
///
|
///
|
||||||
/// If there is no field associated with the edge, null is returned
|
/// If there is no field associated with the edge, or the resolved data-type is not
|
||||||
/// \param parent is the data-type being resolved
|
/// the same size as the given data-type, null is returned.
|
||||||
|
/// \param unresType is the given data-type being resolved
|
||||||
/// \param op is the PcodeOp component of the given edge
|
/// \param op is the PcodeOp component of the given edge
|
||||||
/// \param slot is the slot component of the given edge
|
/// \param slot is the slot component of the given edge
|
||||||
/// \return the associated field as a ResolvedUnion or null
|
/// \return the associated field as a ResolvedUnion or null
|
||||||
const ResolvedUnion *Funcdata::getUnionField(const Datatype *parent,const PcodeOp *op,int4 slot) const
|
const ResolvedUnion *Funcdata::getUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot) const
|
||||||
|
|
||||||
{
|
{
|
||||||
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
|
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
|
||||||
ResolveEdge edge(parent,op,slot);
|
ResolveEdge edge(unresType,op,slot);
|
||||||
|
iter = unionMap.find(edge);
|
||||||
|
if (iter != unionMap.end()) {
|
||||||
|
const ResolvedUnion *res = &(*iter).second;
|
||||||
|
Datatype *dt = res->getDatatype();
|
||||||
|
// Check that the Varnode size matches the data-type
|
||||||
|
if (unresType->getSize() == dt->getSize())
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (const ResolvedUnion *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Get the resolution (union field) associated with an unresolved data-type and the given edge
|
||||||
|
///
|
||||||
|
/// The size of the resolved data-type does not have to match the given data-type.
|
||||||
|
/// If there is no field associated with the edge, null is returned.
|
||||||
|
/// \param unresType is the unresolved data-type
|
||||||
|
/// \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::getUnionResolution(const Datatype *unresType,const PcodeOp *op,int4 slot) const
|
||||||
|
|
||||||
|
{
|
||||||
|
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
|
||||||
|
ResolveEdge edge(unresType,op,slot);
|
||||||
|
iter = unionMap.find(edge);
|
||||||
|
if (iter != unionMap.end()) {
|
||||||
|
const ResolvedUnion *res = &(*iter).second;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
return (const ResolvedUnion *)0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Get any resolution (union field) associated with an unresolved data-type and the given address
|
||||||
|
///
|
||||||
|
/// If there is no associated field, null is returned
|
||||||
|
/// \param unresType is the unresolved data-type
|
||||||
|
/// \param addr is the given address
|
||||||
|
/// \param slot is the slot component the resolution matches
|
||||||
|
/// \return the associated field as a ResolvedUnion or null
|
||||||
|
const ResolvedUnion *Funcdata::getAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot) const
|
||||||
|
|
||||||
|
{
|
||||||
|
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
|
||||||
|
ResolveEdge edge(unresType,addr,slot);
|
||||||
iter = unionMap.find(edge);
|
iter = unionMap.find(edge);
|
||||||
if (iter != unionMap.end())
|
if (iter != unionMap.end())
|
||||||
return &(*iter).second;
|
return &(*iter).second;
|
||||||
return (const ResolvedUnion *)0;
|
return (const ResolvedUnion *)0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Associate a union field with the given edge
|
/// \brief Associate a resolution (union field) with an unresolved data-type and the given edge
|
||||||
///
|
///
|
||||||
/// If there was a previous association, it is overwritten unless it was \e locked.
|
/// 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.
|
/// The method returns \b true except in this case where a previous locked association exists.
|
||||||
/// \param parent is the parent union data-type
|
/// \param unresType is the unresolved data-type
|
||||||
/// \param op is the PcodeOp component of the given edge
|
/// \param op is the PcodeOp component of the given edge
|
||||||
/// \param slot is the slot component of the given edge
|
/// \param slot is the slot component of the given edge
|
||||||
/// \param resolve is the resolved union
|
/// \param resolve is the resolved union
|
||||||
/// \return \b true unless there was a locked association
|
/// \return \b true unless the resolution was locked
|
||||||
bool Funcdata::setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve)
|
bool Funcdata::setUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve)
|
||||||
|
|
||||||
{
|
{
|
||||||
ResolveEdge edge(parent,op,slot);
|
ResolveEdge edge(unresType,op,slot);
|
||||||
pair<map<ResolveEdge,ResolvedUnion>::iterator,bool> res;
|
pair<map<ResolveEdge,ResolvedUnion>::iterator,bool> res;
|
||||||
res = unionMap.emplace(edge,resolve);
|
res = unionMap.emplace(edge,resolve);
|
||||||
if (!res.second) {
|
if (!res.second) {
|
||||||
if ((*res.first).second.isLocked()) {
|
if (!(*res.first).second.update(resolve))
|
||||||
return false;
|
return !(*res.first).second.isLocked();
|
||||||
}
|
|
||||||
(*res.first).second = resolve;
|
|
||||||
}
|
}
|
||||||
if (op->code() == CPUI_MULTIEQUAL && slot >= 0) {
|
if (op->code() == CPUI_MULTIEQUAL && slot >= 0) {
|
||||||
// Data-type propagation doesn't happen between MULTIEQUAL input slots holding the same Varnode
|
// Data-type propagation doesn't happen between MULTIEQUAL input slots holding the same Varnode
|
||||||
@@ -953,54 +996,124 @@ bool Funcdata::setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,
|
|||||||
for(int4 i=0;i<op->numInput();++i) {
|
for(int4 i=0;i<op->numInput();++i) {
|
||||||
if (i == slot) continue;
|
if (i == slot) continue;
|
||||||
if (op->getIn(i) != vn) continue; // Check that different input slot holds same Varnode
|
if (op->getIn(i) != vn) continue; // Check that different input slot holds same Varnode
|
||||||
ResolveEdge dupedge(parent,op,i);
|
ResolveEdge dupedge(unresType,op,i);
|
||||||
res = unionMap.emplace(dupedge,resolve);
|
res = unionMap.emplace(dupedge,resolve);
|
||||||
if (!res.second) {
|
if (!res.second) {
|
||||||
if (!(*res.first).second.isLocked())
|
(*res.first).second.update(resolve);
|
||||||
(*res.first).second = resolve;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Force a specific union field resolution for the given edge
|
/// \brief Associate a resolution (union field) with an unresolved data-type and the given address
|
||||||
///
|
///
|
||||||
/// The \b parent data-type is taken directly from the given Varnode.
|
/// If there was a previous association, it is overwritten unless it was \e locked.
|
||||||
/// \param parent is the parent data-type
|
/// The method returns \b true except in this case where a previous locked association exists.
|
||||||
|
/// \param unresType is the unresolved data-type
|
||||||
|
/// \param addr is the given address
|
||||||
|
/// \param slot is the slot component the resolution matches
|
||||||
|
/// \param resolve is the resolved union
|
||||||
|
/// \return \b true unless there was a locked association
|
||||||
|
bool Funcdata::setAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot,const ResolvedUnion &resolve)
|
||||||
|
|
||||||
|
{
|
||||||
|
ResolveEdge edge(unresType,addr,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 Update the resolution data-type associated with an unresolved data-type for a given edge
|
||||||
|
///
|
||||||
|
/// If further resolution of the cached data-type has happened, update the cache with the new data-type.
|
||||||
|
/// \param unresType is the unresolved data-type
|
||||||
|
/// \param op is the PcodeOp component of the given edge
|
||||||
|
/// \param slot is the slot component of the given edge
|
||||||
|
/// \param resType is the new resolution data-type
|
||||||
|
/// \return \b true unless there was a locked association
|
||||||
|
bool Funcdata::updateUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,Datatype *resType)
|
||||||
|
|
||||||
|
{
|
||||||
|
map<ResolveEdge,ResolvedUnion>::iterator iter;
|
||||||
|
ResolveEdge edge(unresType,op,slot);
|
||||||
|
iter = unionMap.find(edge);
|
||||||
|
if (iter != unionMap.end()) {
|
||||||
|
(*iter).second.setResolve(resType);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Force a specific resolution (union field) resolution for an unresolved data-type and the given edge
|
||||||
|
///
|
||||||
|
/// \param unresType is the unresolved data-type
|
||||||
/// \param fieldNum is the index of the field to force
|
/// \param fieldNum is the index of the field to force
|
||||||
/// \param op is PcodeOp of the edge
|
/// \param op is PcodeOp of the edge
|
||||||
/// \param slot is -1 for the write edge or >=0 indicating the particular read 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)
|
void Funcdata::forceFacingType(Datatype *unresType,int4 fieldNum,PcodeOp *op,int4 slot)
|
||||||
|
|
||||||
{
|
{
|
||||||
Datatype *baseType = parent;
|
Datatype *baseType = unresType;
|
||||||
if (baseType->getMetatype() == TYPE_PTR)
|
if (baseType->getMetatype() == TYPE_PTR)
|
||||||
baseType = ((TypePointer *)baseType)->getPtrTo();
|
baseType = ((TypePointer *)baseType)->getPtrTo();
|
||||||
if (parent->isPointerRel()) {
|
if (unresType->isPointerRel()) {
|
||||||
// Don't associate a relative pointer with the resolution, but convert to a standard pointer
|
// 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());
|
unresType = glb->types->getTypePointer(unresType->getSize(), baseType, ((TypePointer *)unresType)->getWordSize());
|
||||||
}
|
}
|
||||||
ResolvedUnion resolve(parent,fieldNum,*glb->types);
|
ResolvedUnion resolve(unresType,fieldNum,*glb->types);
|
||||||
setUnionField(parent, op, slot, resolve);
|
setUnionField(unresType, op, slot, resolve);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// \brief Copy a read/write facing resolution for a specific data-type from one PcodeOp to another
|
/// \brief Copy a read/write facing resolution for an unresolved data-type from one PcodeOp to another
|
||||||
///
|
///
|
||||||
/// \param parent is the data-type that needs resolution
|
/// \param unresType is the unresolved data-type
|
||||||
/// \param op is the new reading PcodeOp
|
/// \param op is the new reading PcodeOp
|
||||||
/// \param slot is the new slot (-1 for write, >=0 for read)
|
/// \param slot is the new slot (-1 for write, >=0 for read)
|
||||||
/// \param oldOp is the PcodeOp to inherit the resolution from
|
/// \param oldOp is the PcodeOp to inherit the resolution from
|
||||||
/// \param oldSlot is the old slot (-1 for write, >=0 for read)
|
/// \param oldSlot is the old slot (-1 for write, >=0 for read)
|
||||||
int4 Funcdata::inheritResolution(Datatype *parent,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot)
|
/// \return the field number that was inherited
|
||||||
|
int4 Funcdata::inheritUnionField(Datatype *unresType,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot)
|
||||||
|
|
||||||
{
|
{
|
||||||
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
|
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
|
||||||
|
if (slot < 0 && oldOp->isMarker())
|
||||||
|
slot = 0;
|
||||||
|
ResolveEdge edge(unresType,oldOp,oldSlot);
|
||||||
|
iter = unionMap.find(edge);
|
||||||
|
if (iter == unionMap.end())
|
||||||
|
return -1;
|
||||||
|
setUnionField(unresType,op,slot,(*iter).second);
|
||||||
|
return (*iter).second.getFieldNum();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// \brief Create a resolution for an unresolved pointer data-type based on earlier non-pointer resolution
|
||||||
|
///
|
||||||
|
/// \param unresPtr is the unresolved pointer data-type
|
||||||
|
/// \param op is the new reading PcodeOp
|
||||||
|
/// \param slot is the new slot (-1 for write, >=0 for read)
|
||||||
|
/// \param oldOp is the PcodeOp to inherit the resolution from
|
||||||
|
/// \param oldSlot is the old slot (-1 for write, >=0 for read)
|
||||||
|
/// \return the field number that was inherited
|
||||||
|
int4 Funcdata::inheritUnionFieldPtr(Datatype *unresPtr,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot)
|
||||||
|
|
||||||
|
{
|
||||||
|
Datatype *parent = unresPtr->getDepend(0);
|
||||||
|
if (slot < 0 && oldOp->isMarker())
|
||||||
|
slot = 0;
|
||||||
|
map<ResolveEdge,ResolvedUnion>::const_iterator iter;
|
||||||
ResolveEdge edge(parent,oldOp,oldSlot);
|
ResolveEdge edge(parent,oldOp,oldSlot);
|
||||||
iter = unionMap.find(edge);
|
iter = unionMap.find(edge);
|
||||||
if (iter == unionMap.end())
|
if (iter == unionMap.end())
|
||||||
return -1;
|
return -1;
|
||||||
setUnionField(parent,op,slot,(*iter).second);
|
ResolvedUnion ptrres(unresPtr,(*iter).second.getFieldNum(),*glb->types);
|
||||||
|
setUnionField(unresPtr,op,slot,ptrres);
|
||||||
return (*iter).second.getFieldNum();
|
return (*iter).second.getFieldNum();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -529,11 +529,15 @@ public:
|
|||||||
|
|
||||||
bool moveRespectingCover(PcodeOp *op,PcodeOp *lastOp); ///< Move given op past \e lastOp respecting covers if possible
|
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;
|
const ResolvedUnion *getUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot) const;
|
||||||
bool setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve);
|
const ResolvedUnion *getAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot) const;
|
||||||
void forceFacingType(Datatype *parent,int4 fieldNum,PcodeOp *op,int4 slot);
|
const ResolvedUnion *getUnionResolution(const Datatype *unresType,const PcodeOp *op,int4 slot) const;
|
||||||
int4 inheritResolution(Datatype *parent,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
|
bool setUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve);
|
||||||
|
bool setAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot,const ResolvedUnion &resolve);
|
||||||
|
bool updateUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot,Datatype *resType);
|
||||||
|
void forceFacingType(Datatype *unresType,int4 fieldNum,PcodeOp *op,int4 slot);
|
||||||
|
int4 inheritUnionField(Datatype *unresType,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
|
||||||
|
int4 inheritUnionFieldPtr(Datatype *unresPtr,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
|
||||||
// Jumptable routines
|
// Jumptable routines
|
||||||
JumpTable *linkJumpTable(PcodeOp *op); ///< Link jump-table with a given BRANCHIND
|
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
|
JumpTable *findJumpTable(const PcodeOp *op) const; ///< Find a jump-table associated with a given BRANCHIND
|
||||||
|
|||||||
@@ -1656,15 +1656,40 @@ void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
|
|||||||
bool Funcdata::applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash)
|
bool Funcdata::applyUnionFacet(SymbolEntry *entry,DynamicHash &dhash)
|
||||||
|
|
||||||
{
|
{
|
||||||
Symbol *sym = entry->getSymbol();
|
UnionFacetSymbol *sym = (UnionFacetSymbol *)entry->getSymbol();
|
||||||
|
if (sym->isAddrBased()) {
|
||||||
|
ResolvedUnion resolve(sym->getType(), sym->getFieldNumber(), *glb->types);
|
||||||
|
resolve.setLock(true);
|
||||||
|
int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
|
||||||
|
return setAddressBasedUnionField(sym->getType(), entry->getFirstUseAddress(), slot, resolve);
|
||||||
|
}
|
||||||
PcodeOp *op = dhash.findOp(this, entry->getFirstUseAddress(), entry->getHash());
|
PcodeOp *op = dhash.findOp(this, entry->getFirstUseAddress(), entry->getHash());
|
||||||
if (op == (PcodeOp *)0)
|
if (op == (PcodeOp *)0)
|
||||||
return false;
|
return false;
|
||||||
int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
|
int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
|
||||||
int4 fldNum = ((UnionFacetSymbol *)sym)->getFieldNumber();
|
const ResolvedUnion *res = getUnionResolution(sym->getType(), op, slot);
|
||||||
ResolvedUnion resolve(sym->getType(), fldNum, *glb->types);
|
if (res != (const ResolvedUnion *)0 && res->getFieldNum() == sym->getFieldNumber())
|
||||||
|
return false;
|
||||||
|
Varnode *vn = (slot < 0) ? op->getOut() : op->getIn(slot);
|
||||||
|
Datatype *unresType = sym->getType();
|
||||||
|
Datatype *dt = vn->getType();
|
||||||
|
if (dt->getMetatype() == TYPE_PTR) {
|
||||||
|
if (((TypePointer *)dt)->getPtrTo() == unresType) {
|
||||||
|
unresType = dt;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (dt->getMetatype() == TYPE_PARTIALSTRUCT) {
|
||||||
|
if (((TypePartialStruct *)dt)->getParent() == unresType)
|
||||||
|
unresType = dt;
|
||||||
|
}
|
||||||
|
else if (dt->getMetatype() == TYPE_PARTIALUNION) {
|
||||||
|
if (((TypePartialUnion *)dt)->getParentUnion() == unresType)
|
||||||
|
unresType = dt;
|
||||||
|
}
|
||||||
|
ResolvedUnion resolve(unresType,sym->getFieldNumber(), *glb->types);
|
||||||
resolve.setLock(true);
|
resolve.setLock(true);
|
||||||
return setUnionField(sym->getType(),op,slot,resolve);
|
setUnionField(unresType,op,slot,resolve);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search for \e addrtied Varnodes whose storage falls in the global Scope, then
|
/// Search for \e addrtied Varnodes whose storage falls in the global Scope, then
|
||||||
|
|||||||
@@ -416,7 +416,7 @@ PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trim
|
|||||||
Datatype *ct = inVn->getType();
|
Datatype *ct = inVn->getType();
|
||||||
if (ct->needsResolution()) { // If the data-type needs resolution
|
if (ct->needsResolution()) { // If the data-type needs resolution
|
||||||
if (inVn->isWritten()) {
|
if (inVn->isWritten()) {
|
||||||
int4 fieldNum = data.inheritResolution(ct, copyOp, -1, inVn->getDef(), -1);
|
int4 fieldNum = data.inheritUnionField(ct, copyOp, -1, inVn->getDef(), -1);
|
||||||
data.forceFacingType(ct, fieldNum, copyOp, 0);
|
data.forceFacingType(ct, fieldNum, copyOp, 0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -669,7 +669,7 @@ void Merge::trimOpOutput(PcodeOp *op)
|
|||||||
copyop = data.newOp(1,op->getAddr());
|
copyop = data.newOp(1,op->getAddr());
|
||||||
data.opSetOpcode(copyop,CPUI_COPY);
|
data.opSetOpcode(copyop,CPUI_COPY);
|
||||||
if (ct->needsResolution()) {
|
if (ct->needsResolution()) {
|
||||||
int4 fieldNum = data.inheritResolution(ct, copyop, -1, op, -1);
|
int4 fieldNum = data.inheritUnionField(ct, copyop, -1, op, -1);
|
||||||
data.forceFacingType(ct, fieldNum, copyop, 0);
|
data.forceFacingType(ct, fieldNum, copyop, 0);
|
||||||
if (ct->getMetatype() == TYPE_PARTIALUNION)
|
if (ct->getMetatype() == TYPE_PARTIALUNION)
|
||||||
ct = vn->getTypeDefFacing();
|
ct = vn->getTypeDefFacing();
|
||||||
@@ -871,7 +871,7 @@ void Merge::mergeIndirect(PcodeOp *indop)
|
|||||||
PcodeOp *newop = allocateCopyTrim(invn0, indop->getAddr(), indop);
|
PcodeOp *newop = allocateCopyTrim(invn0, indop->getAddr(), indop);
|
||||||
SymbolEntry *entry = outvn->getSymbolEntry();
|
SymbolEntry *entry = outvn->getSymbolEntry();
|
||||||
if (entry != (SymbolEntry *)0 && entry->getSymbol()->getType()->needsResolution()) {
|
if (entry != (SymbolEntry *)0 && entry->getSymbol()->getType()->needsResolution()) {
|
||||||
data.inheritResolution(entry->getSymbol()->getType(), newop, -1, indop, -1);
|
data.inheritUnionField(entry->getSymbol()->getType(), newop, -1, indop, -1);
|
||||||
}
|
}
|
||||||
data.opSetInput(indop,newop->getOut(),0);
|
data.opSetInput(indop,newop->getOut(),0);
|
||||||
data.opInsertBefore(newop,indop);
|
data.opInsertBefore(newop,indop);
|
||||||
|
|||||||
@@ -6517,8 +6517,12 @@ void AddTreeState::buildTree(void)
|
|||||||
// Create PTRADD portion of operation
|
// Create PTRADD portion of operation
|
||||||
if (multNode != (Varnode *)0) {
|
if (multNode != (Varnode *)0) {
|
||||||
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
|
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
|
||||||
if (ptr->getType()->needsResolution())
|
if (ptr->getType()->needsResolution()) {
|
||||||
data.inheritResolution(ptr->getType(),newop, 0, baseOp, baseSlot);
|
if (((TypePointer *)ptr->getType())->getPtrTo()->getSize() == baseType->getSize())
|
||||||
|
data.forceFacingType(ptr->getType(),-1,newop, 0); // Force type not to resolve before the index is applied
|
||||||
|
else
|
||||||
|
data.inheritUnionField(ptr->getType(), newop, 0, baseOp, baseSlot);
|
||||||
|
}
|
||||||
if (data.isTypeRecoveryExceeded())
|
if (data.isTypeRecoveryExceeded())
|
||||||
assignPropagatedType(newop);
|
assignPropagatedType(newop);
|
||||||
multNode = newop->getOut();
|
multNode = newop->getOut();
|
||||||
@@ -6530,7 +6534,7 @@ void AddTreeState::buildTree(void)
|
|||||||
if (isSubtype) {
|
if (isSubtype) {
|
||||||
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
|
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
|
||||||
if (multNode->getType()->needsResolution())
|
if (multNode->getType()->needsResolution())
|
||||||
data.inheritResolution(multNode->getType(),newop, 0, baseOp, baseSlot);
|
data.inheritUnionField(multNode->getType(),newop, 0, baseOp, baseSlot);
|
||||||
if (data.isTypeRecoveryExceeded())
|
if (data.isTypeRecoveryExceeded())
|
||||||
assignPropagatedType(newop);
|
assignPropagatedType(newop);
|
||||||
if (size != 0)
|
if (size != 0)
|
||||||
@@ -6731,7 +6735,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
// Create pointer up to parent
|
// Create pointer up to parent
|
||||||
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,ptrVn,data.newConstant(ptrVn->getSize(),offset));
|
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,ptrVn,data.newConstant(ptrVn->getSize(),offset));
|
||||||
if (ptrVn->getType()->needsResolution())
|
if (ptrVn->getType()->needsResolution())
|
||||||
data.inheritResolution(ptrVn->getType(),newop, 0, op, 1);
|
data.inheritUnionField(ptrVn->getType(),newop, 0, op, 1);
|
||||||
newop->setStopTypePropagation();
|
newop->setStopTypePropagation();
|
||||||
if (newoff != 0) {
|
if (newoff != 0) {
|
||||||
// Add newoff in to get back to zero total offset
|
// Add newoff in to get back to zero total offset
|
||||||
@@ -6769,7 +6773,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
|
|
||||||
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,ptrVn,data.newConstant(ptrVn->getSize(),0));
|
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,ptrVn,data.newConstant(ptrVn->getSize(),0));
|
||||||
if (ptrVn->getType()->needsResolution())
|
if (ptrVn->getType()->needsResolution())
|
||||||
data.inheritResolution(ptrVn->getType(),newop, 0, op, 1);
|
data.inheritUnionField(ptrVn->getType(),newop, 0, op, 1);
|
||||||
newop->setStopTypePropagation();
|
newop->setStopTypePropagation();
|
||||||
data.opSetInput(op,newop->getOut(),1);
|
data.opSetInput(op,newop->getOut(),1);
|
||||||
return 1;
|
return 1;
|
||||||
@@ -7100,10 +7104,11 @@ int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
|
|||||||
{
|
{
|
||||||
int8 extra = 0;
|
int8 extra = 0;
|
||||||
PcodeOp *op = vn->loneDescend();
|
PcodeOp *op = vn->loneDescend();
|
||||||
|
Varnode *nextVn = vn;
|
||||||
while(op != (PcodeOp *)0) {
|
while(op != (PcodeOp *)0) {
|
||||||
OpCode opc = op->code();
|
OpCode opc = op->code();
|
||||||
if (opc == CPUI_INT_ADD) {
|
if (opc == CPUI_INT_ADD) {
|
||||||
int4 slot = op->getSlot(vn);
|
int4 slot = op->getSlot(nextVn);
|
||||||
if (slot == 0 && op->getIn(1)->isConstant()) {
|
if (slot == 0 && op->getIn(1)->isConstant()) {
|
||||||
extra += (int8)op->getIn(1)->getOffset();
|
extra += (int8)op->getIn(1)->getOffset();
|
||||||
data.opRemoveInput(op, 1);
|
data.opRemoveInput(op, 1);
|
||||||
@@ -7120,7 +7125,7 @@ int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
|
|||||||
data.opSetOpcode(op, CPUI_COPY);
|
data.opSetOpcode(op, CPUI_COPY);
|
||||||
}
|
}
|
||||||
else if (opc == CPUI_PTRADD) {
|
else if (opc == CPUI_PTRADD) {
|
||||||
if (op->getIn(0) != vn) break;
|
if (op->getIn(0) != nextVn) break;
|
||||||
// The PTRADD should be converted to an INT_ADD or COPY
|
// The PTRADD should be converted to an INT_ADD or COPY
|
||||||
// as it is associated with the invalid PTRSUB
|
// as it is associated with the invalid PTRSUB
|
||||||
int8 ptraddmult = op->getIn(2)->getOffset();
|
int8 ptraddmult = op->getIn(2)->getOffset();
|
||||||
@@ -7139,9 +7144,11 @@ int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
|
|||||||
else {
|
else {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
vn = op->getOut();
|
nextVn = op->getOut();
|
||||||
op = vn->loneDescend();
|
op = nextVn->loneDescend();
|
||||||
}
|
}
|
||||||
|
if (nextVn != vn)
|
||||||
|
vn->updateType(nextVn->getType());
|
||||||
return extra;
|
return extra;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7561,7 +7568,7 @@ bool RulePieceStructure::convertZextToPiece(PcodeOp *zext,Datatype *ct,int4 offs
|
|||||||
data.opSetOpcode(zext, CPUI_PIECE);
|
data.opSetOpcode(zext, CPUI_PIECE);
|
||||||
data.opInsertInput(zext, zerovn, 0);
|
data.opInsertInput(zext, zerovn, 0);
|
||||||
if (invn->getType()->needsResolution())
|
if (invn->getType()->needsResolution())
|
||||||
data.inheritResolution(invn->getType(), zext, 1, zext, 0); // Transfer invn's resolution to slot 1
|
data.inheritUnionField(invn->getType(), zext, 1, zext, 0); // Transfer invn's resolution to slot 1
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7692,7 +7699,7 @@ int4 RulePieceStructure::applyOp(PcodeOp *op,Funcdata &data)
|
|||||||
data.opInsertBefore(copyOp, node.getOp());
|
data.opInsertBefore(copyOp, node.getOp());
|
||||||
if (vn->getType()->needsResolution()) {
|
if (vn->getType()->needsResolution()) {
|
||||||
// Inherit PIECE's read resolution for COPY's read
|
// Inherit PIECE's read resolution for COPY's read
|
||||||
data.inheritResolution(vn->getType(), copyOp, 0, node.getOp(), node.getSlot());
|
data.inheritUnionField(vn->getType(), copyOp, 0, node.getOp(), node.getSlot());
|
||||||
}
|
}
|
||||||
if (newType->needsResolution()) {
|
if (newType->needsResolution()) {
|
||||||
newType->resolveInFlow(copyOp, -1); // If the piece represents part of a union, resolve it
|
newType->resolveInFlow(copyOp, -1); // If the piece represents part of a union, resolve it
|
||||||
|
|||||||
@@ -2141,7 +2141,7 @@ bool SplitDatatype::RootPointer::backUpPointer(Datatype *impliedBase)
|
|||||||
/// \param op is the LOAD or STORE
|
/// \param op is the LOAD or STORE
|
||||||
/// \param valueType is the specific data-type to match
|
/// \param valueType is the specific data-type to match
|
||||||
/// \return \b true if the root pointer is found
|
/// \return \b true if the root pointer is found
|
||||||
bool SplitDatatype::RootPointer::find(PcodeOp *op,Datatype *valueType)
|
bool SplitDatatype::RootPointer::find(PcodeOp *op,Datatype *valueType,ResolveCache &resolver)
|
||||||
|
|
||||||
{
|
{
|
||||||
Datatype *impliedBase = (Datatype *)0;
|
Datatype *impliedBase = (Datatype *)0;
|
||||||
@@ -2151,12 +2151,14 @@ bool SplitDatatype::RootPointer::find(PcodeOp *op,Datatype *valueType)
|
|||||||
valueType = ((TypeArray *)valueType)->getBase();
|
valueType = ((TypeArray *)valueType)->getBase();
|
||||||
impliedBase = valueType; // we allow an implied array (pointer to element) as a match
|
impliedBase = valueType; // we allow an implied array (pointer to element) as a match
|
||||||
}
|
}
|
||||||
|
int4 key = (op->code() == CPUI_LOAD) ? 0 : 1;
|
||||||
loadStore = op;
|
loadStore = op;
|
||||||
baseOffset = 0;
|
baseOffset = 0;
|
||||||
firstPointer = pointer = op->getIn(1);
|
firstPointer = pointer = op->getIn(1);
|
||||||
Datatype *ct = pointer->getTypeReadFacing(op);
|
Datatype *ct = pointer->getTypeReadFacing(op);
|
||||||
if (ct->getMetatype() != TYPE_PTR)
|
if (ct->getMetatype() != TYPE_PTR)
|
||||||
return false;
|
return false;
|
||||||
|
resolver.addResolution(key, pointer->getType(), op, 1);
|
||||||
ptrType = (TypePointer *)ct;
|
ptrType = (TypePointer *)ct;
|
||||||
if (ptrType->getPtrTo() != valueType) {
|
if (ptrType->getPtrTo() != valueType) {
|
||||||
if (impliedBase != (Datatype *)0)
|
if (impliedBase != (Datatype *)0)
|
||||||
@@ -2169,8 +2171,10 @@ bool SplitDatatype::RootPointer::find(PcodeOp *op,Datatype *valueType)
|
|||||||
// The required pointer is found. We try to back up to pointers to containing structures or arrays
|
// The required pointer is found. We try to back up to pointers to containing structures or arrays
|
||||||
for(int4 i=0;i<3;++i) {
|
for(int4 i=0;i<3;++i) {
|
||||||
if (pointer->isAddrTied() || pointer->loneDescend() == (PcodeOp *)0) break;
|
if (pointer->isAddrTied() || pointer->loneDescend() == (PcodeOp *)0) break;
|
||||||
|
Varnode *lastVn = pointer;
|
||||||
if (!backUpPointer(impliedBase))
|
if (!backUpPointer(impliedBase))
|
||||||
break;
|
break;
|
||||||
|
resolver.addResolution(key, pointer->getType(), lastVn->getDef(), 0);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -2639,9 +2643,15 @@ void SplitDatatype::buildPointers(Varnode *rootVn,TypePointer *ptrType,int4 base
|
|||||||
newOff = 0;
|
newOff = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (tmpType == newType || tmpType->getMetatype() == TYPE_ARRAY) {
|
Datatype *resType;
|
||||||
|
if (newType->needsResolution())
|
||||||
|
resType = resolver.resolve(isInput ? 0 : 1, newType);
|
||||||
|
else
|
||||||
|
resType = newType;
|
||||||
|
|
||||||
|
if (tmpType == resType || tmpType->getMetatype() == TYPE_ARRAY) {
|
||||||
int8 finalOffset = curOff - newOff;
|
int8 finalOffset = curOff - newOff;
|
||||||
int4 sz = newType->getSize(); // Element size in bytes
|
int4 sz = resType->getSize(); // Element size in bytes
|
||||||
finalOffset = finalOffset / sz; // Number of elements
|
finalOffset = finalOffset / sz; // Number of elements
|
||||||
sz = AddrSpace::byteToAddressInt(sz, ptrType->getWordSize());
|
sz = AddrSpace::byteToAddressInt(sz, ptrType->getWordSize());
|
||||||
newOp = data.newOp(3,followOp->getAddr());
|
newOp = data.newOp(3,followOp->getAddr());
|
||||||
@@ -2660,11 +2670,12 @@ void SplitDatatype::buildPointers(Varnode *rootVn,TypePointer *ptrType,int4 base
|
|||||||
data.opSetInput(newOp, inPtr, 0);
|
data.opSetInput(newOp, inPtr, 0);
|
||||||
data.opSetInput(newOp, data.newConstant(inPtr->getSize(), finalOffset), 1);
|
data.opSetInput(newOp, data.newConstant(inPtr->getSize(), finalOffset), 1);
|
||||||
}
|
}
|
||||||
|
resolver.inheritResolution(isInput ? 0 : 1, inPtr, newOp, 0);
|
||||||
inPtr = data.newUniqueOut(inPtr->getSize(), newOp);
|
inPtr = data.newUniqueOut(inPtr->getSize(), newOp);
|
||||||
Datatype *tmpPtr = types->getTypePointerStripArray(ptrType->getSize(), newType, ptrType->getWordSize());
|
Datatype *tmpPtr = types->getTypePointerStripArray(ptrType->getSize(), newType, ptrType->getWordSize());
|
||||||
inPtr->updateType(tmpPtr);
|
inPtr->updateType(tmpPtr);
|
||||||
data.opInsertBefore(newOp, followOp);
|
data.opInsertBefore(newOp, followOp);
|
||||||
tmpType = newType;
|
tmpType = resType;
|
||||||
curOff = newOff;
|
curOff = newOff;
|
||||||
} while(tmpType->getSize() > matchType->getSize());
|
} while(tmpType->getSize() > matchType->getSize());
|
||||||
ptrVarnodes.push_back(inPtr);
|
ptrVarnodes.push_back(inPtr);
|
||||||
@@ -2699,7 +2710,7 @@ bool SplitDatatype::isArithmeticOutput(Varnode *vn)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SplitDatatype::SplitDatatype(Funcdata &func)
|
SplitDatatype::SplitDatatype(Funcdata &func)
|
||||||
: data(func)
|
: data(func), resolver(func)
|
||||||
{
|
{
|
||||||
Architecture *glb = func.getArch();
|
Architecture *glb = func.getArch();
|
||||||
types = glb->types;
|
types = glb->types;
|
||||||
@@ -2729,6 +2740,8 @@ bool SplitDatatype::splitCopy(PcodeOp *copyOp,Datatype *inType,Datatype *outType
|
|||||||
return false;
|
return false;
|
||||||
vector<Varnode *> inVarnodes;
|
vector<Varnode *> inVarnodes;
|
||||||
vector<Varnode *> outVarnodes;
|
vector<Varnode *> outVarnodes;
|
||||||
|
Datatype *unresOutType = outVn->getType();
|
||||||
|
resolver.addResolution(0,unresOutType, copyOp, -1);
|
||||||
if (inVn->isConstant())
|
if (inVn->isConstant())
|
||||||
buildInConstants(inVn,inVarnodes,outVn->getSpace()->isBigEndian());
|
buildInConstants(inVn,inVarnodes,outVn->getSpace()->isBigEndian());
|
||||||
else
|
else
|
||||||
@@ -2741,6 +2754,7 @@ bool SplitDatatype::splitCopy(PcodeOp *copyOp,Datatype *inType,Datatype *outType
|
|||||||
data.opSetInput(newCopyOp,inVarnodes[i],0);
|
data.opSetInput(newCopyOp,inVarnodes[i],0);
|
||||||
data.opSetOutput(newCopyOp,outVarnodes[i]);
|
data.opSetOutput(newCopyOp,outVarnodes[i]);
|
||||||
data.opInsertBefore(newCopyOp, copyOp);
|
data.opInsertBefore(newCopyOp, copyOp);
|
||||||
|
resolver.inheritResolution(0,unresOutType, dataTypePieces[i].offset, outVarnodes[i], newCopyOp, -1);
|
||||||
}
|
}
|
||||||
data.opDestroy(copyOp);
|
data.opDestroy(copyOp);
|
||||||
return true;
|
return true;
|
||||||
@@ -2776,7 +2790,7 @@ bool SplitDatatype::splitLoad(PcodeOp *loadOp,Datatype *inType)
|
|||||||
if (isArithmeticInput(outVn)) // Sanity check on output
|
if (isArithmeticInput(outVn)) // Sanity check on output
|
||||||
return false;
|
return false;
|
||||||
RootPointer root;
|
RootPointer root;
|
||||||
if (!root.find(loadOp,inType))
|
if (!root.find(loadOp,inType,resolver))
|
||||||
return false;
|
return false;
|
||||||
vector<Varnode *> ptrVarnodes;
|
vector<Varnode *> ptrVarnodes;
|
||||||
vector<Varnode *> outVarnodes;
|
vector<Varnode *> outVarnodes;
|
||||||
@@ -2839,12 +2853,12 @@ bool SplitDatatype::splitStore(PcodeOp *storeOp,Datatype *outType)
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
RootPointer storeRoot;
|
RootPointer storeRoot;
|
||||||
if (!storeRoot.find(storeOp,outType))
|
if (!storeRoot.find(storeOp,outType,resolver))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
RootPointer loadRoot;
|
RootPointer loadRoot;
|
||||||
if (loadOp != (PcodeOp *)0) {
|
if (loadOp != (PcodeOp *)0) {
|
||||||
if (!loadRoot.find(loadOp,inType))
|
if (!loadRoot.find(loadOp,inType,resolver))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
|
|
||||||
#include "ruleaction.hh"
|
#include "ruleaction.hh"
|
||||||
#include "transform.hh"
|
#include "transform.hh"
|
||||||
|
#include "unionresolve.hh"
|
||||||
|
|
||||||
namespace ghidra {
|
namespace ghidra {
|
||||||
|
|
||||||
@@ -277,13 +278,14 @@ class SplitDatatype {
|
|||||||
int4 baseOffset; ///< Offset of the LOAD or STORE relative to root pointer
|
int4 baseOffset; ///< Offset of the LOAD or STORE relative to root pointer
|
||||||
bool backUpPointer(Datatype *impliedBase); ///< Follow flow of \b pointer back thru INT_ADD or PTRSUB
|
bool backUpPointer(Datatype *impliedBase); ///< Follow flow of \b pointer back thru INT_ADD or PTRSUB
|
||||||
public:
|
public:
|
||||||
bool find(PcodeOp *op,Datatype *valueType); ///< Locate root pointer for underlying LOAD or STORE
|
bool find(PcodeOp *op,Datatype *valueType,ResolveCache &resolver); ///< Locate root pointer for underlying LOAD or STORE
|
||||||
void duplicateToTemp(Funcdata &data,PcodeOp *followOp); ///< COPY the root varnode into a temp register
|
void duplicateToTemp(Funcdata &data,PcodeOp *followOp); ///< COPY the root varnode into a temp register
|
||||||
void freePointerChain(Funcdata &data); ///< Remove unused pointer calculations
|
void freePointerChain(Funcdata &data); ///< Remove unused pointer calculations
|
||||||
};
|
};
|
||||||
Funcdata &data; ///< The containing function
|
Funcdata &data; ///< The containing function
|
||||||
TypeFactory *types; ///< The data-type container
|
TypeFactory *types; ///< The data-type container
|
||||||
vector<Component> dataTypePieces; ///< Sequence of all data-type pairs being copied
|
vector<Component> dataTypePieces; ///< Sequence of all data-type pairs being copied
|
||||||
|
ResolveCache resolver; ///< Resolved data-types encountered
|
||||||
bool splitStructures; ///< Whether or not structures should be split
|
bool splitStructures; ///< Whether or not structures should be split
|
||||||
bool splitArrays; ///< Whether or not arrays should be split
|
bool splitArrays; ///< Whether or not arrays should be split
|
||||||
bool isLoadStore; ///< True if trying to split LOAD or STORE
|
bool isLoadStore; ///< True if trying to split LOAD or STORE
|
||||||
|
|||||||
@@ -1317,9 +1317,15 @@ Datatype *TypePointer::resolveInFlow(PcodeOp *op,int4 slot)
|
|||||||
if (ptrto->getMetatype() == TYPE_UNION) {
|
if (ptrto->getMetatype() == TYPE_UNION) {
|
||||||
Funcdata *fd = op->getParent()->getFuncdata();
|
Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
const ResolvedUnion *res = fd->getUnionField(this,op,slot);
|
const ResolvedUnion *res = fd->getUnionField(this,op,slot);
|
||||||
if (res != (ResolvedUnion*)0)
|
if (res != (ResolvedUnion *)0)
|
||||||
return res->getDatatype();
|
return res->getDatatype();
|
||||||
ScoreUnionFields scoreFields(*fd->getArch()->types,this,op,slot);
|
res = fd->getAddressBasedUnionField(this, op->getAddr(), slot);
|
||||||
|
if (res != (ResolvedUnion *)0) {
|
||||||
|
ResolvedUnion resolve(this,res->getFieldNum(),*fd->getArch()->types);
|
||||||
|
fd->setUnionField(this,op,slot,resolve);
|
||||||
|
return resolve.getDatatype();
|
||||||
|
}
|
||||||
|
ScoreUnionFields scoreFields(*fd,this,op,slot);
|
||||||
fd->setUnionField(this,op,slot,scoreFields.getResult());
|
fd->setUnionField(this,op,slot,scoreFields.getResult());
|
||||||
return scoreFields.getResult().getDatatype();
|
return scoreFields.getResult().getDatatype();
|
||||||
}
|
}
|
||||||
@@ -1338,6 +1344,15 @@ Datatype* TypePointer::findResolve(const PcodeOp *op,int4 slot)
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int4 TypePointer::findCompatibleResolve(Datatype *ct) const
|
||||||
|
|
||||||
|
{
|
||||||
|
if (ct->getMetatype() == TYPE_PTR) {
|
||||||
|
return ptrto->findCompatibleResolve(((TypePointer *)ct)->ptrto);
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
void TypeArray::printRaw(ostream &s) const
|
void TypeArray::printRaw(ostream &s) const
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -2530,7 +2545,13 @@ Datatype *TypeUnion::resolveInFlow(PcodeOp *op,int4 slot)
|
|||||||
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
||||||
if (res != (ResolvedUnion *)0)
|
if (res != (ResolvedUnion *)0)
|
||||||
return res->getDatatype();
|
return res->getDatatype();
|
||||||
ScoreUnionFields scoreFields(*fd->getArch()->types,this,op,slot);
|
res = fd->getAddressBasedUnionField(this, op->getAddr(), slot);
|
||||||
|
if (res != (ResolvedUnion *)0) {
|
||||||
|
ResolvedUnion resolve(this,res->getFieldNum(),*fd->getArch()->types);
|
||||||
|
fd->setUnionField(this, op, slot, *res);
|
||||||
|
return resolve.getDatatype();
|
||||||
|
}
|
||||||
|
ScoreUnionFields scoreFields(*fd,this,op,slot);
|
||||||
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
||||||
return scoreFields.getResult().getDatatype();
|
return scoreFields.getResult().getDatatype();
|
||||||
}
|
}
|
||||||
@@ -2549,7 +2570,13 @@ const TypeField *TypeUnion::resolveTruncation(int8 offset,PcodeOp *op,int4 slot,
|
|||||||
|
|
||||||
{
|
{
|
||||||
Funcdata *fd = op->getParent()->getFuncdata();
|
Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
const ResolvedUnion *res = fd->getUnionResolution(this, op, slot);
|
||||||
|
if (res == (ResolvedUnion *)0) {
|
||||||
|
res = fd->getAddressBasedUnionField(this, op->getAddr(), slot);
|
||||||
|
if (res != (ResolvedUnion *)0) {
|
||||||
|
fd->setUnionField(this, op, slot, *res);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (res != (ResolvedUnion *)0) {
|
if (res != (ResolvedUnion *)0) {
|
||||||
if (res->getFieldNum() >= 0) {
|
if (res->getFieldNum() >= 0) {
|
||||||
const TypeField *field = getField(res->getFieldNum());
|
const TypeField *field = getField(res->getFieldNum());
|
||||||
@@ -2558,7 +2585,7 @@ const TypeField *TypeUnion::resolveTruncation(int8 offset,PcodeOp *op,int4 slot,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (op->code() == CPUI_SUBPIECE && slot == 1) { // The slot is artificial in this case
|
else if (op->code() == CPUI_SUBPIECE && slot == 1) { // The slot is artificial in this case
|
||||||
ScoreUnionFields scoreFields(*fd->getArch()->types,this,offset,op);
|
ScoreUnionFields scoreFields(*fd,this,offset,op);
|
||||||
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
||||||
if (scoreFields.getResult().getFieldNum() >= 0) {
|
if (scoreFields.getResult().getFieldNum() >= 0) {
|
||||||
newoff = 0;
|
newoff = 0;
|
||||||
@@ -2566,7 +2593,7 @@ const TypeField *TypeUnion::resolveTruncation(int8 offset,PcodeOp *op,int4 slot,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ScoreUnionFields scoreFields(*fd->getArch()->types,this,offset,op,slot);
|
ScoreUnionFields scoreFields(*fd,this,offset,op,slot);
|
||||||
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
||||||
if (scoreFields.getResult().getFieldNum() >= 0) {
|
if (scoreFields.getResult().getFieldNum() >= 0) {
|
||||||
const TypeField *field = getField(scoreFields.getResult().getFieldNum());
|
const TypeField *field = getField(scoreFields.getResult().getFieldNum());
|
||||||
@@ -2588,7 +2615,7 @@ const TypeField *TypeUnion::findTruncation(int8 offset,int4 sz,const PcodeOp *op
|
|||||||
{
|
{
|
||||||
// No new scoring is done, but if a cached result is available, return it.
|
// No new scoring is done, but if a cached result is available, return it.
|
||||||
const Funcdata *fd = op->getParent()->getFuncdata();
|
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
const ResolvedUnion *res = fd->getUnionResolution(this, op, slot);
|
||||||
if (res != (ResolvedUnion *)0 && res->getFieldNum() >= 0) {
|
if (res != (ResolvedUnion *)0 && res->getFieldNum() >= 0) {
|
||||||
const TypeField *field = getField(res->getFieldNum());
|
const TypeField *field = getField(res->getFieldNum());
|
||||||
newoff = offset - field->offset;
|
newoff = offset - field->offset;
|
||||||
@@ -2908,38 +2935,50 @@ void TypePartialUnion::encode(Encoder &encoder) const
|
|||||||
Datatype *TypePartialUnion::resolveInFlow(PcodeOp *op,int4 slot)
|
Datatype *TypePartialUnion::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();
|
||||||
Datatype *curType = container;
|
Datatype *curType = container;
|
||||||
int8 curOff = offset;
|
int8 curOff = offset;
|
||||||
while(curType != (Datatype *)0 && curType->getSize() > size) {
|
while(curType != (Datatype *)0 && curType->getSize() > size) {
|
||||||
if (curType->getMetatype() == TYPE_UNION) {
|
if (curType->getMetatype() == TYPE_PARTIALUNION) {
|
||||||
const TypeField *field = curType->resolveTruncation(curOff, op, slot, curOff);
|
TypePartialUnion *curPartial = (TypePartialUnion *)curType;
|
||||||
curType = (field == (const TypeField *)0) ? (Datatype *)0 : field->type;
|
curOff += curPartial->getOffset();
|
||||||
|
int8 newOff;
|
||||||
|
const TypeField *field = curPartial->getParentUnion()->resolveTruncation(curOff, op, slot, newOff);
|
||||||
|
Architecture *glb = op->getParent()->getFuncdata()->getArch();
|
||||||
|
curType = (Datatype *)0;
|
||||||
|
if (field != (const TypeField *)0)
|
||||||
|
curType = glb->types->getExactPiece(field->type, curOff, size);
|
||||||
|
curOff = 0;
|
||||||
}
|
}
|
||||||
else {
|
else if (curType->getMetatype() == TYPE_UNION) {
|
||||||
curType = curType->getSubType(curOff, &curOff);
|
const TypeField *field = curType->resolveTruncation(curOff, op, slot, curOff);
|
||||||
|
Architecture *glb = op->getParent()->getFuncdata()->getArch();
|
||||||
|
curType = (Datatype *)0;
|
||||||
|
if (field != (const TypeField *)0)
|
||||||
|
curType = glb->types->getExactPiece(field->type, curOff, size);
|
||||||
|
curOff = 0;
|
||||||
|
}
|
||||||
|
else { // Should never reach here
|
||||||
|
curType = (Datatype *)0;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (curType != (Datatype *)0 && curType->getSize() == size)
|
if (curType == (Datatype *)0 || curType->getSize() != size)
|
||||||
return curType;
|
curType = stripped;
|
||||||
return stripped;
|
fd->updateUnionField(this, op, slot, curType);
|
||||||
|
return curType;
|
||||||
}
|
}
|
||||||
|
|
||||||
Datatype* TypePartialUnion::findResolve(const PcodeOp *op,int4 slot)
|
Datatype* TypePartialUnion::findResolve(const PcodeOp *op,int4 slot)
|
||||||
|
|
||||||
{
|
{
|
||||||
Datatype *curType = container;
|
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||||
int8 curOff = offset;
|
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
||||||
while(curType != (Datatype *)0 && curType->getSize() > size) {
|
if (res != (ResolvedUnion *)0)
|
||||||
if (curType->getMetatype() == TYPE_UNION) {
|
return res->getDatatype();
|
||||||
Datatype *newType = curType->findResolve(op, slot);
|
|
||||||
curType = (newType == curType) ? (Datatype *)0 : newType;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
curType = curType->getSubType(curOff, &curOff);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (curType != (Datatype *)0 && curType->getSize() == size)
|
|
||||||
return curType;
|
|
||||||
return stripped;
|
return stripped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4535,9 +4574,6 @@ Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
|
|||||||
}
|
}
|
||||||
if (ct->getSize() == size)
|
if (ct->getSize() == size)
|
||||||
return ct; // Perfect size match
|
return ct; // Perfect size match
|
||||||
if (ct->getMetatype() == TYPE_UNION) {
|
|
||||||
return getTypePartialUnion((TypeUnion *)ct, curOff, size);
|
|
||||||
}
|
|
||||||
lastType = ct;
|
lastType = ct;
|
||||||
lastOff = curOff;
|
lastOff = curOff;
|
||||||
ct = ct->getSubType(curOff,&curOff);
|
ct = ct->getSubType(curOff,&curOff);
|
||||||
@@ -4547,6 +4583,12 @@ Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
|
|||||||
type_metatype meta = lastType->getMetatype();
|
type_metatype meta = lastType->getMetatype();
|
||||||
if (meta == TYPE_STRUCT || meta == TYPE_ARRAY || meta == TYPE_PARTIALSTRUCT)
|
if (meta == TYPE_STRUCT || meta == TYPE_ARRAY || meta == TYPE_PARTIALSTRUCT)
|
||||||
return getTypePartialStruct(lastType, lastOff, size);
|
return getTypePartialStruct(lastType, lastOff, size);
|
||||||
|
else if (meta == TYPE_UNION)
|
||||||
|
return getTypePartialUnion((TypeUnion *)lastType, lastOff, size);
|
||||||
|
else if (meta == TYPE_PARTIALUNION) { // Truncate to smaller partial union
|
||||||
|
TypePartialUnion *partial = (TypePartialUnion *)lastType;
|
||||||
|
return getTypePartialUnion(partial->getParentUnion(),lastOff + partial->getOffset(), size);
|
||||||
|
}
|
||||||
else if (lastType->isEnumType() && !lastType->hasStripped())
|
else if (lastType->isEnumType() && !lastType->hasStripped())
|
||||||
return getTypePartialEnum((TypeEnum *)lastType, lastOff, size);
|
return getTypePartialEnum((TypeEnum *)lastType, lastOff, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -293,7 +293,7 @@ public:
|
|||||||
virtual int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type
|
virtual int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type
|
||||||
virtual const TypeField *resolveTruncation(int8 offset,PcodeOp *op,int4 slot,int8 &newoff);
|
virtual const TypeField *resolveTruncation(int8 offset,PcodeOp *op,int4 slot,int8 &newoff);
|
||||||
int4 typeOrder(const Datatype &op) const { if (this==&op) return 0; return compare(op,10); } ///< Order this with -op- datatype
|
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
|
int4 typeOrderFormal(const Datatype &op) const; ///< Order \b this with \b op for selecting a formal high-level data-type
|
||||||
void encodeRef(Encoder &encoder) const; ///< Encode a reference of \b this to a stream
|
void encodeRef(Encoder &encoder) const; ///< Encode a reference of \b this to a stream
|
||||||
bool isPieceStructured(void) const; ///< Does \b this data-type consist of separate pieces?
|
bool isPieceStructured(void) const; ///< Does \b this data-type consist of separate pieces?
|
||||||
bool isPrimitiveWhole(void) const; ///< Is \b this made up of a single primitive
|
bool isPrimitiveWhole(void) const; ///< Is \b this made up of a single primitive
|
||||||
@@ -479,6 +479,7 @@ public:
|
|||||||
virtual bool isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const;
|
virtual bool isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const;
|
||||||
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
|
virtual Datatype *resolveInFlow(PcodeOp *op,int4 slot);
|
||||||
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
|
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
|
||||||
|
virtual int4 findCompatibleResolve(Datatype *ct) const; ///< Find a resolution compatible with the given data-type
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief Datatype object representing an array of elements
|
/// \brief Datatype object representing an array of elements
|
||||||
@@ -978,17 +979,19 @@ inline uint8 Datatype::getUnsizedId(void) const
|
|||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Order data-types, with special handling of the \e bool data-type. Data-types are compared
|
/// Order data-types, preferring the most specialized, except deemphasize \e partial data-types,
|
||||||
/// using the normal ordering, but \e bool is ordered after all other data-types. A return value
|
/// which can't be formal, and \e bool, which can be over specialized. A return value
|
||||||
/// of 0 indicates the data-types are the same, -1 indicates that \b this is prefered (ordered earlier),
|
/// of 0 indicates the data-types are the same, -1 indicates that \b this is preferred (ordered earlier),
|
||||||
/// and 1 indicates \b this is ordered later.
|
/// and 1 indicates \b this is ordered later.
|
||||||
/// \param op is the other data-type to compare with \b this
|
/// \param op is the other data-type to compare with \b this
|
||||||
/// \return -1, 0, or 1
|
/// \return -1, 0, or 1
|
||||||
inline int4 Datatype::typeOrderBool(const Datatype &op) const
|
inline int4 Datatype::typeOrderFormal(const Datatype &op) const
|
||||||
|
|
||||||
{
|
{
|
||||||
if (this == &op) return 0;
|
if (this == &op) return 0;
|
||||||
if (metatype == TYPE_BOOL) return 1; // Never prefer bool over other data-types
|
if (metatype == TYPE_PARTIALUNION) return 1; // Prefer partials the least
|
||||||
|
if (op.metatype == TYPE_PARTIALUNION) return -1;
|
||||||
|
if (metatype == TYPE_BOOL) return 1; // Prefer bool less than integers
|
||||||
if (op.metatype == TYPE_BOOL) return -1;
|
if (op.metatype == TYPE_BOOL) return -1;
|
||||||
return compare(op,10);
|
return compare(op,10);
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -39,16 +39,19 @@ namespace ghidra {
|
|||||||
class ResolvedUnion {
|
class ResolvedUnion {
|
||||||
friend class ScoreUnionFields;
|
friend class ScoreUnionFields;
|
||||||
Datatype *resolve; ///< The resolved data-type
|
Datatype *resolve; ///< The resolved data-type
|
||||||
Datatype *baseType; ///< Union or Structure being resolved
|
Datatype *baseType; ///< Union or Structure being resolved (pointers and partials stripped)
|
||||||
int4 fieldNum; ///< Index of field referenced by \b resolve
|
int4 fieldNum; ///< Index of field referenced by \b resolve
|
||||||
bool lock; ///< If \b true, resolution cannot be overridden
|
bool lock; ///< If \b true, resolution cannot be overridden
|
||||||
public:
|
public:
|
||||||
ResolvedUnion(Datatype *parent); ///< Construct a data-type that resolves to itself
|
ResolvedUnion(Datatype *unresType); ///< Construct a data-type that resolves to itself
|
||||||
ResolvedUnion(Datatype *parent,int4 fldNum,TypeFactory &typegrp); ///< Construct a reference to a field
|
ResolvedUnion(Datatype *unresType,int4 fldNum,TypeFactory &typegrp); ///< Construct a resolution with a specific field number
|
||||||
|
ResolvedUnion(const ResolvedUnion &op,Datatype *res); ///< Copy constructor with updated resolve data-type
|
||||||
Datatype *getDatatype(void) const { return resolve; } ///< Get the resolved data-type
|
Datatype *getDatatype(void) const { return resolve; } ///< Get the resolved data-type
|
||||||
Datatype *getBase(void) const { return baseType; } ///< Get the union or structure being referenced
|
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
|
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
|
bool isLocked(void) const { return lock; } ///< Return \b true if the field resolution is locked
|
||||||
|
bool update(const ResolvedUnion &op); ///< Update a resolution with a new data-type
|
||||||
|
void setResolve(Datatype *res) { resolve = res; } ///< Update the resolution data-type (without changing field resolution)
|
||||||
void setLock(bool val) { lock = val; } ///< Set whether \b this resolution is locked against overrides
|
void setLock(bool val) { lock = val; } ///< Set whether \b this resolution is locked against overrides
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -62,7 +65,8 @@ class ResolveEdge {
|
|||||||
uintm opTime; ///< Id of PcodeOp edge
|
uintm opTime; ///< Id of PcodeOp edge
|
||||||
int4 encoding; ///< Encoding of the slot and pointer-ness
|
int4 encoding; ///< Encoding of the slot and pointer-ness
|
||||||
public:
|
public:
|
||||||
ResolveEdge(const Datatype *parent,const PcodeOp *op,int4 slot); ///< Construct from components
|
ResolveEdge(const Datatype *unresType,const PcodeOp *op,int4 slot); ///< Construct from components
|
||||||
|
ResolveEdge(const Datatype *unresType,const Address &addr,int4 slot); ///< Construct address based resolve
|
||||||
bool operator<(const ResolveEdge &op2) const; ///< Compare two edges
|
bool operator<(const ResolveEdge &op2) const; ///< Compare two edges
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -92,7 +96,7 @@ class ScoreUnionFields {
|
|||||||
PcodeOp *op; ///< The PcodeOp reading the Varnode (or null)
|
PcodeOp *op; ///< The PcodeOp reading the Varnode (or null)
|
||||||
int4 inslot; ///< The slot reading the Varnode (or -1)
|
int4 inslot; ///< The slot reading the Varnode (or -1)
|
||||||
dir_type direction; ///< Direction to push fit. 0=down 1=up
|
dir_type direction; ///< Direction to push fit. 0=down 1=up
|
||||||
bool array; ///< Field can be accessed as an array
|
int4 maxLength; ///< Maximum byte offset that can be added to \b fitType as a pointer
|
||||||
Datatype *fitType; ///< The putative data-type of the Varnode
|
Datatype *fitType; ///< The putative data-type of the Varnode
|
||||||
int4 scoreIndex; ///< The original field being scored by \b this trial
|
int4 scoreIndex; ///< The original field being scored by \b this trial
|
||||||
public:
|
public:
|
||||||
@@ -102,18 +106,18 @@ class ScoreUnionFields {
|
|||||||
/// \param slot is the input slot being read
|
/// \param slot is the input slot being read
|
||||||
/// \param ct is the trial data-type to fit
|
/// \param ct is the trial data-type to fit
|
||||||
/// \param index is the scoring index
|
/// \param index is the scoring index
|
||||||
/// \param isArray is \b true if the data-type to fit is a pointer to an array
|
/// \param max is the biggest offset that can be added to this data-type as a pointer (or 0 if there is no known restriction)
|
||||||
Trial(PcodeOp *o,int4 slot,Datatype *ct,int4 index,bool isArray) {
|
Trial(PcodeOp *o,int4 slot,Datatype *ct,int4 index,int4 max) {
|
||||||
op = o; inslot = slot; direction = fit_down; fitType = ct; scoreIndex = index; vn = o->getIn(slot); array=isArray; }
|
op = o; inslot = slot; direction = fit_down; fitType = ct; scoreIndex = index; vn = o->getIn(slot); maxLength = max; }
|
||||||
|
|
||||||
/// \brief Construct an upward trial for a Varnode
|
/// \brief Construct an upward trial for a Varnode
|
||||||
///
|
///
|
||||||
/// \param v is the Varnode to fit
|
/// \param v is the Varnode to fit
|
||||||
/// \param ct is the trial data-type to fit
|
/// \param ct is the trial data-type to fit
|
||||||
/// \param index is the scoring index
|
/// \param index is the scoring index
|
||||||
/// \param isArray is \b true if the data-type to fit is a pointer to an array
|
/// \param max is the biggest offset that can be added to this data-type as a pointer (or 0 if there is no known restriction)
|
||||||
Trial(Varnode *v,Datatype *ct,int4 index,bool isArray) {
|
Trial(Varnode *v,Datatype *ct,int4 index,int4 max) {
|
||||||
vn = v; op = (PcodeOp *)0; inslot=-1; direction = fit_up; fitType = ct; scoreIndex = index; array=isArray; }
|
vn = v; op = (PcodeOp *)0; inslot=-1; direction = fit_up; fitType = ct; scoreIndex = index; maxLength = max; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/// \brief A mark accumulated when a given Varnode is visited with a specific field index
|
/// \brief A mark accumulated when a given Varnode is visited with a specific field index
|
||||||
@@ -133,6 +137,7 @@ class ScoreUnionFields {
|
|||||||
return (index < op2.index);
|
return (index < op2.index);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
Funcdata &data; ///< Function containing data-flow being scored
|
||||||
TypeFactory &typegrp; ///< The factory containing data-types
|
TypeFactory &typegrp; ///< The factory containing data-types
|
||||||
vector<int4> scores; ///< Score for each field, indexed by fieldNum + 1 (whole union is index=0)
|
vector<int4> scores; ///< Score for each field, indexed by fieldNum + 1 (whole union is index=0)
|
||||||
vector<Datatype *> fields; ///< Field corresponding to each score
|
vector<Datatype *> fields; ///< Field corresponding to each score
|
||||||
@@ -147,11 +152,11 @@ class ScoreUnionFields {
|
|||||||
bool testArrayArithmetic(PcodeOp *op,int4 inslot); ///< Check if given PcodeOp is operating on array with union elements
|
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
|
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 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 scoreParameter(Datatype *ct,const FuncProto *proto,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
|
int4 scoreReturnType(Datatype *ct,const FuncProto *proto); ///< 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
|
Datatype *derefPointer(const Trial &trial,Varnode *vn,int4 &score); ///< Score trial 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 newTrialsDown(Varnode *vn,Datatype *ct,int4 scoreIndex,int4 max); ///< 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 newTrials(PcodeOp *op,int4 slot,Datatype *ct,int4 scoreIndex,int4 max); ///< 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 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
|
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
|
Datatype *scoreTruncation(Datatype *ct,Varnode *vn,int4 offset,int4 scoreIndex); ///< Score a truncation in the data-flow
|
||||||
@@ -160,12 +165,47 @@ class ScoreUnionFields {
|
|||||||
void computeBestIndex(void); ///< Assuming scoring is complete, compute the best index
|
void computeBestIndex(void); ///< Assuming scoring is complete, compute the best index
|
||||||
void run(void); ///< Calculate best fitting field
|
void run(void); ///< Calculate best fitting field
|
||||||
public:
|
public:
|
||||||
ScoreUnionFields(TypeFactory &tgrp,Datatype *parentType,PcodeOp *op,int4 slot);
|
ScoreUnionFields(Funcdata &fd,Datatype *parentType,PcodeOp *op,int4 slot);
|
||||||
ScoreUnionFields(TypeFactory &tgrp,TypeUnion *unionType,int4 offset,PcodeOp *op);
|
ScoreUnionFields(Funcdata &fd,TypeUnion *unionType,int4 offset,PcodeOp *op);
|
||||||
ScoreUnionFields(TypeFactory &tgrp,TypeUnion *unionType,int4 offset,PcodeOp *op,int4 slot);
|
ScoreUnionFields(Funcdata &fd,TypeUnion *unionType,int4 offset,PcodeOp *op,int4 slot);
|
||||||
const ResolvedUnion &getResult(void) const { return result; } ///< Get the resulting best field resolution
|
const ResolvedUnion &getResult(void) const { return result; } ///< Get the resulting best field resolution
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// \brief A collection of specific union data-type and how they resolve in a given context
|
||||||
|
///
|
||||||
|
/// Union resolutions are collected before a transform via addResolution(). Then afterwards Varnodes
|
||||||
|
/// can inherit the the same resolutions via the inheritResolution() methods.
|
||||||
|
/// Resolutions for multiple contexts can stored and retrieved by providing an id for the context
|
||||||
|
/// in the \b key parameter.
|
||||||
|
class ResolveCache {
|
||||||
|
/// \brief A specific resolution of a union data-type
|
||||||
|
class Record {
|
||||||
|
public:
|
||||||
|
Datatype *baseType; ///< The union or structure needing resolution (pointers and partials stripped)
|
||||||
|
int4 fieldNum; ///< Index of the specific resolution
|
||||||
|
int4 key; ///< Context key
|
||||||
|
Record(int4 k,Datatype *dt,int4 fldNum) { baseType = dt; fieldNum = fldNum; key = k; } ///< Constructor
|
||||||
|
bool match(int4 k,Datatype *dt) const { return (key == k && baseType == dt); } ///< Does the given data-type match \b this record
|
||||||
|
};
|
||||||
|
Funcdata &data; ///< Function to which resolutions apply
|
||||||
|
list<Record> resolveList; ///< List of known resolutions
|
||||||
|
public:
|
||||||
|
ResolveCache(Funcdata &fd) : data(fd) {} ///< Constructor
|
||||||
|
void addResolution(int4 key,Datatype *dt,PcodeOp *op,int4 slot); ///< Add a specific resolution to the cache
|
||||||
|
Datatype *resolve(int4 key,Datatype *dt) const; ///< Look up the in context resolution for the given data-type
|
||||||
|
void inheritResolution(int4 key,Datatype *dt,int4 off,Varnode *vn,PcodeOp *op,int4 slot) const;
|
||||||
|
|
||||||
|
/// \brief Associate a cached resolution with a Varnode and its new read/write edge
|
||||||
|
///
|
||||||
|
/// \param key is the context id
|
||||||
|
/// \param vn is the new Varnode inheriting the resolution
|
||||||
|
/// \param op is the PcodeOp reading/writing the Varnode
|
||||||
|
/// \param slot is the read/write edge
|
||||||
|
void inheritResolution(int4 key,Varnode *vn,PcodeOp *op,int4 slot) const {
|
||||||
|
inheritResolution(key,vn->getType(),0,vn,op,slot);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Compare based on the data-type, the \b slot, and the PcodeOp's unique id.
|
/// 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
|
/// \param op2 is the other edge to compare with \b this
|
||||||
/// \return \b true if \b this should be ordered before the other edge
|
/// \return \b true if \b this should be ordered before the other edge
|
||||||
|
|||||||
@@ -389,7 +389,7 @@ Varnode *HighVariable::getTypeRepresentative(void) const
|
|||||||
if (vn->isTypeLock())
|
if (vn->isTypeLock())
|
||||||
rep = vn;
|
rep = vn;
|
||||||
}
|
}
|
||||||
else if (0>vn->getType()->typeOrderBool(*rep->getType()))
|
else if (0>vn->getType()->typeOrderFormal(*rep->getType()))
|
||||||
rep = vn;
|
rep = vn;
|
||||||
}
|
}
|
||||||
return rep;
|
return rep;
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -47,6 +47,11 @@ public class ClangFieldToken extends ClangToken {
|
|||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Varnode getVarnode() {
|
||||||
|
return op.getOutput();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PcodeOp getPcodeOp() {
|
public PcodeOp getPcodeOp() {
|
||||||
return op;
|
return op;
|
||||||
|
|||||||
+66
-23
@@ -55,6 +55,40 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
|||||||
// setKeyBindingData(new KeyBindingData(KeyEvent.VK_L, 0));
|
// setKeyBindingData(new KeyBindingData(KeyEvent.VK_L, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find any union data-type associated with the token and return it. Otherwise return null.
|
||||||
|
* @param tokenAtCursor is the decompiler token
|
||||||
|
* @return the union data-type or null
|
||||||
|
*/
|
||||||
|
private static Union findUnion(ClangToken tokenAtCursor) {
|
||||||
|
if (tokenAtCursor instanceof ClangFieldToken) {
|
||||||
|
Composite composite = getCompositeDataType(tokenAtCursor);
|
||||||
|
if (composite instanceof Union) {
|
||||||
|
return (Union) composite;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Varnode vn = tokenAtCursor.getVarnode();
|
||||||
|
if (vn != null) {
|
||||||
|
DataType dt = vn.getHigh().getDataType();
|
||||||
|
if (dt instanceof TypeDef) {
|
||||||
|
dt = ((TypeDef) dt).getBaseDataType();
|
||||||
|
}
|
||||||
|
if (dt instanceof Pointer) {
|
||||||
|
dt = ((Pointer) dt).getDataType();
|
||||||
|
}
|
||||||
|
else if (dt instanceof PartialUnion) {
|
||||||
|
dt = ((PartialUnion) dt).getParent();
|
||||||
|
}
|
||||||
|
if (dt instanceof TypeDef) {
|
||||||
|
dt = ((TypeDef) dt).getBaseDataType();
|
||||||
|
}
|
||||||
|
if (dt instanceof Union)
|
||||||
|
return (Union) dt;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||||
Function function = context.getFunction();
|
Function function = context.getFunction();
|
||||||
@@ -63,11 +97,7 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||||
if (!(tokenAtCursor instanceof ClangFieldToken)) {
|
return findUnion(tokenAtCursor) != null;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
Composite composite = getCompositeDataType(tokenAtCursor);
|
|
||||||
return (composite instanceof Union);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -147,26 +177,39 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
parentDt = typeIsUnionRelated(accessOp.getOutput()); // Its possible the output of PTRSUB is the union
|
||||||
else {
|
|
||||||
parentDt = null;
|
|
||||||
for (accessSlot = 0; accessSlot < accessOp.getNumInputs(); ++accessSlot) {
|
|
||||||
accessVn = accessOp.getInput(accessSlot);
|
|
||||||
parentDt = typeIsUnionRelated(accessVn);
|
|
||||||
if (parentDt != null) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (parentDt != null) {
|
if (parentDt != null) {
|
||||||
if (opcode == PcodeOp.SUBPIECE && accessSlot == 0 &&
|
accessVn = accessOp.getOutput();
|
||||||
!(parentDt instanceof Pointer)) {
|
accessSlot = -1;
|
||||||
// SUBPIECE acts directly as resolution operator
|
PcodeOp readOp = accessVn.getLoneDescend();
|
||||||
// Choose field based on output varnode, even though it isn't the union data-type
|
if (readOp != null && readOp.getOpcode() != PcodeOp.MULTIEQUAL &&
|
||||||
accessSlot = -1;
|
readOp.getOpcode() != PcodeOp.INDIRECT) {
|
||||||
accessVn = accessOp.getOutput();
|
accessOp = readOp;
|
||||||
|
accessSlot = accessOp.getSlot(accessVn); // Transfer to lone reading Op
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
accessOp = null; // Give up. Could not find union type.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
parentDt = null;
|
||||||
|
for (accessSlot = 0; accessSlot < accessOp.getNumInputs(); ++accessSlot) {
|
||||||
|
accessVn = accessOp.getInput(accessSlot);
|
||||||
|
parentDt = typeIsUnionRelated(accessVn);
|
||||||
|
if (parentDt != null) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (parentDt != null) {
|
||||||
|
if (opcode == PcodeOp.SUBPIECE && accessSlot == 0 &&
|
||||||
|
!(parentDt instanceof Pointer)) {
|
||||||
|
// SUBPIECE acts directly as resolution operator
|
||||||
|
// Choose field based on output varnode, even though it isn't the union data-type
|
||||||
|
accessSlot = -1;
|
||||||
|
accessVn = accessOp.getOutput();
|
||||||
|
}
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
accessSlot = -1;
|
accessSlot = -1;
|
||||||
accessVn = accessOp.getOutput();
|
accessVn = accessOp.getOutput();
|
||||||
@@ -262,7 +305,7 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
|||||||
Program program = context.getProgram();
|
Program program = context.getProgram();
|
||||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||||
HighFunction highFunction = context.getHighFunction();
|
HighFunction highFunction = context.getHighFunction();
|
||||||
unionDt = (Union) getCompositeDataType(tokenAtCursor);
|
unionDt = findUnion(tokenAtCursor);
|
||||||
determineFacet(tokenAtCursor);
|
determineFacet(tokenAtCursor);
|
||||||
if (accessOp == null || accessVn == null) {
|
if (accessOp == null || accessVn == null) {
|
||||||
Msg.showError(this, null, "Force Union failed", "Could not recover p-code op");
|
Msg.showError(this, null, "Force Union failed", "Could not recover p-code op");
|
||||||
@@ -280,7 +323,7 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
|||||||
int transaction = program.startTransaction("Force Union");
|
int transaction = program.startTransaction("Force Union");
|
||||||
try {
|
try {
|
||||||
HighFunctionDBUtil.writeUnionFacet(function, parentDt, fieldNumber, pcAddr,
|
HighFunctionDBUtil.writeUnionFacet(function, parentDt, fieldNumber, pcAddr,
|
||||||
dhash.getHash(), SourceType.USER_DEFINED);
|
dhash.getHash(), true, SourceType.USER_DEFINED);
|
||||||
}
|
}
|
||||||
catch (DuplicateNameException e) {
|
catch (DuplicateNameException e) {
|
||||||
Msg.showError(this, null, "Force Union failed", e.getMessage());
|
Msg.showError(this, null, "Force Union failed", e.getMessage());
|
||||||
|
|||||||
+26
-9
@@ -877,42 +877,53 @@ public class HighFunctionDBUtil {
|
|||||||
/**
|
/**
|
||||||
* Write a union facet to the database (UnionFacetSymbol). Parameters provide the
|
* Write a union facet to the database (UnionFacetSymbol). Parameters provide the
|
||||||
* pieces for building the dynamic LocalVariable. This method clears out any preexisting
|
* pieces for building the dynamic LocalVariable. This method clears out any preexisting
|
||||||
* union facet with the same dynamic hash and firstUseOffset.
|
* union facet with the same dynamic hash and firstUseOffset. The new facet can optionally
|
||||||
|
* be "address based", meaning that all reads/writes of the union at the address are
|
||||||
|
* controlled by this single facet.
|
||||||
* @param function is the function affected by the union facet
|
* @param function is the function affected by the union facet
|
||||||
* @param dt is the parent data-type; a union, a pointer to a union, or a partial union
|
* @param dt is the parent data-type; a union, a pointer to a union, or a partial union
|
||||||
* @param fieldNum is the ordinal of the desired union field
|
* @param fieldNum is the ordinal of the desired union field
|
||||||
* @param addr is the first use address of the facet
|
* @param addr is the first use address of the facet
|
||||||
* @param hash is the dynamic hash
|
* @param hash is the dynamic hash
|
||||||
|
* @param isAddr is true if the new facet is address based
|
||||||
* @param source is the SourceType for the LocalVariable
|
* @param source is the SourceType for the LocalVariable
|
||||||
* @throws InvalidInputException if the LocalVariable cannot be created
|
* @throws InvalidInputException if the LocalVariable cannot be created
|
||||||
* @throws DuplicateNameException if the (auto-generated) name is used elsewhere
|
* @throws DuplicateNameException if the (auto-generated) name is used elsewhere
|
||||||
*/
|
*/
|
||||||
public static void writeUnionFacet(Function function, DataType dt, int fieldNum, Address addr,
|
public static void writeUnionFacet(Function function, DataType dt, int fieldNum, Address addr,
|
||||||
long hash, SourceType source) throws InvalidInputException, DuplicateNameException {
|
long hash, boolean isAddr, SourceType source)
|
||||||
if (dt instanceof PartialUnion) {
|
throws InvalidInputException, DuplicateNameException {
|
||||||
dt = ((PartialUnion) dt).getParent();
|
|
||||||
}
|
|
||||||
int firstUseOffset = (int) addr.subtract(function.getEntryPoint());
|
int firstUseOffset = (int) addr.subtract(function.getEntryPoint());
|
||||||
String symbolName = UnionFacetSymbol.buildSymbolName(fieldNum, addr);
|
|
||||||
boolean nameCollision = false;
|
boolean nameCollision = false;
|
||||||
Variable[] localVariables =
|
Variable[] localVariables =
|
||||||
function.getLocalVariables(VariableFilter.UNIQUE_VARIABLE_FILTER);
|
function.getLocalVariables(VariableFilter.UNIQUE_VARIABLE_FILTER);
|
||||||
// Clean out any facet symbols with bad data-types
|
|
||||||
for (int i = 0; i < localVariables.length; ++i) {
|
for (int i = 0; i < localVariables.length; ++i) {
|
||||||
Variable var = localVariables[i];
|
Variable var = localVariables[i];
|
||||||
if (var.getName().startsWith(UnionFacetSymbol.BASENAME)) {
|
if (var.getName().startsWith(UnionFacetSymbol.BASENAME)) {
|
||||||
if (!UnionFacetSymbol.isUnionType(var.getDataType())) {
|
if (!UnionFacetSymbol.isUnionType(var.getDataType())) { // Clean out any facet symbols with bad data-types
|
||||||
function.removeVariable(var);
|
function.removeVariable(var);
|
||||||
localVariables[i] = null;
|
localVariables[i] = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
localVariables[i] = null; // Ignore symbols that aren't facets
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
String symbolName = UnionFacetSymbol.buildSymbolName(fieldNum, addr, isAddr);
|
||||||
Variable preexistingVar = null;
|
Variable preexistingVar = null;
|
||||||
for (Variable var : localVariables) {
|
for (Variable var : localVariables) {
|
||||||
if (var == null) {
|
if (var == null) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (var.getFirstUseOffset() == firstUseOffset &&
|
if (isAddr && var.getFirstUseOffset() == firstUseOffset) {
|
||||||
|
if (preexistingVar == null) {
|
||||||
|
preexistingVar = var;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
function.removeVariable(var); // Address based facets override all other facets at the same address
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (!isAddr && var.getFirstUseOffset() == firstUseOffset &&
|
||||||
var.getFirstStorageVarnode().getOffset() == hash) {
|
var.getFirstStorageVarnode().getOffset() == hash) {
|
||||||
preexistingVar = var;
|
preexistingVar = var;
|
||||||
}
|
}
|
||||||
@@ -920,6 +931,12 @@ public class HighFunctionDBUtil {
|
|||||||
nameCollision = true;
|
nameCollision = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (dt instanceof PartialUnion) {
|
||||||
|
dt = ((PartialUnion) dt).getParent();
|
||||||
|
}
|
||||||
|
if (isAddr && dt instanceof Pointer) {
|
||||||
|
dt = ((Pointer) dt).getDataType();
|
||||||
|
}
|
||||||
if (nameCollision) { // Uniquify the name if necessary
|
if (nameCollision) { // Uniquify the name if necessary
|
||||||
symbolName = symbolName + '_' + Integer.toHexString(DynamicHash.getComparable(hash));
|
symbolName = symbolName + '_' + Integer.toHexString(DynamicHash.getComparable(hash));
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-2
@@ -461,8 +461,7 @@ public class LocalSymbolMap {
|
|||||||
}
|
}
|
||||||
HighSymbol sym;
|
HighSymbol sym;
|
||||||
if (DynamicHash.getMethodFromHash(hash) > 3 && UnionFacetSymbol.isUnionType(dt)) {
|
if (DynamicHash.getMethodFromHash(hash) > 3 && UnionFacetSymbol.isUnionType(dt)) {
|
||||||
int fieldNum = UnionFacetSymbol.extractFieldNumber(nm);
|
sym = new UnionFacetSymbol(id, nm, dt, func);
|
||||||
sym = new UnionFacetSymbol(id, nm, dt, fieldNum, func);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
sym = new HighSymbol(id, nm, dt, func);
|
sym = new HighSymbol(id, nm, dt, func);
|
||||||
|
|||||||
+32
-7
@@ -4,9 +4,9 @@
|
|||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@@ -35,11 +35,13 @@ import ghidra.program.model.data.*;
|
|||||||
public class UnionFacetSymbol extends HighSymbol {
|
public class UnionFacetSymbol extends HighSymbol {
|
||||||
public static String BASENAME = "unionfacet";
|
public static String BASENAME = "unionfacet";
|
||||||
private int fieldNumber; // Ordinal of field within union being selected
|
private int fieldNumber; // Ordinal of field within union being selected
|
||||||
|
private boolean isAddrBased; // Controls facets for any op at the address
|
||||||
|
|
||||||
public UnionFacetSymbol(long uniqueId, String nm, DataType dt, int fldNum, HighFunction func) {
|
public UnionFacetSymbol(long uniqueId, String nm, DataType dt, HighFunction func) {
|
||||||
super(uniqueId, nm, dt, func);
|
super(uniqueId, nm, dt, func);
|
||||||
category = 2;
|
category = 2;
|
||||||
fieldNumber = fldNum;
|
fieldNumber = extractFieldNumber(nm);
|
||||||
|
isAddrBased = extractAddressBased(nm);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -47,6 +49,7 @@ public class UnionFacetSymbol extends HighSymbol {
|
|||||||
encoder.openElement(ELEM_FACETSYMBOL);
|
encoder.openElement(ELEM_FACETSYMBOL);
|
||||||
encodeHeader(encoder);
|
encodeHeader(encoder);
|
||||||
encoder.writeSignedInteger(ATTRIB_FIELD, fieldNumber);
|
encoder.writeSignedInteger(ATTRIB_FIELD, fieldNumber);
|
||||||
|
encoder.writeBool(ATTRIB_ADDRTIED, isAddrBased);
|
||||||
dtmanage.encodeTypeRef(encoder, type, getSize());
|
dtmanage.encodeTypeRef(encoder, type, getSize());
|
||||||
encoder.closeElement(ELEM_FACETSYMBOL);
|
encoder.closeElement(ELEM_FACETSYMBOL);
|
||||||
}
|
}
|
||||||
@@ -55,11 +58,16 @@ public class UnionFacetSymbol extends HighSymbol {
|
|||||||
* Generate an automatic symbol name, given a field number and address
|
* Generate an automatic symbol name, given a field number and address
|
||||||
* @param fldNum is the field number
|
* @param fldNum is the field number
|
||||||
* @param addr is the Address
|
* @param addr is the Address
|
||||||
|
* @param isAddr is true if the facet should be address based
|
||||||
* @return the name
|
* @return the name
|
||||||
*/
|
*/
|
||||||
public static String buildSymbolName(int fldNum, Address addr) {
|
public static String buildSymbolName(int fldNum, Address addr, boolean isAddr) {
|
||||||
StringBuilder buffer = new StringBuilder();
|
StringBuilder buffer = new StringBuilder();
|
||||||
buffer.append(BASENAME).append(fldNum + 1).append('_');
|
buffer.append(BASENAME);
|
||||||
|
if (isAddr) {
|
||||||
|
buffer.append('a');
|
||||||
|
}
|
||||||
|
buffer.append(fldNum + 1).append('_');
|
||||||
buffer.append(Long.toHexString(addr.getOffset()));
|
buffer.append(Long.toHexString(addr.getOffset()));
|
||||||
return buffer.toString();
|
return buffer.toString();
|
||||||
}
|
}
|
||||||
@@ -74,11 +82,28 @@ public class UnionFacetSymbol extends HighSymbol {
|
|||||||
if (pos < 0) {
|
if (pos < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
pos += BASENAME.length();
|
||||||
|
if (nm.length() > pos && nm.charAt(pos) == 'a') {
|
||||||
|
pos = pos + 1;
|
||||||
|
}
|
||||||
int endpos = nm.indexOf('_', pos);
|
int endpos = nm.indexOf('_', pos);
|
||||||
if (endpos < 0) {
|
if (endpos < 0) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return Integer.decode(nm.substring(pos + BASENAME.length(), endpos)) - 1;
|
return Integer.decode(nm.substring(pos, endpos)) - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* First character of 'a' after BASENAME indicates an address based facet
|
||||||
|
* @param nm is the symbol name
|
||||||
|
* @return true if the facet is address based
|
||||||
|
*/
|
||||||
|
public static boolean extractAddressBased(String nm) {
|
||||||
|
int pos = nm.indexOf(BASENAME);
|
||||||
|
if (pos < 0 || nm.length() <= pos) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return nm.charAt(pos + BASENAME.length()) == 'a';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user