GP-5038 Support for data-type recursion through typedef

This commit is contained in:
caheckman 2024-10-28 20:44:52 +00:00
parent 6d5a5da013
commit 2e09cf4ef3
6 changed files with 75 additions and 23 deletions

View file

@ -30,7 +30,7 @@ AttributeId ATTRIB_ARRAYSIZE = AttributeId("arraysize",48);
AttributeId ATTRIB_CHAR = AttributeId("char",49); AttributeId ATTRIB_CHAR = AttributeId("char",49);
AttributeId ATTRIB_CORE = AttributeId("core",50); AttributeId ATTRIB_CORE = AttributeId("core",50);
AttributeId ATTRIB_ENUM = AttributeId("enum",51); AttributeId ATTRIB_ENUM = AttributeId("enum",51);
//AttributeId ATTRIB_ENUMSIGNED = AttributeId("enumsigned",52); // deprecated AttributeId ATTRIB_INCOMPLETE = AttributeId("incomplete",52);
//AttributeId ATTRIB_ENUMSIZE = AttributeId("enumsize",53); // deprecated //AttributeId ATTRIB_ENUMSIZE = AttributeId("enumsize",53); // deprecated
//AttributeId ATTRIB_INTSIZE = AttributeId("intsize",54); // deprecated //AttributeId ATTRIB_INTSIZE = AttributeId("intsize",54); // deprecated
//AttributeId ATTRIB_LONGSIZE = AttributeId("longsize",55); // deprecated //AttributeId ATTRIB_LONGSIZE = AttributeId("longsize",55); // deprecated
@ -647,6 +647,10 @@ void Datatype::decodeBasic(Decoder &decoder)
else if (attrib == ATTRIB_LABEL) { else if (attrib == ATTRIB_LABEL) {
displayName = decoder.readString(); displayName = decoder.readString();
} }
else if (attrib == ATTRIB_INCOMPLETE) {
if (decoder.readBool())
flags |= type_incomplete;
}
} }
if (size < 0) if (size < 0)
throw LowlevelError("Bad size for type "+name); throw LowlevelError("Bad size for type "+name);
@ -1885,10 +1889,10 @@ string TypeStruct::decodeFields(Decoder &decoder,TypeFactory &typegrp)
if (curAlign > calcAlign) if (curAlign > calcAlign)
calcAlign = curAlign; calcAlign = curAlign;
} }
if (size == 0) // We can decode an incomplete structure, indicated by 0 size if (size == 0) // Old way to indicate an incomplete structure
flags |= type_incomplete; flags |= type_incomplete;
else if (field.size() > 0)
markComplete(); // Otherwise the structure is complete markComplete(); // If we have fields, mark as complete
if (field.size() == 1) { // A single field if (field.size() == 1) { // A single field
if (field[0].type->getSize() == size) // that fills the whole structure if (field[0].type->getSize() == size) // that fills the whole structure
flags |= needs_resolution; // needs special resolution flags |= needs_resolution; // needs special resolution
@ -2043,10 +2047,10 @@ void TypeUnion::decodeFields(Decoder &decoder,TypeFactory &typegrp)
if (curAlign > calcAlign) if (curAlign > calcAlign)
calcAlign = curAlign; calcAlign = curAlign;
} }
if (size == 0) // We can decode an incomplete structure, indicated by 0 size if (size == 0) // Old way to indicate union is incomplete
flags |= type_incomplete; flags |= type_incomplete;
else if (field.size() > 0)
markComplete(); // Otherwise the union is complete markComplete(); // If we have fields, the union is complete
if (alignment < 1) if (alignment < 1)
alignment = calcAlign; alignment = calcAlign;
alignSize = calcAlignSize(size,alignment); alignSize = calcAlignSize(size,alignment);
@ -3188,6 +3192,7 @@ void TypeFactory::clear(void)
nametree.clear(); nametree.clear();
clearCache(); clearCache();
warnings.clear(); warnings.clear();
incompleteTypedef.clear();
} }
/// Delete anything that isn't a core type /// Delete anything that isn't a core type
@ -3209,6 +3214,7 @@ void TypeFactory::clearNoncore(void)
delete ct; delete ct;
} }
warnings.clear(); warnings.clear();
incompleteTypedef.clear();
} }
TypeFactory::~TypeFactory(void) TypeFactory::~TypeFactory(void)
@ -3698,6 +3704,42 @@ void TypeFactory::removeWarning(Datatype *dt)
} }
} }
/// Run through typedefs that were initially defined on incomplete data-types. If the data-type is now complete,
/// copy the fields or prototype into the typedef and remove it from the list.
void TypeFactory::resolveIncompleteTypedefs(void)
{
list<Datatype *>::iterator iter = incompleteTypedef.begin();
while(iter != incompleteTypedef.end()) {
Datatype *dt = *iter;
Datatype *defedType = dt->getTypedef();
if (!defedType->isIncomplete()) {
if (dt->getMetatype() == TYPE_STRUCT) {
TypeStruct *prevStruct = (TypeStruct *)dt;
TypeStruct *defedStruct = (TypeStruct *)defedType;
setFields(defedStruct->field,prevStruct,defedStruct->size,defedStruct->alignment,defedStruct->flags);
iter = incompleteTypedef.erase(iter);
}
else if (dt->getMetatype() == TYPE_UNION) {
TypeUnion *prevUnion = (TypeUnion *)dt;
TypeUnion *defedUnion = (TypeUnion *)defedType;
setFields(defedUnion->field,prevUnion,defedUnion->size,defedUnion->alignment,defedUnion->flags);
iter = incompleteTypedef.erase(iter);
}
else if (dt->getMetatype() == TYPE_CODE) {
TypeCode *prevCode = (TypeCode *)dt;
TypeCode *defedCode = (TypeCode *)defedType;
setPrototype(defedCode->proto, prevCode, defedCode->flags);
iter = incompleteTypedef.erase(iter);
}
else
++iter;
}
else
++iter;
}
}
/// Find or create a data-type identical to the given data-type except for its name and id. /// Find or create a data-type identical to the given data-type except for its name and id.
/// If the name and id already describe an incompatible data-type, an exception is thrown. /// If the name and id already describe an incompatible data-type, an exception is thrown.
/// \param ct is the given data-type to clone /// \param ct is the given data-type to clone
@ -3724,6 +3766,8 @@ Datatype *TypeFactory::getTypedef(Datatype *ct,const string &name,uint8 id,uint4
res->typedefImm = ct; res->typedefImm = ct;
res->setDisplayFormat(format); res->setDisplayFormat(format);
insert(res); insert(res);
if (res->isIncomplete())
incompleteTypedef.push_back(res);
return res; return res;
} }
@ -4234,6 +4278,7 @@ Datatype* TypeFactory::decodeStruct(Decoder &decoder,bool forcecore)
} }
if (!warning.empty()) if (!warning.empty())
insertWarning(ct, warning); insertWarning(ct, warning);
resolveIncompleteTypedefs();
// decoder.closeElement(elemId); // decoder.closeElement(elemId);
return ct; return ct;
} }
@ -4264,6 +4309,7 @@ Datatype* TypeFactory::decodeUnion(Decoder &decoder,bool forcecore)
else { // If structure is a placeholder stub else { // If structure is a placeholder stub
setFields(tu.field,(TypeUnion*)ct,tu.size,tu.alignment,tu.flags); // Define structure now by copying fields setFields(tu.field,(TypeUnion*)ct,tu.size,tu.alignment,tu.flags); // Define structure now by copying fields
} }
resolveIncompleteTypedefs();
// decoder.closeElement(elemId); // decoder.closeElement(elemId);
return ct; return ct;
} }
@ -4299,6 +4345,7 @@ Datatype *TypeFactory::decodeCode(Decoder &decoder,bool isConstructor,bool isDes
else { // If there was a placeholder stub else { // If there was a placeholder stub
setPrototype(tc.proto, (TypeCode *)ct, tc.flags); setPrototype(tc.proto, (TypeCode *)ct, tc.flags);
} }
resolveIncompleteTypedefs();
// decoder.closeElement(elemId); // decoder.closeElement(elemId);
return ct; return ct;
} }

View file

@ -28,7 +28,7 @@ extern AttributeId ATTRIB_ARRAYSIZE; ///< Marshaling attribute "arraysize"
extern AttributeId ATTRIB_CHAR; ///< Marshaling attribute "char" extern AttributeId ATTRIB_CHAR; ///< Marshaling attribute "char"
extern AttributeId ATTRIB_CORE; ///< Marshaling attribute "core" extern AttributeId ATTRIB_CORE; ///< Marshaling attribute "core"
extern AttributeId ATTRIB_ENUM; ///< Marshaling attribute "enum" extern AttributeId ATTRIB_ENUM; ///< Marshaling attribute "enum"
//extern AttributeId ATTRIB_ENUMSIGNED; ///< Marshaling attribute "enumsigned" deprecated extern AttributeId ATTRIB_INCOMPLETE; ///< Marshaling attribute "incomplete"
//extern AttributeId ATTRIB_ENUMSIZE; ///< Marshaling attribute "enumsize" deprecated //extern AttributeId ATTRIB_ENUMSIZE; ///< Marshaling attribute "enumsize" deprecated
//extern AttributeId ATTRIB_INTSIZE; ///< Marshaling attribute "intsize" deprecated //extern AttributeId ATTRIB_INTSIZE; ///< Marshaling attribute "intsize" deprecated
//extern AttributeId ATTRIB_LONGSIZE; ///< Marshaling attribute "longsize" deprecated //extern AttributeId ATTRIB_LONGSIZE; ///< Marshaling attribute "longsize" deprecated
@ -738,6 +738,7 @@ class TypeFactory {
Datatype *type_nochar; ///< Same dimensions as char but acts and displays as an INT Datatype *type_nochar; ///< Same dimensions as char but acts and displays as an INT
Datatype *charcache[5]; ///< Cached character data-types Datatype *charcache[5]; ///< Cached character data-types
list<DatatypeWarning> warnings; ///< Warnings for the user about data-types in \b this factory list<DatatypeWarning> warnings; ///< Warnings for the user about data-types in \b this factory
list<Datatype *> incompleteTypedef; ///< Incomplete data-types defined as a \e typedef
Datatype *findNoName(Datatype &ct); ///< Find data-type (in this container) by function Datatype *findNoName(Datatype &ct); ///< Find data-type (in this container) by function
void insert(Datatype *newtype); ///< Insert pointer into the cross-reference sets void insert(Datatype *newtype); ///< Insert pointer into the cross-reference sets
Datatype *findAdd(Datatype &ct); ///< Find data-type in this container or add it Datatype *findAdd(Datatype &ct); ///< Find data-type in this container or add it
@ -757,6 +758,7 @@ class TypeFactory {
void recalcPointerSubmeta(Datatype *base,sub_metatype sub); ///< Recalculate submeta for pointers to given base data-type void recalcPointerSubmeta(Datatype *base,sub_metatype sub); ///< Recalculate submeta for pointers to given base data-type
void insertWarning(Datatype *dt,string warn); ///< Register a new data-type warning with \b this factory void insertWarning(Datatype *dt,string warn); ///< Register a new data-type warning with \b this factory
void removeWarning(Datatype *dt); ///< Remove the warning associated with the given data-type void removeWarning(Datatype *dt); ///< Remove the warning associated with the given data-type
void resolveIncompleteTypedefs(void); ///< Redefine incomplete typedefs of data-types that are now complete
protected: protected:
Architecture *glb; ///< The Architecture object that owns this TypeFactory Architecture *glb; ///< The Architecture object that owns this TypeFactory
Datatype *findByIdLocal(const string &nm,uint8 id) const; ///< Search locally by name and id Datatype *findByIdLocal(const string &nm,uint8 id) const; ///< Search locally by name and id

View file

@ -340,7 +340,7 @@ public class DecompileDebug {
new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes); new DataTypeDependencyOrderer(program.getDataTypeManager(), dtypes);
//First output all structures as zero size so to avoid any cyclic dependencies. //First output all structures as zero size so to avoid any cyclic dependencies.
for (DataType dataType : TypeOrderer.getCompositeList()) { for (DataType dataType : TypeOrderer.getCompositeList()) {
dtmanage.encodeCompositeZeroSizePlaceholder(encoder, dataType); dtmanage.encodeCompositePlaceholder(encoder, dataType);
} }
//Next, use the dependency stack to output types. //Next, use the dependency stack to output types.
for (DataType dataType : TypeOrderer.getDependencyList()) { for (DataType dataType : TypeOrderer.getDependencyList()) {

View file

@ -337,8 +337,9 @@ public class DataTypeDependencyOrderer {
if (!doneSet.contains(subEntry)) { if (!doneSet.contains(subEntry)) {
procSet.add(subEntry); procSet.add(subEntry);
} }
if (entry.dataType instanceof Pointer) { //avoid cycles with structures/composites if (subType instanceof Composite) {
if (subType instanceof Composite) { // Trim dependency from pointer or typedef to a composite to prevent cycles
if (entry.dataType instanceof Pointer || entry.dataType instanceof TypeDef) {
return; return;
} }
} }

View file

@ -115,7 +115,7 @@ public record AttributeId(String name, int id) {
public static final AttributeId ATTRIB_CHAR = new AttributeId("char", 49); public static final AttributeId ATTRIB_CHAR = new AttributeId("char", 49);
public static final AttributeId ATTRIB_CORE = new AttributeId("core", 50); public static final AttributeId ATTRIB_CORE = new AttributeId("core", 50);
public static final AttributeId ATTRIB_ENUM = new AttributeId("enum", 51); public static final AttributeId ATTRIB_ENUM = new AttributeId("enum", 51);
// public static final AttributeId ATTRIB_ENUMSIGNED = new AttributeId("enumsigned", 52); // deprecated public static final AttributeId ATTRIB_INCOMPLETE = new AttributeId("incomplete", 52);
// public static final AttributeId ATTRIB_ENUMSIZE = new AttributeId("enumsize", 53); // deprecated // public static final AttributeId ATTRIB_ENUMSIZE = new AttributeId("enumsize", 53); // deprecated
// public static final AttributeId ATTRIB_INTSIZE = new AttributeId("intsize", 54); // deprecated // public static final AttributeId ATTRIB_INTSIZE = new AttributeId("intsize", 54); // deprecated
// public static final AttributeId ATTRIB_LONGSIZE = new AttributeId("longsize", 55); // deprecated // public static final AttributeId ATTRIB_LONGSIZE = new AttributeId("longsize", 55); // deprecated

View file

@ -799,12 +799,12 @@ public class PcodeDataTypeManager {
} }
/** /**
* Encode a Structure to the stream that has its size reported as zero. * Encode a Structure/Union to the stream without listing its fields
* @param encoder is the stream encoder * @param encoder is the stream encoder
* @param type data type to encode * @param type data type to encode
* @throws IOException for errors in the underlying stream * @throws IOException for errors in the underlying stream
*/ */
public void encodeCompositeZeroSizePlaceholder(Encoder encoder, DataType type) public void encodeCompositePlaceholder(Encoder encoder, DataType type)
throws IOException { throws IOException {
String metaString; String metaString;
if (type instanceof Structure) { if (type instanceof Structure) {
@ -820,7 +820,9 @@ public class PcodeDataTypeManager {
encoder.writeString(ATTRIB_NAME, type.getDisplayName()); encoder.writeString(ATTRIB_NAME, type.getDisplayName());
encoder.writeUnsignedInteger(ATTRIB_ID, progDataTypes.getID(type)); encoder.writeUnsignedInteger(ATTRIB_ID, progDataTypes.getID(type));
encoder.writeString(ATTRIB_METATYPE, metaString); encoder.writeString(ATTRIB_METATYPE, metaString);
encoder.writeSignedInteger(ATTRIB_SIZE, 0); encoder.writeSignedInteger(ATTRIB_SIZE, type.getLength());
encoder.writeSignedInteger(ATTRIB_ALIGNMENT, type.getAlignment());
encoder.writeBool(ATTRIB_INCOMPLETE, true);
encoder.closeElement(ELEM_TYPE); encoder.closeElement(ELEM_TYPE);
} }