Merge remote-tracking branch 'origin/GP-3309_ArrayAsUnion'

This commit is contained in:
Ryan Kurtz 2023-04-28 06:04:50 -04:00
commit 2eb1ef975e
4 changed files with 36 additions and 25 deletions

View file

@ -2395,7 +2395,7 @@ int4 ActionSetCasts::castOutput(PcodeOp *op,Funcdata &data,CastStrategy *castStr
if (tokenct == outHighType) {
if (tokenct->needsResolution()) {
// operation copies directly to outvn AS a union
ResolvedUnion resolve(tokenct);
ResolvedUnion resolve(tokenct); // Force the varnode to resolve to the parent data-type
data.setUnionField(tokenct, op, -1, resolve);
}
// Short circuit more sophisticated casting tests. If they are the same type, there is no cast

View file

@ -1047,17 +1047,26 @@ void TypeArray::encode(Encoder &encoder) const
Datatype *TypeArray::resolveInFlow(PcodeOp *op,int4 slot)
{
// This is currently only called if the array size is 1
// in which case this should always resolve to the element data-type
return arrayof;
Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0)
return res->getDatatype();
int4 fieldNum = TypeStruct::scoreSingleComponent(this,op,slot);
ResolvedUnion compFill(this,fieldNum,*fd->getArch()->types);
fd->setUnionField(this, op, slot, compFill);
return compFill.getDatatype();
}
Datatype* TypeArray::findResolve(const PcodeOp *op,int4 slot)
{
// This is currently only called if the array size is 1
// in which case this should always resolve to the element data-type
return arrayof;
const Funcdata *fd = op->getParent()->getFuncdata();
const ResolvedUnion *res = fd->getUnionField(this, op, slot);
if (res != (ResolvedUnion *)0)
return res->getDatatype();
return arrayof; // If not calculated before, assume referring to the element
}
int4 TypeArray::findCompatibleResolve(Datatype *ct) const
@ -1569,14 +1578,15 @@ void TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp)
}
}
/// We know if this method is called that \b this structure has a single field that fills the entire
/// structure. The indicated Varnode can either be referred either by naming the struture or naming
/// the field. This method returns an indication of the best fit: either 0 for the field or
/// -1 for the structure.
/// If this method is called, the given data-type has a single component that fills it entirely
/// (either a field or an element). The indicated Varnode can be resolved either by naming the
/// data-type or naming the component. This method returns an indication of the best fit:
/// either 0 for the component or -1 for the data-type.
/// \param parent is the given data-type with a single component
/// \param op is the given PcodeOp using the Varnode
/// \param slot is -1 if the Varnode is an output or >=0 indicating the input slot
/// \return either 0 to indicate the field or -1 to indicate the structure
int4 TypeStruct::scoreFill(PcodeOp *op,int4 slot) const
int4 TypeStruct::scoreSingleComponent(Datatype *parent,PcodeOp *op,int4 slot)
{
if (op->code() == CPUI_COPY || op->code() == CPUI_INDIRECT) {
@ -1585,14 +1595,14 @@ int4 TypeStruct::scoreFill(PcodeOp *op,int4 slot) const
vn = op->getOut();
else
vn = op->getIn(0);
if (vn->isTypeLock() && vn->getType() == this)
if (vn->isTypeLock() && vn->getType() == parent)
return -1; // COPY of the structure directly, use whole structure
}
else if ((op->code() == CPUI_LOAD && slot == -1)||(op->code() == CPUI_STORE && slot == 2)) {
Varnode *vn = op->getIn(1);
if (vn->isTypeLock()) {
Datatype *ct = vn->getTypeReadFacing(op);
if (ct->getMetatype() == TYPE_PTR && ((TypePointer *)ct)->getPtrTo() == this)
if (ct->getMetatype() == TYPE_PTR && ((TypePointer *)ct)->getPtrTo() == parent)
return -1; // LOAD or STORE of the structure directly, use whole structure
}
}
@ -1605,11 +1615,11 @@ int4 TypeStruct::scoreFill(PcodeOp *op,int4 slot) const
param = fc->getParam(slot-1);
else if (slot < 0 && fc->isOutputLocked())
param = fc->getOutput();
if (param != (ProtoParameter *)0 && param->getType() == this)
return -1; // Function signature refers to structure directly, use whole structure
if (param != (ProtoParameter *)0 && param->getType() == parent)
return -1; // Function signature refers to parent directly, resolve to parent
}
}
return 0; // In all other cases refer to the field
return 0; // In all other cases resolve to the component
}
Datatype *TypeStruct::resolveInFlow(PcodeOp *op,int4 slot)
@ -1620,7 +1630,7 @@ Datatype *TypeStruct::resolveInFlow(PcodeOp *op,int4 slot)
if (res != (ResolvedUnion *)0)
return res->getDatatype();
int4 fieldNum = scoreFill(op,slot);
int4 fieldNum = scoreSingleComponent(this,op,slot);
ResolvedUnion compFill(this,fieldNum,*fd->getArch()->types);
fd->setUnionField(this, op, slot, compFill);
@ -4044,6 +4054,8 @@ void TypeFactory::decodeCoreTypes(Decoder &decoder)
void TypeFactory::decodeDataOrganization(Decoder &decoder)
{
uint4 defaultSize = glb->getDefaultSize();
align = 0;
uint4 elemId = decoder.openElement(ELEM_DATA_ORGANIZATION);
for(;;) {
uint4 subId = decoder.openElement();
@ -4055,14 +4067,14 @@ void TypeFactory::decodeDataOrganization(Decoder &decoder)
sizeOfLong = decoder.readSignedInteger(ATTRIB_VALUE);
}
else if (subId == ELEM_SIZE_ALIGNMENT_MAP) {
align = 0;
for(;;) {
uint4 mapId = decoder.openElement();
if (mapId != ELEM_ENTRY) break;
int4 sz = decoder.readSignedInteger(ATTRIB_SIZE);
int4 val = decoder.readSignedInteger(ATTRIB_ALIGNMENT);
decoder.closeElement(mapId);
if (val > align) // Take maximum size alignment
if (sz <= defaultSize)
align = val;
decoder.closeElement(mapId);
}
}
else {

View file

@ -436,7 +436,6 @@ protected:
int4 getFieldIter(int4 off) const; ///< Get index into field list
int4 getLowerBoundField(int4 off) const; ///< Get index of last field before or equal to given offset
void decodeFields(Decoder &decoder,TypeFactory &typegrp); ///< Restore fields from a stream
int4 scoreFill(PcodeOp *op,int4 slot) const; ///< Determine best type fit for given PcodeOp use
public:
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
TypeStruct(void) : Datatype(0,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty TypeStruct
@ -456,6 +455,7 @@ public:
virtual Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const;
static void assignFieldOffsets(vector<TypeField> &list,int4 align); ///< Assign field offsets given a byte alignment
static int4 scoreSingleComponent(Datatype *parent,PcodeOp *op,int4 slot); ///< Determine best type fit for given PcodeOp use
};
/// \brief A collection of overlapping Datatype objects: A \b union of component \b fields

View file

@ -18,7 +18,8 @@
namespace ghidra {
/// The original parent must either be a union, a pointer to a union, or a partial union.
/// The original parent must either be a union, a partial union, a structure with a single field,
/// an array with a single element, or a pointer to one of these data-types.
/// The object is set up initially to resolve to the parent.
/// \param parent is the original parent data-type
ResolvedUnion::ResolvedUnion(Datatype *parent)
@ -27,8 +28,6 @@ ResolvedUnion::ResolvedUnion(Datatype *parent)
baseType = parent;
if (baseType->getMetatype() == TYPE_PTR)
baseType = ((TypePointer *)baseType)->getPtrTo();
if (baseType->getMetatype() != TYPE_UNION && baseType->getMetatype() != TYPE_STRUCT)
throw LowlevelError("Unsupported data-type for ResolveUnion");
resolve = parent;
fieldNum = -1;
lock = false;