다음을 통해 공유


DebuggerVisualizer for DynamicMethod (Show me the IL)

Have you ever tried DynamicMethod, one of the coolest features in the .NET 2.0? Hope you have; otherwise, you can try it now with the examples 1, 2.

Like emitting IL to MethodBuilder, we first get ILGenerator from a DynamicMethod, and make a series of ILGenerator.Emit calls to emit the IL instructions. If the emit sequence/logic is complicated, we are likely to wanna check the on-the-fly IL content when debugging. (In fact, class DynamicILInfo provides an alternative way to set the IL code for dynamic method.)

It is not straightforward to find out this information and show it. Those instructions are stored in a byte array, so we need an ILReader to parse it; if the ILDasm-style output is preferred, we need to resolve type/field/method back from tokens (DynamicMethod has its own token management mechanism). By the way, Yiru wrote an excellent post "Debugging LCG", where windbg + SOS were used, and !dumpil was called with the DynamicMethod's MethodDesc (which is not available until jit'ting)

What if we want to live with the nice-looking Visual Studio 2005 environment, and still be able to see what has been emitted by far while we are debugging the dynamic method? Peli (our CLR team member and also an active Emit/LCG user) proposed that DebuggerVisualizer is a good solution. If you are interested in DebuggerVisualizer in general, some references can be found at Scott's blog (or msdn: how to write a visualizer)

Introducing my DynamicMethod DebuggerVisualizer... here are some visualizer-in-action pictures:

pic1

pic2

We can launch the visualizer dialog by clicking the magnifying glass visualizer button, from the local/watch windows or any DynamicMethod variable's data tip.

pic3

This is my DynamicMethod DebuggerVisualizer dialog window. The main area shows the IL we emitted so far. "Show bytes" checkbox allows us to specify whether we want to see the raw byte data. The window size/position and other settings are saved in the registry (unfortunately).

It contains two dlls:

  1. DynamicMethodVisualizer: Just some routine debugger visualizer code here. Since DynamicMethod is not serializable, I have to prepare all necessary info in the debuggee side first, and save them into my MethodBodyInfo class. All IL instructions turn into the string format. No doubt, there are some side-effects on the the debuggee side.
  2. ILReader: I mentioned a Reflection-based ILReader implementation in my previous post. In addition we need know some DynamicMethod implementation details (you can sleuth it using Reflector or Rotor 2.0 source code in the future): the internal m_ILStream field in class DynamicILGenerateor is used to store IL instructions; another class DynamicScope is to keep track of those used tokens. In order to retrieve the byte array and to resolve those tokens to some meaningful members, reflection APIs (such as FieldInfo.GetValue, PropertyInfo.GetValue etc) are used to explore those internal fields;

LEGAL NOTE: All source code is provided as is, with no warranties intended or implied. Use at your own risk.

Also, the implementation depends on internal DynamicMethod implementation, and does not ensure continuing working in the future. Such approach is not recommended for any production code either.

You may download the source code and binaries here at gotdotnet.com (which also includes a visualizer test program). To let this visualizer help your DynamicMethod debugging, (build &) copy DynamicMethodVisualizer.dll and ILReader.dll to your "My Documents\Visual Studio 2005\Visualizers" folder (or follow this search result).

Any comments are welcome.

Update (December 30, 2005): As Toby and others pointed out below, there was some issue around branch instructions. I fixed it and updated the source code at gotdotnet site. Also this version avoids using registry to keep the application settings.

Update (December 1, 2006): New version can be found here.

DynamicMethodVisualizer.zip

Comments

  • Anonymous
    October 25, 2005
    This is very cool.
    FWIW, the CLR also offers full support for debugging traditional Reflection-Emit code, including stepping and setting breakpoints.
    See here:
    http://blogs.msdn.com/jmstall/archive/2005/02/03/366429.aspx
    for details.

  • Anonymous
    December 26, 2005
    The comment has been removed

  • Anonymous
    December 29, 2005
    Thank you Toby. This is my bug. Trying to fix it soon

  • Anonymous
    April 22, 2006
    My upcoming Tech-Ed Talk in Israel will be all about what’s new and Cool in .NET 2.0 Reflection. Over...

  • Anonymous
    June 27, 2006
    Many many thanks, this is extremely useful for poking MSIL that my code has generated; I don't know what I'd do without it.

  • Anonymous
    July 04, 2006
    Being able to dynamically call an arbitrary method on an object or the ability t

  • Anonymous
    November 16, 2006
    I was glad to hear many positive feedbacks about the DebuggerVisualizer for DynamicMethod ; on the sad

  • Anonymous
    December 29, 2006
    Your DynamicMethod support in your ILReader here doesn't work when the DynamicMethod is created from an existing Method as you describe here: http://blogs.msdn.com/haibo_luo/archive/2006/11/07/turn-methodinfo-to-dynamicmethod.aspx Can you update the sample so it supports DynamicMethods created either way? Also, can you add the DynamicMethod support to the ILReader library on GotDotNet?

  • Anonymous
    March 29, 2007
    Hi, I don't know if there are some updates, but I added some (incomplete) code to get the .locals directive at the top of IL returned code (in this way I can see if I push the value to the right variable). If you'd like it let me know at support[at]neodatatype[dot]net.

  • Anonymous
    October 11, 2008
    IL Visualization DebuggerVisualizer for DynamicMethod Take Two: IL Visualizer The Marvels of Monads Generics in C#, Java, and C++ AmazNode] You give it a topic and it searches Amazon, displaying a network of related items. .NET BackgroundWorker class..