Combining Managed and Unmanaged Code in a Code Profiler
An incorrectly written profiler can cause circular references to itself, resulting in unpredictable behavior.
A review of the CLR profiling API may create the impression that you can write a profiler that contains managed and unmanaged components that call each other through COM interop or indirect calls.
Although this is possible from a design perspective, the profiling API does not support managed components. A CLR profiler must be completely unmanaged. Attempts to combine managed and unmanaged code in a CLR profiler may cause access violations, program failure, or deadlocks. The managed components of the profiler will fire events back to their unmanaged components, which would subsequently call the managed components again, resulting in circular references.
The only location where a CLR profiler can call managed code safely is in the Microsoft intermediate language (MSIL) body of a method. Before the just-in-time (JIT) compilation of a function is completed, the profiler can insert managed calls in the MSIL body of a method and then JIT-compile it (see the ICorProfilerInfo::GetILFunctionBody method). This technique can successfully be used for selective instrumentation of managed code, or to gather statistics and performance data about the JIT.
Alternatively, a code profiler can insert native hooks in the MSIL body of every managed function that calls into unmanaged code. This technique can be used for instrumentation and coverage. For example, a code profiler could insert instrumentation hooks after every MSIL block to ensure that the block has been executed. The modification of the MSIL body of a method is a very delicate operation, and there are many factors that should be taken into consideration.