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());
        }
Esempio n. 3
0
        /// <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");
            }
        }