Going from IL to Source

Question from the mail bag:

I am trying to get some information on what I can do usefully with the “+ 0xnn” part at the end of a call stack line in VS IDE 2003.

So when I see (in the call stack window)
cf-gfmaa!Microsoft.Xml.Serialization.GeneratedAssembly.XmlSerializationWriter1.Write3_ArrayOfExtendedAnnotationElement(System.Object o = {MyStuff.MyClass}) + 0x4f bytes

What can I do with the “+ 0x4f bytes” part to see more accurately where we’ve stopped (at a break point)?

The 0x4f is the native offset into the method that you’ve stopped at. Ideally, the debugger should translate that  native offset back to a source line for you to show you the source of the current line.  

Technical background on translating native-offsets to source-Lines:
This is done by first translating the native offset to an IL offset. The debugger gets the IL-to-native map from ICorDebugCode::GetILToNativeMapping(). It then does a reverse lookup in there to get the IL offset. We need an ICorDebug API for this because it’s the JITter that compiles IL to native, and so only the JITter ultimately knows the IL-to-native mapping. The JITter cooperates with the debugging services to pass this information back through the ICorDebug API.

PDBs contain a set of sequence points which map certain IL offsets to source locations (as you can see from the PDB2Xml reader here). The debugger can use this map to lookup the source location for the IL offset. Since the IL-to-source map is determined at compile time, this information can reliably be in a static PDB and does not need any ICorDebug support.

Visual Studio 2005 does not provide debugging supporting on the IL level, but other debuggers could add this feature. (As proof, recall that MDbg has an ILasm extension to do this). So if you don’t have the source, then you’re out of luck. There are several ways this could happen:
1) You’re debugging somebody else’s code and you just don’t have the source for it. I think this is by far the most common scenario. We’ve added Just-My-Code support in CLR 2.0 (VS 2005) to provide a better user experience here.
2) You’re debugging some generated code:
    2a) Perhaps it’s generated by reflection emit but without proper debug info.
    2b) Or perhaps it’s some other throwaway generated code. For example, Serialization / Deserialization will generate assemblies on the fly.  In these cases, you’ll need some way of getting those libraries to produce the additional debug information (such as spewing PDBs, spewing source-code for the IL they generate, etc). Since each library is different, this must be done on a case by case basis. For the XML case, see a tip here.
3) You’re debugging optimized code and things have been so optimized / inlined / rearranged that source-level debugging is not practical.
4) For VS2003 and earlier, you’re debugging code without “Tracking Debug Information”. This means that the IL-to-Native maps could be missing, which means the code is basically not debuggable.

Note the example above look like case 2b. 
So to answer the question above, if the debugger doesn’t automatically show you the source, try to determine which of the cases above you fall into and take the appropriate answer.

Comments (1)

  1. adam says:

    Thanks for the response.

    The specific example I posted was 2b but I also wanted to know for the other reasons.

    In my case adding the secret trace switch (also saw a post to use a value of 4) does give the code and I have put a break point on it (once I found it). Basically it mostly works and sometimes does not. I get a cast exception, it might be related to the plug-in architecture, but anyway that’s my problem.