diff --git a/build/common.props b/build/common.props index 1ea6663..da1adb2 100644 --- a/build/common.props +++ b/build/common.props @@ -3,7 +3,7 @@ - 0 + 7 13.0.0.$(GITHUB_RUN_NUMBER) 11.0 enable diff --git a/src/BUTR.CrashReport.Bannerlord.Source/CrashReportCreatorHelper.cs b/src/BUTR.CrashReport.Bannerlord.Source/CrashReportCreatorHelper.cs index eb7c21a..22b3f74 100644 --- a/src/BUTR.CrashReport.Bannerlord.Source/CrashReportCreatorHelper.cs +++ b/src/BUTR.CrashReport.Bannerlord.Source/CrashReportCreatorHelper.cs @@ -44,14 +44,11 @@ namespace BUTR.CrashReport.Bannerlord { - using global::Bannerlord.BUTR.Shared.Extensions; using global::Bannerlord.BUTR.Shared.Helpers; using global::Bannerlord.ModuleManager; - using global::BUTR.CrashReport.Extensions; using global::BUTR.CrashReport.Interfaces; using global::BUTR.CrashReport.Models; - using global::BUTR.CrashReport.Utils; using global::HarmonyLib; using global::HarmonyLib.BUTR.Extensions; @@ -59,11 +56,9 @@ namespace BUTR.CrashReport.Bannerlord using global::System; using global::System.Collections.Generic; using global::System.Diagnostics; - using global::System.Globalization; using global::System.IO; using global::System.Linq; using global::System.Reflection; - using global::System.Security.Cryptography; internal class CrashReportInfoHelper : IAssemblyUtilities, @@ -88,9 +83,13 @@ private static List GetPlugins() .Select(x => x.Substring("Bannerlord.BLSE.Features.".Length)) .Select(x => x.Substring(0, x.IndexOf('.') is var idx and not -1 ? idx : x.Length)) .Distinct() - .Select(x => $"BLSE.{x}"); + .Select(x => $"BLSE.{x}") + .ToList(); - return featurePatches.Concat(new[] { "BLSE.AssemblyResolver"}).Select(x => new LoaderPluginInfo + if (featurePatches.Count > 0) + featurePatches.Add("BLSE.AssemblyResolver"); + + return featurePatches.Select(x => new LoaderPluginInfo { Id = x, Version = null, diff --git a/src/BUTR.CrashReport.Bannerlord.Source/HarmonyProvider.cs b/src/BUTR.CrashReport.Bannerlord.Source/HarmonyProvider.cs index 4f68f97..708b926 100644 --- a/src/BUTR.CrashReport.Bannerlord.Source/HarmonyProvider.cs +++ b/src/BUTR.CrashReport.Bannerlord.Source/HarmonyProvider.cs @@ -44,29 +44,84 @@ namespace BUTR.CrashReport.Bannerlord { - using global::Bannerlord.BUTR.Shared.Extensions; - using global::Bannerlord.BUTR.Shared.Helpers; - using global::Bannerlord.ModuleManager; - - using global::BUTR.CrashReport.Extensions; using global::BUTR.CrashReport.Interfaces; - using global::BUTR.CrashReport.Models; - using global::BUTR.CrashReport.Utils; using global::HarmonyLib; - using global::HarmonyLib.BUTR.Extensions; using global::System; using global::System.Collections.Generic; using global::System.Diagnostics; - using global::System.Globalization; - using global::System.IO; using global::System.Linq; using global::System.Reflection; - using global::System.Security.Cryptography; + + using static global::HarmonyLib.BUTR.Extensions.AccessTools2; public class HarmonyProvider : IHarmonyProvider { + private static class MonoModUtils + { + private delegate object GetCurrentRuntimeDelegate(); + private static readonly GetCurrentRuntimeDelegate? CurrentRuntimeMethod = GetPropertyGetterDelegate( + "MonoMod.RuntimeDetour.DetourHelper:Runtime", logErrorInTrace: false); + + private delegate MethodBase GetIdentifiableOldDelegate(object instance, MethodBase method); + private static readonly GetIdentifiableOldDelegate? GetIdentifiableOldMethod = GetDelegate( + "MonoMod.RuntimeDetour.IDetourRuntimePlatform:GetIdentifiable", logErrorInTrace: false); + + private delegate IntPtr GetNativeStartDelegate(object instance, MethodBase method); + private static readonly GetNativeStartDelegate? GetNativeStartMethod = GetDelegate( + "MonoMod.RuntimeDetour.IDetourRuntimePlatform:GetNativeStart", logErrorInTrace: false); + + + private delegate object GetCurrentPlatformTripleDelegate(); + private static readonly GetCurrentPlatformTripleDelegate? CurrentPlatformTripleMethod = GetPropertyGetterDelegate( + "MonoMod.Core.Platforms.PlatformTriple:Current", logErrorInTrace: false); + + private delegate MethodBase GetIdentifiableDelegate(object instance, MethodBase method); + private static readonly GetIdentifiableDelegate? GetIdentifiableMethod = GetDelegate( + "MonoMod.Core.Platforms.PlatformTriple:GetIdentifiable", logErrorInTrace: false); + + private delegate IntPtr GetNativeMethodBodyDelegate(object instance, MethodBase method); + private static readonly GetNativeMethodBodyDelegate? GetNativeMethodBodyMethod = GetDelegate( + "MonoMod.Core.Platforms.PlatformTriple:GetNativeMethodBody", logErrorInTrace: false); + + public static MethodBase? GetIdentifiable(MethodBase method) + { + try + { + if (CurrentRuntimeMethod?.Invoke() is { } runtime) + return GetIdentifiableOldMethod?.Invoke(runtime, method); + + if (CurrentPlatformTripleMethod?.Invoke() is { } platformTriple) + return GetIdentifiableMethod?.Invoke(platformTriple, method); + } + catch (Exception e) + { + Trace.TraceError(e.ToString()); + } + + return null; + } + + public static IntPtr GetNativeMethodBody(MethodBase method) + { + try + { + if (CurrentRuntimeMethod?.Invoke() is { } runtine) + return GetNativeStartMethod?.Invoke(runtine, method) ?? IntPtr.Zero; + + if (CurrentPlatformTripleMethod?.Invoke() is { } platformTriple) + return GetNativeMethodBodyMethod?.Invoke(platformTriple, method) ?? IntPtr.Zero; + } + catch (Exception e) + { + Trace.TraceError(e.ToString()); + } + + return IntPtr.Zero; + } + } + public virtual IEnumerable GetAllPatchedMethods() => Harmony.GetAllPatchedMethods(); public virtual global::BUTR.CrashReport.Models.HarmonyPatches? GetPatchInfo(MethodBase originalMethod) @@ -118,6 +173,10 @@ public class HarmonyProvider : IHarmonyProvider return null; } } + + public MethodBase? GetIdentifiable(MethodBase method) => MonoModUtils.GetIdentifiable(method); + + public IntPtr GetNativeMethodBody(MethodBase method) => MonoModUtils.GetNativeMethodBody(method); } } diff --git a/src/BUTR.CrashReport.Bannerlord.Source/LoaderPluginInfo.cs b/src/BUTR.CrashReport.Bannerlord.Source/LoaderPluginInfo.cs index 5db9136..f616ec2 100644 --- a/src/BUTR.CrashReport.Bannerlord.Source/LoaderPluginInfo.cs +++ b/src/BUTR.CrashReport.Bannerlord.Source/LoaderPluginInfo.cs @@ -44,13 +44,8 @@ namespace BUTR.CrashReport.Bannerlord { - using global::Bannerlord.BUTR.Shared.Helpers; - using global::BUTR.CrashReport.Models; - using global::System.Collections.Generic; - using global::System.Linq; - internal class LoaderPluginInfo : ILoaderPluginInfo { /// diff --git a/src/BUTR.CrashReport.Bannerlord.Source/ModuleInfo.cs b/src/BUTR.CrashReport.Bannerlord.Source/ModuleInfo.cs index 522dbf2..1b455a8 100644 --- a/src/BUTR.CrashReport.Bannerlord.Source/ModuleInfo.cs +++ b/src/BUTR.CrashReport.Bannerlord.Source/ModuleInfo.cs @@ -45,6 +45,7 @@ namespace BUTR.CrashReport.Bannerlord { using global::Bannerlord.BUTR.Shared.Helpers; + using global::BUTR.CrashReport.Models; using global::System.Collections.Generic; diff --git a/src/BUTR.CrashReport.Decompilers/Utils/MethodDecompiler.Iced.cs b/src/BUTR.CrashReport.Decompilers/Utils/MethodDecompiler.Iced.cs index 8d1a4b1..329444e 100644 --- a/src/BUTR.CrashReport.Decompilers/Utils/MethodDecompiler.Iced.cs +++ b/src/BUTR.CrashReport.Decompilers/Utils/MethodDecompiler.Iced.cs @@ -6,12 +6,9 @@ using System.Collections.Generic; using System.Diagnostics; using System.Linq; -using System.Reflection; using System.Runtime.InteropServices; using System.Text; -using static BUTR.CrashReport.Decompilers.Utils.MonoModUtils; - using Decoder = iced::Iced.Intel.Decoder; namespace BUTR.CrashReport.Decompilers.Utils; @@ -21,13 +18,10 @@ partial class MethodDecompiler /// /// Gets the Native representation of the methods /// - public static string[] DecompileNativeCode(MethodBase? method, int nativeILOffset) + public static string[] DecompileNativeCode(IntPtr nativeCodePtr, int nativeILOffset) { - static IEnumerable GetLines(MethodBase method, int nativeILOffset) + static IEnumerable GetLines(IntPtr nativeCodePtr, int nativeILOffset) { - var nativeCodePtr = GetNativeMethodBody(method); - if (nativeCodePtr == IntPtr.Zero) yield break; - var length = (uint) nativeILOffset + 16; var bytecode = new byte[length]; @@ -43,8 +37,7 @@ static IEnumerable GetLines(MethodBase method, int nativeILOffset) { Options = { - DigitSeparator = "`", - FirstOperandCharIndex = 10 + FirstOperandCharIndex = 10, } }; @@ -52,18 +45,18 @@ static IEnumerable GetLines(MethodBase method, int nativeILOffset) { var instr = decoder.Decode(); formatter.Format(instr, output); // Don't use instr.ToString(), it allocates more, uses masm syntax and default options - sb.Append(instr.IP.ToString("X4")).Append(" ").Append(output.ToStringAndReset()); + sb.Append(instr.IP.ToString("X4")).Append(' ').Append(output.ToStringAndReset()); yield return sb.ToString(); sb.Clear(); } } - if (method is null) return Array.Empty(); + if (nativeCodePtr == IntPtr.Zero) return Array.Empty(); if (nativeILOffset == StackFrame.OFFSET_UNKNOWN) return Array.Empty(); try { - return GetLines(method, nativeILOffset).ToArray(); + return GetLines(nativeCodePtr, nativeILOffset).ToArray(); } catch (Exception e) { diff --git a/src/BUTR.CrashReport.Decompilers/Utils/MonoModUtils.cs b/src/BUTR.CrashReport.Decompilers/Utils/MonoModUtils.cs deleted file mode 100644 index 419c956..0000000 --- a/src/BUTR.CrashReport.Decompilers/Utils/MonoModUtils.cs +++ /dev/null @@ -1,82 +0,0 @@ -using System; -using System.Diagnostics; -using System.Reflection; - -using static HarmonyLib.BUTR.Extensions.AccessTools2; - -namespace BUTR.CrashReport.Decompilers.Utils; - -/// -/// Wrapper for MonoMod methods, since MonoMod.Core is not a dependency for us -/// -public static class MonoModUtils -{ - private delegate object GetCurrentRuntimeDelegate(); - private static readonly GetCurrentRuntimeDelegate? CurrentRuntimeMethod = GetPropertyGetterDelegate( - "MonoMod.RuntimeDetour.DetourHelper:Runtime", logErrorInTrace: false); - - private delegate MethodBase GetIdentifiableOldDelegate(object instance, MethodBase method); - private static readonly GetIdentifiableOldDelegate? GetIdentifiableOldMethod = GetDelegate( - "MonoMod.RuntimeDetour.IDetourRuntimePlatform:GetIdentifiable", logErrorInTrace: false); - - private delegate IntPtr GetNativeStartDelegate(object instance, MethodBase method); - private static readonly GetNativeStartDelegate? GetNativeStartMethod = GetDelegate( - "MonoMod.RuntimeDetour.IDetourRuntimePlatform:GetNativeStart", logErrorInTrace: false); - - - private delegate object GetCurrentPlatformTripleDelegate(); - private static readonly GetCurrentPlatformTripleDelegate? CurrentPlatformTripleMethod = GetPropertyGetterDelegate( - "MonoMod.Core.Platforms.PlatformTriple:Current", logErrorInTrace: false); - - private delegate MethodBase GetIdentifiableDelegate(object instance, MethodBase method); - private static readonly GetIdentifiableDelegate? GetIdentifiableMethod = GetDelegate( - "MonoMod.Core.Platforms.PlatformTriple:GetIdentifiable", logErrorInTrace: false); - - private delegate IntPtr GetNativeMethodBodyDelegate(object instance, MethodBase method); - private static readonly GetNativeMethodBodyDelegate? GetNativeMethodBodyMethod = GetDelegate( - "MonoMod.Core.Platforms.PlatformTriple:GetNativeMethodBody", logErrorInTrace: false); - - /// - /// - /// - /// - public static MethodBase? GetIdentifiable(MethodBase method) - { - try - { - if (CurrentRuntimeMethod?.Invoke() is { } runtime) - return GetIdentifiableOldMethod?.Invoke(runtime, method); - - if (CurrentPlatformTripleMethod?.Invoke() is { } platformTriple) - return GetIdentifiableMethod?.Invoke(platformTriple, method); - } - catch (Exception e) - { - Trace.TraceError(e.ToString()); - } - - return null; - } - - /// - /// - /// - /// - public static IntPtr GetNativeMethodBody(MethodBase method) - { - try - { - if (CurrentRuntimeMethod?.Invoke() is { } runtine) - return GetNativeStartMethod?.Invoke(runtine, method) ?? IntPtr.Zero; - - if (CurrentPlatformTripleMethod?.Invoke() is { } platformTriple) - return GetNativeMethodBodyMethod?.Invoke(platformTriple, method) ?? IntPtr.Zero; - } - catch (Exception e) - { - Trace.TraceError(e.ToString()); - } - - return IntPtr.Zero; - } -} \ No newline at end of file diff --git a/src/BUTR.CrashReport.Models/EnhancedStacktraceFrameModel.cs b/src/BUTR.CrashReport.Models/EnhancedStacktraceFrameModel.cs index aeeb1db..1b5c425 100644 --- a/src/BUTR.CrashReport.Models/EnhancedStacktraceFrameModel.cs +++ b/src/BUTR.CrashReport.Models/EnhancedStacktraceFrameModel.cs @@ -36,7 +36,7 @@ public sealed record EnhancedStacktraceFrameModel public required MethodExecuting ExecutingMethod { get; set; } /// - /// The original method that might be patched. + /// The original method that is being patched. Is null when no patches exists. Use instead. /// public required MethodSimple? OriginalMethod { get; set; } diff --git a/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.Html.cs b/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.Html.cs index d6e02df..bf66c71 100644 --- a/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.Html.cs +++ b/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.Html.cs @@ -80,6 +80,9 @@ private static string GetBase(CrashReportModel crashReport, IEnumerable + + + @@ -127,7 +130,9 @@ Most likely this error was caused by a custom installed module. {{Container("enhanced-stacktrace", "Enhanced Stacktrace", GetEnhancedStacktraceHtml(crashReport))}} {{Container("involved", "Involved Modules and Plugins", GetInvolvedHtml(crashReport))}} {{Container("installed-modules", "Installed Modules", GetInstalledModulesHtml(crashReport))}} -{{Container("installed-plugins", $"Loaded {crashReport.Metadata.LoaderPluginProviderName} Plugins", GetLoadedBLSEPluginsHtml(crashReport))}} +{{(crashReport.Metadata.LoaderPluginProviderName is not null + ? Container("installed-plugins", $"Loaded {crashReport.Metadata.LoaderPluginProviderName} Plugins", GetLoadedBLSEPluginsHtml(crashReport)) + : string.Empty)}} {{Container("assemblies", "Assemblies", $""" @@ -152,6 +157,8 @@ Most likely this error was caused by a custom installed module. + + {{Scripts}} @@ -306,13 +313,11 @@ private static string Container(string id, string name, string content, bool hid """; - private static string ContainerCode(string id, string name, string content, bool hide = false) => $""" + private static string ContainerCode(string id, string name, string content, string language, bool hide = false) => $"""
+ {name}
"""; diff --git a/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.cs b/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.cs index 5f8f43e..53bfa8d 100644 --- a/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.cs +++ b/src/BUTR.CrashReport.Renderer.Html/CrashReportHtml.cs @@ -147,13 +147,13 @@ private static string GetEnhancedStacktraceHtml(CrashReportModel crashReport) .Append("Approximate IL Offset: ").Append(stacktrace.ILOffset is not null ? $"{stacktrace.ILOffset:X4}" : "UNKNOWN").Append("
") .Append("Native Offset: ").Append(stacktrace.NativeOffset is not null ? $"{stacktrace.NativeOffset:X4}" : "UNKNOWN").Append("
") .AppendIf(stacktrace.ExecutingMethod.ILInstructions.Count > 0, sp => sp - .Append(ContainerCode($"{id1}", "IL:", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.ILInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id1}", "IL:", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.ILInstructions.Select(x => x.EscapeGenerics())), "cil"))) .AppendIf(stacktrace.ExecutingMethod.CSharpILMixedInstructions.Count > 0, sp => sp - .Append(ContainerCode($"{id2}", "IL with C#:", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.CSharpILMixedInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id2}", "IL with C#:", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.CSharpILMixedInstructions.Select(x => x.EscapeGenerics())), "cil"))) .AppendIf(stacktrace.ExecutingMethod.CSharpInstructions.Count > 0, sp => sp - .Append(ContainerCode($"{id3}", "C#:", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.CSharpInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id3}", "C#:", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.CSharpInstructions.Select(x => x.EscapeGenerics())), "csharp"))) .AppendIf(stacktrace.ExecutingMethod.NativeInstructions.Count > 0, sp => sp - .Append(ContainerCode($"{id4}", "Native:", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.NativeInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id4}", "Native (NASM):", string.Join(Environment.NewLine, stacktrace.ExecutingMethod.NativeInstructions.Select(x => x.EscapeGenerics())), "nasm"))) .Append("") .Append(""); @@ -176,11 +176,11 @@ private static string GetEnhancedStacktraceHtml(CrashReportModel crashReport) .AppendIf(pluginId != "UNKNOWN", sb => sb.Append("Plugin Id: ").Append("").Append(pluginId).Append("").Append("
")) .Append("Method: ").Append(method.MethodFullDescription.EscapeGenerics()).Append("
") .AppendIf(method.ILInstructions.Count > 0, sp => sp - .Append(ContainerCode($"{id01}", "IL:", string.Join(Environment.NewLine, method.ILInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id01}", "IL:", string.Join(Environment.NewLine, method.ILInstructions.Select(x => x.EscapeGenerics())), "cil"))) .AppendIf(method.CSharpILMixedInstructions.Count > 0, sp => sp - .Append(ContainerCode($"{id02}", "IL with C#:", string.Join(Environment.NewLine, method.CSharpILMixedInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id02}", "IL with C#:", string.Join(Environment.NewLine, method.CSharpILMixedInstructions.Select(x => x.EscapeGenerics())), "cil"))) .AppendIf(method.CSharpInstructions.Count > 0, sp => sp - .Append(ContainerCode($"{id03}", "C#:", string.Join(Environment.NewLine, method.CSharpInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id03}", "C#:", string.Join(Environment.NewLine, method.CSharpInstructions.Select(x => x.EscapeGenerics())), "csharp"))) .Append(""); } sbMain.Append(""); @@ -201,11 +201,11 @@ private static string GetEnhancedStacktraceHtml(CrashReportModel crashReport) .AppendIf(pluginId3 != "UNKNOWN", sb => sb.Append("Plugin Id: ").Append("").Append(pluginId3).Append("").Append("
")) .Append("Method: ").Append(stacktrace.OriginalMethod.MethodFullDescription.EscapeGenerics()).Append("
") .AppendIf(stacktrace.OriginalMethod.ILInstructions.Count > 0, sb => sb - .Append(ContainerCode($"{id01}", "IL:", string.Join(Environment.NewLine, stacktrace.OriginalMethod.ILInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id01}", "IL:", string.Join(Environment.NewLine, stacktrace.OriginalMethod.ILInstructions.Select(x => x.EscapeGenerics())), "cil"))) .AppendIf(stacktrace.OriginalMethod.CSharpILMixedInstructions.Count > 0, sb => sb - .Append(ContainerCode($"{id02}", "IL with C#:", string.Join(Environment.NewLine, stacktrace.OriginalMethod.CSharpILMixedInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id02}", "IL with C#:", string.Join(Environment.NewLine, stacktrace.OriginalMethod.CSharpILMixedInstructions.Select(x => x.EscapeGenerics())), "cil"))) .AppendIf(stacktrace.OriginalMethod.CSharpInstructions.Count > 0, sb => sb - .Append(ContainerCode($"{id03}", "C#:", string.Join(Environment.NewLine, stacktrace.OriginalMethod.CSharpInstructions.Select(x => x.EscapeGenerics()))))) + .Append(ContainerCode($"{id03}", "C#:", string.Join(Environment.NewLine, stacktrace.OriginalMethod.CSharpInstructions.Select(x => x.EscapeGenerics())), "csharp"))) .Append("") .Append(""); } diff --git a/src/BUTR.CrashReport/Interfaces/IHarmonyProvider.cs b/src/BUTR.CrashReport/Interfaces/IHarmonyProvider.cs index a2d5a27..57dc07e 100644 --- a/src/BUTR.CrashReport/Interfaces/IHarmonyProvider.cs +++ b/src/BUTR.CrashReport/Interfaces/IHarmonyProvider.cs @@ -1,4 +1,5 @@ -using BUTR.CrashReport.Models; +using System; +using BUTR.CrashReport.Models; using System.Collections.Generic; using System.Diagnostics; @@ -32,4 +33,14 @@ public interface IHarmonyProvider /// Returns the method from a stackframe. /// MethodBase? GetMethodFromStackframe(StackFrame frame); + + /// + /// The runtime can return several different MethodInfo's that point to the same method. Will return the correct one. + /// + MethodBase? GetIdentifiable(MethodBase method); + + /// + /// Returns the JIT compiled (native) start address of a method. + /// + IntPtr GetNativeMethodBody(MethodBase method); } \ No newline at end of file diff --git a/src/BUTR.CrashReport/Utils/CrashReportUtils.cs b/src/BUTR.CrashReport/Utils/CrashReportUtils.cs index 662325b..8df2f1c 100644 --- a/src/BUTR.CrashReport/Utils/CrashReportUtils.cs +++ b/src/BUTR.CrashReport/Utils/CrashReportUtils.cs @@ -10,7 +10,6 @@ using System.Reflection; using static BUTR.CrashReport.Decompilers.Utils.MethodDecompiler; -using static BUTR.CrashReport.Decompilers.Utils.MonoModUtils; using HarmonyPatch = BUTR.CrashReport.Models.HarmonyPatch; @@ -29,12 +28,12 @@ public record StackframePatchData /// /// /// - public required MethodBase? Original { get; set; } + public required MethodBase? OriginalMethod { get; set; } /// /// /// - public required MethodInfo? Replacement { get; set; } + public required MethodInfo? ExecutingMethod { get; set; } /// /// @@ -51,8 +50,8 @@ public record StackframePatchData /// public void Deconstruct(out MethodBase? original, out MethodInfo? replacement, out List patches, out bool issues) { - original = Original; - replacement = Replacement; + original = OriginalMethod; + replacement = ExecutingMethod; patches = Patches; issues = Issues; } @@ -175,17 +174,17 @@ public void Deconstruct(out MethodBase? original, out MethodInfo? replacement, o /// public static StackframePatchData GetHarmonyData(StackFrame frame, IHarmonyProvider harmonyProvider, IModuleProvider moduleProvider, ILoaderPluginProvider loaderPluginProvider) { - MethodBase? method; + MethodBase? executingMethod; var methodFromStackframeIssue = false; try { - method = harmonyProvider.GetMethodFromStackframe(frame); + executingMethod = harmonyProvider.GetMethodFromStackframe(frame); } // NullReferenceException means the method was not found. Harmony doesn't handle this case gracefully catch (NullReferenceException e) { Trace.TraceError(e.ToString()); - method = frame.GetMethod()!; + executingMethod = frame.GetMethod()!; } // The given generic instantiation was invalid. // From what I understand, this will occur with generic methods @@ -194,17 +193,17 @@ public static StackframePatchData GetHarmonyData(StackFrame frame, IHarmonyProvi { Trace.TraceError(e.ToString()); methodFromStackframeIssue = true; - method = frame.GetMethod()!; + executingMethod = frame.GetMethod()!; } - var methods = new List(); - var identifiableMethod = method is MethodInfo mi ? GetIdentifiable(mi) is MethodInfo v ? v : mi : null; - var original = identifiableMethod is not null ? harmonyProvider.GetOriginalMethod(identifiableMethod) : null; - var patches = original is not null ? harmonyProvider.GetPatchInfo(original) : null; + var patches = new List(); + var executingIdentifiableMethod = executingMethod is MethodInfo mi ? harmonyProvider.GetIdentifiable(mi) as MethodInfo ?? mi : null; + var originalIdentifiableMethod = executingIdentifiableMethod is not null ? harmonyProvider.GetOriginalMethod(executingIdentifiableMethod) : null; + var harmonyPatches = originalIdentifiableMethod is not null ? harmonyProvider.GetPatchInfo(originalIdentifiableMethod) : null; - foreach (var (patch, moduleInfo, loaderPluginInfo) in GetHarmonyPatchMethods(patches, moduleProvider, loaderPluginProvider)) + foreach (var (patch, moduleInfo, loaderPluginInfo) in GetHarmonyPatchMethods(harmonyPatches, moduleProvider, loaderPluginProvider)) { - methods.Add(new MethodEntryHarmony + patches.Add(new MethodEntryHarmony { Patch = patch, Method = patch.PatchMethod, @@ -218,9 +217,9 @@ public static StackframePatchData GetHarmonyData(StackFrame frame, IHarmonyProvi return new() { - Original = original, - Replacement = identifiableMethod, - Patches = methods, + OriginalMethod = originalIdentifiableMethod, + ExecutingMethod = executingIdentifiableMethod, + Patches = patches, Issues = methodFromStackframeIssue, }; } @@ -242,32 +241,33 @@ public static IEnumerable GetAllInvolvedModules(Exception ex, I { if (!frame.HasMethod()) continue; - var (original, identifiableMethod, patches, methodFromStackframeIssue) = GetHarmonyData(frame, harmonyProvider, moduleProvider, loaderPluginProvider); + var (originalMethod, executingMethod, patches, methodFromStackframeIssue) = GetHarmonyData(frame, harmonyProvider, moduleProvider, loaderPluginProvider); var ilOffset = frame.GetILOffset(); var nativeILOffset = frame.GetNativeOffset(); + var nativeCodePtr = executingMethod is not null ? harmonyProvider.GetNativeMethodBody(executingMethod) : IntPtr.Zero; yield return new() { - Method = identifiableMethod!, - OriginalMethod = original is not null ? new() + Method = executingMethod!, + OriginalMethod = originalMethod is not null && originalMethod != executingMethod ? new() { - Method = original, - ModuleInfo = GetModuleInfoIfMod(original, assemblies, moduleProvider), - LoaderPluginInfo = GetLoaderPluginIfMod(original, assemblies, loaderPluginProvider), - ILInstructions = DecompileILCode(original), - CSharpILMixedInstructions = DecompileILWithCSharpCode(original), - CSharpInstructions = DecompileCSharpCode(original), + Method = originalMethod, + ModuleInfo = GetModuleInfoIfMod(originalMethod, assemblies, moduleProvider), + LoaderPluginInfo = GetLoaderPluginIfMod(originalMethod, assemblies, loaderPluginProvider), + ILInstructions = DecompileILCode(originalMethod), + CSharpILMixedInstructions = DecompileILWithCSharpCode(originalMethod), + CSharpInstructions = DecompileCSharpCode(originalMethod), } : null, MethodFromStackframeIssue = methodFromStackframeIssue, - ModuleInfo = GetModuleInfoIfMod(identifiableMethod, assemblies, moduleProvider), - LoaderPluginInfo = GetLoaderPluginIfMod(identifiableMethod, assemblies, loaderPluginProvider), + ModuleInfo = GetModuleInfoIfMod(executingMethod, assemblies, moduleProvider), + LoaderPluginInfo = GetLoaderPluginIfMod(executingMethod, assemblies, loaderPluginProvider), ILOffset = ilOffset != StackFrame.OFFSET_UNKNOWN ? ilOffset : null, NativeOffset = nativeILOffset != StackFrame.OFFSET_UNKNOWN ? nativeILOffset : null, StackFrameDescription = frame.ToString(), - NativeInstructions = DecompileNativeCode(identifiableMethod, nativeILOffset), - ILInstructions = DecompileILCode(identifiableMethod), - CSharpILMixedInstructions = DecompileILWithCSharpCode(identifiableMethod), - CSharpInstructions = DecompileCSharpCode(identifiableMethod), + NativeInstructions = DecompileNativeCode(nativeCodePtr, nativeILOffset), + ILInstructions = DecompileILCode(executingMethod), + CSharpILMixedInstructions = DecompileILWithCSharpCode(executingMethod), + CSharpInstructions = DecompileCSharpCode(executingMethod), PatchMethods = patches.ToArray(), }; }