diff --git a/Cpp2IL.Core/Cpp2IlRuntimeArgs.cs b/Cpp2IL.Core/Cpp2IlRuntimeArgs.cs index e1c336ef..dba49879 100644 --- a/Cpp2IL.Core/Cpp2IlRuntimeArgs.cs +++ b/Cpp2IL.Core/Cpp2IlRuntimeArgs.cs @@ -19,7 +19,7 @@ public class Cpp2IlRuntimeArgs public List ProcessingLayersToRun = []; public readonly Dictionary ProcessingLayerConfigurationOptions = new(); - public Cpp2IlOutputFormat? OutputFormat; + public IEnumerable? OutputFormats; public string OutputRootDirectory = null!; public bool LowMemoryMode; diff --git a/Cpp2IL/CommandLineArgs.cs b/Cpp2IL/CommandLineArgs.cs index bd3f8e80..b2f4cb6e 100644 --- a/Cpp2IL/CommandLineArgs.cs +++ b/Cpp2IL/CommandLineArgs.cs @@ -43,9 +43,8 @@ public class CommandLineArgs [Option("list-output-formats", HelpText = "List the available output formats and exit.")] public bool ListOutputFormats { get; set; } - //FUTURE: Allow multiple of these? [Option("output-as", HelpText = "Specify the ID of the output format you wish to use.")] - public string? OutputFormatId { get; set; } + public IEnumerable OutputFormatIds { get; set; } = new List(); [Option("output-to", HelpText = "Root directory to output to. Defaults to cpp2il_out in the current working directory.")] public string OutputRootDir { get; set; } = Path.GetFullPath("cpp2il_out"); diff --git a/Cpp2IL/Program.cs b/Cpp2IL/Program.cs index 97396db8..2c6eff40 100644 --- a/Cpp2IL/Program.cs +++ b/Cpp2IL/Program.cs @@ -483,7 +483,12 @@ private static void HandleIpa(string gamePath, ref Cpp2IlRuntimeArgs args) #endif private static Cpp2IlRuntimeArgs GetRuntimeOptionsFromCommandLine(string[] commandLine) { - var parserResult = Parser.Default.ParseArguments(commandLine); + var parserResult = new Parser(settings => + { + settings.AllowMultiInstance = true; + settings.HelpWriter = Console.Out; + }) + .ParseArguments(commandLine); if (parserResult is NotParsed notParsed && notParsed.Errors.Count() == 1 && notParsed.Errors.All(e => e.Tag is ErrorType.VersionRequestedError or ErrorType.HelpRequestedError)) //Version or help requested @@ -530,7 +535,7 @@ private static Cpp2IlRuntimeArgs GetRuntimeOptionsFromCommandLine(string[] comma if (options.GamePath != null && options.GamePath.StartsWith("~")) options.GamePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + options.GamePath[1..]; #endif - + ResolvePathsFromCommandLine(options.GamePath, options.ExeName, ref result); } else @@ -555,12 +560,12 @@ private static Cpp2IlRuntimeArgs GetRuntimeOptionsFromCommandLine(string[] comma // if(string.IsNullOrEmpty(options.OutputFormatId)) // throw new SoftException("No output format specified, so nothing to do!"); - if (!string.IsNullOrEmpty(options.OutputFormatId)) + if (options.OutputFormatIds.Any() == true) { try { - result.OutputFormat = OutputFormatRegistry.GetFormat(options.OutputFormatId!); - Logger.VerboseNewline($"Selected output format: {result.OutputFormat.OutputFormatName}"); + result.OutputFormats = options.OutputFormatIds.Select(OutputFormatRegistry.GetFormat).ToList(); + Logger.VerboseNewline($"Selected output formats: [{string.Join(", ", options.OutputFormatIds)}]"); } catch (Exception e) { @@ -647,7 +652,13 @@ public static int MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs) var executionStart = DateTime.Now; - runtimeArgs.OutputFormat?.OnOutputFormatSelected(); + if (runtimeArgs.OutputFormats != null) + { + foreach (Cpp2IlOutputFormat format in runtimeArgs.OutputFormats) + { + format.OnOutputFormatSelected(); + } + } GCSettings.LatencyMode = runtimeArgs.LowMemoryMode ? GCLatencyMode.Interactive : GCLatencyMode.SustainedLowLatency; @@ -687,14 +698,16 @@ public static int MainWithArgs(Cpp2IlRuntimeArgs runtimeArgs) var outputStart = DateTime.Now; - if (runtimeArgs.OutputFormat != null) + if (runtimeArgs.OutputFormats != null) { - if (runtimeArgs.LowMemoryMode) - GC.Collect(); - - Logger.InfoNewline($"Outputting as {runtimeArgs.OutputFormat.OutputFormatName} to {runtimeArgs.OutputRootDirectory}..."); - runtimeArgs.OutputFormat.DoOutput(Cpp2IlApi.CurrentAppContext, runtimeArgs.OutputRootDirectory); - Logger.InfoNewline($"Finished outputting in {(DateTime.Now - outputStart).TotalMilliseconds}ms"); + foreach (Cpp2IlOutputFormat format in runtimeArgs.OutputFormats) + { + if (runtimeArgs.LowMemoryMode) + GC.Collect(); + Logger.InfoNewline($"Outputting as {format.OutputFormatName} to {runtimeArgs.OutputRootDirectory}..."); + format.DoOutput(Cpp2IlApi.CurrentAppContext, runtimeArgs.OutputRootDirectory); + Logger.InfoNewline($"Finished outputting in {(DateTime.Now - outputStart).TotalMilliseconds}ms"); + } } else { diff --git a/LibCpp2IL/BinarySearcher.cs b/LibCpp2IL/BinarySearcher.cs index bd3998f3..f01e451d 100644 --- a/LibCpp2IL/BinarySearcher.cs +++ b/LibCpp2IL/BinarySearcher.cs @@ -169,34 +169,58 @@ internal ulong FindCodeRegistrationPost2019(Il2CppMetadata metadata) pSomewhereInCodegenModules = pSomewhereInCodegenModules.Select(va => va - ptrSize * (ulong)initialBacktrack); //Slightly experimental, but we're gonna try backtracking most of the way through the number of modules. Not all the way because we don't want to overshoot. - int backtrack; - for (backtrack = initialBacktrack; backtrack < sanityCheckNumberOfModules && (pCodegenModules?.Count() ?? 0) != 1; backtrack++) - { - pCodegenModules = FindAllMappedWords(pSomewhereInCodegenModules).ToList(); - //Sanity check the count, which is one pointer back - if (pCodegenModules.Count == 1) + List FindCodegenModules(int initialBacktrackParam) + { + List foundModules = []; + + for (int backtrack = initialBacktrackParam; backtrack < sanityCheckNumberOfModules && foundModules.Count != 1; backtrack++) { - binary.Reader.Position = binary.MapVirtualAddressToRaw(pCodegenModules.First() - ptrSize); - var moduleCount = binary.Reader.ReadInt32(); + foundModules = FindAllMappedWords(pSomewhereInCodegenModules).ToList(); - if (moduleCount < 0 || moduleCount > sanityCheckNumberOfModules) - pCodegenModules = []; - else - LibLogger.VerboseNewline($"\t\t\tFound valid address for pCodegenModules after a backtrack of {backtrack}, module count is {LibCpp2IlMain.TheMetadata!.imageDefinitions.Length}"); + //Sanity check the count, which is one pointer back + if (foundModules.Count == 1) + { + if (foundModules.Any()) + { + binary.Reader.Position = binary.MapVirtualAddressToRaw(foundModules.First() - ptrSize); + var moduleCount = binary.Reader.ReadInt32(); + + if (moduleCount < 0 || moduleCount > sanityCheckNumberOfModules) + foundModules = []; + else + LibLogger.VerboseNewline($"\t\t\tFound valid address for pCodegenModules after a backtrack of {backtrack}/{LibCpp2IlMain.TheMetadata!.imageDefinitions.Length}: {foundModules[0]:X}"); + } + } + else if (foundModules.Count > 1) + { + LibLogger.VerboseNewline($"\t\t\tFound {foundModules.Count} potential pCodegenModules addresses after a backtrack of {backtrack}, which is too many (> 1). Will try backtracking further."); + } + pSomewhereInCodegenModules = pSomewhereInCodegenModules.Select(va => va - ptrSize); } - else if (pCodegenModules.Count > 1) + + return foundModules; + } + + var backtrackedModules = FindCodegenModules(initialBacktrack); + if (backtrackedModules.Count < 1) + { + LibLogger.WarnNewline($"Hit backtrack limit of {sanityCheckNumberOfModules} modules and still didn't find a valid pCodegenModules pointer. Switching to the fallback non-backtracked search"); + pSomewhereInCodegenModules = pMscorlibCodegenEntryInCodegenModulesList.AsEnumerable(); + var unbacktrackedModules = FindCodegenModules(0); + if (unbacktrackedModules.Count < 1) { - LibLogger.VerboseNewline($"\t\t\tFound {pCodegenModules.Count} potential pCodegenModules addresses after a backtrack of {backtrack}, which is too many (> 1). Will try backtracking further."); + LibLogger.WarnNewline("Fallback search failed to find a valid pCodegen modules pointer."); + return 0; + } + else + { + pCodegenModules = unbacktrackedModules; } - - pSomewhereInCodegenModules = pSomewhereInCodegenModules.Select(va => va - ptrSize); } - - if (backtrack == sanityCheckNumberOfModules && (pCodegenModules?.Count() ?? 0) != 1) + else { - LibLogger.WarnNewline($"Hit backtrack limit of {backtrack} modules and still didn't find a valid pCodegenModules pointer."); - return 0; + pCodegenModules = backtrackedModules; } if (pCodegenModules?.Any() != true)