2017-09-22 50 views
0

我正在为某些自定义需求构建.Net Profiler。.NET Profiler进入/离开函数挂钩不会在异常情况下调用

我想挂钩在输入和离开一些特定的方法。为了达到这个目的,我尝试了两种方法。

  1. IL重写 - 我能够在两个地方注入自定义代码。它已成功注入并调用自定义代码。我也能够得到输入参数'this'并返回值。在Enter处注入并不困难。然而,在Leave中注入很复杂,因为在方法中可能会有多个地方返回。我必须在写入return语句的每个地方注入代码。

    这有点复杂,但有点可行。但是,如果有任何异常,执行没有达到返回语句,因此我的注入代码没有被调用。

  2. 根据给出的样本代码here订阅Enter /通过SetEnterLeaveFunctionHooks2ICorProfilerInfo2中。

在这两种情况下,在方法中发生异常的情况下,不会调用Leave。

如何处理?我想要在所有情况下的返回值。如果有例外,我应该知道有一个例外;我会考虑为'没有回报价值'。也许,我可能也需要异常细节。

下面是一个示例方法。我想在Enter和Leave for GetString方法上挂钩。它有多个回报。我能够在正常情况下捕获返回值。但是,如果发生异常,执行立即停止,并且由于返回时的钩子没有被调用。

public int GetInt() 
    { 
     //int retVal = 10; 
     int retVal = 1010; 
     //throw new Exception("test"); 
     return retVal; 
    } 

    public string GetString() 
    { 
     var retunValue = "Return string "; 

     if (GetInt() > 100) 
     { 
      retunValue += " inside IF > 100"; 
      return retunValue; 
     } 

     return retunValue + " at last return"; 
    } 
+0

很难理解这一点。如果你打算使用profiler api来重写IL,那么你最好在代码开始执行之前这么做。换句话说,您需要JITCompilationStarted回调。如果你使用SetEnterLeaveFunctionHooks2来实现,那么死亡就会被施放,IL已经得到了解决,并且改变它不会有任何影响。有了另外一个明显的优点,那就是当你用JITCompilationStarted完成时,你不必再担心异常。 –

+0

@HansPassant,对于IL Rewrite,我在ModuleLoadFinished回调中执行,一切正常,我的代码被注入并在正常执行流程中调用。但是,如果我在GetValue方法中取消注释抛出异常语句,它不会被调用(由于显而易见的原因)。 GetValue仅仅是示例代码插图的目的,在实际场景中异常随时可以得到。 – Hitesh

回答

1

要使用IL重写时得到异常通知,您需要注入try-finally或try-catch-throw。由于ret指令在try块内无效,因此您需要用leave指令替换它们,该指令在插入的异常处理程序后分支到指令并从那里返回。

另一种选择是在您致电SetEventMask时加入COR_PRF_MONITOR_EXCEPTIONS,并听取ExceptionUnwindFunctionEnterExceptionUnwindFunctionLeave回调。这些回调不包括抛出的异常。你可能trackExceptionThrown的例外,但这可能会误导,当一个异常离开一个过滤块,因为运行时将它视为返回false并继续以前的异常,但IIRC,没有回调来表明这种情况发生时。

+0

感谢Brian回复。你能提供一些关于如何注入try/catch/finally块的帮助吗? – Hitesh

+0

对于另一种方法,我可以处理ExceptionUnwindFunctionEnter/Leave方法。但是,正如你所提到的,它没有提供例外细节。您能否提供更多信息,我如何获得例外情况? – Hitesh

+1

异常处理程序在传递给SetILFunctionBody的函数体的数据部分中指定。格式的详细信息可以在[EMCA-335](https://www.ecma-international.org/publications/standards/Ecma-335.htm)中找到。分区II第25.4节 –

相关问题