private static void ChecksStackTrace() { var st = new StackTrace(1, false); var method = Harmony.GetMethodFromStackframe(st.GetFrame(0)); // Replacement will be HarmonyLibTests.Extras.RetrieveOriginalMethod.PatchTarget_Patch1 // We should be able to go from this method, back to HarmonyLibTests.Extras.PatchTarget if (method is MethodInfo replacement) { var original = Harmony.GetOriginalMethod(replacement); Assert.NotNull(original); Assert.AreEqual(original, AccessTools.Method(typeof(RetrieveOriginalMethod), nameof(RetrieveOriginalMethod.PatchTarget))); } }
public static string GetStackTraceString(StackTrace st, out List <MethodMeta> methods) { var stringBuilder = new StringBuilder(255); methods = new List <MethodMeta>(); for (int i = 0; i < st.FrameCount; i++) { var method = Harmony.GetMethodFromStackframe(st.GetFrame(i)); if (method is MethodInfo replacement) { var original = Harmony.GetOriginalMethod(replacement); if (original != null) { method = original; } } GetStringForMethod(ref stringBuilder, method); if (method != null) { var p = Harmony.GetPatchInfo(method); if (p != null && p.Owners.Count != 0) { var pString = GetPatchStrings(method, p); if (pString != null) { stringBuilder.Append(pString); } } methods.Add(new MethodMeta(method, p)); } else { methods.Add(null); } stringBuilder.Append("\n"); } return(stringBuilder.ToString()); }
/// <summary> /// If the provided method is a Harmony patched method, finds the original method /// that was patched. /// /// The returned method might not be callable, but it can be used to figure out the /// patches that were applied. /// </summary> /// <param name="patched">The potentially patched method.</param> /// <returns>The original method which was targeted by the patch.</returns> internal static MethodBase GetOriginalMethod(MethodBase patched) { MethodBase newMethod = null; if (patched == null) { throw new ArgumentNullException("patched"); } if (patched is MethodInfo info) { newMethod = Harmony.GetOriginalMethod(info); } if (newMethod == null) { newMethod = patched; } return(newMethod); }
internal static void Prefix(string id) { try { if (Utility.IsNotAnalyzerPatch(id) is false) { return; } // Can't be sure that the JIT won't inline the constructor of harmony // so we need to manually trawl until we find a method which doesn't belong // to either dpa or harmony. (this prefix, and the harmony ctor) var frames = new StackTrace(false).GetFrames(); if (frames == null) { return; } var methods = frames.Select(Harmony.GetMethodFromStackframe).Select(m => m is MethodInfo mi ? Harmony.GetOriginalMethod(mi) ?? m : m); // find the first non harmony/dpa method in the stack trace and assoc the asm // that method is from with the stack trace foreach (var method in methods) { var asm = method.DeclaringType?.Assembly ?? method.ReflectedType?.Assembly; if (asm == null) { continue; } if (asm.FullName.Contains("Harmony") || asm == dpaAssembly) { continue; } // we snipe this in another way if (method.Name == "ApplyHarmonyPatches") { return; } StackTraceUtility.RegisterHarmonyId(id, asm); return; } } catch (Exception e) // lets be exceedingly careful. { ThreadSafeLogger.ReportException(e, "Failed to capture Harmony ctor"); } }