Skip to content

Commit

Permalink
v2.3 optimizes stacktrace handling even for other mods
Browse files Browse the repository at this point in the history
  • Loading branch information
pardeike committed Mar 29, 2024
1 parent 4a84b49 commit 1222b87
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 44 deletions.
2 changes: 1 addition & 1 deletion About/About.xml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<name>Harmony</name>
<author>Andreas Pardeike</author>
<packageId>brrainz.harmony</packageId>
<modVersion>2.2.0.0</modVersion>
<modVersion>2.3.0.0</modVersion>
<url>https://github.com/pardeike/HarmonyRimWorld</url>
<supportedVersions>
<li>1.2</li>
Expand Down
2 changes: 1 addition & 1 deletion About/Manifest.xml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Manifest>
<identifier>net.pardeike.rimworld.mod.harmony</identifier>
<version>2.2.0.0</version>
<version>2.3.0.0</version>
<targetVersions>
<li>1.2.0</li>
<li>1.3.0</li>
Expand Down
Binary file modified Current/Assemblies/HarmonyMod.dll
Binary file not shown.
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<ModName>HarmonyMod</ModName>
<ModFileName>HarmonyMod</ModFileName>
<Repository>https://github.com/pardeike/HarmonyRimworld</Repository>
<ModVersion>2.2.0.0</ModVersion>
<ModVersion>2.3.0.0</ModVersion>
<ProjectGuid>{C0C9BB35-9100-47A8-886E-32932EF301ED}</ProjectGuid>
</PropertyGroup>

Expand Down
79 changes: 39 additions & 40 deletions Source/ExceptionAnalyser.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,64 +9,63 @@

namespace HarmonyMod
{
static class ExceptionTools
public static class ExceptionTools
{
static readonly AccessTools.FieldRef<StackTrace, StackTrace[]> captured_traces_ref = AccessTools.FieldRefAccess<StackTrace, StackTrace[]>("captured_traces");
static readonly AccessTools.FieldRef<StackFrame, string> internalMethodName_ref = AccessTools.FieldRefAccess<StackFrame, string>("internalMethodName");
static readonly AccessTools.FieldRef<StackFrame, long> methodAddress_ref = AccessTools.FieldRefAccess<StackFrame, long>("methodAddress");
public static readonly AccessTools.FieldRef<StackTrace, StackTrace[]> captured_traces = AccessTools.FieldRefAccess<StackTrace, StackTrace[]>("captured_traces");
public static readonly AccessTools.FieldRef<StackFrame, string> internalMethodName = AccessTools.FieldRefAccess<StackFrame, string>("internalMethodName");
public static readonly AccessTools.FieldRef<StackFrame, long> methodAddress = AccessTools.FieldRefAccess<StackFrame, long>("methodAddress");

delegate void GetFullNameForStackTrace(StackTrace instance, StringBuilder sb, MethodBase mi);
static readonly MethodInfo m_GetFullNameForStackTrace = AccessTools.Method(typeof(StackTrace), "GetFullNameForStackTrace");
static readonly GetFullNameForStackTrace getFullNameForStackTrace = AccessTools.MethodDelegate<GetFullNameForStackTrace>(m_GetFullNameForStackTrace);
public delegate void GetFullNameForStackTraceDelegate(StackTrace instance, StringBuilder sb, MethodBase mi);
private static readonly MethodInfo m_GetFullNameForStackTrace = AccessTools.Method(typeof(StackTrace), "GetFullNameForStackTrace");
public static readonly GetFullNameForStackTraceDelegate GetFullNameForStackTrace = AccessTools.MethodDelegate<GetFullNameForStackTraceDelegate>(m_GetFullNameForStackTrace);

delegate uint GetMethodIndex(StackFrame instance);
static readonly MethodInfo m_GetMethodIndex = AccessTools.Method(typeof(StackFrame), "GetMethodIndex");
static readonly GetMethodIndex getMethodIndex = AccessTools.MethodDelegate<GetMethodIndex>(m_GetMethodIndex);
public delegate uint GetMethodIndexDelegate(StackFrame instance);
private static readonly MethodInfo m_GetMethodIndex = AccessTools.Method(typeof(StackFrame), "GetMethodIndex");
public static readonly GetMethodIndexDelegate GetMethodIndex = AccessTools.MethodDelegate<GetMethodIndexDelegate>(m_GetMethodIndex);

delegate string GetSecureFileName(StackFrame instance);
static readonly MethodInfo m_GetSecureFileName = AccessTools.Method(typeof(StackFrame), "GetSecureFileName");
static readonly GetSecureFileName getSecureFileName = AccessTools.MethodDelegate<GetSecureFileName>(m_GetSecureFileName);
public delegate string GetSecureFileNameDelegate(StackFrame instance);
private static readonly MethodInfo m_GetSecureFileName = AccessTools.Method(typeof(StackFrame), "GetSecureFileName");
public static readonly GetSecureFileNameDelegate GetSecureFileName = AccessTools.MethodDelegate<GetSecureFileNameDelegate>(m_GetSecureFileName);

delegate string GetAotId();
static readonly MethodInfo m_GetAotId = AccessTools.Method(typeof(StackTrace), "GetAotId");
static readonly GetAotId getAotId = AccessTools.MethodDelegate<GetAotId>(m_GetAotId);
public delegate string GetAotIdDelegate();
private static readonly MethodInfo m_GetAotId = AccessTools.Method(typeof(StackTrace), "GetAotId");
public static readonly GetAotIdDelegate GetAotId = AccessTools.MethodDelegate<GetAotIdDelegate>(m_GetAotId);

public static readonly ConcurrentBag<int> seenStacktraces = [];
public static readonly ConcurrentDictionary<int, int> seenStacktraces = [];

public static string ExtractHarmonyEnhancedStackTrace()
{
try
{
return ExtractHarmonyEnhancedStackTrace(new StackTrace(3, true));
return ExtractHarmonyEnhancedStackTrace(new StackTrace(3, true), false, out _);
}
catch (System.Exception)
{
return StackTraceUtility.ExtractStackTrace();
}
}

public static string ExtractHarmonyEnhancedStackTrace(StackTrace trace)
public static string ExtractHarmonyEnhancedStackTrace(StackTrace trace, bool forceRefresh, out int hash)
{
var sb = new StringBuilder();
if (captured_traces_ref(trace) != null)
{
var traces = captured_traces_ref(trace);
var traces = captured_traces(trace);
if (traces != null)
for (int i = 0; i < traces.Length; i++)
{
if (sb.AddHarmonyFrames(traces[i]))
_ = sb.Append("\n--- End of stack trace from previous location where exception was thrown ---\n");
}
}
_ = sb.AddHarmonyFrames(trace);
var stacktrace = sb.ToString();
var hash = stacktrace.GetHashCode();
if (seenStacktraces.Contains(hash))
return $"[Ref {hash:X}] Duplicate stacktrace, see ref for original";
seenStacktraces.Add(hash);
return $"[Ref {hash:X}]\n{stacktrace}";
hash = stacktrace.GetHashCode();
var hashRef = $"[Ref {hash:X}]";
if (forceRefresh)
return $"{hashRef}\n{stacktrace}";
var count = seenStacktraces.AddOrUpdate(hash, 1, (k, v) => v + 1);
if (count > 1)
return $"{hashRef} Duplicate stacktrace, see ref for original";
return $"{hashRef}\n{stacktrace}";
}

static bool AddHarmonyFrames(this StringBuilder sb, StackTrace trace)
public static bool AddHarmonyFrames(this StringBuilder sb, StackTrace trace)
{
if (trace.FrameCount == 0)
return false;
Expand All @@ -81,29 +80,29 @@ static bool AddHarmonyFrames(this StringBuilder sb, StackTrace trace)
var method = Harmony.GetOriginalMethodFromStackframe(frame);
if (method == null)
{
var internalMethodName = internalMethodName_ref(frame);
var internalMethodName = ExceptionTools.internalMethodName(frame);
if (internalMethodName != null)
_ = sb.Append(internalMethodName);
else
_ = sb.AppendFormat("<0x{0:x5} + 0x{1:x5}> <unknown method>", methodAddress_ref(frame), frame.GetNativeOffset());
_ = sb.AppendFormat("<0x{0:x5} + 0x{1:x5}> <unknown method>", methodAddress(frame), frame.GetNativeOffset());
}
else
{
getFullNameForStackTrace(trace, sb, method);
GetFullNameForStackTrace(trace, sb, method);
if (frame.GetILOffset() == -1)
{
_ = sb.AppendFormat(" <0x{0:x5} + 0x{1:x5}>", methodAddress_ref(frame), frame.GetNativeOffset());
if (getMethodIndex(frame) != 16777215U)
_ = sb.AppendFormat(" {0}", getMethodIndex(frame));
_ = sb.AppendFormat(" <0x{0:x5} + 0x{1:x5}>", methodAddress(frame), frame.GetNativeOffset());
if (GetMethodIndex(frame) != 16777215U)
_ = sb.AppendFormat(" {0}", GetMethodIndex(frame));
}
else
_ = sb.AppendFormat(" [0x{0:x5}]", frame.GetILOffset());

var fileName = getSecureFileName(frame);
var fileName = GetSecureFileName(frame);
if (fileName[0] == '<')
{
var versionId = method.Module.ModuleVersionId.ToString("N");
var aotId = getAotId();
var aotId = GetAotId();
if (frame.GetILOffset() != -1 || aotId == null)
fileName = string.Format("<{0}>", versionId);
else
Expand All @@ -124,7 +123,7 @@ static bool AddHarmonyFrames(this StringBuilder sb, StackTrace trace)
return true;
}

static void AppendPatch(this StringBuilder sb, MethodBase method, IEnumerable<Patch> fixes, string name)
public static void AppendPatch(this StringBuilder sb, MethodBase method, IEnumerable<Patch> fixes, string name)
{
foreach (var patch in PatchProcessor.GetSortedPatchMethods(method, fixes.ToArray()))
{
Expand Down
2 changes: 1 addition & 1 deletion Source/Main.cs
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public static bool Prefix(Exception e, bool needFileInfo, ref string __result)
try
{
var stackTrace = e == null ? new StackTrace(needFileInfo) : new StackTrace(e, needFileInfo);
__result = ExceptionTools.ExtractHarmonyEnhancedStackTrace(stackTrace);
__result = ExceptionTools.ExtractHarmonyEnhancedStackTrace(stackTrace, false, out _);
return false;
}
catch (Exception)
Expand Down

0 comments on commit 1222b87

Please sign in to comment.