mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-22 06:05:37 +08:00
GP-6492 Adjustments to union scoring
This commit is contained in:
@@ -205,7 +205,13 @@ StringSequence::StringSequence(Funcdata &fdata,Datatype *ct,SymbolEntry *ent,Pco
|
||||
break;
|
||||
arrayType = parentType;
|
||||
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);
|
||||
if (parentType != ct || arrayType == (Datatype *)0 || arrayType->getMetatype() != TYPE_ARRAY)
|
||||
return;
|
||||
@@ -296,8 +302,20 @@ Varnode *StringSequence::constructTypedPointer(PcodeOp *insertPoint)
|
||||
if (baseType->getMetatype() == TYPE_ARRAY)
|
||||
elSize = ((TypeArray *)baseType)->getBase()->getAlignSize();
|
||||
int8 newOff;
|
||||
baseType = baseType->getSubType(curOff, &newOff );
|
||||
if (baseType == (Datatype *)0) break;
|
||||
if (baseType->needsResolution()) {
|
||||
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;
|
||||
baseOff = AddrSpace::byteToAddress(curOff, spc->getWordSize());
|
||||
if (elSize >= 0) {
|
||||
@@ -318,6 +336,8 @@ Varnode *StringSequence::constructTypedPointer(PcodeOp *insertPoint)
|
||||
data.opSetInput(ptrsub,data.newConstant(spacePtr->getSize(), baseOff), 1);
|
||||
}
|
||||
data.opSetInput(ptrsub,spacePtr,0);
|
||||
if (curType->needsResolution())
|
||||
data.inheritUnionFieldPtr(curType, ptrsub, 0, insertPoint, -1);
|
||||
spacePtr = data.newUniqueOut(spacePtr->getSize(), ptrsub);
|
||||
data.opInsertBefore(ptrsub, insertPoint);
|
||||
curType = types->getTypePointerStripArray(spacePtr->getSize(), baseType, spc->getWordSize());
|
||||
@@ -364,6 +384,8 @@ PcodeOp *StringSequence::buildStringCopy(void)
|
||||
Varnode *destPtr = constructTypedPointer(insertPoint);
|
||||
data.opSetInput(copyOp, destPtr, 1);
|
||||
data.opSetInput(copyOp, srcPtr, 2);
|
||||
if (destPtr->getType()->needsResolution())
|
||||
data.inheritUnionFieldPtr(destPtr->getType(), copyOp, 1, insertPoint, -1);
|
||||
Varnode *lenVn = data.newConstant(4,index);
|
||||
lenVn->updateType(copyOp->inputTypeLocal(3));
|
||||
data.opSetInput(copyOp, lenVn, 3);
|
||||
@@ -460,12 +482,12 @@ bool StringSequence::transform(void)
|
||||
return true;
|
||||
}
|
||||
|
||||
/// From a starting pointer, backtrack through PTRADDs and COPYs to a putative root Varnode pointer.
|
||||
/// \param initPtr is pointer Varnode into the root STORE
|
||||
void HeapSequence::findBasePointer(Varnode *initPtr)
|
||||
/// From a starting pointer to \b rootOp, backtrack through PTRADDs and COPYs to a putative root Varnode pointer.
|
||||
void HeapSequence::findBasePointer(void)
|
||||
|
||||
{
|
||||
basePointer = initPtr;
|
||||
basePointer = rootOp->getIn(1);
|
||||
immedRead = rootOp;
|
||||
while(basePointer->isWritten()) {
|
||||
PcodeOp *op = basePointer->getDef();
|
||||
OpCode opc = op->code();
|
||||
@@ -476,6 +498,7 @@ void HeapSequence::findBasePointer(Varnode *initPtr)
|
||||
else if (opc != CPUI_COPY)
|
||||
break;
|
||||
basePointer = op->getIn(0);
|
||||
immedRead = op;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -745,6 +768,8 @@ PcodeOp *HeapSequence::buildStringCopy(void)
|
||||
data.opSetInput(ptrAdd,data.newConstant(basePointer->getSize(), charType->getAlignSize()),2);
|
||||
destPtr->updateType(charPtrType);
|
||||
data.opInsertBefore(ptrAdd, insertPoint);
|
||||
if (basePointer->getType()->needsResolution())
|
||||
data.inheritUnionField(basePointer->getType(), ptrAdd, 0, immedRead, immedRead->getSlot(basePointer));
|
||||
}
|
||||
int4 index;
|
||||
uint4 builtInId = selectStringCopyFunction(index);
|
||||
@@ -758,6 +783,8 @@ PcodeOp *HeapSequence::buildStringCopy(void)
|
||||
lenVn->updateType(copyOp->inputTypeLocal(3));
|
||||
data.opSetInput(copyOp, lenVn, 3);
|
||||
data.opInsertBefore(copyOp, insertPoint);
|
||||
if (destPtr->getType()->needsResolution())
|
||||
data.inheritUnionField(destPtr->getType(), copyOp, 1, immedRead, immedRead->getSlot(destPtr));
|
||||
return copyOp;
|
||||
}
|
||||
|
||||
@@ -910,7 +937,7 @@ HeapSequence::HeapSequence(Funcdata &fdata,Datatype *ct,PcodeOp *root)
|
||||
baseOffset = 0;
|
||||
storeSpace = root->getIn(0)->getSpaceFromConst();
|
||||
ptrAddMult = AddrSpace::byteToAddressInt(charType->getAlignSize(), storeSpace->getWordSize());
|
||||
findBasePointer(rootOp->getIn(1));
|
||||
findBasePointer();
|
||||
if (!collectStoreOps())
|
||||
return;
|
||||
if (!checkInterference())
|
||||
@@ -956,7 +983,7 @@ int4 RuleStringCopy::applyOp(PcodeOp *op,Funcdata &data)
|
||||
{
|
||||
if (!op->getIn(0)->isConstant()) return 0; // Constant
|
||||
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->isOpaqueString()) 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
|
||||
};
|
||||
Varnode *basePointer; ///< Pointer that sequence is stored to
|
||||
PcodeOp *immedRead; ///< Op immediately reading basePointer
|
||||
uint8 baseOffset; ///< Offset relative to pointer to root STORE
|
||||
AddrSpace *storeSpace; ///< Address space being STOREed to
|
||||
int4 ptrAddMult; ///< Required multiplier for PTRADD ops
|
||||
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 findInitialStores(vector<PcodeOp *> &stores);
|
||||
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);
|
||||
}
|
||||
|
||||
/// \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
|
||||
/// unions, the CAST can sometimes be eliminated by adjusting the data-type resolutions
|
||||
/// of the Varnodes relative to the PcodeOp
|
||||
/// \param op is the PcodeOp reading the input Varnode and writing the output Varnode
|
||||
/// \param slot is the index of the input Varnode
|
||||
/// \param op is the COPY
|
||||
/// \param data is the function
|
||||
/// \return \b true if an adjustment is made so that a CAST is no longer needed
|
||||
bool ActionSetCasts::tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &data)
|
||||
bool ActionSetCasts::tryResolutionCopy(PcodeOp *op,Funcdata &data)
|
||||
|
||||
{
|
||||
Varnode *outvn = op->getOut();
|
||||
if (outvn == (Varnode *)0)
|
||||
return false;
|
||||
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;
|
||||
int4 inResolve = -1;
|
||||
int4 outResolve = -1;
|
||||
@@ -2478,7 +2509,7 @@ bool ActionSetCasts::tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &dat
|
||||
inResolve = inType->findCompatibleResolve(outType);
|
||||
if (inResolve < 0) return false;
|
||||
}
|
||||
if (outType->needsResolution()) {
|
||||
if (outType->needsResolution() && outType->getMetatype() != TYPE_PTR) {
|
||||
if (inResolve >= 0)
|
||||
outResolve = outType->findCompatibleResolve(inType->getDepend(inResolve));
|
||||
else
|
||||
@@ -2487,12 +2518,12 @@ bool ActionSetCasts::tryResolutionAdjustment(PcodeOp *op,int4 slot,Funcdata &dat
|
||||
}
|
||||
|
||||
TypeFactory *typegrp = data.getArch()->types;
|
||||
if (inType->needsResolution()) {
|
||||
if (inResolve >= 0) {
|
||||
ResolvedUnion resolve(inType,inResolve,*typegrp);
|
||||
if (!data.setUnionField(inType, op, slot, resolve))
|
||||
if (!data.setUnionField(inType, op, 0, resolve))
|
||||
return false;
|
||||
}
|
||||
if (outType->needsResolution()) {
|
||||
if (outResolve >= 0) {
|
||||
ResolvedUnion resolve(outType,outResolve,*typegrp);
|
||||
if (!data.setUnionField(outType, op, -1, resolve))
|
||||
return false;
|
||||
@@ -2537,10 +2568,12 @@ int4 ActionSetCasts::resolveUnion(PcodeOp *op,int4 slot,Funcdata &data,CastStrat
|
||||
Datatype *dt = vn->getHigh()->getType();
|
||||
if (!dt->needsResolution())
|
||||
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
|
||||
const ResolvedUnion *resUnion = data.getUnionField(dt, op,slot);
|
||||
if (resUnion != (ResolvedUnion*)0 && resUnion->getFieldNum() >= 0) {
|
||||
resUnion = data.getUnionField(dt, op, slot);
|
||||
}
|
||||
if (resUnion != (ResolvedUnion *)0 && resUnion->getFieldNum() >= 0) {
|
||||
if (dt->getMetatype() == TYPE_PTR) {
|
||||
// Test if a cast is still needed even after resolution
|
||||
Datatype *reqtype = vn->getTypeReadFacing(op);
|
||||
@@ -2577,12 +2610,11 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||
Datatype *outct,*ct,*tokenct;
|
||||
Varnode *vn,*outvn;
|
||||
PcodeOp *newop;
|
||||
Datatype *outHighType;
|
||||
bool force=false;
|
||||
|
||||
tokenct = op->getOpcode()->getOutputToken(op,castStrategy);
|
||||
outvn = op->getOut();
|
||||
outHighType = outvn->getHigh()->getType();
|
||||
Datatype *outHighType = outvn->getHigh()->getType();
|
||||
if (tokenct == outHighType) {
|
||||
if (tokenct->needsResolution()) {
|
||||
// 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
|
||||
return 0;
|
||||
}
|
||||
Datatype *outHighResolve = outHighType;
|
||||
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
|
||||
}
|
||||
Datatype *outHighResolve = outvn->getHighTypeDefFacing();
|
||||
if (outvn->isImplied()) {
|
||||
// implied varnode must have parse type
|
||||
if (outvn->isTypeLock()) {
|
||||
@@ -2632,6 +2659,8 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||
ct = castStrategy->castStandard(outct,tokenct,false,true);
|
||||
if (ct == (Datatype *)0) return 0;
|
||||
}
|
||||
if (tryResolutionAdjustment(tokenct, op, -1, data))
|
||||
return 0;
|
||||
}
|
||||
// Generate the cast op
|
||||
vn = data.newUnique(outvn->getSize());
|
||||
@@ -2652,7 +2681,7 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
|
||||
if (tokenct->needsResolution())
|
||||
data.forceFacingType(tokenct, -1, newop, 0);
|
||||
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;
|
||||
}
|
||||
@@ -2735,10 +2764,12 @@ int4 ActionSetCasts::castInput(PcodeOp *op,int4 slot,Funcdata &data,CastStrategy
|
||||
// Insert a PTRSUB(vn,#0) instead of a CAST
|
||||
newop = insertPtrsubZero(op, slot, ct, data);
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
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;
|
||||
}
|
||||
@@ -2796,9 +2827,18 @@ int4 ActionSetCasts::apply(Funcdata &data)
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
if (opc == CPUI_LOAD) {
|
||||
@@ -2807,9 +2847,8 @@ int4 ActionSetCasts::apply(Funcdata &data)
|
||||
else if (opc == CPUI_STORE) {
|
||||
checkPointerIssues(op, op->getIn(2), data);
|
||||
}
|
||||
Varnode *vn = op->getOut();
|
||||
if (vn == (Varnode *)0) continue;
|
||||
count += castOutput(op,data,castStrategy);
|
||||
if (vn != (Varnode *)0)
|
||||
count += castOutput(op,data,castStrategy);
|
||||
}
|
||||
}
|
||||
return 0; // Indicate full completion
|
||||
@@ -5127,13 +5166,15 @@ bool ActionInferTypes::propagateTypeEdge(TypeFactory *typegrp,PcodeOp *op,int4 i
|
||||
{
|
||||
Varnode *invn,*outvn;
|
||||
|
||||
if (inslot == outslot) return false; // don't backtrack
|
||||
invn = (inslot==-1) ? op->getOut() : op->getIn(inslot);
|
||||
Datatype *alttype = invn->getTempType();
|
||||
if (alttype->needsResolution()) {
|
||||
// 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)
|
||||
outvn = op->getOut();
|
||||
else {
|
||||
|
||||
@@ -320,7 +320,8 @@ public:
|
||||
class ActionSetCasts : public Action {
|
||||
static void checkPointerIssues(PcodeOp *op,Varnode *vn,Funcdata &data);
|
||||
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 int4 resolveUnion(PcodeOp *op,int4 slot,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 unionDt is the union data-type being forced
|
||||
/// \param fldNum is the particular field to force (-1 indicates the whole union)
|
||||
UnionFacetSymbol::UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum)
|
||||
/// \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)
|
||||
{
|
||||
fieldNum = fldNum;
|
||||
category = union_facet;
|
||||
addrBased = isAddr;
|
||||
}
|
||||
|
||||
void UnionFacetSymbol::encode(Encoder &encoder) const
|
||||
@@ -701,6 +703,7 @@ void UnionFacetSymbol::encode(Encoder &encoder) const
|
||||
encoder.openElement(ELEM_FACETSYMBOL);
|
||||
encodeHeader(encoder);
|
||||
encoder.writeSignedInteger(ATTRIB_FIELD, fieldNum);
|
||||
encoder.writeBool(ATTRIB_ADDRTIED, true);
|
||||
encodeBody(encoder);
|
||||
encoder.closeElement(ELEM_FACETSYMBOL);
|
||||
}
|
||||
@@ -711,6 +714,7 @@ void UnionFacetSymbol::decode(Decoder &decoder)
|
||||
uint4 elemId = decoder.openElement(ELEM_FACETSYMBOL);
|
||||
decodeHeader(decoder);
|
||||
fieldNum = decoder.readSignedInteger(ATTRIB_FIELD);
|
||||
addrBased = decoder.readBool(ATTRIB_ADDRTIED);
|
||||
|
||||
decodeBody(decoder);
|
||||
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.
|
||||
class UnionFacetSymbol : public Symbol {
|
||||
int4 fieldNum; ///< Particular field to associate with Symbol access
|
||||
bool addrBased; ///< Set to \b true if facet matches any PcodeOp at the address
|
||||
public:
|
||||
UnionFacetSymbol(Scope *sc,const string &nm,Datatype *unionDt,int4 fldNum); ///< Constructor from components
|
||||
UnionFacetSymbol(Scope *sc) : Symbol(sc) { fieldNum = -1; category = union_facet; } ///< Constructor for decode
|
||||
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; addrBased = false; } ///< Constructor for decode
|
||||
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 decode(Decoder &decoder);
|
||||
};
|
||||
|
||||
@@ -222,6 +222,25 @@ void FloatFormat::calcPrecision(void)
|
||||
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 type points to the floating-point class, which is passed back
|
||||
/// \return the equivalent double value
|
||||
|
||||
@@ -64,6 +64,7 @@ private:
|
||||
public:
|
||||
FloatFormat(int4 sz); ///< Construct default IEEE 754 standard settings
|
||||
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
|
||||
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
|
||||
@@ -71,6 +72,7 @@ public:
|
||||
uintb extractFractionalCode(uintb x) const; ///< Extract the fractional part of 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 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
|
||||
|
||||
|
||||
@@ -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
|
||||
/// \param parent is the data-type being resolved
|
||||
/// If there is no field associated with the edge, or the resolved data-type is not
|
||||
/// 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 slot is the slot component of the given edge
|
||||
/// \return the associated field as a ResolvedUnion or null
|
||||
const ResolvedUnion *Funcdata::getUnionField(const Datatype *parent,const PcodeOp *op,int4 slot) const
|
||||
const ResolvedUnion *Funcdata::getUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot) const
|
||||
|
||||
{
|
||||
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);
|
||||
if (iter != unionMap.end())
|
||||
return &(*iter).second;
|
||||
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.
|
||||
/// 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 slot is the slot component of the given edge
|
||||
/// \param resolve is the resolved union
|
||||
/// \return \b true unless there was a locked association
|
||||
bool Funcdata::setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve)
|
||||
/// \return \b true unless the resolution was locked
|
||||
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;
|
||||
res = unionMap.emplace(edge,resolve);
|
||||
if (!res.second) {
|
||||
if ((*res.first).second.isLocked()) {
|
||||
return false;
|
||||
}
|
||||
(*res.first).second = resolve;
|
||||
if (!(*res.first).second.update(resolve))
|
||||
return !(*res.first).second.isLocked();
|
||||
}
|
||||
if (op->code() == CPUI_MULTIEQUAL && slot >= 0) {
|
||||
// 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) {
|
||||
if (i == slot) continue;
|
||||
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);
|
||||
if (!res.second) {
|
||||
if (!(*res.first).second.isLocked())
|
||||
(*res.first).second = resolve;
|
||||
(*res.first).second.update(resolve);
|
||||
}
|
||||
}
|
||||
}
|
||||
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.
|
||||
/// \param parent is the parent data-type
|
||||
/// If there was a previous association, it is overwritten unless it was \e locked.
|
||||
/// The method returns \b true except in this case where a previous locked association exists.
|
||||
/// \param 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 op is PcodeOp of the edge
|
||||
/// \param slot is -1 for the write edge or >=0 indicating the particular read edge
|
||||
void Funcdata::forceFacingType(Datatype *parent,int4 fieldNum,PcodeOp *op,int4 slot)
|
||||
void Funcdata::forceFacingType(Datatype *unresType,int4 fieldNum,PcodeOp *op,int4 slot)
|
||||
|
||||
{
|
||||
Datatype *baseType = parent;
|
||||
Datatype *baseType = unresType;
|
||||
if (baseType->getMetatype() == TYPE_PTR)
|
||||
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
|
||||
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);
|
||||
setUnionField(parent, op, slot, resolve);
|
||||
ResolvedUnion resolve(unresType,fieldNum,*glb->types);
|
||||
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 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)
|
||||
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;
|
||||
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);
|
||||
iter = unionMap.find(edge);
|
||||
if (iter == unionMap.end())
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -529,11 +529,15 @@ public:
|
||||
|
||||
bool moveRespectingCover(PcodeOp *op,PcodeOp *lastOp); ///< Move given op past \e lastOp respecting covers if possible
|
||||
|
||||
const ResolvedUnion *getUnionField(const Datatype *parent,const PcodeOp *op,int4 slot) const;
|
||||
bool setUnionField(const Datatype *parent,const PcodeOp *op,int4 slot,const ResolvedUnion &resolve);
|
||||
void forceFacingType(Datatype *parent,int4 fieldNum,PcodeOp *op,int4 slot);
|
||||
int4 inheritResolution(Datatype *parent,const PcodeOp *op,int4 slot,PcodeOp *oldOp,int4 oldSlot);
|
||||
|
||||
const ResolvedUnion *getUnionField(const Datatype *unresType,const PcodeOp *op,int4 slot) const;
|
||||
const ResolvedUnion *getAddressBasedUnionField(const Datatype *unresType,const Address &addr,int4 slot) const;
|
||||
const ResolvedUnion *getUnionResolution(const Datatype *unresType,const PcodeOp *op,int4 slot) const;
|
||||
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 *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
|
||||
|
||||
@@ -1656,15 +1656,40 @@ void Funcdata::coverVarnodes(SymbolEntry *entry,vector<Varnode *> &list)
|
||||
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());
|
||||
if (op == (PcodeOp *)0)
|
||||
return false;
|
||||
int4 slot = DynamicHash::getSlotFromHash(entry->getHash());
|
||||
int4 fldNum = ((UnionFacetSymbol *)sym)->getFieldNumber();
|
||||
ResolvedUnion resolve(sym->getType(), fldNum, *glb->types);
|
||||
const ResolvedUnion *res = getUnionResolution(sym->getType(), op, slot);
|
||||
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);
|
||||
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
|
||||
|
||||
@@ -416,7 +416,7 @@ PcodeOp *Merge::allocateCopyTrim(Varnode *inVn,const Address &addr,PcodeOp *trim
|
||||
Datatype *ct = inVn->getType();
|
||||
if (ct->needsResolution()) { // If the data-type needs resolution
|
||||
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);
|
||||
}
|
||||
else {
|
||||
@@ -669,7 +669,7 @@ void Merge::trimOpOutput(PcodeOp *op)
|
||||
copyop = data.newOp(1,op->getAddr());
|
||||
data.opSetOpcode(copyop,CPUI_COPY);
|
||||
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);
|
||||
if (ct->getMetatype() == TYPE_PARTIALUNION)
|
||||
ct = vn->getTypeDefFacing();
|
||||
@@ -871,7 +871,7 @@ void Merge::mergeIndirect(PcodeOp *indop)
|
||||
PcodeOp *newop = allocateCopyTrim(invn0, indop->getAddr(), indop);
|
||||
SymbolEntry *entry = outvn->getSymbolEntry();
|
||||
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.opInsertBefore(newop,indop);
|
||||
|
||||
@@ -6517,8 +6517,12 @@ void AddTreeState::buildTree(void)
|
||||
// Create PTRADD portion of operation
|
||||
if (multNode != (Varnode *)0) {
|
||||
newop = data.newOpBefore(baseOp,CPUI_PTRADD,ptr,multNode,data.newConstant(ptrsize,size));
|
||||
if (ptr->getType()->needsResolution())
|
||||
data.inheritResolution(ptr->getType(),newop, 0, baseOp, baseSlot);
|
||||
if (ptr->getType()->needsResolution()) {
|
||||
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())
|
||||
assignPropagatedType(newop);
|
||||
multNode = newop->getOut();
|
||||
@@ -6530,7 +6534,7 @@ void AddTreeState::buildTree(void)
|
||||
if (isSubtype) {
|
||||
newop = data.newOpBefore(baseOp,CPUI_PTRSUB,multNode,data.newConstant(ptrsize,offset));
|
||||
if (multNode->getType()->needsResolution())
|
||||
data.inheritResolution(multNode->getType(),newop, 0, baseOp, baseSlot);
|
||||
data.inheritUnionField(multNode->getType(),newop, 0, baseOp, baseSlot);
|
||||
if (data.isTypeRecoveryExceeded())
|
||||
assignPropagatedType(newop);
|
||||
if (size != 0)
|
||||
@@ -6731,7 +6735,7 @@ int4 RuleStructOffset0::applyOp(PcodeOp *op,Funcdata &data)
|
||||
// Create pointer up to parent
|
||||
PcodeOp *newop = data.newOpBefore(op,CPUI_PTRSUB,ptrVn,data.newConstant(ptrVn->getSize(),offset));
|
||||
if (ptrVn->getType()->needsResolution())
|
||||
data.inheritResolution(ptrVn->getType(),newop, 0, op, 1);
|
||||
data.inheritUnionField(ptrVn->getType(),newop, 0, op, 1);
|
||||
newop->setStopTypePropagation();
|
||||
if (newoff != 0) {
|
||||
// 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));
|
||||
if (ptrVn->getType()->needsResolution())
|
||||
data.inheritResolution(ptrVn->getType(),newop, 0, op, 1);
|
||||
data.inheritUnionField(ptrVn->getType(),newop, 0, op, 1);
|
||||
newop->setStopTypePropagation();
|
||||
data.opSetInput(op,newop->getOut(),1);
|
||||
return 1;
|
||||
@@ -7100,10 +7104,11 @@ int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
|
||||
{
|
||||
int8 extra = 0;
|
||||
PcodeOp *op = vn->loneDescend();
|
||||
Varnode *nextVn = vn;
|
||||
while(op != (PcodeOp *)0) {
|
||||
OpCode opc = op->code();
|
||||
if (opc == CPUI_INT_ADD) {
|
||||
int4 slot = op->getSlot(vn);
|
||||
int4 slot = op->getSlot(nextVn);
|
||||
if (slot == 0 && op->getIn(1)->isConstant()) {
|
||||
extra += (int8)op->getIn(1)->getOffset();
|
||||
data.opRemoveInput(op, 1);
|
||||
@@ -7120,7 +7125,7 @@ int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
|
||||
data.opSetOpcode(op, CPUI_COPY);
|
||||
}
|
||||
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
|
||||
// as it is associated with the invalid PTRSUB
|
||||
int8 ptraddmult = op->getIn(2)->getOffset();
|
||||
@@ -7139,9 +7144,11 @@ int8 RulePtrsubUndo::removeLocalAdds(Varnode *vn,Funcdata &data)
|
||||
else {
|
||||
break;
|
||||
}
|
||||
vn = op->getOut();
|
||||
op = vn->loneDescend();
|
||||
nextVn = op->getOut();
|
||||
op = nextVn->loneDescend();
|
||||
}
|
||||
if (nextVn != vn)
|
||||
vn->updateType(nextVn->getType());
|
||||
return extra;
|
||||
}
|
||||
|
||||
@@ -7561,7 +7568,7 @@ bool RulePieceStructure::convertZextToPiece(PcodeOp *zext,Datatype *ct,int4 offs
|
||||
data.opSetOpcode(zext, CPUI_PIECE);
|
||||
data.opInsertInput(zext, zerovn, 0);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -7692,7 +7699,7 @@ int4 RulePieceStructure::applyOp(PcodeOp *op,Funcdata &data)
|
||||
data.opInsertBefore(copyOp, node.getOp());
|
||||
if (vn->getType()->needsResolution()) {
|
||||
// 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()) {
|
||||
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 valueType is the specific data-type to match
|
||||
/// \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;
|
||||
@@ -2151,12 +2151,14 @@ bool SplitDatatype::RootPointer::find(PcodeOp *op,Datatype *valueType)
|
||||
valueType = ((TypeArray *)valueType)->getBase();
|
||||
impliedBase = valueType; // we allow an implied array (pointer to element) as a match
|
||||
}
|
||||
int4 key = (op->code() == CPUI_LOAD) ? 0 : 1;
|
||||
loadStore = op;
|
||||
baseOffset = 0;
|
||||
firstPointer = pointer = op->getIn(1);
|
||||
Datatype *ct = pointer->getTypeReadFacing(op);
|
||||
if (ct->getMetatype() != TYPE_PTR)
|
||||
return false;
|
||||
resolver.addResolution(key, pointer->getType(), op, 1);
|
||||
ptrType = (TypePointer *)ct;
|
||||
if (ptrType->getPtrTo() != valueType) {
|
||||
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
|
||||
for(int4 i=0;i<3;++i) {
|
||||
if (pointer->isAddrTied() || pointer->loneDescend() == (PcodeOp *)0) break;
|
||||
Varnode *lastVn = pointer;
|
||||
if (!backUpPointer(impliedBase))
|
||||
break;
|
||||
resolver.addResolution(key, pointer->getType(), lastVn->getDef(), 0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -2639,9 +2643,15 @@ void SplitDatatype::buildPointers(Varnode *rootVn,TypePointer *ptrType,int4 base
|
||||
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;
|
||||
int4 sz = newType->getSize(); // Element size in bytes
|
||||
int4 sz = resType->getSize(); // Element size in bytes
|
||||
finalOffset = finalOffset / sz; // Number of elements
|
||||
sz = AddrSpace::byteToAddressInt(sz, ptrType->getWordSize());
|
||||
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, data.newConstant(inPtr->getSize(), finalOffset), 1);
|
||||
}
|
||||
resolver.inheritResolution(isInput ? 0 : 1, inPtr, newOp, 0);
|
||||
inPtr = data.newUniqueOut(inPtr->getSize(), newOp);
|
||||
Datatype *tmpPtr = types->getTypePointerStripArray(ptrType->getSize(), newType, ptrType->getWordSize());
|
||||
inPtr->updateType(tmpPtr);
|
||||
data.opInsertBefore(newOp, followOp);
|
||||
tmpType = newType;
|
||||
tmpType = resType;
|
||||
curOff = newOff;
|
||||
} while(tmpType->getSize() > matchType->getSize());
|
||||
ptrVarnodes.push_back(inPtr);
|
||||
@@ -2699,7 +2710,7 @@ bool SplitDatatype::isArithmeticOutput(Varnode *vn)
|
||||
}
|
||||
|
||||
SplitDatatype::SplitDatatype(Funcdata &func)
|
||||
: data(func)
|
||||
: data(func), resolver(func)
|
||||
{
|
||||
Architecture *glb = func.getArch();
|
||||
types = glb->types;
|
||||
@@ -2729,6 +2740,8 @@ bool SplitDatatype::splitCopy(PcodeOp *copyOp,Datatype *inType,Datatype *outType
|
||||
return false;
|
||||
vector<Varnode *> inVarnodes;
|
||||
vector<Varnode *> outVarnodes;
|
||||
Datatype *unresOutType = outVn->getType();
|
||||
resolver.addResolution(0,unresOutType, copyOp, -1);
|
||||
if (inVn->isConstant())
|
||||
buildInConstants(inVn,inVarnodes,outVn->getSpace()->isBigEndian());
|
||||
else
|
||||
@@ -2741,6 +2754,7 @@ bool SplitDatatype::splitCopy(PcodeOp *copyOp,Datatype *inType,Datatype *outType
|
||||
data.opSetInput(newCopyOp,inVarnodes[i],0);
|
||||
data.opSetOutput(newCopyOp,outVarnodes[i]);
|
||||
data.opInsertBefore(newCopyOp, copyOp);
|
||||
resolver.inheritResolution(0,unresOutType, dataTypePieces[i].offset, outVarnodes[i], newCopyOp, -1);
|
||||
}
|
||||
data.opDestroy(copyOp);
|
||||
return true;
|
||||
@@ -2776,7 +2790,7 @@ bool SplitDatatype::splitLoad(PcodeOp *loadOp,Datatype *inType)
|
||||
if (isArithmeticInput(outVn)) // Sanity check on output
|
||||
return false;
|
||||
RootPointer root;
|
||||
if (!root.find(loadOp,inType))
|
||||
if (!root.find(loadOp,inType,resolver))
|
||||
return false;
|
||||
vector<Varnode *> ptrVarnodes;
|
||||
vector<Varnode *> outVarnodes;
|
||||
@@ -2839,12 +2853,12 @@ bool SplitDatatype::splitStore(PcodeOp *storeOp,Datatype *outType)
|
||||
return false;
|
||||
|
||||
RootPointer storeRoot;
|
||||
if (!storeRoot.find(storeOp,outType))
|
||||
if (!storeRoot.find(storeOp,outType,resolver))
|
||||
return false;
|
||||
|
||||
RootPointer loadRoot;
|
||||
if (loadOp != (PcodeOp *)0) {
|
||||
if (!loadRoot.find(loadOp,inType))
|
||||
if (!loadRoot.find(loadOp,inType,resolver))
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "ruleaction.hh"
|
||||
#include "transform.hh"
|
||||
#include "unionresolve.hh"
|
||||
|
||||
namespace ghidra {
|
||||
|
||||
@@ -277,13 +278,14 @@ class SplitDatatype {
|
||||
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
|
||||
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 freePointerChain(Funcdata &data); ///< Remove unused pointer calculations
|
||||
};
|
||||
Funcdata &data; ///< The containing function
|
||||
TypeFactory *types; ///< The data-type container
|
||||
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 splitArrays; ///< Whether or not arrays should be split
|
||||
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) {
|
||||
Funcdata *fd = op->getParent()->getFuncdata();
|
||||
const ResolvedUnion *res = fd->getUnionField(this,op,slot);
|
||||
if (res != (ResolvedUnion*)0)
|
||||
if (res != (ResolvedUnion *)0)
|
||||
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());
|
||||
return scoreFields.getResult().getDatatype();
|
||||
}
|
||||
@@ -1338,6 +1344,15 @@ Datatype* TypePointer::findResolve(const PcodeOp *op,int4 slot)
|
||||
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
|
||||
|
||||
{
|
||||
@@ -2530,7 +2545,13 @@ Datatype *TypeUnion::resolveInFlow(PcodeOp *op,int4 slot)
|
||||
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
||||
if (res != (ResolvedUnion *)0)
|
||||
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());
|
||||
return scoreFields.getResult().getDatatype();
|
||||
}
|
||||
@@ -2549,7 +2570,13 @@ const TypeField *TypeUnion::resolveTruncation(int8 offset,PcodeOp *op,int4 slot,
|
||||
|
||||
{
|
||||
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->getFieldNum() >= 0) {
|
||||
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
|
||||
ScoreUnionFields scoreFields(*fd->getArch()->types,this,offset,op);
|
||||
ScoreUnionFields scoreFields(*fd,this,offset,op);
|
||||
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
||||
if (scoreFields.getResult().getFieldNum() >= 0) {
|
||||
newoff = 0;
|
||||
@@ -2566,7 +2593,7 @@ const TypeField *TypeUnion::resolveTruncation(int8 offset,PcodeOp *op,int4 slot,
|
||||
}
|
||||
}
|
||||
else {
|
||||
ScoreUnionFields scoreFields(*fd->getArch()->types,this,offset,op,slot);
|
||||
ScoreUnionFields scoreFields(*fd,this,offset,op,slot);
|
||||
fd->setUnionField(this, op, slot, scoreFields.getResult());
|
||||
if (scoreFields.getResult().getFieldNum() >= 0) {
|
||||
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.
|
||||
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) {
|
||||
const TypeField *field = getField(res->getFieldNum());
|
||||
newoff = offset - field->offset;
|
||||
@@ -2908,38 +2935,50 @@ void TypePartialUnion::encode(Encoder &encoder) const
|
||||
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;
|
||||
int8 curOff = offset;
|
||||
while(curType != (Datatype *)0 && curType->getSize() > size) {
|
||||
if (curType->getMetatype() == TYPE_UNION) {
|
||||
const TypeField *field = curType->resolveTruncation(curOff, op, slot, curOff);
|
||||
curType = (field == (const TypeField *)0) ? (Datatype *)0 : field->type;
|
||||
if (curType->getMetatype() == TYPE_PARTIALUNION) {
|
||||
TypePartialUnion *curPartial = (TypePartialUnion *)curType;
|
||||
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 {
|
||||
curType = curType->getSubType(curOff, &curOff);
|
||||
else if (curType->getMetatype() == TYPE_UNION) {
|
||||
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)
|
||||
return curType;
|
||||
return stripped;
|
||||
if (curType == (Datatype *)0 || curType->getSize() != size)
|
||||
curType = stripped;
|
||||
fd->updateUnionField(this, op, slot, curType);
|
||||
return curType;
|
||||
}
|
||||
|
||||
Datatype* TypePartialUnion::findResolve(const PcodeOp *op,int4 slot)
|
||||
|
||||
{
|
||||
Datatype *curType = container;
|
||||
int8 curOff = offset;
|
||||
while(curType != (Datatype *)0 && curType->getSize() > size) {
|
||||
if (curType->getMetatype() == TYPE_UNION) {
|
||||
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;
|
||||
const Funcdata *fd = op->getParent()->getFuncdata();
|
||||
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
|
||||
if (res != (ResolvedUnion *)0)
|
||||
return res->getDatatype();
|
||||
return stripped;
|
||||
}
|
||||
|
||||
@@ -4535,9 +4574,6 @@ Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
|
||||
}
|
||||
if (ct->getSize() == size)
|
||||
return ct; // Perfect size match
|
||||
if (ct->getMetatype() == TYPE_UNION) {
|
||||
return getTypePartialUnion((TypeUnion *)ct, curOff, size);
|
||||
}
|
||||
lastType = ct;
|
||||
lastOff = curOff;
|
||||
ct = ct->getSubType(curOff,&curOff);
|
||||
@@ -4547,6 +4583,12 @@ Datatype *TypeFactory::getExactPiece(Datatype *ct,int4 offset,int4 size)
|
||||
type_metatype meta = lastType->getMetatype();
|
||||
if (meta == TYPE_STRUCT || meta == TYPE_ARRAY || meta == TYPE_PARTIALSTRUCT)
|
||||
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())
|
||||
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 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 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
|
||||
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
|
||||
@@ -479,6 +479,7 @@ public:
|
||||
virtual bool isPtrsubMatching(int8 off,int8 extra,int8 multiplier) const;
|
||||
virtual Datatype *resolveInFlow(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
|
||||
@@ -978,17 +979,19 @@ inline uint8 Datatype::getUnsizedId(void) const
|
||||
return id;
|
||||
}
|
||||
|
||||
/// Order data-types, with special handling of the \e bool data-type. Data-types are compared
|
||||
/// using the normal ordering, but \e bool is ordered after all other data-types. A return value
|
||||
/// of 0 indicates the data-types are the same, -1 indicates that \b this is prefered (ordered earlier),
|
||||
/// Order data-types, preferring the most specialized, except deemphasize \e partial data-types,
|
||||
/// 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 preferred (ordered earlier),
|
||||
/// and 1 indicates \b this is ordered later.
|
||||
/// \param op is the other data-type to compare with \b this
|
||||
/// \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 (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;
|
||||
return compare(op,10);
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -39,16 +39,19 @@ namespace ghidra {
|
||||
class ResolvedUnion {
|
||||
friend class ScoreUnionFields;
|
||||
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
|
||||
bool lock; ///< If \b true, resolution cannot be overridden
|
||||
public:
|
||||
ResolvedUnion(Datatype *parent); ///< Construct a data-type that resolves to itself
|
||||
ResolvedUnion(Datatype *parent,int4 fldNum,TypeFactory &typegrp); ///< Construct a reference to a field
|
||||
ResolvedUnion(Datatype *unresType); ///< Construct a data-type that resolves to itself
|
||||
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 *getBase(void) const { return baseType; } ///< Get the union or structure being referenced
|
||||
int4 getFieldNum(void) const { return fieldNum; } ///< Get the index of the resolved field or -1
|
||||
bool isLocked(void) const { return lock; } ///< Is \b this locked against overrides
|
||||
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
|
||||
};
|
||||
|
||||
@@ -62,7 +65,8 @@ class ResolveEdge {
|
||||
uintm opTime; ///< Id of PcodeOp edge
|
||||
int4 encoding; ///< Encoding of the slot and pointer-ness
|
||||
public:
|
||||
ResolveEdge(const Datatype *parent,const PcodeOp *op,int4 slot); ///< Construct from components
|
||||
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
|
||||
};
|
||||
|
||||
@@ -92,7 +96,7 @@ class ScoreUnionFields {
|
||||
PcodeOp *op; ///< The PcodeOp reading the Varnode (or null)
|
||||
int4 inslot; ///< The slot reading the Varnode (or -1)
|
||||
dir_type direction; ///< Direction to push fit. 0=down 1=up
|
||||
bool array; ///< Field can be accessed as an array
|
||||
int4 maxLength; ///< Maximum byte offset that can be added to \b fitType as a pointer
|
||||
Datatype *fitType; ///< The putative data-type of the Varnode
|
||||
int4 scoreIndex; ///< The original field being scored by \b this trial
|
||||
public:
|
||||
@@ -102,18 +106,18 @@ class ScoreUnionFields {
|
||||
/// \param slot is the input slot being read
|
||||
/// \param ct is the trial data-type to fit
|
||||
/// \param index is the scoring index
|
||||
/// \param isArray is \b true if the data-type to fit is a pointer to an array
|
||||
Trial(PcodeOp *o,int4 slot,Datatype *ct,int4 index,bool isArray) {
|
||||
op = o; inslot = slot; direction = fit_down; fitType = ct; scoreIndex = index; vn = o->getIn(slot); array=isArray; }
|
||||
/// \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,int4 max) {
|
||||
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
|
||||
///
|
||||
/// \param v is the Varnode to fit
|
||||
/// \param ct is the trial data-type to fit
|
||||
/// \param index is the scoring index
|
||||
/// \param isArray is \b true if the data-type to fit is a pointer to an array
|
||||
Trial(Varnode *v,Datatype *ct,int4 index,bool isArray) {
|
||||
vn = v; op = (PcodeOp *)0; inslot=-1; direction = fit_up; fitType = ct; scoreIndex = index; array=isArray; }
|
||||
/// \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,int4 max) {
|
||||
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
|
||||
@@ -133,6 +137,7 @@ class ScoreUnionFields {
|
||||
return (index < op2.index);
|
||||
}
|
||||
};
|
||||
Funcdata &data; ///< Function containing data-flow being scored
|
||||
TypeFactory &typegrp; ///< The factory containing data-types
|
||||
vector<int4> scores; ///< Score for each field, indexed by fieldNum + 1 (whole union is index=0)
|
||||
vector<Datatype *> fields; ///< Field corresponding to each score
|
||||
@@ -147,11 +152,11 @@ class ScoreUnionFields {
|
||||
bool testArrayArithmetic(PcodeOp *op,int4 inslot); ///< Check if given PcodeOp is operating on array with union elements
|
||||
bool testSimpleCases(PcodeOp *op,int4 inslot,Datatype *parent); ///< Preliminary checks before doing full scoring
|
||||
int4 scoreLockedType(Datatype *ct,Datatype *lockType); ///< Score trial data-type against a locked data-type
|
||||
int4 scoreParameter(Datatype *ct,const PcodeOp *callOp,int4 paramSlot); ///< Score trial data-type against a parameter
|
||||
int4 scoreReturnType(Datatype *ct,const PcodeOp *callOp); ///< Score trial data-type against return data-type of function
|
||||
Datatype *derefPointer(Datatype *ct,Varnode *vn,int4 &score); ///< Score trial data-type as a pointer to LOAD/STORE
|
||||
void newTrialsDown(Varnode *vn,Datatype *ct,int4 scoreIndex,bool isArray); ///< Create new trials based an reads of given Varnode
|
||||
void newTrials(PcodeOp *op,int4 slot,Datatype *ct,int4 scoreIndex,bool isArray); ///< Create new trials based on given input slot
|
||||
int4 scoreParameter(Datatype *ct,const FuncProto *proto,int4 paramSlot); ///< Score trial data-type against a parameter
|
||||
int4 scoreReturnType(Datatype *ct,const FuncProto *proto); ///< Score trial data-type against return data-type of function
|
||||
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,int4 max); ///< Create new trials based an reads of given Varnode
|
||||
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 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
|
||||
@@ -160,12 +165,47 @@ class ScoreUnionFields {
|
||||
void computeBestIndex(void); ///< Assuming scoring is complete, compute the best index
|
||||
void run(void); ///< Calculate best fitting field
|
||||
public:
|
||||
ScoreUnionFields(TypeFactory &tgrp,Datatype *parentType,PcodeOp *op,int4 slot);
|
||||
ScoreUnionFields(TypeFactory &tgrp,TypeUnion *unionType,int4 offset,PcodeOp *op);
|
||||
ScoreUnionFields(TypeFactory &tgrp,TypeUnion *unionType,int4 offset,PcodeOp *op,int4 slot);
|
||||
ScoreUnionFields(Funcdata &fd,Datatype *parentType,PcodeOp *op,int4 slot);
|
||||
ScoreUnionFields(Funcdata &fd,TypeUnion *unionType,int4 offset,PcodeOp *op);
|
||||
ScoreUnionFields(Funcdata &fd,TypeUnion *unionType,int4 offset,PcodeOp *op,int4 slot);
|
||||
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.
|
||||
/// \param op2 is the other edge to compare with \b this
|
||||
/// \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())
|
||||
rep = vn;
|
||||
}
|
||||
else if (0>vn->getType()->typeOrderBool(*rep->getType()))
|
||||
else if (0>vn->getType()->typeOrderFormal(*rep->getType()))
|
||||
rep = vn;
|
||||
}
|
||||
return rep;
|
||||
|
||||
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -47,6 +47,11 @@ public class ClangFieldToken extends ClangToken {
|
||||
return offset;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Varnode getVarnode() {
|
||||
return op.getOutput();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PcodeOp getPcodeOp() {
|
||||
return op;
|
||||
|
||||
+66
-23
@@ -55,6 +55,40 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||
// 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
|
||||
protected boolean isEnabledForDecompilerContext(DecompilerActionContext context) {
|
||||
Function function = context.getFunction();
|
||||
@@ -63,11 +97,7 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||
}
|
||||
|
||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||
if (!(tokenAtCursor instanceof ClangFieldToken)) {
|
||||
return false;
|
||||
}
|
||||
Composite composite = getCompositeDataType(tokenAtCursor);
|
||||
return (composite instanceof Union);
|
||||
return findUnion(tokenAtCursor) != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -147,26 +177,39 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
parentDt = null;
|
||||
for (accessSlot = 0; accessSlot < accessOp.getNumInputs(); ++accessSlot) {
|
||||
accessVn = accessOp.getInput(accessSlot);
|
||||
parentDt = typeIsUnionRelated(accessVn);
|
||||
if (parentDt != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
parentDt = typeIsUnionRelated(accessOp.getOutput()); // Its possible the output of PTRSUB is the union
|
||||
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();
|
||||
accessVn = accessOp.getOutput();
|
||||
accessSlot = -1;
|
||||
PcodeOp readOp = accessVn.getLoneDescend();
|
||||
if (readOp != null && readOp.getOpcode() != PcodeOp.MULTIEQUAL &&
|
||||
readOp.getOpcode() != PcodeOp.INDIRECT) {
|
||||
accessOp = readOp;
|
||||
accessSlot = accessOp.getSlot(accessVn); // Transfer to lone reading Op
|
||||
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;
|
||||
accessVn = accessOp.getOutput();
|
||||
@@ -262,7 +305,7 @@ public class ForceUnionAction extends AbstractDecompilerAction {
|
||||
Program program = context.getProgram();
|
||||
ClangToken tokenAtCursor = context.getTokenAtCursor();
|
||||
HighFunction highFunction = context.getHighFunction();
|
||||
unionDt = (Union) getCompositeDataType(tokenAtCursor);
|
||||
unionDt = findUnion(tokenAtCursor);
|
||||
determineFacet(tokenAtCursor);
|
||||
if (accessOp == null || accessVn == null) {
|
||||
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");
|
||||
try {
|
||||
HighFunctionDBUtil.writeUnionFacet(function, parentDt, fieldNumber, pcAddr,
|
||||
dhash.getHash(), SourceType.USER_DEFINED);
|
||||
dhash.getHash(), true, SourceType.USER_DEFINED);
|
||||
}
|
||||
catch (DuplicateNameException e) {
|
||||
Msg.showError(this, null, "Force Union failed", e.getMessage());
|
||||
|
||||
+26
-9
@@ -877,42 +877,53 @@ public class HighFunctionDBUtil {
|
||||
/**
|
||||
* Write a union facet to the database (UnionFacetSymbol). Parameters provide the
|
||||
* 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 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 addr is the first use address of the facet
|
||||
* @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
|
||||
* @throws InvalidInputException if the LocalVariable cannot be created
|
||||
* @throws DuplicateNameException if the (auto-generated) name is used elsewhere
|
||||
*/
|
||||
public static void writeUnionFacet(Function function, DataType dt, int fieldNum, Address addr,
|
||||
long hash, SourceType source) throws InvalidInputException, DuplicateNameException {
|
||||
if (dt instanceof PartialUnion) {
|
||||
dt = ((PartialUnion) dt).getParent();
|
||||
}
|
||||
long hash, boolean isAddr, SourceType source)
|
||||
throws InvalidInputException, DuplicateNameException {
|
||||
int firstUseOffset = (int) addr.subtract(function.getEntryPoint());
|
||||
String symbolName = UnionFacetSymbol.buildSymbolName(fieldNum, addr);
|
||||
boolean nameCollision = false;
|
||||
Variable[] localVariables =
|
||||
function.getLocalVariables(VariableFilter.UNIQUE_VARIABLE_FILTER);
|
||||
// Clean out any facet symbols with bad data-types
|
||||
for (int i = 0; i < localVariables.length; ++i) {
|
||||
Variable var = localVariables[i];
|
||||
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);
|
||||
localVariables[i] = null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
localVariables[i] = null; // Ignore symbols that aren't facets
|
||||
}
|
||||
}
|
||||
String symbolName = UnionFacetSymbol.buildSymbolName(fieldNum, addr, isAddr);
|
||||
Variable preexistingVar = null;
|
||||
for (Variable var : localVariables) {
|
||||
if (var == null) {
|
||||
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) {
|
||||
preexistingVar = var;
|
||||
}
|
||||
@@ -920,6 +931,12 @@ public class HighFunctionDBUtil {
|
||||
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
|
||||
symbolName = symbolName + '_' + Integer.toHexString(DynamicHash.getComparable(hash));
|
||||
}
|
||||
|
||||
+1
-2
@@ -461,8 +461,7 @@ public class LocalSymbolMap {
|
||||
}
|
||||
HighSymbol sym;
|
||||
if (DynamicHash.getMethodFromHash(hash) > 3 && UnionFacetSymbol.isUnionType(dt)) {
|
||||
int fieldNum = UnionFacetSymbol.extractFieldNumber(nm);
|
||||
sym = new UnionFacetSymbol(id, nm, dt, fieldNum, func);
|
||||
sym = new UnionFacetSymbol(id, nm, dt, func);
|
||||
}
|
||||
else {
|
||||
sym = new HighSymbol(id, nm, dt, func);
|
||||
|
||||
+32
-7
@@ -4,9 +4,9 @@
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
@@ -35,11 +35,13 @@ import ghidra.program.model.data.*;
|
||||
public class UnionFacetSymbol extends HighSymbol {
|
||||
public static String BASENAME = "unionfacet";
|
||||
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);
|
||||
category = 2;
|
||||
fieldNumber = fldNum;
|
||||
fieldNumber = extractFieldNumber(nm);
|
||||
isAddrBased = extractAddressBased(nm);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -47,6 +49,7 @@ public class UnionFacetSymbol extends HighSymbol {
|
||||
encoder.openElement(ELEM_FACETSYMBOL);
|
||||
encodeHeader(encoder);
|
||||
encoder.writeSignedInteger(ATTRIB_FIELD, fieldNumber);
|
||||
encoder.writeBool(ATTRIB_ADDRTIED, isAddrBased);
|
||||
dtmanage.encodeTypeRef(encoder, type, getSize());
|
||||
encoder.closeElement(ELEM_FACETSYMBOL);
|
||||
}
|
||||
@@ -55,11 +58,16 @@ public class UnionFacetSymbol extends HighSymbol {
|
||||
* Generate an automatic symbol name, given a field number and address
|
||||
* @param fldNum is the field number
|
||||
* @param addr is the Address
|
||||
* @param isAddr is true if the facet should be address based
|
||||
* @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();
|
||||
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()));
|
||||
return buffer.toString();
|
||||
}
|
||||
@@ -74,11 +82,28 @@ public class UnionFacetSymbol extends HighSymbol {
|
||||
if (pos < 0) {
|
||||
return -1;
|
||||
}
|
||||
pos += BASENAME.length();
|
||||
if (nm.length() > pos && nm.charAt(pos) == 'a') {
|
||||
pos = pos + 1;
|
||||
}
|
||||
int endpos = nm.indexOf('_', pos);
|
||||
if (endpos < 0) {
|
||||
return -1;
|
||||
}
|
||||
return Integer.decode(nm.substring(pos + BASENAME.length(), endpos)) - 1;
|
||||
return Integer.decode(nm.substring(pos, endpos)) - 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* First character of 'a' after BASENAME indicates an address based facet
|
||||
* @param nm is the symbol name
|
||||
* @return true if the facet is address based
|
||||
*/
|
||||
public static boolean extractAddressBased(String nm) {
|
||||
int pos = nm.indexOf(BASENAME);
|
||||
if (pos < 0 || nm.length() <= pos) {
|
||||
return false;
|
||||
}
|
||||
return nm.charAt(pos + BASENAME.length()) == 'a';
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user