smaller tweaks, hack around loops in cpp type layouting

This commit is contained in:
LukeFZ
2025-02-08 17:40:15 +01:00
parent e6bd289aa4
commit ffb1996252
6 changed files with 71 additions and 23 deletions

View File

@@ -228,6 +228,14 @@ namespace Il2CppInspector.Cpp
ns.ReserveName("_"); ns.ReserveName("_");
fieldType = types.Struct(name + "__Fields"); fieldType = types.Struct(name + "__Fields");
var baseFieldType = types[TypeNamer.GetName(ti.BaseType) + "__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); fieldType.AddField("_", baseFieldType);
GenerateFieldList(fieldType, ns, ti); GenerateFieldList(fieldType, ns, ti);
} }
@@ -437,17 +445,31 @@ namespace Il2CppInspector.Cpp
/// <returns>A string containing C type declarations</returns> /// <returns>A string containing C type declarations</returns>
public List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType, public List<(TypeInfo ilType, CppComplexType valueType, CppComplexType referenceType, CppComplexType fieldsType,
CppComplexType vtableType, CppComplexType staticsType)> GenerateRemainingTypeDeclarations() { CppComplexType vtableType, CppComplexType staticsType)> GenerateRemainingTypeDeclarations() {
try
{
var decl = GenerateVisitedFieldStructs().Select(s => var decl = GenerateVisitedFieldStructs().Select(s =>
(s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType) null, (CppComplexType) null)).ToList(); (s.ilType, s.valueType, s.referenceType, s.fieldsType, (CppComplexType)null,
(CppComplexType)null))
.ToList();
foreach (var ti in TodoTypeStructs) { foreach (var ti in TodoTypeStructs)
{
var (cls, statics, vtable) = GenerateTypeStruct(ti); var (cls, statics, vtable) = GenerateTypeStruct(ti);
decl.Add((ti, null, cls, null, vtable, statics)); decl.Add((ti, null, cls, null, vtable, statics));
} }
TodoTypeStructs.Clear();
return decl; return decl;
} }
catch (Exception)
{
return null;
}
finally
{
TodoTypeStructs.Clear();
TodoFieldStructs.Clear();
}
}
#endregion #endregion
#region Method Generation #region Method Generation

View File

@@ -4,8 +4,6 @@
All rights reserved. All rights reserved.
*/ */
using System;
namespace Il2CppInspector.Cpp namespace Il2CppInspector.Cpp
{ {
// A field in a C++ type // A field in a C++ type

View File

@@ -337,7 +337,15 @@ namespace Il2CppInspector
} }
// Read method invoker pointer indices - one per method // Read method invoker pointer indices - one per method
MethodInvokerIndices.Add(module, Image.ReadMappedPrimitiveArray<int>(module.InvokerIndices, (int) module.MethodPointerCount)); try
{
MethodInvokerIndices.Add(module,
Image.ReadMappedPrimitiveArray<int>(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]; var type = TypeReferences[i];
if (type.Type.IsTypeDefinitionEnum()) if (type.Type.IsTypeDefinitionEnum())
{ {
if (type.Data.Type.PointerValue >= baseDefinitionPtr)
type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize; type.Data.Value = (type.Data.Type.PointerValue - baseDefinitionPtr) / definitionSize;
Debug.Assert(Metadata!.Types.Length > type.Data.KlassIndex);
} }
else if (type.Type.IsGenericParameterEnum()) else if (type.Type.IsGenericParameterEnum())
{ {
if (type.Data.Type.PointerValue >= baseGenericPtr)
type.Data.Value = (type.Data.Type.PointerValue - baseGenericPtr) / genericParameterSize; 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); builder.Add(type);
} }
TypeReferences = builder.MoveToImmutable(); TypeReferences = builder.MoveToImmutable();

View File

@@ -236,7 +236,17 @@ namespace Il2CppInspector.Model
break; break;
case MetadataUsageType.MethodDef or MetadataUsageType.MethodRef: case MetadataUsageType.MethodDef or MetadataUsageType.MethodRef:
var method = TypeModel.GetMetadataUsageMethod(usage); var method = TypeModel.GetMetadataUsageMethod(usage);
declarationGenerator.IncludeMethod(method); 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()); AddTypes(declarationGenerator.GenerateRemainingTypeDeclarations());
// Any method here SHOULD already be in the Methods list // 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.Add(method, fnPtr, new AppMethod(method, fnPtr) { Group = Group });
} }
Methods[method].MethodInfoPtrAddress = address; Methods[method].MethodInfoPtrAddress = address;
break; break;
// FieldInfo is used for array initializers. // FieldInfo is used for array initializers.

View File

@@ -430,7 +430,7 @@ namespace Il2CppInspector.Outputs
if (method.VirtualAddress.HasValue) { if (method.VirtualAddress.HasValue) {
var args = new List<(string,object)> { var args = new List<(string,object)> {
("RVA", (method.VirtualAddress.Value.Start - model.Package.BinaryImage.ImageBase).ToAddressString()), ("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()) ("VA", method.VirtualAddress.Value.Start.ToAddressString())
}; };
if (method.Definition.Slot != ushort.MaxValue) if (method.Definition.Slot != ushort.MaxValue)
@@ -470,7 +470,7 @@ namespace Il2CppInspector.Outputs
return def.AddAttribute(module, attributeAttribute, return def.AddAttribute(module, attributeAttribute,
("Name", ca.AttributeType.Name), ("Name", ca.AttributeType.Name),
("RVA", (ca.VirtualAddress.Start - model.Package.BinaryImage.ImageBase).ToAddressString()), ("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}")
); );
} }

View File

@@ -165,10 +165,9 @@ namespace Il2CppInspector.Reflection
// Generic type definitions have an invoker index of -1 // Generic type definitions have an invoker index of -1
foreach (var method in MethodsByDefinitionIndex) { foreach (var method in MethodsByDefinitionIndex) {
var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition); var index = package.GetInvokerIndex(method.DeclaringType.Assembly.ModuleDefinition, method.Definition);
if (index != -1) { if (index != -1)
if (MethodInvokers[index] == null) {
MethodInvokers[index] = new MethodInvoker(method, index); MethodInvokers[index] ??= new MethodInvoker(method, index);
method.Invoker = MethodInvokers[index]; method.Invoker = MethodInvokers[index];
} }
} }
@@ -176,12 +175,13 @@ namespace Il2CppInspector.Reflection
// Create method invokers sourced from generic method invoker indices // Create method invokers sourced from generic method invoker indices
foreach (var spec in GenericMethods.Keys) { foreach (var spec in GenericMethods.Keys) {
if (package.GenericMethodInvokerIndices.TryGetValue(spec, out var index)) { if (package.GenericMethodInvokerIndices.TryGetValue(spec, out var index)) {
if (MethodInvokers[index] == null) if (index != -1)
MethodInvokers[index] = new MethodInvoker(GenericMethods[spec], index); {
MethodInvokers[index] ??= new MethodInvoker(GenericMethods[spec], index);
GenericMethods[spec].Invoker = MethodInvokers[index]; GenericMethods[spec].Invoker = MethodInvokers[index];
} }
} }
}
// Post-processing hook // Post-processing hook
PluginHooks.PostProcessTypeModel(this); PluginHooks.PostProcessTypeModel(this);