GP-6492 Adjustments to union scoring

This commit is contained in:
caheckman
2026-02-26 19:53:42 +00:00
parent 7928bef769
commit e12d821d86
25 changed files with 952 additions and 333 deletions
@@ -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
@@ -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;
@@ -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;
@@ -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());
@@ -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));
} }
@@ -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);
@@ -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';
} }
/** /**