diff --git a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs index 3652065..528e88d 100644 --- a/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs +++ b/Il2CppInspector.Common/Cpp/CppDeclarationGenerator.cs @@ -228,6 +228,14 @@ namespace Il2CppInspector.Cpp ns.ReserveName("_"); fieldType = types.Struct(name + "__Fields"); var baseFieldType = types[TypeNamer.GetName(ti.BaseType) + "__Fields"]; + + if (baseFieldType == null) + { + // if we end up here, there is a loop in the type generation. + // this is not currently supported, so we throw an exception. + throw new InvalidOperationException($"Failed to generate type for {ti}"); + } + fieldType.AddField("_", baseFieldType); GenerateFieldList(fieldType, ns, ti); } @@ -437,16 +445,30 @@ namespace Il2CppInspector.Cpp /// A string containing C type declarations public List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType, CppComplexType vtableType, CppComplexType staticsType)> GenerateRemainingTypeDeclarations() { - var decl = GenerateVisitedFieldStructs().Select(s => - (s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType) null, (CppComplexType) null)).ToList(); + try + { + var decl = GenerateVisitedFieldStructs().Select(s => + (s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType)null, + (CppComplexType)null)) + .ToList(); - foreach (var ti in TodoTypeStructs) { - var (cls, statics, vtable) = GenerateTypeStruct(ti); - decl.Add((ti, null, cls, null, vtable, statics)); + foreach (var ti in TodoTypeStructs) + { + var (cls, statics, vtable) = GenerateTypeStruct(ti); + decl.Add((ti, null, cls, null, vtable, statics)); + } + + return decl; + } + catch (Exception) + { + return null; + } + finally + { + TodoTypeStructs.Clear(); + TodoFieldStructs.Clear(); } - TodoTypeStructs.Clear(); - - return decl; } #endregion diff --git a/Il2CppInspector.Common/Cpp/CppField.cs b/Il2CppInspector.Common/Cpp/CppField.cs index 2ac419f..631e762 100644 --- a/Il2CppInspector.Common/Cpp/CppField.cs +++ b/Il2CppInspector.Common/Cpp/CppField.cs @@ -4,8 +4,6 @@ All rights reserved. */ -using System; - namespace Il2CppInspector.Cpp { // A field in a C++ type diff --git a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs index 64b087f..42503c9 100644 --- a/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs +++ b/Il2CppInspector.Common/IL2CPP/Il2CppBinary.cs @@ -337,7 +337,15 @@ namespace Il2CppInspector } // Read method invoker pointer indices - one per method - MethodInvokerIndices.Add(module, Image.ReadMappedPrimitiveArray(module.InvokerIndices, (int) module.MethodPointerCount)); + try + { + MethodInvokerIndices.Add(module, + Image.ReadMappedPrimitiveArray(module.InvokerIndices, (int)module.MethodPointerCount)); + } + catch (InvalidOperationException) + { + MethodInvokerIndices.Add(module, [..new int[(int)module.MethodPointerCount]]); + } } } @@ -398,12 +406,21 @@ namespace Il2CppInspector var type = TypeReferences[i]; if (type.Type.IsTypeDefinitionEnum()) { - type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize; + if (type.Data.Type.PointerValue >= baseDefinitionPtr) + type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize; + + Debug.Assert(Metadata!.Types.Length > type.Data.KlassIndex); } else if (type.Type.IsGenericParameterEnum()) { - type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize; + if (type.Data.Type.PointerValue >= baseGenericPtr) + type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize; + + Debug.Assert(Metadata!.GenericParameters.Length > type.Data.KlassIndex); } + + Debug.Assert((long)type.Data.Value >= 0); + builder.Add(type); } TypeReferences = builder.MoveToImmutable(); diff --git a/Il2CppInspector.Common/Model/AppModel.cs b/Il2CppInspector.Common/Model/AppModel.cs index 923e6ee..59822fc 100644 --- a/Il2CppInspector.Common/Model/AppModel.cs +++ b/Il2CppInspector.Common/Model/AppModel.cs @@ -236,7 +236,17 @@ namespace Il2CppInspector.Model break; case MetadataUsageType.MethodDef or MetadataUsageType.MethodRef: var method = TypeModel.GetMetadataUsageMethod(usage); + declarationGenerator.IncludeMethod(method); + var definitions = declarationGenerator.GenerateRemainingTypeDeclarations(); + if (definitions == null) + { + // if we end up here, type generation has failed + // todo: this try/catch is a massive hack to sidestep the original issue of generation failing, + // todo: this needs to be improved. + break; + } + AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations()); // Any method here SHOULD already be in the Methods list @@ -247,6 +257,7 @@ namespace Il2CppInspector.Model Methods.Add(method, fnPtr, new AppMethod(method, fnPtr) { Group = Group }); } Methods[method].MethodInfoPtrAddress = address; + break; // FieldInfo is used for array initializers. diff --git a/Il2CppInspector.Common/Outputs/AssemblyShims.cs b/Il2CppInspector.Common/Outputs/AssemblyShims.cs index c111691..3446761 100644 --- a/Il2CppInspector.Common/Outputs/AssemblyShims.cs +++ b/Il2CppInspector.Common/Outputs/AssemblyShims.cs @@ -430,7 +430,7 @@ namespace Il2CppInspector.Outputs if (method.VirtualAddress.HasValue) { var args = new List<(string,object)> { ("RVA", (method.VirtualAddress.Value.Start - model.Package.BinaryImage.ImageBase).ToAddressString()), - ("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start))), + ("Offset", $"0x{model.Package.BinaryImage.MapVATR(method.VirtualAddress.Value.Start):X}"), ("VA", method.VirtualAddress.Value.Start.ToAddressString()) }; if (method.Definition.Slot != ushort.MaxValue) @@ -470,7 +470,7 @@ namespace Il2CppInspector.Outputs return def.AddAttribute(module, attributeAttribute, ("Name", ca.AttributeType.Name), ("RVA", (ca.VirtualAddress.Start - model.Package.BinaryImage.ImageBase).ToAddressString()), - ("Offset", string.Format("0x{0:X}", model.Package.BinaryImage.MapVATR(ca.VirtualAddress.Start))) + ("Offset", $"0x{model.Package.BinaryImage.MapVATR(ca.VirtualAddress.Start):X}") ); } diff --git a/Il2CppInspector.Common/Reflection/TypeModel.cs b/Il2CppInspector.Common/Reflection/TypeModel.cs index 2cdfd7f..1dbb8b0 100644 --- a/Il2CppInspector.Common/Reflection/TypeModel.cs +++ b/Il2CppInspector.Common/Reflection/TypeModel.cs @@ -165,10 +165,9 @@ namespace Il2CppInspector.Reflection // Generic type definitions have an invoker index of -1 foreach (var method in MethodsByDefinitionIndex) { var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition); - if (index != -1) { - if (MethodInvokers[index] == null) - MethodInvokers[index] = new MethodInvoker(method, index); - + if (index != -1) + { + MethodInvokers[index] ??= new MethodInvoker(method, index); method.Invoker = MethodInvokers[index]; } } @@ -176,10 +175,11 @@ namespace Il2CppInspector.Reflection // Create method invokers sourced from generic method invoker indices foreach (var spec in GenericMethods.Keys) { if (package.GenericMethodInvokerIndices.TryGetValue(spec, out var index)) { - if (MethodInvokers[index] == null) - MethodInvokers[index] = new MethodInvoker(GenericMethods[spec], index); - - GenericMethods[spec].Invoker = MethodInvokers[index]; + if (index != -1) + { + MethodInvokers[index] ??= new MethodInvoker(GenericMethods[spec], index); + GenericMethods[spec].Invoker = MethodInvokers[index]; + } } }