Search code examples
c++.netclr-profiling-api

.NET Profiler enter/leave function hooks does not get called in case of exception


I am building a .Net Profiler for some custom requirement.

I want to hook at Enter and Leave for some specific methods. To achieve this, I have tried below two approaches.

  1. IL Rewrite - I am able to inject the custom code at both the places. It is successfully getting injected and calling the custom code. I am also able to get the input arguments, 'this' and return value. Injecting at the Enter is not much difficult. However, it's complex to inject at Leave as there could be return at multiple places in a method. I have to inject the code at every place where return statement is written.

    It's bit complex but somewhat doable. But, if there any exception, the execution is not reaching to return statement and hence my injected code is not getting invoked.

  2. Subscribe to Enter/Leave through SetEnterLeaveFunctionHooks2 in ICorProfilerInfo2 as per the sample code given here.

In both the cases, hook at the Leave is not getting invoked in case of exception in the method.

How to handle this? I want a return value in all the scenarios. In case of an exception, I should know there is an exception; I will consider as 'No return value'. Probably, I may need exception details as well.

Below is a sample method. I want to hook at Enter and Leave for GetString method. It has multiple returns. I am able to capture the return value in a normal scenario. But in case of exception, execution stops immediately and due to that the hook at return is not getting invoked.

    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";
    }

Solution

  • To get the exception notification when using IL re-writing, you need to inject a try-finally or try-catch-throw. Since the ret instruction is not valid within a try block, you will need to replace them with a leave instruction that branches to an instruction after the inserted exception handler and return from there.

    Another option is to include COR_PRF_MONITOR_EXCEPTIONS in your call to SetEventMask and listen on the ExceptionUnwindFunctionEnter and ExceptionUnwindFunctionLeave callbacks. These callbacks don't include the thrown exception however. You could track the exception from ExceptionThrown, but this may be misleading when an exception leaves a filter block as the runtime will treat it as returning false and continue with the previous exception, but IIRC, there is no callback to indicate when this happens.