MDbg extension to debug IL

I've updated the MDbg gui to provide IL debugging. I blogged here that the CLR actually lets you debug at the IL level (with some restrictions), but no debugger actually exposes this feature. People were skeptical, and now that we shipped whidbey, I've had enough time to go add this functionality to the MDbg gui and demonstrate that it is indeed possible.

Here's a screen shot stopped at a for-loop. The current IP is at IL_10.

I press F10 and now the current IP moves to IL_16, which is in the middle of a source line.

Note that the IL-level step couldn't stop at IL_11 because there was no actual native code for that. Since the CLR is ultimately debugging the underlying native code produced from the IL, it can't stop on IL opcodes that don't produce any native code. Efficient codegen means that not all IL opcodes have a direct mapping to native opcodes. I discuss that issue in more depth here.

What does it do?
The window stitches together 3 sources of data. The actual source is in red with source lines on the left. In this case, this is souce line 53. The corresponding IL opcodes are in blue, and the IL offsets are displayed as IL_<hex>. And then the native code ranges associated with each IL range are displayed below the IL ranges. So IL opcodes 0x10 and 0x11 map to 8 bytes of native code starting at native offset 0x2d.  IL offset 0x16 maps to 1 byte of native code starting at native offset 0x35.

//     53:		Console.WriteLine(x);
IL_10 : ldloc.0
IL_11 : call System.Console.WriteLine
IL:0x10,0x16 --> Native:0x2d,0x35 (N. size=0x8 bytes)

IL_16 : nop
IL:0x16,0x17 --> Native:0x35,0x36 (N. size=0x1 bytes)

If I had a native disassembler lying around, I could print the real native opcodes instead of just the native ranges. If I had an IL disassembler with IL-to-Source mappings (I don't think reflector provides this), then I could step into a function without any source and decompile the IL.

It's also built on top of existing ICorDebug functionality. ICorDebug already provides the ability to get the raw IL bytes for a method, and then the gui just uses an Il disassembler (which we already provided in the mdbg sample) to decode those bytes into the strings you see. This doesn't require any modifications to the debuggee. Specifically, you don't need to do the trick where you round-trip it through ilasm. You don't need to adjust the DebuggableAttribute (see Rick's blog here). You don't need to run the debuggee under any special flags. You don't need to func-eval anything to use some IL VS visualizer.

It also exposes scenarios that we didn't target before. Specifically, we target source-level debugging. I've found some cases where it looks like the IL map is wrong for IL spots inbetween source-lines. So nobody would find these bugs just using a source-level debugger.

What doesn't it do?
This does have some restrictions:
1) Although the IL window binds F10 to a real IL level step, it doesn't support F9 setting IL-level breakpoints. There's no restriction here, I was just too lazy to deal with synchronizing breakpoints between multiple copies of the source and figured it wasn't needed to prove the point. .
2) It doesn't show the IL evaluation stack. It turns out ICorDebug doesn't support this functionality (despite what our interfaces may lead you to believe).
3) It doesn't have a full IL disassembler. I just used the IL disassembler from the the Mdbg extension, which handles most of the IL opcodes. I don't think it handles generics. And it doesn't use PDB info to give you local names instead of IL numbers.

More sceenshots:
And here's a screen shot of inside Console.WriteLine.

And another screen shot that's stopped somewhere. This shot shows how having multiple statements on a single line work and how having a single statement span multiple lines works.

We'll roll this back into the MDbg sample and release the full source at some future point. I will of course blog when that happens. But for now, I wanted to give folks a heads up. The basic gui and ildasm extension samples are already available. The only thing that's missing is stitching them altogether.

This update also fixes a bunch of other random issues in the gui, but I'll blog about that later.

Comments (14)

  1. rhm says:

    This is so cool, it’s going to help compiler writers no end.

    Just one question: couldn’t you find the yellow arrow icon that VS uses? 🙂

  2. Sameer says:

    Very cool!!!

  3. rhm – everybody makes fun of the yellow arrow. They think it’s from sesame street.

    I think the real question is: couldn’t VS find the yellow arrow icon that I use?

  4. Szokelizer – no, I haven’t seen it. I just checked it out, and it looks very neat.

    I guess the proof was already out there 🙂

  5. Hello Mike,

    I’m not surprised of that you haven’t heard about DILE. I didn’t want to advertise it until it’s really useful and worths people’s attention therefore only a few developers know about it.

    Anyway, I will keep developing it and I plan to release the final 0.2 version soon which will have even more features. Some healthy "competition" is always welcome. 😉


    Zsolt Petrény

  6. Zsolt – MDbg is just a sample which we work on in our free time, so you shouldn’t expect too much competition from it 🙂

    If I had known DILE existed, I wouldn’t have even bothered adding IL support to MDbg.

  7. Hi Mike,

    I was wondering if you would consider creating a shared folder (using Microsoft FolderShare) that contains the latest version of the MDbg related stuff you’ve been doing.

    I have found this to be a great way to keep a collection of files in sync and up do date. It makes particular sense when you’re dealing with a collection of apps and sample code that needs to play nicely with each other.

    You can see how I’m doing it here:

    Let me know if you’d like help setting up an auto invite page. Otherwise you can just get people to sent their email address and process the invites by hand.

    Thanks, Jamie.

  8. Maty says:

    Sorry for this off-topic question, but I’m desperately searching for a solution. I wrote a a VS add-in which manipulates assemblies using ILDAsm/ILAsm roundtrips. Using the /LINENUM switch in ILDasm and the /DEBUG switch in ILAsm, I was able to debug the roundtrip result in the original language (like C#) in VS 2003. Doing the same with VS 2005/.NET 2.0, VS tells me: "The following module was built either with optimizations enabled or without debug information…" I’m no more able to debug the code, neither in IL nor in C#. Is there anything I missed after the introduction of .NET 2.0? I’d appreciate any idea to the matter or any contact to people, who probably know an answer.

  9. Maty – I just tried it out and things worked as expected. What exactly are you passing to the command line?

  10. PBunt says:

    Maty, I just ran into that problem on a completely different project, but a search on the error message got me here. Are you by any chance signing your binaries? I found out that you can’t debug signed binaries- disable signing if you want to debug.

  11. The Fix says:

    Just had that problem, was looking for a solution and it brought me here. i realized that visual studio somehow had set all my assemblies configuration to release. The solution is simple, just go to Build -> Configuration Manager [Menu], select debug from the active solution configuration, then set configuration to Debug for the projects u want to debug.

  12. Murl says:

    In regards to "The following module was built either with optimizations enabled or without debug information: " message. I have set it to Debug mode, verified it’s not set to optimize code and it’s still giving me the same message as well. I signed the file, and added it to the GAC for assembly attribute purposes, but when debugging I get that message and can’t get around it yet. If anyone has an update on this, it looks as if this is one of few places where people are talking about it…Thanks

  13. Felice Pollano is working on project to make merge Reflector (an IL–&amp;gt;C# decompiler) and Mdbg (a managed…

Skip to main content