我可以在C#中更改当前的堆栈跟踪吗?

时间:2014-08-11 13:22:38

标签: c# mono unity3d

简而言之,我需要修改C#中的当前堆栈跟踪,因此我调用的方法(我无法修改)会认为是其他人调用它。

现在,给出一个关于我为什么需要做这么可怕的黑客攻击的背景。

在Unity3d中,Debug.Log在开发者控制台中创建了一条新记录。双击它时,它会打开IDE以显示负责该记录的确切文件和行。但是,由于各种原因(在生产中禁用调试,使其在其他线程中可用)我创建了一个包装类Print,而不是使用UnityEngine.Debug。

但是使用包装器,现在当开发人员在控制台中单击日志记录时,它会被Print打开,而不是被调用Print.Log的实际位置。并且由于Debug.Log无论错误消息或上下文对象如何都这样做,我认为它使用调用堆栈来标识要打开的文件。不用说,我想解决这个问题。

2 个答案:

答案 0 :(得分:4)

我不相信这是可能的。查看Environment.StackTrace的源代码以及随后的GetStackTrace()调用,每当调用它时,我们都可以看到它creates the stacktrace。由于似乎没有什么可以注入来改变它的一些工作,我认为可以安全地得出结论,你不能改变堆栈跟踪而不修改它的调用方式。

如果您有可能这样做,您可以使用类似这样的内容来检索当前的堆栈跟踪并使用反射来更改最新的StackFrame method模仿你之后是什么的领域。

void Main()
{
    DoSomething();
}

void DoSomething(){
    Console.WriteLine (Environment.StackTrace); // Last frame: at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)

    var frames = new StackTrace().GetFrames();
    var lastframe = frames[0]; // last frame: DoSomething at offset 100 in file:line:column <filename unknown>:0:0
    var methodField = lastframe.GetType().GetField("method", BindingFlags.Instance | BindingFlags.NonPublic);
    var redirectedMethod = typeof(Redirect).GetMethod("RedirectToMethod", BindingFlags.Instance | BindingFlags.Public);
    methodField.SetValue(lastframe, redirectedMethod);
    Console.WriteLine (frames); // last frame: RedirectToMethod at offset 100 in file:line:column <filename unknown>:0:0
    Console.WriteLine (Environment.StackTrace); // last frame: at System.Environment.GetStackTrace(Exception e, Boolean needFileInfo)
}

public class Redirect {
    public void RedirectToMethod() { }
}

但又一次:这是非常脆弱的,在你目前的情况下不适用。你要做的事情是相当奇特的,应该完全避免。

至于一个实际的解决方案:我担心我没有任何Unity经验,所以我只能谷歌,但this thread可能会对你感兴趣。我在这里提到了.NET源代码,但你可以在Mono源代码中找到very similar code

答案 1 :(得分:2)

解决这个问题的方法是将Print类编译成统一兼容的Dll(我认为是.Net 2)。当双击日志时,控制台将忽略dll信息并转到Print的调用位置。