Compiling in Debug Mode

Compiling in Debug Mode

When a managed compiler compiles source code in debug mode, you can expect at least two occurrences. First, the resulting module has the custom attribute [mscorlib]System.Diagnostics.DebuggableAttribute attached to the Module record or, if it is a prime module, to the Assembly record. Second, the compiler produces a PDB file containing data about the source files and the compiler, the local variable names, and the tables binding source lines and columns to the code offsets. Of course, the compiler can perform other tasks as well in debug mode—for example, emitting different IL code.

When a module is round-tripped, or when a high-level compiler produces the ILAsm source code as an intermediate step, it is usually desirable to preserve the debug information binding the original source code to the final IL code. ILAsm provides two directives facilitating this:

  • The .language <Language_GUID>[,<Vendor_GUID>[,<Document_ GUID>]] directive defines the source language and, optionally, the compiler vendor and the source document type.

  • The .line <line_num>[:<column_num> [<file_name>]] directive identifies the line and column in the original source file that are “responsible” for the IL code that follows the .line directive.

For example, the following Visual C# .NET code

using System; public class arr {    private static int[,] MakeArray() {       return (int[,])Array.CreateInstance(typeof(int),          new int[]{2,3}, new int[]{-1, 0});    }    private static void Main() {       int[,] _aTgt = MakeArray();       foreach (int i in _aTgt) {          Console.Write(i + " ");       }    } }

compiled in debug mode, is disassembled, using the option /LINENUM, into the following ILAsm code:

 .class public auto ansi beforefieldinit arr        extends [mscorlib]System.Object {    .method private hidebysig static int32[0...,0...]             MakeArray() cil managed    {       // Code size       53 (0x35)       .maxstack  5       .locals init ([0] int32[0...,0...] CS$00000003$00000000,              [1] int32[] CS$00000002$00000001,              [2] int32[] CS$00000002$00000002)       .language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}',                  '{994B45C4-E6E9-11D2-903F-00C04FA302A1}',                  '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'       .line 6:3 'C:\\MyDirectory\\arr.cs'       IL_0000:  ldtoken    [mscorlib]System.Int32       IL_0005:  call class [mscorlib]System.Type                 [mscorlib]System.Type::GetTypeFromHandle(                    valuetype [mscorlib]System.RuntimeTypeHandle)       IL_000a:  ldc.i4.2       IL_000b:  newarr     [mscorlib]System.Int32       IL_0010:  stloc.1       IL_0011:  ldloc.1       IL_0012:  ldc.i4.0       IL_0013:  ldc.i4.2       IL_0014:  stelem.i4       IL_0015:  ldloc.1       IL_0016:  ldc.i4.1       IL_0017:  ldc.i4.3       IL_0018:  stelem.i4       IL_0019:  ldloc.1       IL_001a:  ldc.i4.2       IL_001b:  newarr     [mscorlib]System.Int32       IL_0020:  stloc.2       IL_0021:  ldloc.2       IL_0022:  ldc.i4.0       IL_0023:  ldc.i4.m1       IL_0024:  stelem.i4       IL_0025:  ldloc.2       IL_0026:  call class [mscorlib]System.Array                  [mscorlib]System.Array::CreateInstance(                           class [mscorlib]System.Type,                           int32[],                           int32[])       IL_002b:  castclass  int32[0...,0...]       IL_0030:  stloc.0       IL_0031:  br.s       IL_0033       .line 7:2       IL_0033:  ldloc.0       IL_0034:  ret    } // End of method arr::MakeArray    .method private hidebysig static void  Main() cil managed    {       .entrypoint       // Code size       103 (0x67)       .maxstack  3       .locals init ([0] int32[0...,0...] _aTgt,               [1] int32 i,               [2] int32[0...,0...] CS$00000007$00000000,               [3] int32 CS$00000264$00000001,               [4] int32 CS$00000265$00000002,               [5] int32 CS$00000008$00000003,               [6] int32 CS$00000009$00000004)       .line 10:3       IL_0000:  call       int32[0...,0...] arr::MakeArray()       IL_0005:  stloc.0       .line 11:21       IL_0006:  ldloc.0       IL_0007:  stloc.2       IL_0008:  ldloc.2       IL_0009:  ldc.i4.0       IL_000a:  callvirt instance int32                  [mscorlib]System.Array::GetUpperBound(int32)       IL_000f:  stloc.3       IL_0010:  ldloc.2       IL_0011:  ldc.i4.1       IL_0012:  callvirt   instance int32                 [mscorlib]System.Array::GetUpperBound(int32)       IL_0017:  stloc.s    CS$00000265$00000002       IL_0019:  ldloc.2       IL_001a:  ldc.i4.0       IL_001b:  callvirt   instance int32                  [mscorlib]System.Array::GetLowerBound(int32)       IL_0020:  stloc.s    CS$00000008$00000003       IL_0022:  br.s       IL_0061       IL_0024:  ldloc.2       IL_0025:  ldc.i4.1       IL_0026:  callvirt   instance int32                 [mscorlib]System.Array::GetLowerBound(int32)       IL_002b:  stloc.s    CS$00000009$00000004       IL_002d:  br.s       IL_0055       .line 11:12       IL_002f:  ldloc.2       IL_0030:  ldloc.s    CS$00000008$00000003       IL_0032:  ldloc.s    CS$00000009$00000004       IL_0034:  call                        instance int32 int32[0...,0...]::Get(int32int32)       IL_0039:  stloc.1       .line 12:8       IL_003a:  ldloc.1       IL_003b:  box        [mscorlib]System.Int32       IL_0040:  ldstr      " "       IL_0045:  call       string              [mscorlib]System.String::Concat(objectobject)       IL_004a:  call void [mscorlib]System.Console::Write(string)       .line 11:3       IL_004f:  ldloc.s    CS$00000009$00000004       IL_0051:  ldc.i4.1       IL_0052:  add       IL_0053:  stloc.s    CS$00000009$00000004       IL_0055:  ldloc.s    CS$00000009$00000004       IL_0057:  ldloc.s    CS$00000265$00000002       IL_0059:  ble.s      IL_002f       IL_005b:  ldloc.s    CS$00000008$00000003       IL_005d:  ldc.i4.1       IL_005e:  add       IL_005f:  stloc.s    CS$00000008$00000003       IL_0061:  ldloc.s    CS$00000008$00000003       IL_0063:  ldloc.3       IL_0064:  ble.s      IL_0024       .line 14:2       IL_0066:  ret    } // End of method arr::Main    .method public hidebysig specialname rtspecialname             instance void  .ctor() cil managed    {       // Code size       7 (0x7)       .maxstack  1       IL_0000:  ldarg.0       IL_0001:  call                        instance void [mscorlib]System.Object::.ctor()       IL_0006:  ret    } // End of method arr::.ctor } // End of class arr

The .language directive sets the GUIDs for all following code until it is superseded by another .language directive.

You’ll encounter a slight problem with the .line directive in the first release of the ILAsm compiler and disassembler: the directive specifies the starting line and column of the original source statement that has been compiled into ILAsm code following the .line directive. This doesn’t bode well for the Microsoft Visual Studio .NET debugger, which wants to see the line/column interval (starting line and column and ending line and column) for each original source statement. This problem will be corrected in future releases of the ILAsm compiler and disassembler.

In short, if you want the resulting code bound to the original source code, you need to do the following:

  • If your compiler generates ILAsm source code, it must insert .language and .line directives at appropriate points.

  • If you are round-tripping a module compiled from a high-level language, use the disassembler option /LINENUM (or /LIN).

  • In any case, don’t forget to use the option /DEBUG (or /DEB) of the ILAsm compiler.



Inside Microsoft. NET IL Assembler
Inside Microsoft .NET IL Assembler
ISBN: 0735615470
EAN: 2147483647
Year: 2005
Pages: 147
Authors: SERGE LIDIN

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net