Model: Ensure all TypeRefs are initialized with the model
Ensures that all types are output in the IDA Python script Includes TypeRefs that aren't used in any type definition or member
This commit is contained in:
@@ -17,20 +17,20 @@ namespace Il2CppInspector.Reflection
|
||||
public Il2CppInspector Package { get; }
|
||||
public List<Assembly> Assemblies { get; } = new List<Assembly>();
|
||||
|
||||
// List of all types ordered by their TypeDefinitionIndex
|
||||
// List of all types from TypeDefs ordered by their TypeDefinitionIndex
|
||||
public TypeInfo[] TypesByDefinitionIndex { get; }
|
||||
|
||||
// List of all type definitions by fully qualified name
|
||||
// List of all types from TypeRefs ordered by index
|
||||
public TypeInfo[] TypesByReferenceIndex { get; }
|
||||
|
||||
// List of all type definitions by fully qualified name (TypeDefs only)
|
||||
public Dictionary<string, TypeInfo> TypesByFullName { get; } = new Dictionary<string, TypeInfo>();
|
||||
|
||||
// List of all type references ordered by index
|
||||
public TypeInfo[] TypeReferences { get; }
|
||||
|
||||
// List of type usages that are initialized via pointers in the image
|
||||
// List of type references that are initialized via pointers in the image
|
||||
public ConcurrentDictionary<ulong, TypeInfo> TypesByVirtualAddress { get; } = new ConcurrentDictionary<ulong, TypeInfo>();
|
||||
|
||||
// Every type
|
||||
public IEnumerable<TypeInfo> Types => new IEnumerable<TypeInfo>[] {TypesByDefinitionIndex, TypeReferences, TypesByVirtualAddress.Values}.SelectMany(t => t);
|
||||
public IEnumerable<TypeInfo> Types => new IEnumerable<TypeInfo>[] {TypesByDefinitionIndex, TypesByReferenceIndex, TypesByVirtualAddress.Values}.SelectMany(t => t);
|
||||
|
||||
// List of all methods ordered by their MethodDefinitionIndex
|
||||
public MethodBase[] MethodsByDefinitionIndex { get; }
|
||||
@@ -38,67 +38,66 @@ namespace Il2CppInspector.Reflection
|
||||
// List of all generated CustomAttributeData objects by their index into AttributeTypeIndices
|
||||
public ConcurrentDictionary<int, CustomAttributeData> AttributesByIndices { get; } = new ConcurrentDictionary<int, CustomAttributeData>();
|
||||
|
||||
public Il2CppModel(Il2CppInspector package) {
|
||||
Package = package;
|
||||
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
|
||||
TypeReferences = new TypeInfo[package.TypeReferences.Count];
|
||||
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
|
||||
|
||||
// Create Assembly objects from Il2Cpp package
|
||||
for (var image = 0; image < package.Images.Length; image++)
|
||||
Assemblies.Add(new Assembly(this, image));
|
||||
}
|
||||
|
||||
// Get an assembly by its image name
|
||||
public Assembly GetAssembly(string name) => Assemblies.FirstOrDefault(a => a.ShortName == name);
|
||||
|
||||
private TypeInfo getNewTypeUsage(Il2CppType usage, MemberTypes memberType) {
|
||||
// Create type model
|
||||
public Il2CppModel(Il2CppInspector package) {
|
||||
Package = package;
|
||||
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
|
||||
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count];
|
||||
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
|
||||
|
||||
// Recursively create hierarchy of assemblies and types from TypeDefs
|
||||
// No code that executes here can access any type through a TypeRef (ie. via TypesByReferenceIndex)
|
||||
for (var image = 0; image < package.Images.Length; image++)
|
||||
Assemblies.Add(new Assembly(this, image));
|
||||
|
||||
// Create and reference types from TypeRefs
|
||||
// Note that you can't resolve any TypeRefs until all the TypeDefs have been processed
|
||||
for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Count; typeRefIndex++) {
|
||||
var typeRef = Package.TypeReferences[typeRefIndex];
|
||||
var referencedType = resolveTypeReference(typeRef);
|
||||
|
||||
TypesByReferenceIndex[typeRefIndex] = referencedType;
|
||||
}
|
||||
}
|
||||
|
||||
private TypeInfo resolveTypeReference(Il2CppType typeRef) {
|
||||
TypeInfo underlyingType;
|
||||
|
||||
switch (usage.type) {
|
||||
switch (typeRef.type) {
|
||||
// Classes defined in the metadata (reference to a TypeDef)
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
||||
// Classes defined in the metadata
|
||||
underlyingType = TypesByDefinitionIndex[usage.datapoint]; // klassIndex
|
||||
underlyingType = TypesByDefinitionIndex[typeRef.datapoint]; // klassIndex
|
||||
break;
|
||||
|
||||
// Constructed types
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
|
||||
|
||||
// Generic type and generic method parameters
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
||||
// Everything that requires special handling
|
||||
underlyingType = new TypeInfo(this, usage, memberType);
|
||||
|
||||
underlyingType = new TypeInfo(this, typeRef);
|
||||
break;
|
||||
|
||||
// Primitive types
|
||||
default:
|
||||
// Primitive types
|
||||
underlyingType = GetTypeFromTypeEnum(usage.type);
|
||||
underlyingType = getTypeDefinitionFromTypeEnum(typeRef.type);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create a reference type if necessary
|
||||
return usage.byref ? underlyingType.MakeByRefType() : underlyingType;
|
||||
return typeRef.byref ? underlyingType.MakeByRefType() : underlyingType;
|
||||
}
|
||||
|
||||
// Get or generate a type from its IL2CPP binary type usage reference
|
||||
// (field, return type, generic type parameter etc.)
|
||||
public TypeInfo GetTypeFromUsage(int typeUsageIndex, MemberTypes memberType = MemberTypes.All) {
|
||||
|
||||
// Already generated type previously?
|
||||
if (TypeReferences[typeUsageIndex] != null)
|
||||
return TypeReferences[typeUsageIndex];
|
||||
|
||||
var usage = Package.TypeReferences[typeUsageIndex];
|
||||
var newUsage = getNewTypeUsage(usage, memberType);
|
||||
|
||||
TypeReferences[typeUsageIndex] = newUsage;
|
||||
return newUsage;
|
||||
}
|
||||
|
||||
// Basic primitive types
|
||||
public TypeInfo GetTypeFromTypeEnum(Il2CppTypeEnum t) {
|
||||
// Basic primitive types are specified via a flag value
|
||||
private TypeInfo getTypeDefinitionFromTypeEnum(Il2CppTypeEnum t) {
|
||||
if ((int) t >= Il2CppConstants.FullNameTypeString.Count)
|
||||
return null;
|
||||
|
||||
@@ -107,16 +106,17 @@ namespace Il2CppInspector.Reflection
|
||||
}
|
||||
|
||||
// Type from a virtual address pointer
|
||||
// These are always nested types frorm usages within another type
|
||||
// These are always nested types from references within another TypeRef
|
||||
// TODO: Eliminate GetTypeFromVirtualAddress() - use base and offset from MetadataRegistration.ptypes (Package.TypeReferences) instead
|
||||
public TypeInfo GetTypeFromVirtualAddress(ulong ptr) {
|
||||
if (TypesByVirtualAddress.ContainsKey(ptr))
|
||||
return TypesByVirtualAddress[ptr];
|
||||
|
||||
var type = Package.BinaryImage.ReadMappedObject<Il2CppType>(ptr);
|
||||
var newUsage = getNewTypeUsage(type, MemberTypes.NestedType);
|
||||
var referencedType = resolveTypeReference(type);
|
||||
|
||||
TypesByVirtualAddress.TryAdd(ptr, newUsage);
|
||||
return newUsage;
|
||||
TypesByVirtualAddress.TryAdd(ptr, referencedType);
|
||||
return referencedType;
|
||||
}
|
||||
|
||||
// The attribute index is an index into AttributeTypeRanges, each of which is a start-end range index into AttributeTypeIndices, each of which is a TypeIndex
|
||||
@@ -131,12 +131,12 @@ namespace Il2CppInspector.Reflection
|
||||
return index;
|
||||
}
|
||||
|
||||
// Get the name of a metadata usage
|
||||
// Get the name of a metadata typeRef
|
||||
public string GetMetadataUsageName(MetadataUsage usage) {
|
||||
switch (usage.Type) {
|
||||
case MetadataUsageType.TypeInfo:
|
||||
case MetadataUsageType.Type:
|
||||
var type = GetTypeFromUsage(usage.SourceIndex);
|
||||
var type = TypesByReferenceIndex[usage.SourceIndex];
|
||||
return type.Name;
|
||||
|
||||
case MetadataUsageType.MethodDef:
|
||||
@@ -145,7 +145,7 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
case MetadataUsageType.FieldInfo:
|
||||
var fieldRef = Package.FieldRefs[usage.SourceIndex];
|
||||
type = GetTypeFromUsage(fieldRef.typeIndex);
|
||||
type = TypesByReferenceIndex[fieldRef.typeIndex];
|
||||
var field = type.DeclaredFields.First(f => f.Index == type.Definition.fieldStart + fieldRef.fieldIndex);
|
||||
return $"{type.Name}.{field.Name}";
|
||||
|
||||
|
||||
Reference in New Issue
Block a user