diff --git a/Cpp2IL.Core/Cpp2IlCorePlugin.cs b/Cpp2IL.Core/Cpp2IlCorePlugin.cs index 04258280..60458a00 100644 --- a/Cpp2IL.Core/Cpp2IlCorePlugin.cs +++ b/Cpp2IL.Core/Cpp2IlCorePlugin.cs @@ -41,7 +41,10 @@ public override void OnLoad() Logger.VerboseNewline("\tRegistering built-in output formats...", "Core Plugin"); - OutputFormatRegistry.Register(); + OutputFormatRegistry.Register(); + OutputFormatRegistry.Register(); + OutputFormatRegistry.Register(); + OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); OutputFormatRegistry.Register(); diff --git a/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatDefault.cs b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatDefault.cs new file mode 100644 index 00000000..efa81604 --- /dev/null +++ b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatDefault.cs @@ -0,0 +1,17 @@ +using AsmResolver.DotNet; +using AssetRipper.CIL; +using Cpp2IL.Core.Model.Contexts; + +namespace Cpp2IL.Core.OutputFormats; + +public class AsmResolverDllOutputFormatDefault : AsmResolverDllOutputFormat +{ + public override string OutputFormatId => "dll_default"; + + public override string OutputFormatName => "DLL files with default method bodies"; + + protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) + { + methodDefinition.FillMethodBodyWithStub(); + } +} diff --git a/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatEmpty.cs b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatEmpty.cs new file mode 100644 index 00000000..5b82b18a --- /dev/null +++ b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatEmpty.cs @@ -0,0 +1,18 @@ +using AsmResolver.DotNet; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Utils.AsmResolver; + +namespace Cpp2IL.Core.OutputFormats; + +public class AsmResolverDllOutputFormatEmpty : AsmResolverDllOutputFormat +{ + public override string OutputFormatId => "dll_empty"; + + public override string OutputFormatName => "DLL files with empty method bodies"; + + protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) + { + if (methodDefinition.IsManagedMethodWithBody()) + methodDefinition.CilMethodBody = new(methodDefinition); + } +} diff --git a/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatIlRecovery.cs b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatIlRecovery.cs new file mode 100644 index 00000000..129f3a7b --- /dev/null +++ b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatIlRecovery.cs @@ -0,0 +1,24 @@ +using AsmResolver.DotNet; +using AsmResolver.PE.DotNet.Cil; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Utils.AsmResolver; + +namespace Cpp2IL.Core.OutputFormats; + +public class AsmResolverDllOutputFormatIlRecovery : AsmResolverDllOutputFormat +{ + public override string OutputFormatId => "dll_il_recovery"; + + public override string OutputFormatName => "DLL files with IL Recovery"; + + protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) + { + if (methodDefinition.IsManagedMethodWithBody()) + { + methodDefinition.CilMethodBody = new(methodDefinition); + var instructions = methodDefinition.CilMethodBody.Instructions; + instructions.Add(CilOpCodes.Ldnull); + instructions.Add(CilOpCodes.Throw); + } + } +} diff --git a/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatThrowNull.cs b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatThrowNull.cs new file mode 100644 index 00000000..c554c1b9 --- /dev/null +++ b/Cpp2IL.Core/OutputFormats/AsmResolverDllOutputFormatThrowNull.cs @@ -0,0 +1,24 @@ +using AsmResolver.DotNet; +using AsmResolver.PE.DotNet.Cil; +using Cpp2IL.Core.Model.Contexts; +using Cpp2IL.Core.Utils.AsmResolver; + +namespace Cpp2IL.Core.OutputFormats; + +public class AsmResolverDllOutputFormatThrowNull : AsmResolverDllOutputFormat +{ + public override string OutputFormatId => "dll_throw_null"; + + public override string OutputFormatName => "DLL files with method bodies containing throw null"; + + protected override void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext) + { + if (methodDefinition.IsManagedMethodWithBody()) + { + methodDefinition.CilMethodBody = new(methodDefinition); + var instructions = methodDefinition.CilMethodBody.Instructions; + instructions.Add(CilOpCodes.Ldnull); + instructions.Add(CilOpCodes.Throw); + } + } +} diff --git a/Cpp2IL.Core/OutputFormats/AsmResolverDummyDllOutputFormat.cs b/Cpp2IL.Core/OutputFormats/AsmResolverDummyDllOutputFormat.cs index 68aa5da4..6a97759a 100644 --- a/Cpp2IL.Core/OutputFormats/AsmResolverDummyDllOutputFormat.cs +++ b/Cpp2IL.Core/OutputFormats/AsmResolverDummyDllOutputFormat.cs @@ -18,20 +18,16 @@ namespace Cpp2IL.Core.OutputFormats; -public class AsmResolverDummyDllOutputFormat : Cpp2IlOutputFormat +public abstract class AsmResolverDllOutputFormat : Cpp2IlOutputFormat { - public override string OutputFormatId => "dummydll"; - - public override string OutputFormatName => "Stub (\"Dummy\") DLL Files"; - private AssemblyDefinition? MostRecentCorLib { get; set; } - public override void DoOutput(ApplicationAnalysisContext context, string outputRoot) + public sealed override void DoOutput(ApplicationAnalysisContext context, string outputRoot) { var ret = BuildAssemblies(context); var start = DateTime.Now; - Logger.Verbose("Generating PE images...", "DummyDllOutput"); + Logger.Verbose("Generating PE images...", "DllOutput"); if (!Directory.Exists(outputRoot)) Directory.CreateDirectory(outputRoot); @@ -42,10 +38,10 @@ public override void DoOutput(ApplicationAnalysisContext context, string outputR .Select(a => (image: a.ManifestModule!.ToPEImage(new ManagedPEImageBuilder()), name: a.ManifestModule.Name!)) .ToList(); - Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DummyDllOutput"); + Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DllOutput"); start = DateTime.Now; - Logger.Verbose("Building and writing managed PE files to disk...", "DummyDllOutput"); + Logger.Verbose("Building and writing managed PE files to disk...", "DllOutput"); //Save them var fileBuilder = new ManagedPEFileBuilder(); @@ -55,7 +51,7 @@ public override void DoOutput(ApplicationAnalysisContext context, string outputR fileBuilder.CreateFile(image).Write(dllPath); } - Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DummyDllOutput"); + Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DllOutput"); } public List BuildAssemblies(ApplicationAnalysisContext context) @@ -72,46 +68,76 @@ public List BuildAssemblies(ApplicationAnalysisContext conte //Build the stub assemblies var start = DateTime.Now; #if VERBOSE_LOGGING - Logger.Verbose($"Building stub assemblies ({asmCount} assemblies, {typeCount} types)...", "DummyDllOutput"); + Logger.Verbose($"Building stub assemblies ({asmCount} assemblies, {typeCount} types)...", "DllOutput"); #else - Logger.Verbose($"Building stub assemblies...", "DummyDllOutput"); + Logger.Verbose($"Building stub assemblies...", "DllOutput"); #endif List ret = BuildStubAssemblies(context); - Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DummyDllOutput"); + Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DllOutput"); start = DateTime.Now; - Logger.Verbose("Configuring inheritance and generics...", "DummyDllOutput"); + Logger.Verbose("Configuring inheritance and generics...", "DllOutput"); Parallel.ForEach(context.Assemblies, AsmResolverAssemblyPopulator.ConfigureHierarchy); - Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DummyDllOutput"); + Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DllOutput"); //Populate them start = DateTime.Now; #if VERBOSE_LOGGING - Logger.Verbose($"Adding {fieldCount} fields, {methodCount} methods, {propertyCount} properties, and {eventCount} events (in parallel)...", "DummyDllOutput"); + Logger.Verbose($"Adding {fieldCount} fields, {methodCount} methods, {propertyCount} properties, and {eventCount} events (in parallel)...", "DllOutput"); #else - Logger.Verbose($"Adding fields, methods, properties, and events (in parallel)...", "DummyDllOutput"); + Logger.Verbose($"Adding fields, methods, properties, and events (in parallel)...", "DllOutput"); #endif MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverAssemblyPopulator.CopyDataFromIl2CppToManaged); - MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverMethodFiller.FillManagedMethodBodies); + MiscUtils.ExecuteParallel(context.Assemblies, FillMethodBodies); - Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DummyDllOutput"); + Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DllOutput"); //Populate custom attributes start = DateTime.Now; - Logger.Verbose("Adding custom attributes to all of the above...", "DummyDllOutput"); + Logger.Verbose("Adding custom attributes to all of the above...", "DllOutput"); MiscUtils.ExecuteParallel(context.Assemblies, AsmResolverAssemblyPopulator.PopulateCustomAttributes); - Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DummyDllOutput"); + Logger.VerboseNewline($"{(DateTime.Now - start).TotalMilliseconds:F1}ms", "DllOutput"); TypeDefinitionsAsmResolver.Reset(); return ret; } + protected abstract void FillMethodBody(MethodDefinition methodDefinition, MethodAnalysisContext methodContext); + + protected virtual void FillMethodBodies(AssemblyAnalysisContext context) + { + foreach (var typeContext in context.Types) + { + if (AsmResolverAssemblyPopulator.IsTypeContextModule(typeContext)) + continue; + +#if !DEBUG + try +#endif + { + foreach (var methodCtx in typeContext.Methods) + { + var managedMethod = methodCtx.GetExtraData("AsmResolverMethod") ?? throw new($"AsmResolver method not found in method analysis context for {typeContext.Definition?.FullName}.{methodCtx.Definition?.Name}"); + + FillMethodBody(managedMethod, methodCtx); + } + } +#if !DEBUG + catch (System.Exception e) + { + var managedType = typeContext.GetExtraData("AsmResolverType") ?? throw new($"AsmResolver type not found in type analysis context for {typeContext.Definition?.FullName}"); + throw new($"Failed to process type {managedType.FullName} (module {managedType.Module?.Name}, declaring type {managedType.DeclaringType?.FullName}) in {asmContext.Definition.AssemblyName.Name}", e); + } +#endif + } + } + private List BuildStubAssemblies(ApplicationAnalysisContext context) { var assemblyResolver = new Il2CppAssemblyResolver(); diff --git a/Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs b/Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs deleted file mode 100644 index 0f832abc..00000000 --- a/Cpp2IL.Core/Utils/AsmResolver/AsmResolverMethodFiller.cs +++ /dev/null @@ -1,36 +0,0 @@ -using AsmResolver.DotNet; -using AssetRipper.CIL; -using Cpp2IL.Core.Model.Contexts; - -namespace Cpp2IL.Core.Utils.AsmResolver; - -internal static class AsmResolverMethodFiller -{ - public static void FillManagedMethodBodies(AssemblyAnalysisContext asmContext) - { - foreach (var typeContext in asmContext.Types) - { - if (AsmResolverAssemblyPopulator.IsTypeContextModule(typeContext)) - continue; - -#if !DEBUG - try -#endif - { - foreach (var methodCtx in typeContext.Methods) - { - var managedMethod = methodCtx.GetExtraData("AsmResolverMethod") ?? throw new($"AsmResolver method not found in method analysis context for {typeContext.Definition?.FullName}.{methodCtx.Definition?.Name}"); - - managedMethod.FillMethodBodyWithStub(); - } - } -#if !DEBUG - catch (System.Exception e) - { - var managedType = typeContext.GetExtraData("AsmResolverType") ?? throw new($"AsmResolver type not found in type analysis context for {typeContext.Definition?.FullName}"); - throw new($"Failed to process type {managedType.FullName} (module {managedType.Module?.Name}, declaring type {managedType.DeclaringType?.FullName}) in {asmContext.Definition.AssemblyName.Name}", e); - } -#endif - } - } -}