Model: Handle nested types

This commit is contained in:
Katy Coe
2019-10-31 16:02:32 +01:00
parent cb9d391d52
commit 70a541c36c
7 changed files with 53 additions and 27 deletions

View File

@@ -31,6 +31,7 @@ namespace Il2CppInspector
public Il2CppPropertyDefinition[] Properties => Metadata.Properties;
public Il2CppEventDefinition[] Events => Metadata.Events;
public int[] InterfaceUsageIndices => Metadata.InterfaceUsageIndices;
public int[] NestedTypeIndices => Metadata.NestedTypeIndices;
public Dictionary<int, object> FieldDefaultValue { get; } = new Dictionary<int, object>();
public List<long> FieldOffsets { get; }
public List<Il2CppType> TypeUsages => Binary.Types;

View File

@@ -15,20 +15,18 @@ namespace Il2CppInspector.Reflection
public Il2CppInspector Package { get; }
public List<Assembly> Assemblies { get; } = new List<Assembly>();
// List of all types ordered by their TypeDefinitionIndex
public TypeInfo[] TypesByIndex { get; }
public Il2CppModel(Il2CppInspector package) {
Package = package;
TypesByIndex = new TypeInfo[package.TypeDefinitions.Length];
// Create Assembly objects from Il2Cpp package
for (var image = 0; image < package.Images.Length; image++)
Assemblies.Add(new Assembly(this, image));
}
// Get the assembly in which a type is defined
public Assembly GetAssembly(TypeInfo type) => Assemblies.FirstOrDefault(x => x.DefinedTypes.Contains(type));
// Get a type from its IL2CPP type index
public TypeInfo GetTypeFromIndex(long typeIndex) => Assemblies.SelectMany(x => x.DefinedTypes).FirstOrDefault(x => x.Index == typeIndex);
// Get or generate a type from its IL2CPP binary type usage reference
// (field, return type, generic type parameter etc.)
public TypeInfo GetType(Il2CppType pType, MemberTypes memberType = MemberTypes.All) {
@@ -36,7 +34,7 @@ namespace Il2CppInspector.Reflection
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
// Classes defined in the metadata
return GetTypeFromIndex((int) pType.datapoint);
return TypesByIndex[(int) pType.datapoint];
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
@@ -57,7 +55,8 @@ namespace Il2CppInspector.Reflection
if ((int)t >= Il2CppConstants.FullNameTypeString.Count)
return null;
return Assemblies.SelectMany(x => x.DefinedTypes).First(x => x.FullName == Il2CppConstants.FullNameTypeString[(int)t]);
var fqn = Il2CppConstants.FullNameTypeString[(int) t];
return TypesByIndex.First(x => x.FullName == fqn);
}
}
}

View File

@@ -28,6 +28,7 @@ namespace Il2CppInspector
public Il2CppEventDefinition[] Events { get; }
public int[] InterfaceUsageIndices { get; }
public int[] NestedTypeIndices { get; }
public Dictionary<int, string> Strings { get; } = new Dictionary<int, string>();
@@ -96,6 +97,7 @@ namespace Il2CppInspector
Properties = ReadArray<Il2CppPropertyDefinition>(Header.propertiesOffset, Header.propertiesCount / Sizeof(typeof(Il2CppPropertyDefinition)));
Events = ReadArray<Il2CppEventDefinition>(Header.eventsOffset, Header.eventsCount / Sizeof(typeof(Il2CppEventDefinition)));
InterfaceUsageIndices = ReadArray<int>(Header.interfacesOffset, Header.interfacesCount / sizeof(int));
NestedTypeIndices = ReadArray<int>(Header.nestedTypesOffset, Header.nestedTypesCount / sizeof(int));
// TODO: ParameterDefaultValue, GenericParameters, ParameterConstraints, GenericContainers, MetadataUsage, CustomAttributes
// Get all string literals

View File

@@ -47,7 +47,7 @@ namespace Il2CppInspector.Reflection {
// Generate types in DefinedTypes from typeStart to typeStart+typeCount-1
for (var t = Definition.typeStart; t < Definition.typeStart + Definition.typeCount; t++) {
var type = new TypeInfo(Model.Package, t, this);
var type = new TypeInfo(t, this);
// Don't add empty module definitions
if (type.Name != "<Module>")

View File

@@ -18,7 +18,8 @@ namespace Il2CppInspector.Reflection {
public IEnumerable<CustomAttributeData> CustomAttributes => throw new NotImplementedException();
// Type that this type is declared in for nested types
public TypeInfo DeclaringType { get; }
protected int declaringTypeDefinitionIndex { private get; set; } = -1;
public TypeInfo DeclaringType => declaringTypeDefinitionIndex != -1? Assembly.Model.TypesByIndex[declaringTypeDefinitionIndex] : null;
// What sort of member this is, eg. method, field etc.
public abstract MemberTypes MemberType { get; }
@@ -29,16 +30,13 @@ namespace Il2CppInspector.Reflection {
// TODO: GetCustomAttributes etc.
// For top-level members in an assembly (ie. non-nested types)
protected MemberInfo(Assembly asm, TypeInfo declaringType = null) {
Assembly = asm;
DeclaringType = declaringType;
}
protected MemberInfo(Assembly asm) => Assembly = asm;
// For lower level members, eg. fields, properties etc. and nested types
protected MemberInfo(TypeInfo declaringType) {
protected MemberInfo(TypeInfo declaringType = null) {
if (declaringType != null) {
Assembly = declaringType.Assembly;
DeclaringType = declaringType;
declaringTypeDefinitionIndex = declaringType.Index;
}
}

View File

@@ -38,7 +38,7 @@ namespace Il2CppInspector.Reflection
public TypeInfo ParameterType => Member.Assembly.Model.GetType(paramType, MemberTypes.TypeInfo);
// Zero-indexed position of the parameter in parameter list
public int Position { get; private set; }
public int Position { get; }
// Create a parameter. Specify paramIndex == -1 for a return type parameter
public ParameterInfo(Il2CppInspector pkg, int paramIndex, MethodBase declaringMethod) {

View File

@@ -47,7 +47,10 @@ namespace Il2CppInspector.Reflection {
public List<FieldInfo> DeclaredFields { get; } = new List<FieldInfo>();
public List<MemberInfo> DeclaredMembers => throw new NotImplementedException();
public List<MethodInfo> DeclaredMethods { get; } = new List<MethodInfo>();
public List<TypeInfo> DeclaredNestedTypes => throw new NotImplementedException();
private int[] declaredNestedTypes;
public IEnumerable<TypeInfo> DeclaredNestedTypes => declaredNestedTypes.Select(x => Assembly.Model.TypesByIndex[x]);
public List<PropertyInfo> DeclaredProperties { get; } = new List<PropertyInfo>();
// Method that the type is declared in if this is a type parameter of a generic method
@@ -68,6 +71,7 @@ namespace Il2CppInspector.Reflection {
public string FullName => (IsPointer? "void *" : "")
+ Namespace
+ (Namespace.Length > 0? "." : "")
+ (DeclaringType != null? DeclaringType.Name + "." : "")
+ base.Name
+ (GenericTypeParameters != null ? "<" + string.Join(", ", GenericTypeParameters.Select(x => x.Name)) + ">" : "")
+ (IsArray? "[]" : "");
@@ -91,7 +95,7 @@ namespace Il2CppInspector.Reflection {
public bool IsGenericTypeDefinition => throw new NotImplementedException();
public bool IsImport => (Attributes & TypeAttributes.Import) == TypeAttributes.Import;
public bool IsInterface => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
public bool IsNested { get; } // TODO: Partially implemented
public bool IsNested => DeclaringType != null;
public bool IsNestedAssembly => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedAssembly;
public bool IsNestedFamANDAssem => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamANDAssem;
public bool IsNestedFamily => (Attributes & TypeAttributes.VisibilityMask) == TypeAttributes.NestedFamily;
@@ -108,7 +112,8 @@ namespace Il2CppInspector.Reflection {
public bool IsSpecialName => (Attributes & TypeAttributes.SpecialName) == TypeAttributes.SpecialName;
public bool IsValueType => BaseType?.FullName == "System.ValueType";
public override MemberTypes MemberType { get; }
// May get overridden by Il2CppType-based constructor below
public override MemberTypes MemberType { get; } = MemberTypes.TypeInfo;
public override string Name {
get => (IsPointer ? "void *" : "")
@@ -118,7 +123,11 @@ namespace Il2CppInspector.Reflection {
protected set => base.Name = value;
}
public string Namespace { get; }
private string @namespace;
public string Namespace {
get => !string.IsNullOrEmpty(@namespace) ? @namespace : DeclaringType?.Namespace ?? "<default namespace>";
set => @namespace = value;
}
// Number of dimensions of an array
private readonly int arrayRank;
@@ -135,8 +144,11 @@ namespace Il2CppInspector.Reflection {
// TODO: Generic stuff
// Initialize from specified type index in metadata
public TypeInfo(Il2CppInspector pkg, int typeIndex, Assembly owner) :
base(owner) {
// Top-level types
public TypeInfo(int typeIndex, Assembly owner) : base(owner) {
var pkg = Assembly.Model.Package;
Definition = pkg.TypeDefinitions[typeIndex];
Index = typeIndex;
Namespace = pkg.Strings[Definition.namespaceIndex];
@@ -145,6 +157,14 @@ namespace Il2CppInspector.Reflection {
if (Definition.parentIndex >= 0)
baseType = pkg.TypeUsages[Definition.parentIndex];
// Nested type?
if (Definition.declaringTypeIndex >= 0) {
declaringTypeDefinitionIndex = (int) pkg.TypeUsages[Definition.declaringTypeIndex].datapoint;
}
// Add to global type definition list
Assembly.Model.TypesByIndex[Index] = this;
if ((Definition.flags & Il2CppConstants.TYPE_ATTRIBUTE_SERIALIZABLE) != 0)
Attributes |= TypeAttributes.Serializable;
if ((Definition.flags & Il2CppConstants.TYPE_ATTRIBUTE_VISIBILITY_MASK) == Il2CppConstants.TYPE_ATTRIBUTE_PUBLIC)
@@ -187,6 +207,11 @@ namespace Il2CppInspector.Reflection {
for (var i = 0; i < Definition.interfaces_count; i++)
implementedInterfaces[i] = pkg.TypeUsages[pkg.InterfaceUsageIndices[Definition.interfacesStart + i]];
// Add all nested types
declaredNestedTypes = new int[Definition.nested_type_count];
for (var n = 0; n < Definition.nested_type_count; n++)
declaredNestedTypes[n] = pkg.NestedTypeIndices[Definition.nestedTypesStart + n];
// Add all fields
for (var f = Definition.fieldStart; f < Definition.fieldStart + Definition.field_count; f++)
DeclaredFields.Add(new FieldInfo(pkg, f, this));
@@ -207,20 +232,21 @@ namespace Il2CppInspector.Reflection {
// Add all events
for (var e = Definition.eventStart; e < Definition.eventStart + Definition.event_count; e++)
DeclaredEvents.Add(new EventInfo(pkg, e, this));
MemberType = MemberTypes.TypeInfo;
}
// Initialize type from binary usage
public TypeInfo(Il2CppModel model, Il2CppType pType, MemberTypes memberType) : base(null) {
public TypeInfo(Il2CppModel model, Il2CppType pType, MemberTypes memberType) {
var image = model.Package.BinaryImage;
IsNested = true;
// TODO: IsNested = true;
MemberType = memberType;
// TODO: Set Assembly and DeclaringType
// Generic type unresolved and concrete instance types
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) {
var generic = image.ReadMappedObject<Il2CppGenericClass>(pType.datapoint);
var genericTypeDef = model.GetTypeFromIndex(generic.typeDefinitionIndex);
var genericTypeDef = model.TypesByIndex[generic.typeDefinitionIndex];
Namespace = genericTypeDef.Namespace;
Name = genericTypeDef.Name;