From ae18f168030a74563d74e3f3c383da3b813e2bef Mon Sep 17 00:00:00 2001 From: ghorsington Date: Sun, 24 Jul 2022 22:28:16 +0300 Subject: [PATCH] Il2Cpp: Redirect stderr on Windows to log CoreCLR crash messages On Windows, emit BepInEx/ErrorLog.log that will contain the latest stderr This allows to catch any errors CoreCLR writes before closing on a fatal crash On Unix, same is already possible via normal piping --- BepInEx.IL2CPP/Preloader.cs | 3 ++ .../RuntimeFixes/RedirectStdErrFix.cs | 49 +++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 BepInEx.IL2CPP/RuntimeFixes/RedirectStdErrFix.cs diff --git a/BepInEx.IL2CPP/Preloader.cs b/BepInEx.IL2CPP/Preloader.cs index b2e7fd0..f6f283b 100644 --- a/BepInEx.IL2CPP/Preloader.cs +++ b/BepInEx.IL2CPP/Preloader.cs @@ -1,6 +1,7 @@ using System; using System.Reflection; using System.Runtime.InteropServices; +using BepInEx.IL2CPP.RuntimeFixes; using BepInEx.Logging; using BepInEx.Preloader.Core; using BepInEx.Preloader.Core.Logging; @@ -38,6 +39,8 @@ public static class Preloader Logger.Listeners.Add(new ConsoleLogListener()); } + RedirectStdErrFix.Apply(); + ChainloaderLogHelper.PrintLogInfo(Log); Logger.Log(LogLevel.Info, $"Running under Unity {UnityInfo.Version}"); diff --git a/BepInEx.IL2CPP/RuntimeFixes/RedirectStdErrFix.cs b/BepInEx.IL2CPP/RuntimeFixes/RedirectStdErrFix.cs new file mode 100644 index 0000000..03f4f3d --- /dev/null +++ b/BepInEx.IL2CPP/RuntimeFixes/RedirectStdErrFix.cs @@ -0,0 +1,49 @@ +using System.IO; +using System.Runtime.InteropServices; +using BepInEx.Logging; +using MonoMod.Utils; + +namespace BepInEx.IL2CPP.RuntimeFixes; + +internal static class RedirectStdErrFix +{ + private const int STD_ERROR_HANDLE = -12; + private const int INVALID_HANDLE_VALUE = -1; + private const int FILE_SHARE_READ = 1; + private const int GENERIC_WRITE = 0x40000000; + private const int CREATE_ALWAYS = 2; + private const int FILE_ATTRIBUTE_NORMAL = 0x00000080; + + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern nint CreateFile(string fileName, + uint desiredAccess, + int shareMode, + nint securityAttributes, + int creationDisposition, + int flagsAndAttributes, + nint templateFile); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool SetStdHandle(int nStdHandle, nint hConsoleOutput); + + + public static void Apply() + { + if (PlatformHelper.Is(Platform.Windows)) + { + Logger.Log(LogLevel.Info, "Redirecting stderr"); + var errorFile = CreateFile(Path.Combine(Paths.BepInExRootPath, "ErrorLog.log"), GENERIC_WRITE, + FILE_SHARE_READ, + 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (errorFile == INVALID_HANDLE_VALUE) + { + Logger.Log(LogLevel.Warning, "Failed to open error log file; skipping error redirection"); + return; + } + + if (!SetStdHandle(STD_ERROR_HANDLE, errorFile)) + Logger.Log(LogLevel.Warning, "Failed to redirect stderr; skipping error redirection"); + } + // On unix, we can generally redirect stderr to a file "normally" via piping + } +}