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 == outHighType) {
if (tokenct->needsResolution()) { if (tokenct->needsResolution()) {
// operation copies directly to outvn AS a union // 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); data.setUnionField(tokenct, op, -1, resolve);
} }
// Short circuit more sophisticated casting tests. If they are the same type, there is no cast // Short circuit more sophisticated casting tests. If they are the same type, there is no cast

View file

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

View file

@ -436,7 +436,6 @@ protected:
int4 getFieldIter(int4 off) const; ///< Get index into field list 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 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 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: public:
TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct TypeStruct(const TypeStruct &op); ///< Construct from another TypeStruct
TypeStruct(void) : Datatype(0,TYPE_STRUCT) { flags |= type_incomplete; } ///< Construct incomplete/empty 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 Datatype* findResolve(const PcodeOp *op,int4 slot);
virtual int4 findCompatibleResolve(Datatype *ct) const; virtual int4 findCompatibleResolve(Datatype *ct) const;
static void assignFieldOffsets(vector<TypeField> &list,int4 align); ///< Assign field offsets given a byte alignment 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 /// \brief A collection of overlapping Datatype objects: A \b union of component \b fields

View file

@ -18,7 +18,8 @@
namespace ghidra { 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. /// The object is set up initially to resolve to the parent.
/// \param parent is the original parent data-type /// \param parent is the original parent data-type
ResolvedUnion::ResolvedUnion(Datatype *parent) ResolvedUnion::ResolvedUnion(Datatype *parent)
@ -27,8 +28,6 @@ ResolvedUnion::ResolvedUnion(Datatype *parent)
baseType = parent; baseType = parent;
if (baseType->getMetatype() == TYPE_PTR) if (baseType->getMetatype() == TYPE_PTR)
baseType = ((TypePointer *)baseType)->getPtrTo(); baseType = ((TypePointer *)baseType)->getPtrTo();
if (baseType->getMetatype() != TYPE_UNION && baseType->getMetatype() != TYPE_STRUCT)
throw LowlevelError("Unsupported data-type for ResolveUnion");
resolve = parent; resolve = parent;
fieldNum = -1; fieldNum = -1;
lock = false; lock = false;