diff --git a/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs index 93fa1fcd..9958d0d8 100644 --- a/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/ApplicationAnalysisContext.cs @@ -211,6 +211,17 @@ private void PopulateMethodsByAddressTable() return ConcreteGenericMethodsByRef.TryGetValue(methodReference, out var context) ? context : new(methodReference, this); } + + [return: NotNullIfNotNull(nameof(methodReference))] + public MethodAnalysisContext? ResolveContextForMethod(MetadataUsage? methodReference) + { + return methodReference?.Type switch + { + null => null, + MetadataUsageType.MethodDef => ResolveContextForMethod(methodReference.AsMethod()), + MetadataUsageType.MethodRef => ResolveContextForMethod(methodReference.AsGenericMethodRef()), + }; + } public FieldAnalysisContext? ResolveContextForField(Il2CppFieldDefinition? field) { diff --git a/Cpp2IL.Core/Model/Contexts/AssemblyAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/AssemblyAnalysisContext.cs index 0beb8817..2199dd69 100644 --- a/Cpp2IL.Core/Model/Contexts/AssemblyAnalysisContext.cs +++ b/Cpp2IL.Core/Model/Contexts/AssemblyAnalysisContext.cs @@ -30,6 +30,11 @@ public class AssemblyAnalysisContext : HasCustomAttributesAndName /// public IEnumerable TopLevelTypes => Types.Where(t => t.DeclaringType == null); + /// + /// The analysis context object for the manifest module of the assembly. + /// + public ModuleAnalysisContext ManifestModule { get; } + /// /// The analysis context objects for all types exported by this assembly. /// @@ -185,6 +190,8 @@ public AssemblyAnalysisContext(Il2CppAssemblyDefinition? assemblyDefinition, App Definition = assemblyDefinition; + ManifestModule = new(this); + if (AppContext.MetadataVersion >= 24.2f) CodeGenModule = AppContext.Binary.GetCodegenModuleByName(Definition.Image.Name!); diff --git a/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs b/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs index 9a55b9d9..5fe10bb1 100644 --- a/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs +++ b/Cpp2IL.Core/Model/Contexts/HasCustomAttributes.cs @@ -279,23 +279,20 @@ private void AnalyzeCustomAttributeDataV29() //Diagnostic data var startOfData = blobStream.Position; - var perAttributeStartOffsets = new Dictionary(); + var perAttributeStartOffsets = new Dictionary(); CustomAttributes = []; foreach (var constructor in constructors) { perAttributeStartOffsets[constructor] = blobStream.Position; - var attributeTypeContext = AppContext.ResolveContextForType(constructor.DeclaringType!) ?? throw new($"Unable to find type {constructor.DeclaringType!.FullName}"); - var attributeMethodContext = attributeTypeContext.GetMethod(constructor) ?? throw new($"Unable to find method {constructor.Name} in type {attributeTypeContext.Definition?.FullName}"); - try { - CustomAttributes.Add(V29AttributeUtils.ReadAttribute(blobStream, attributeMethodContext, AppContext)); + CustomAttributes.Add(V29AttributeUtils.ReadAttribute(blobStream, constructor, AppContext)); } catch (Exception e) { - Logger.ErrorNewline($"Failed to read attribute data for {constructor}, which has parameters {string.Join(", ", constructor.Parameters!.Select(p => p.Type))}", "CA Restore"); + Logger.ErrorNewline($"Failed to read attribute data for {constructor}, which has parameters {string.Join(", ", constructor.Parameters.Select(p => p.ParameterType))}", "CA Restore"); Logger.ErrorNewline($"This member ({ToString()}) has {RawIl2CppCustomAttributeData.Length} bytes of data starting at 0x{GetV29BlobOffsets()!.Value.blobStart:X}", "CA Restore"); Logger.ErrorNewline($"The post-constructor data started at 0x{startOfData:X} bytes into our blob", "CA Restore"); Logger.ErrorNewline($"Data for this constructor started at 0x{perAttributeStartOffsets[constructor]:X} bytes into our blob, we are now 0x{blobStream.Position:X} bytes into the blob", "CA Restore"); diff --git a/Cpp2IL.Core/Model/Contexts/ModuleAnalysisContext.cs b/Cpp2IL.Core/Model/Contexts/ModuleAnalysisContext.cs new file mode 100644 index 00000000..9176e1b4 --- /dev/null +++ b/Cpp2IL.Core/Model/Contexts/ModuleAnalysisContext.cs @@ -0,0 +1,23 @@ +namespace Cpp2IL.Core.Model.Contexts; + +/// +/// Represents a single Module that was converted using IL2CPP. +/// +public class ModuleAnalysisContext : HasCustomAttributesAndName +{ + private AssemblyAnalysisContext _assemblyContext; + + /// + override protected int CustomAttributeIndex => -1; + /// + public override AssemblyAnalysisContext CustomAttributeAssembly => _assemblyContext; + /// + public override string DefaultName => _assemblyContext.Definition!.Image.Name!; + + public ModuleAnalysisContext(AssemblyAnalysisContext asmCtx) : base(asmCtx.Definition?.ModuleToken ?? 1, asmCtx.AppContext) + { + _assemblyContext = asmCtx; + + InitCustomAttributeData(); + } +} diff --git a/Cpp2IL.Core/ProcessingLayers/AttributeAnalysisProcessingLayer.cs b/Cpp2IL.Core/ProcessingLayers/AttributeAnalysisProcessingLayer.cs index 04396250..5bd462de 100644 --- a/Cpp2IL.Core/ProcessingLayers/AttributeAnalysisProcessingLayer.cs +++ b/Cpp2IL.Core/ProcessingLayers/AttributeAnalysisProcessingLayer.cs @@ -14,8 +14,12 @@ public override void Process(ApplicationAnalysisContext appContext, Action 1 + t.Events.Count + t.Fields.Count + t.Methods.Count + t.Properties.Count).Sum(); - int count = 0; - appContext.Assemblies.ForEach(a => AnalyzeAndRaise(a, ref count, total, progressCallback)); + var count = 0; + foreach (var a in appContext.Assemblies) + { + AnalyzeAndRaise(a, ref count, total, progressCallback); + AnalyzeAndRaise(a.ManifestModule, ref count, total, progressCallback); + } //TODO look into making this parallel foreach (var type in appContext.AllTypes) diff --git a/Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs b/Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs index 1eeeccf0..a2618eac 100644 --- a/Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs +++ b/Cpp2IL.Core/Utils/AsmResolver/AsmResolverAssemblyPopulator.cs @@ -261,7 +261,9 @@ public static void PopulateCustomAttributes(AssemblyAnalysisContext asmContext) try #endif { - CopyCustomAttributes(asmContext, asmContext.GetExtraData("AsmResolverAssembly")!.CustomAttributes); + var assembly = asmContext.GetExtraData("AsmResolverAssembly")!; + CopyCustomAttributes(asmContext, assembly.CustomAttributes); + CopyCustomAttributes(asmContext.ManifestModule, assembly.ManifestModule!.CustomAttributes); foreach (var type in asmContext.Types) { diff --git a/Cpp2IL.Core/Utils/V29AttributeUtils.cs b/Cpp2IL.Core/Utils/V29AttributeUtils.cs index 3812a087..166e4645 100644 --- a/Cpp2IL.Core/Utils/V29AttributeUtils.cs +++ b/Cpp2IL.Core/Utils/V29AttributeUtils.cs @@ -14,7 +14,7 @@ namespace Cpp2IL.Core.Utils; public static class V29AttributeUtils { - public static Il2CppMethodDefinition[] ReadConstructors(Stream stream, uint count, ApplicationAnalysisContext context) + public static MethodAnalysisContext[] ReadConstructors(Stream stream, uint count, ApplicationAnalysisContext context) { using var reader = new BinaryReader(stream, Encoding.UTF8, true); var indices = new uint[count]; @@ -25,7 +25,10 @@ public static Il2CppMethodDefinition[] ReadConstructors(Stream stream, uint coun if (ClassReadingBinaryReader.EnableReadableSizeInformation) context.Metadata.TrackRead((int)(4 * count), trackIfFinishedReading: true); - return indices.Select(i => context.Metadata.methodDefs[i]).ToArray(); //TODO DynWidth: Validate against v105 CA blob once we have one. + if (context.Metadata.MetadataVersion >= 104) + return indices.Select(i => context.ResolveContextForMethod(MetadataUsage.DecodeMetadataUsage(i, 0, context.LibCpp2IlContext)!)).ToArray(); + else + return indices.Select(i => context.ResolveContextForMethod(context.Metadata.methodDefs[i])!).ToArray(); } public static AnalyzedCustomAttribute ReadAttribute(Stream stream, MethodAnalysisContext constructor, ApplicationAnalysisContext context) @@ -83,8 +86,14 @@ private static T ResolveMemberFromIndex(Stream stream, MethodAnalysisContext memberIndex = -(memberIndex + 1); //Resolve type - var typeDef = context.Metadata.GetTypeDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int)typeIndex)); //DynWidth: typeIndex is already compressed, they didn't make it dynamic - var typeContext = context.ResolveContextForType(typeDef) ?? throw new("Unable to find type " + typeDef); + TypeAnalysisContext typeContext; + if (context.Metadata.MetadataVersion >= 104) + typeContext = constructor.DeclaringType!.DeclaringAssembly.ResolveIl2CppType(context.Binary.GetType(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int)typeIndex))); + else + { + var typeDef = context.Metadata.GetTypeDefinitionFromIndex(Il2CppVariableWidthIndex.MakeTemporaryForFixedWidthUsage((int)typeIndex)); //DynWidth: typeIndex is already compressed, they didn't make it dynamic + typeContext = context.ResolveContextForType(typeDef) ?? throw new("Unable to find type " + typeDef); + } //Get member member = memberListGetter(typeContext)[memberIndex];