Struct reading and disassembly script overhaul, various misc. loading fixes, bump to .NET 9 (#13)
* Bump projects to .net 9 and update nugets * add VersionedSerialization + source generator * migrate versioning to StructVersion class, add handling/detection for 29.2/31.2 * add new struct definitions * rename serialization methods and add BinaryObjectStreamReader for interop * Rework metadata struct loading to use new struct versioning * move 29/31.1/.2 to use tags (-2022,-2023) instead of minor versions * fix metadata usage validity checks * rework code registration offsetting a bit and add second 29/31.1 condition * tweak .1 condition (again) * 29/31.2 was a psyop * also remove 29.2 from the readme * remove loading of packed dlls - this was a very unsafe feature * support auto-recovering type indices from type handles fixes loading of memory-dumped v29+ libraries since those replacee their class indices on load with a pointer to the corresponding type * support loading PEs without an export table * also read UnresolvedVirtualCallCount on regular v31 * Disable plugin loading for now * Overhaul disassembler script + add Binary Ninja target (#12) * Overhaul diassembler scripts: - No longer defines top level functions - Split into three classes: StatusHandler (like before), DisassemblerInterface (for interfacing with the used program API), ScriptContext (for definiting general functions that use the disassembler interface) - Add type annotations to all class methods and remove 2.7 compatibility stuff (Ghidra now supports Python 3 so this is unnecessary anymore) - Disassembler backends are now responsible for launching metadata/script processing, to better support disassembler differences - String handling is back in the base ScriptContext class, disassembler interfaces opt into the fake string segment creation and fall back to the old method if it isn't supported * Add Binary Ninja disassembler script backend This uses the new backend-controlled execution to launch metadata processing on a background thread to keep the ui responsive * make binary ninja script use own _BINARYNINJA_ define and add define helpers to header * Update README to account for new script and binary ninja backend * implement fake string segment functions for binary ninja but don't advertise support * also cache API function types in binary ninja backend * fix ida script and disable folders again * Fix metadata usage issues caused by it being a value type now * make TryMapVATR overrideable and implement it for ELFs * Make field offset reading use TryMapVATR to reduce exceptions * Fix NRE in Assembly ctor on < v24.2 * Update actions workflow to produce cross-platform CLI binaries, update readme to reflect .net 9 changes * workflow: only restore packages for projects that are being built * workflow: tweak caching and fix gui compilation * workflow: remove double .zip in CLI artifact name * 29/31.2 don't actually exist, this logic is not needed
This commit is contained in:
@@ -7,6 +7,8 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Il2CppInspector.Next.BinaryMetadata;
|
||||
using Il2CppInspector.Next.Metadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection {
|
||||
public class Assembly
|
||||
@@ -43,37 +45,38 @@ namespace Il2CppInspector.Reflection {
|
||||
public Assembly(TypeModel model, int imageIndex) {
|
||||
Model = model;
|
||||
ImageDefinition = Model.Package.Images[imageIndex];
|
||||
AssemblyDefinition = Model.Package.Assemblies[ImageDefinition.assemblyIndex];
|
||||
AssemblyDefinition = Model.Package.Assemblies[ImageDefinition.AssemblyIndex];
|
||||
|
||||
if (AssemblyDefinition.imageIndex != imageIndex)
|
||||
if (AssemblyDefinition.ImageIndex != imageIndex)
|
||||
throw new InvalidOperationException("Assembly/image index mismatch");
|
||||
|
||||
MetadataToken = (int) AssemblyDefinition.token;
|
||||
Index = ImageDefinition.assemblyIndex;
|
||||
ShortName = Model.Package.Strings[ImageDefinition.nameIndex];
|
||||
MetadataToken = (int) AssemblyDefinition.Token;
|
||||
Index = ImageDefinition.AssemblyIndex;
|
||||
ShortName = Model.Package.Strings[ImageDefinition.NameIndex];
|
||||
|
||||
// Get full assembly name
|
||||
var nameDef = AssemblyDefinition.aname;
|
||||
var name = Regex.Replace(Model.Package.Strings[nameDef.nameIndex], @"[^A-Za-z0-9_\-\.()]", "");
|
||||
var culture = Model.Package.Strings[nameDef.cultureIndex];
|
||||
var nameDef = AssemblyDefinition.Aname;
|
||||
var name = Regex.Replace(Model.Package.Strings[nameDef.NameIndex], @"[^A-Za-z0-9_\-\.()]", "");
|
||||
var culture = Model.Package.Strings[nameDef.CultureIndex];
|
||||
if (string.IsNullOrEmpty(culture))
|
||||
culture = "neutral";
|
||||
var pkt = BitConverter.ToString(nameDef.publicKeyToken).Replace("-", "");
|
||||
var pkt = Convert.ToHexString(nameDef.PublicKeyToken);
|
||||
if (pkt == "0000000000000000")
|
||||
pkt = "null";
|
||||
var version = string.Format($"{nameDef.major}.{nameDef.minor}.{nameDef.build}.{nameDef.revision}");
|
||||
var version = string.Format($"{nameDef.Major}.{nameDef.Minor}.{nameDef.Build}.{nameDef.Revision}");
|
||||
|
||||
FullName = string.Format($"{name}, Version={version}, Culture={culture}, PublicKeyToken={pkt.ToLower()}");
|
||||
|
||||
if (ImageDefinition.entryPointIndex != -1) {
|
||||
if (ImageDefinition.EntryPointIndex != -1) {
|
||||
// TODO: Generate EntryPoint method from entryPointIndex
|
||||
}
|
||||
|
||||
// Find corresponding module (we'll need this for method pointers)
|
||||
ModuleDefinition = Model.Package.Modules?[ShortName];
|
||||
// Find corresponding module (we'll need this for method pointers on V24.2+)
|
||||
if (Model.Package.Modules != null)
|
||||
ModuleDefinition = Model.Package.Modules[ShortName];
|
||||
|
||||
// Generate types in DefinedTypes from typeStart to typeStart+typeCount-1
|
||||
for (var t = ImageDefinition.typeStart; t < ImageDefinition.typeStart + ImageDefinition.typeCount; t++) {
|
||||
for (var t = ImageDefinition.TypeStart; t < ImageDefinition.TypeStart + ImageDefinition.TypeCount; t++) {
|
||||
var type = new TypeInfo(t, this);
|
||||
|
||||
// Don't add empty module definitions
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Il2CppInspector.Next;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
@@ -88,13 +89,13 @@ namespace Il2CppInspector.Reflection
|
||||
var pkg = asm.Model.Package;
|
||||
|
||||
// Attribute type ranges weren't included before v21 (customASttributeGenerators was though)
|
||||
if (pkg.Version < 21)
|
||||
if (pkg.Version < MetadataVersions.V210)
|
||||
yield break;
|
||||
|
||||
if (pkg.Version < 29)
|
||||
if (pkg.Version < MetadataVersions.V290)
|
||||
{
|
||||
var range = pkg.AttributeTypeRanges[customAttributeIndex];
|
||||
for (var i = range.start; i < range.start + range.count; i++)
|
||||
for (var i = range.Start; i < range.Start + range.Count; i++)
|
||||
{
|
||||
var typeIndex = pkg.AttributeTypeIndices[i];
|
||||
|
||||
@@ -117,8 +118,8 @@ namespace Il2CppInspector.Reflection
|
||||
var range = pkg.Metadata.AttributeDataRanges[customAttributeIndex];
|
||||
var next = pkg.Metadata.AttributeDataRanges[customAttributeIndex + 1];
|
||||
|
||||
var startOffset = pkg.Metadata.Header.attributeDataOffset + range.startOffset;
|
||||
var endOffset = pkg.Metadata.Header.attributeDataOffset + next.startOffset;
|
||||
var startOffset = (uint)pkg.Metadata.Header.AttributeDataOffset + range.StartOffset;
|
||||
var endOffset = (uint)pkg.Metadata.Header.AttributeDataOffset + next.StartOffset;
|
||||
|
||||
var reader = new CustomAttributeDataReader(pkg, asm, pkg.Metadata, startOffset, endOffset);
|
||||
if (reader.Count == 0)
|
||||
@@ -142,13 +143,17 @@ namespace Il2CppInspector.Reflection
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(Assembly asm, int token, int customAttributeIndex) =>
|
||||
getCustomAttributes(asm, asm.Model.GetCustomAttributeIndex(asm, token, customAttributeIndex)).ToList();
|
||||
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(Assembly asm) => GetCustomAttributes(asm, asm.MetadataToken, asm.AssemblyDefinition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(EventInfo evt) => GetCustomAttributes(evt.Assembly, evt.MetadataToken, evt.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(FieldInfo field) => GetCustomAttributes(field.Assembly, field.MetadataToken, field.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(MethodBase method) => GetCustomAttributes(method.Assembly, method.MetadataToken, method.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo param) => GetCustomAttributes(param.DeclaringMethod.Assembly, param.MetadataToken, param.Definition.customAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(Assembly asm) => GetCustomAttributes(asm, asm.MetadataToken, asm.AssemblyDefinition.CustomAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(EventInfo evt) => GetCustomAttributes(evt.Assembly, evt.MetadataToken, evt.Definition.CustomAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(FieldInfo field) => GetCustomAttributes(field.Assembly, field.MetadataToken, field.Definition.CustomAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(MethodBase method) => GetCustomAttributes(method.Assembly, method.MetadataToken, method.Definition.CustomAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo param) => GetCustomAttributes(param.DeclaringMethod.Assembly, param.MetadataToken, param.Definition.CustomAttributeIndex);
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(PropertyInfo prop)
|
||||
=> prop.Definition != null ? GetCustomAttributes(prop.Assembly, prop.MetadataToken, prop.Definition.customAttributeIndex) : new List<CustomAttributeData>();
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(TypeInfo type) => type.Definition != null? GetCustomAttributes(type.Assembly, type.MetadataToken, type.Definition.customAttributeIndex) : new List<CustomAttributeData>();
|
||||
=> prop.Definition.IsValid
|
||||
? GetCustomAttributes(prop.Assembly, prop.MetadataToken, prop.Definition.CustomAttributeIndex)
|
||||
: new List<CustomAttributeData>();
|
||||
public static IList<CustomAttributeData> GetCustomAttributes(TypeInfo type) => type.Definition.IsValid
|
||||
? GetCustomAttributes(type.Assembly, type.MetadataToken, type.Definition.CustomAttributeIndex)
|
||||
: new List<CustomAttributeData>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Il2CppInspector.Next.Metadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection
|
||||
{
|
||||
@@ -41,25 +42,25 @@ namespace Il2CppInspector.Reflection
|
||||
public EventInfo(Il2CppInspector pkg, int eventIndex, TypeInfo declaringType) :
|
||||
base(declaringType) {
|
||||
Definition = pkg.Events[eventIndex];
|
||||
MetadataToken = (int) Definition.token;
|
||||
MetadataToken = (int) Definition.Token;
|
||||
Index = eventIndex;
|
||||
Name = pkg.Strings[Definition.nameIndex];
|
||||
Name = pkg.Strings[Definition.NameIndex];
|
||||
rootDefinition = this;
|
||||
|
||||
eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
||||
var eventType = pkg.TypeReferences[Definition.typeIndex];
|
||||
eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.TypeIndex);
|
||||
var eventType = pkg.TypeReferences[Definition.TypeIndex];
|
||||
|
||||
// Copy attributes
|
||||
Attributes = (EventAttributes) eventType.attrs;
|
||||
Attributes = (EventAttributes) eventType.Attrs;
|
||||
|
||||
// NOTE: This relies on methods being added to TypeInfo.DeclaredMethods in the same order they are defined in the Il2Cpp metadata
|
||||
// add, remove and raise are method indices from the first method of the declaring type
|
||||
if (Definition.add >= 0)
|
||||
AddMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.add);
|
||||
if (Definition.remove >= 0)
|
||||
RemoveMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.remove);
|
||||
if (Definition.raise >= 0)
|
||||
RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.raise);
|
||||
if (Definition.Add >= 0)
|
||||
AddMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Add);
|
||||
if (Definition.Remove >= 0)
|
||||
RemoveMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Remove);
|
||||
if (Definition.Raise >= 0)
|
||||
RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Raise);
|
||||
}
|
||||
|
||||
public EventInfo(EventInfo eventDef, TypeInfo declaringType) : base(declaringType) {
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Diagnostics.CodeAnalysis;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Il2CppInspector.Next.Metadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection {
|
||||
public class FieldInfo : MemberInfo // L-TODO: Add support for [ThreadLocal] fields
|
||||
@@ -96,9 +97,9 @@ namespace Il2CppInspector.Reflection {
|
||||
public FieldInfo(Il2CppInspector pkg, int fieldIndex, TypeInfo declaringType) :
|
||||
base(declaringType) {
|
||||
Definition = pkg.Fields[fieldIndex];
|
||||
MetadataToken = (int) Definition.token;
|
||||
MetadataToken = (int) Definition.Token;
|
||||
Index = fieldIndex;
|
||||
Name = pkg.Strings[Definition.nameIndex];
|
||||
Name = pkg.Strings[Definition.NameIndex];
|
||||
|
||||
rawOffset = pkg.FieldOffsets[fieldIndex];
|
||||
if (0 > rawOffset)
|
||||
@@ -109,11 +110,11 @@ namespace Il2CppInspector.Reflection {
|
||||
|
||||
rootDefinition = this;
|
||||
|
||||
fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
||||
var fieldType = pkg.TypeReferences[Definition.typeIndex];
|
||||
fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.TypeIndex);
|
||||
var fieldType = pkg.TypeReferences[Definition.TypeIndex];
|
||||
|
||||
// Copy attributes
|
||||
Attributes = (FieldAttributes) fieldType.attrs;
|
||||
Attributes = (FieldAttributes) fieldType.Attrs;
|
||||
|
||||
// Default initialization value if present
|
||||
if (pkg.FieldDefaultValue.TryGetValue(fieldIndex, out (ulong address, object variant) value)) {
|
||||
@@ -123,7 +124,7 @@ namespace Il2CppInspector.Reflection {
|
||||
}
|
||||
|
||||
public FieldInfo(FieldInfo fieldDef, TypeInfo declaringType) : base(declaringType) {
|
||||
if (fieldDef.Definition == null)
|
||||
if (!fieldDef.Definition.IsValid)
|
||||
throw new ArgumentException("Argument must be a bare field definition");
|
||||
|
||||
rootDefinition = fieldDef;
|
||||
|
||||
@@ -10,6 +10,7 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using Il2CppInspector.Next.Metadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection
|
||||
{
|
||||
@@ -117,9 +118,9 @@ namespace Il2CppInspector.Reflection
|
||||
// Initialize a method from a method definition (MethodDef)
|
||||
protected MethodBase(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(declaringType) {
|
||||
Definition = pkg.Methods[methodIndex];
|
||||
MetadataToken = (int) Definition.token;
|
||||
MetadataToken = (int) Definition.Token;
|
||||
Index = methodIndex;
|
||||
Name = pkg.Strings[Definition.nameIndex];
|
||||
Name = pkg.Strings[Definition.NameIndex];
|
||||
|
||||
// Find method pointer
|
||||
VirtualAddress = pkg.GetMethodPointer(Assembly.ModuleDefinition, Definition);
|
||||
@@ -130,28 +131,28 @@ namespace Il2CppInspector.Reflection
|
||||
rootDefinition = this;
|
||||
|
||||
// Generic method definition?
|
||||
if (Definition.genericContainerIndex >= 0) {
|
||||
if (Definition.GenericContainerIndex >= 0) {
|
||||
IsGenericMethod = true;
|
||||
|
||||
// Store the generic type parameters for later instantiation
|
||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
||||
var container = pkg.GenericContainers[Definition.GenericContainerIndex];
|
||||
genericArguments = Enumerable.Range(container.GenericParameterStart, container.TypeArgc)
|
||||
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
||||
genericMethodInstances = new Dictionary<TypeInfo[], MethodBase>(new TypeInfo.TypeArgumentsComparer());
|
||||
genericMethodInstances[genericArguments] = this;
|
||||
}
|
||||
|
||||
// Copy attributes
|
||||
Attributes = (MethodAttributes) Definition.flags;
|
||||
MethodImplementationFlags = (MethodImplAttributes) Definition.iflags;
|
||||
Attributes = (MethodAttributes) Definition.Flags;
|
||||
MethodImplementationFlags = (MethodImplAttributes) Definition.ImplFlags;
|
||||
|
||||
// Add arguments
|
||||
for (var p = Definition.parameterStart; p < Definition.parameterStart + Definition.parameterCount; p++)
|
||||
for (var p = Definition.ParameterStart; p < Definition.ParameterStart + Definition.ParameterCount; p++)
|
||||
DeclaredParameters.Add(new ParameterInfo(pkg, p, this));
|
||||
}
|
||||
|
||||
protected MethodBase(MethodBase methodDef, TypeInfo declaringType) : base(declaringType) {
|
||||
if (methodDef.Definition == null)
|
||||
if (!methodDef.Definition.IsValid)
|
||||
throw new ArgumentException("Argument must be a bare method definition");
|
||||
|
||||
rootDefinition = methodDef;
|
||||
|
||||
@@ -8,6 +8,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Il2CppInspector.Next.Metadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection
|
||||
{
|
||||
@@ -64,28 +65,28 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
if (paramIndex == -1) {
|
||||
Position = -1;
|
||||
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, declaringMethod.Definition.returnType);
|
||||
MetadataToken = declaringMethod.Definition.returnParameterToken;
|
||||
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, declaringMethod.Definition.ReturnType);
|
||||
MetadataToken = (int)declaringMethod.Definition.ReturnParameterToken;
|
||||
Attributes |= ParameterAttributes.Retval;
|
||||
return;
|
||||
}
|
||||
|
||||
Definition = pkg.Params[Index];
|
||||
MetadataToken = (int) Definition.token;
|
||||
Name = pkg.Strings[Definition.nameIndex];
|
||||
MetadataToken = (int) Definition.Token;
|
||||
Name = pkg.Strings[Definition.NameIndex];
|
||||
rootDefinition = this;
|
||||
|
||||
// Handle unnamed/obfuscated parameter names
|
||||
if (string.IsNullOrEmpty(Name))
|
||||
Name = string.Format($"param_{Index:x8}");
|
||||
|
||||
Position = paramIndex - declaringMethod.Definition.parameterStart;
|
||||
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, Definition.typeIndex);
|
||||
Position = paramIndex - declaringMethod.Definition.ParameterStart;
|
||||
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, Definition.TypeIndex);
|
||||
|
||||
var paramType = pkg.TypeReferences[Definition.typeIndex];
|
||||
var paramType = pkg.TypeReferences[Definition.TypeIndex];
|
||||
|
||||
// Copy attributes
|
||||
Attributes = (ParameterAttributes) paramType.attrs;
|
||||
Attributes = (ParameterAttributes) paramType.Attrs;
|
||||
|
||||
// Default initialization value if present
|
||||
if (pkg.ParameterDefaultValue.TryGetValue(paramIndex, out (ulong address, object variant) value)) {
|
||||
|
||||
@@ -8,6 +8,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Il2CppInspector.Next.Metadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection {
|
||||
public class PropertyInfo : MemberInfo
|
||||
@@ -52,25 +53,24 @@ namespace Il2CppInspector.Reflection {
|
||||
base(declaringType) {
|
||||
Index = propIndex;
|
||||
Definition = pkg.Properties[propIndex];
|
||||
MetadataToken = (int) Definition.token;
|
||||
Name = pkg.Strings[Definition.nameIndex];
|
||||
MetadataToken = (int) Definition.Token;
|
||||
Name = pkg.Strings[Definition.NameIndex];
|
||||
rootDefinition = this;
|
||||
|
||||
// Copy attributes
|
||||
Attributes = (PropertyAttributes) Definition.attrs;
|
||||
Attributes = (PropertyAttributes) Definition.Attrs;
|
||||
|
||||
// prop.get and prop.set are method indices from the first method of the declaring type
|
||||
if (Definition.get >= 0)
|
||||
GetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.get);
|
||||
if (Definition.set >= 0)
|
||||
SetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.set);
|
||||
if (Definition.Get >= 0)
|
||||
GetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Get);
|
||||
if (Definition.Set >= 0)
|
||||
SetMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.MethodIndex + Definition.Set);
|
||||
}
|
||||
|
||||
// Create a property based on a get and set method
|
||||
public PropertyInfo(MethodInfo getter, MethodInfo setter, TypeInfo declaringType) :
|
||||
base(declaringType) {
|
||||
Index = -1;
|
||||
Definition = null;
|
||||
rootDefinition = this;
|
||||
|
||||
Name = (getter ?? setter).Name.Replace(".get_", ".").Replace(".set_", ".");
|
||||
|
||||
@@ -13,6 +13,8 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using Il2CppInspector.Next.BinaryMetadata;
|
||||
using Il2CppInspector.Next.Metadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection
|
||||
{
|
||||
@@ -53,9 +55,9 @@ namespace Il2CppInspector.Reflection
|
||||
return null;
|
||||
if (IsArray)
|
||||
return Assembly.Model.TypesByFullName["System.Array"];
|
||||
if (Definition != null) {
|
||||
if (Definition.parentIndex >= 0)
|
||||
return Assembly.Model.TypesByReferenceIndex[Definition.parentIndex];
|
||||
if (Definition.IsValid) {
|
||||
if (Definition.ParentIndex >= 0)
|
||||
return Assembly.Model.TypesByReferenceIndex[Definition.ParentIndex];
|
||||
}
|
||||
if (genericTypeDefinition != null) {
|
||||
return genericTypeDefinition.BaseType.SubstituteGenericArguments(genericArguments);
|
||||
@@ -73,15 +75,15 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
public override TypeInfo DeclaringType {
|
||||
get {
|
||||
if (Definition != null) {
|
||||
if (Definition.IsValid) {
|
||||
/* Type definition */
|
||||
if (Definition.declaringTypeIndex == -1)
|
||||
if (Definition.DeclaringTypeIndex == -1)
|
||||
return null;
|
||||
var type = Assembly.Model.TypesByReferenceIndex[Definition.declaringTypeIndex];
|
||||
var type = Assembly.Model.TypesByReferenceIndex[Definition.DeclaringTypeIndex];
|
||||
if (type == null) {
|
||||
/* This might happen while initially setting up the types */
|
||||
var typeRef = Assembly.Model.Package.TypeReferences[Definition.declaringTypeIndex];
|
||||
type = Assembly.Model.TypesByDefinitionIndex[(int)typeRef.datapoint];
|
||||
var typeRef = Assembly.Model.Package.TypeReferences[Definition.DeclaringTypeIndex];
|
||||
type = Assembly.Model.TypesByDefinitionIndex[typeRef.Data.KlassIndex];
|
||||
}
|
||||
return type;
|
||||
}
|
||||
@@ -253,11 +255,11 @@ namespace Il2CppInspector.Reflection
|
||||
public PropertyInfo GetProperty(string name) => DeclaredProperties.FirstOrDefault(p => p.Name == name);
|
||||
|
||||
public MethodBase[] GetVTable() {
|
||||
if (Definition != null) {
|
||||
if (!Definition.IsValid) {
|
||||
MetadataUsage[] vt = Assembly.Model.Package.GetVTable(Definition);
|
||||
MethodBase[] res = new MethodBase[vt.Length];
|
||||
for (int i = 0; i < vt.Length; i++) {
|
||||
if (vt[i] != null)
|
||||
if (vt[i].IsValid)
|
||||
res[i] = Assembly.Model.GetMetadataUsageMethod(vt[i]);
|
||||
}
|
||||
return res;
|
||||
@@ -667,7 +669,7 @@ namespace Il2CppInspector.Reflection
|
||||
private readonly TypeRef[] implementedInterfaceReferences;
|
||||
public IEnumerable<TypeInfo> ImplementedInterfaces {
|
||||
get {
|
||||
if (Definition != null)
|
||||
if (Definition.IsValid)
|
||||
return implementedInterfaceReferences.Select(x => x.Value);
|
||||
if (genericTypeDefinition != null)
|
||||
return genericTypeDefinition.ImplementedInterfaces.Select(t => t.SubstituteGenericArguments(genericArguments));
|
||||
@@ -687,7 +689,7 @@ namespace Il2CppInspector.Reflection
|
||||
public bool IsEnum { get; }
|
||||
public bool IsGenericParameter { get; }
|
||||
public bool IsGenericType { get; }
|
||||
public bool IsGenericTypeDefinition => (Definition != null) && genericArguments.Any();
|
||||
public bool IsGenericTypeDefinition => (Definition.IsValid) && genericArguments.Any();
|
||||
public bool IsImport => (Attributes & TypeAttributes.Import) == TypeAttributes.Import;
|
||||
public bool IsInterface => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Interface;
|
||||
public bool IsNested => (MemberType & MemberTypes.NestedType) == MemberTypes.NestedType;
|
||||
@@ -746,13 +748,13 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
Definition = pkg.TypeDefinitions[typeIndex];
|
||||
Sizes = pkg.TypeDefinitionSizes[typeIndex];
|
||||
MetadataToken = (int) Definition.token;
|
||||
MetadataToken = (int) Definition.Token;
|
||||
Index = typeIndex;
|
||||
Namespace = Regex.Replace(pkg.Strings[Definition.namespaceIndex], @"[^A-Za-z0-9_\-\.<>{}]", "");
|
||||
Name = pkg.Strings[Definition.nameIndex];
|
||||
Namespace = Regex.Replace(pkg.Strings[Definition.NamespaceIndex], @"[^A-Za-z0-9_\-\.<>{}]", "");
|
||||
Name = pkg.Strings[Definition.NameIndex];
|
||||
|
||||
// Nested type?
|
||||
if (Definition.declaringTypeIndex >= 0) {
|
||||
if (Definition.DeclaringTypeIndex >= 0) {
|
||||
MemberType |= MemberTypes.NestedType;
|
||||
}
|
||||
|
||||
@@ -760,14 +762,14 @@ namespace Il2CppInspector.Reflection
|
||||
Assembly.Model.TypesByDefinitionIndex[Index] = this;
|
||||
|
||||
// Generic type definition?
|
||||
if (Definition.genericContainerIndex >= 0) {
|
||||
if (Definition.GenericContainerIndex >= 0) {
|
||||
IsGenericType = true;
|
||||
IsGenericParameter = false;
|
||||
|
||||
// Store the generic type parameters for later instantiation
|
||||
var container = pkg.GenericContainers[Definition.genericContainerIndex];
|
||||
var container = pkg.GenericContainers[Definition.GenericContainerIndex];
|
||||
|
||||
genericArguments = Enumerable.Range((int)container.genericParameterStart, container.type_argc)
|
||||
genericArguments = Enumerable.Range((int)container.GenericParameterStart, container.TypeArgc)
|
||||
.Select(index => Assembly.Model.GetGenericParameterType(index)).ToArray();
|
||||
genericTypeInstances = new Dictionary<TypeInfo[], TypeInfo>(new TypeArgumentsComparer());
|
||||
genericTypeInstances[genericArguments] = this;
|
||||
@@ -777,12 +779,12 @@ namespace Il2CppInspector.Reflection
|
||||
Assembly.Model.TypesByFullName[FullName] = this;
|
||||
|
||||
// Copy attributes
|
||||
Attributes = (TypeAttributes) Definition.flags;
|
||||
Attributes = (TypeAttributes) Definition.Flags;
|
||||
|
||||
// Enumerations - bit 1 of bitfield indicates this (also the baseTypeReference will be System.Enum)
|
||||
if (((Definition.bitfield >> 1) & 1) == 1) {
|
||||
if (Definition.Bitfield.EnumType) {
|
||||
IsEnum = true;
|
||||
enumUnderlyingTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.elementTypeIndex);
|
||||
enumUnderlyingTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.ElementTypeIndex);
|
||||
}
|
||||
|
||||
// Pass-by-reference type
|
||||
@@ -792,24 +794,24 @@ namespace Il2CppInspector.Reflection
|
||||
IsByRef = false;
|
||||
|
||||
// Add all implemented interfaces
|
||||
implementedInterfaceReferences = new TypeRef[Definition.interfaces_count];
|
||||
for (var i = 0; i < Definition.interfaces_count; i++)
|
||||
implementedInterfaceReferences[i] = TypeRef.FromReferenceIndex(Assembly.Model, pkg.InterfaceUsageIndices[Definition.interfacesStart + i]);
|
||||
implementedInterfaceReferences = new TypeRef[Definition.InterfacesCount];
|
||||
for (var i = 0; i < Definition.InterfacesCount; i++)
|
||||
implementedInterfaceReferences[i] = TypeRef.FromReferenceIndex(Assembly.Model, pkg.InterfaceUsageIndices[Definition.InterfacesIndex + i]);
|
||||
|
||||
// Add all nested types
|
||||
declaredNestedTypes = new TypeRef[Definition.nested_type_count];
|
||||
for (var n = 0; n < Definition.nested_type_count; n++)
|
||||
declaredNestedTypes[n] = TypeRef.FromDefinitionIndex(Assembly.Model, pkg.NestedTypeIndices[Definition.nestedTypesStart + n]);
|
||||
declaredNestedTypes = new TypeRef[Definition.NestedTypeCount];
|
||||
for (var n = 0; n < Definition.NestedTypeCount; n++)
|
||||
declaredNestedTypes[n] = TypeRef.FromDefinitionIndex(Assembly.Model, pkg.NestedTypeIndices[Definition.NestedTypeIndex + n]);
|
||||
|
||||
// Add all fields
|
||||
declaredFields = new List<FieldInfo>();
|
||||
for (var f = Definition.fieldStart; f < Definition.fieldStart + Definition.field_count; f++)
|
||||
for (var f = Definition.FieldIndex; f < Definition.FieldIndex + Definition.FieldCount; f++)
|
||||
declaredFields.Add(new FieldInfo(pkg, f, this));
|
||||
|
||||
// Add all methods
|
||||
declaredConstructors = new List<ConstructorInfo>();
|
||||
declaredMethods = new List<MethodInfo>();
|
||||
for (var m = Definition.methodStart; m < Definition.methodStart + Definition.method_count; m++) {
|
||||
for (var m = Definition.MethodIndex; m < Definition.MethodIndex + Definition.MethodCount; m++) {
|
||||
var method = new MethodInfo(pkg, m, this);
|
||||
if (method.Name == ConstructorInfo.ConstructorName || method.Name == ConstructorInfo.TypeConstructorName)
|
||||
declaredConstructors.Add(new ConstructorInfo(pkg, m, this));
|
||||
@@ -819,7 +821,7 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
// Add all properties
|
||||
declaredProperties = new List<PropertyInfo>();
|
||||
for (var p = Definition.propertyStart; p < Definition.propertyStart + Definition.property_count; p++)
|
||||
for (var p = Definition.PropertyIndex; p < Definition.PropertyIndex + Definition.PropertyCount; p++)
|
||||
declaredProperties.Add(new PropertyInfo(pkg, p, this));
|
||||
|
||||
// There are rare cases when explicitly implemented interface properties
|
||||
@@ -856,7 +858,7 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
// Add all events
|
||||
declaredEvents = new List<EventInfo>();
|
||||
for (var e = Definition.eventStart; e < Definition.eventStart + Definition.event_count; e++)
|
||||
for (var e = Definition.EventIndex; e < Definition.EventIndex + Definition.EventCount; e++)
|
||||
declaredEvents.Add(new EventInfo(pkg, e, this));
|
||||
|
||||
// TODO: Events have the same edge case issue as properties above, eg. PoGo 0.35.0
|
||||
@@ -937,21 +939,21 @@ namespace Il2CppInspector.Reflection
|
||||
Namespace = declaringType.Namespace;
|
||||
|
||||
// Special constraints
|
||||
GenericParameterAttributes = (GenericParameterAttributes)param.flags;
|
||||
GenericParameterAttributes = (GenericParameterAttributes)param.Flags;
|
||||
|
||||
// Type constraints
|
||||
genericParameterConstraints = new TypeRef[param.constraintsCount];
|
||||
for (int c = 0; c < param.constraintsCount; c++)
|
||||
genericParameterConstraints[c] = TypeRef.FromReferenceIndex(Assembly.Model, Assembly.Model.Package.GenericConstraintIndices[param.constraintsStart + c]);
|
||||
genericParameterConstraints = new TypeRef[param.ConstraintsCount];
|
||||
for (int c = 0; c < param.ConstraintsCount; c++)
|
||||
genericParameterConstraints[c] = TypeRef.FromReferenceIndex(Assembly.Model, Assembly.Model.Package.GenericConstraintIndices[param.ConstraintsStart + c]);
|
||||
|
||||
// Base type of object (set by default)
|
||||
// TODO: ImplementedInterfaces should be set to interface types constraints
|
||||
|
||||
// Name of parameter
|
||||
Name = Assembly.Model.Package.Strings[param.nameIndex];
|
||||
Name = Assembly.Model.Package.Strings[param.NameIndex];
|
||||
|
||||
// Position
|
||||
GenericParameterPosition = param.num;
|
||||
GenericParameterPosition = param.Num;
|
||||
|
||||
IsGenericParameter = true;
|
||||
IsGenericType = false;
|
||||
|
||||
@@ -5,10 +5,12 @@
|
||||
All rights reserved.
|
||||
*/
|
||||
|
||||
using Il2CppInspector.Next;
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Il2CppInspector.Next.BinaryMetadata;
|
||||
|
||||
namespace Il2CppInspector.Reflection
|
||||
{
|
||||
@@ -85,7 +87,7 @@ namespace Il2CppInspector.Reflection
|
||||
public TypeModel(Il2CppInspector package) {
|
||||
Package = package;
|
||||
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
|
||||
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Count];
|
||||
TypesByReferenceIndex = new TypeInfo[package.TypeReferences.Length];
|
||||
GenericParameterTypes = new TypeInfo[package.GenericParameters.Length];
|
||||
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
|
||||
MethodInvokers = new MethodInvoker[package.MethodInvokePointers.Length];
|
||||
@@ -97,7 +99,7 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
// 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++) {
|
||||
for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Length; typeRefIndex++) {
|
||||
if(TypesByReferenceIndex[typeRefIndex] != null) {
|
||||
/* type already generated - probably by forward reference through GetTypeFromVirtualAddress */
|
||||
continue;
|
||||
@@ -111,13 +113,13 @@ namespace Il2CppInspector.Reflection
|
||||
|
||||
// Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP)
|
||||
foreach (var spec in Package.MethodSpecs) {
|
||||
var methodDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex];
|
||||
var methodDefinition = MethodsByDefinitionIndex[spec.MethodDefinitionIndex];
|
||||
var declaringType = methodDefinition.DeclaringType;
|
||||
|
||||
// Concrete instance of a generic class
|
||||
// If the class index is not specified, we will later create a generic method in a non-generic class
|
||||
if (spec.classIndexIndex != -1) {
|
||||
var genericInstance = Package.GenericInstances[spec.classIndexIndex];
|
||||
if (spec.ClassIndexIndex != -1) {
|
||||
var genericInstance = Package.GenericInstances[spec.ClassIndexIndex];
|
||||
var genericArguments = ResolveGenericArguments(genericInstance);
|
||||
declaringType = declaringType.MakeGenericType(genericArguments);
|
||||
}
|
||||
@@ -128,8 +130,8 @@ namespace Il2CppInspector.Reflection
|
||||
else
|
||||
method = declaringType.GetMethodByDefinition((MethodInfo)methodDefinition);
|
||||
|
||||
if (spec.methodIndexIndex != -1) {
|
||||
var genericInstance = Package.GenericInstances[spec.methodIndexIndex];
|
||||
if (spec.MethodIndexIndex != -1) {
|
||||
var genericInstance = Package.GenericInstances[spec.MethodIndexIndex];
|
||||
var genericArguments = ResolveGenericArguments(genericInstance);
|
||||
method = method.MakeGenericMethod(genericArguments);
|
||||
}
|
||||
@@ -189,7 +191,7 @@ namespace Il2CppInspector.Reflection
|
||||
public TypeInfo[] ResolveGenericArguments(Il2CppGenericInst inst) {
|
||||
|
||||
// Get list of pointers to type parameters (both unresolved and concrete)
|
||||
var genericTypeArguments = Package.BinaryImage.ReadMappedArray<ulong>(inst.type_argv, (int)inst.type_argc);
|
||||
var genericTypeArguments = Package.BinaryImage.ReadMappedUWordArray(inst.TypeArgv, (int)inst.TypeArgc);
|
||||
|
||||
return genericTypeArguments.Select(a => GetTypeFromVirtualAddress(a)).ToArray();
|
||||
}
|
||||
@@ -200,67 +202,67 @@ namespace Il2CppInspector.Reflection
|
||||
var image = Package.BinaryImage;
|
||||
TypeInfo underlyingType;
|
||||
|
||||
switch (typeRef.type) {
|
||||
switch (typeRef.Type) {
|
||||
// Classes defined in the metadata (reference to a TypeDef)
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
||||
underlyingType = TypesByDefinitionIndex[typeRef.datapoint]; // klassIndex
|
||||
underlyingType = TypesByDefinitionIndex[typeRef.Data.KlassIndex]; // klassIndex
|
||||
break;
|
||||
|
||||
// Constructed types
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
||||
// TODO: Replace with array load from Il2CppMetadataRegistration.genericClasses
|
||||
var generic = image.ReadMappedObject<Il2CppGenericClass>(typeRef.datapoint); // Il2CppGenericClass *
|
||||
var generic = image.ReadMappedVersionedObject<Il2CppGenericClass>(typeRef.Data.GenericClass); // Il2CppGenericClass *
|
||||
|
||||
// Get generic type definition
|
||||
TypeInfo genericTypeDef;
|
||||
if (Package.Version < 27) {
|
||||
if (Package.Version < MetadataVersions.V270) {
|
||||
// It appears that TypeRef can be -1 if the generic depth recursion limit
|
||||
// (--maximum-recursive-generic-depth=) is reached in Il2Cpp. In this case,
|
||||
// no generic instance type is generated, so we just produce a null TypeInfo here.
|
||||
if ((generic.typeDefinitionIndex & 0xffff_ffff) == 0x0000_0000_ffff_ffff)
|
||||
if ((generic.TypeDefinitionIndex & 0xffff_ffff) == 0x0000_0000_ffff_ffff)
|
||||
return null;
|
||||
|
||||
genericTypeDef = TypesByDefinitionIndex[generic.typeDefinitionIndex];
|
||||
genericTypeDef = TypesByDefinitionIndex[generic.TypeDefinitionIndex];
|
||||
} else {
|
||||
genericTypeDef = GetTypeFromVirtualAddress(generic.type);
|
||||
genericTypeDef = GetTypeFromVirtualAddress(generic.Type);
|
||||
}
|
||||
|
||||
// Get the instantiation
|
||||
// TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts
|
||||
var genericInstance = image.ReadMappedObject<Il2CppGenericInst>(generic.context.class_inst);
|
||||
var genericInstance = image.ReadMappedVersionedObject<Il2CppGenericInst>(generic.Context.ClassInst);
|
||||
var genericArguments = ResolveGenericArguments(genericInstance);
|
||||
|
||||
underlyingType = genericTypeDef.MakeGenericType(genericArguments);
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||
var descriptor = image.ReadMappedObject<Il2CppArrayType>(typeRef.datapoint);
|
||||
var elementType = GetTypeFromVirtualAddress(descriptor.etype);
|
||||
underlyingType = elementType.MakeArrayType(descriptor.rank);
|
||||
var descriptor = image.ReadMappedVersionedObject<Il2CppArrayType>(typeRef.Data.ArrayType);
|
||||
var elementType = GetTypeFromVirtualAddress(descriptor.ElementType);
|
||||
underlyingType = elementType.MakeArrayType(descriptor.Rank);
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
||||
elementType = GetTypeFromVirtualAddress(typeRef.datapoint);
|
||||
elementType = GetTypeFromVirtualAddress(typeRef.Data.Type);
|
||||
underlyingType = elementType.MakeArrayType(1);
|
||||
break;
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
|
||||
elementType = GetTypeFromVirtualAddress(typeRef.datapoint);
|
||||
elementType = GetTypeFromVirtualAddress(typeRef.Data.Type);
|
||||
underlyingType = elementType.MakePointerType();
|
||||
break;
|
||||
|
||||
// Generic type and generic method parameters
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
||||
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
||||
underlyingType = GetGenericParameterType((int)typeRef.datapoint);
|
||||
underlyingType = GetGenericParameterType(typeRef.Data.GenericParameterIndex);
|
||||
break;
|
||||
|
||||
// Primitive types
|
||||
default:
|
||||
underlyingType = GetTypeDefinitionFromTypeEnum(typeRef.type);
|
||||
underlyingType = GetTypeDefinitionFromTypeEnum(typeRef.Type);
|
||||
break;
|
||||
}
|
||||
|
||||
// Create a reference type if necessary
|
||||
return typeRef.byref ? underlyingType.MakeByRefType() : underlyingType;
|
||||
return typeRef.ByRef ? underlyingType.MakeByRefType() : underlyingType;
|
||||
}
|
||||
|
||||
// Basic primitive types are specified via a flag value
|
||||
@@ -301,14 +303,14 @@ namespace Il2CppInspector.Reflection
|
||||
return GenericParameterTypes[index];
|
||||
|
||||
var paramType = Package.GenericParameters[index]; // genericParameterIndex
|
||||
var container = Package.GenericContainers[paramType.ownerIndex];
|
||||
var container = Package.GenericContainers[paramType.OwnerIndex];
|
||||
TypeInfo result;
|
||||
|
||||
if (container.is_method == 1) {
|
||||
var owner = MethodsByDefinitionIndex[container.ownerIndex];
|
||||
if (container.IsMethod == 1) {
|
||||
var owner = MethodsByDefinitionIndex[container.OwnerIndex];
|
||||
result = new TypeInfo(owner, paramType);
|
||||
} else {
|
||||
var owner = TypesByDefinitionIndex[container.ownerIndex];
|
||||
var owner = TypesByDefinitionIndex[container.OwnerIndex];
|
||||
result = new TypeInfo(owner, paramType);
|
||||
}
|
||||
GenericParameterTypes[index] = result;
|
||||
@@ -318,12 +320,12 @@ namespace Il2CppInspector.Reflection
|
||||
// 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
|
||||
public int GetCustomAttributeIndex(Assembly asm, int token, int customAttributeIndex) {
|
||||
// Prior to v24.1, Type, Field, Parameter, Method, Event, Property, Assembly definitions had their own customAttributeIndex field
|
||||
if (Package.Version <= 24.0)
|
||||
if (Package.Version <= MetadataVersions.V240)
|
||||
return customAttributeIndex;
|
||||
|
||||
// From v24.1 onwards, token was added to Il2CppCustomAttributeTypeRange and each Il2CppImageDefinition noted the CustomAttributeTypeRanges for the image
|
||||
// v29 uses this same system but with CustomAttributeDataRanges instead
|
||||
if (!Package.AttributeIndicesByToken.TryGetValue(asm.ImageDefinition.customAttributeStart, out var indices)
|
||||
if (!Package.AttributeIndicesByToken.TryGetValue(asm.ImageDefinition.CustomAttributeStart, out var indices)
|
||||
|| !indices.TryGetValue((uint)token, out var index))
|
||||
return -1;
|
||||
|
||||
@@ -344,7 +346,7 @@ namespace Il2CppInspector.Reflection
|
||||
case MetadataUsageType.FieldInfo:
|
||||
var fieldRef = Package.FieldRefs[usage.SourceIndex];
|
||||
var type = GetMetadataUsageType(usage);
|
||||
var field = type.DeclaredFields.First(f => f.Index == type.Definition.fieldStart + fieldRef.fieldIndex);
|
||||
var field = type.DeclaredFields.First(f => f.Index == type.Definition.FieldIndex + fieldRef.FieldIndex);
|
||||
return $"{type.Name}.{field.Name}";
|
||||
|
||||
case MetadataUsageType.StringLiteral:
|
||||
@@ -358,7 +360,7 @@ namespace Il2CppInspector.Reflection
|
||||
case MetadataUsageType.FieldRva:
|
||||
fieldRef = Package.FieldRefs[usage.SourceIndex];
|
||||
type = GetMetadataUsageType(usage);
|
||||
field = type.DeclaredFields.First(f => f.Index == type.Definition.fieldStart + fieldRef.fieldIndex);
|
||||
field = type.DeclaredFields.First(f => f.Index == type.Definition.FieldIndex + fieldRef.FieldIndex);
|
||||
return $"{type.Name}.{field.Name}_Default"; // TODO: Find out if this is really needed for anything
|
||||
}
|
||||
throw new NotImplementedException("Unknown metadata usage type: " + usage.Type);
|
||||
@@ -368,7 +370,7 @@ namespace Il2CppInspector.Reflection
|
||||
public TypeInfo GetMetadataUsageType(MetadataUsage usage) => usage.Type switch {
|
||||
MetadataUsageType.Type or MetadataUsageType.TypeInfo => TypesByReferenceIndex[usage.SourceIndex],
|
||||
MetadataUsageType.MethodDef or MetadataUsageType.MethodRef => GetMetadataUsageMethod(usage).DeclaringType,
|
||||
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => TypesByReferenceIndex[Package.FieldRefs[usage.SourceIndex].typeIndex],
|
||||
MetadataUsageType.FieldInfo or MetadataUsageType.FieldRva => TypesByReferenceIndex[Package.FieldRefs[usage.SourceIndex].TypeIndex],
|
||||
_ => throw new InvalidOperationException("Incorrect metadata usage type to retrieve referenced type")
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user