@ Harald - My assumption is that NETMF has limited the amount of debug info loaded onto the physical hardware to limit the amount of memory taken by an assembly.
However, you can do that mapping manually if it is really required. The IP (instruction pointer) address included in the exception is the address of the offending IL instruction (actually it is 1 higher than the start of the address) relative to the start of the method, so using ILDasm you can inspect the code and relatively easily map it back to your original source code.
Just to share an example of what I am saying, here is a contrived and admittedly non-complex demonstration.
Given the following code
public class Test
{
static void Main(string[] args)
{
DoSomething(5);
DoSomething(0);
Debug.Print("Done");
}
static int DoSomething(int x)
{
return 15 / x;
}
}
We will get the following DivideByZeroException
#### Exception System.Exception - CLR_E_DIVIDE_BY_ZERO (1) ####
#### Message:
#### StackTraceDemo.Test::DoSomething [IP: 0005] ####
#### StackTraceDemo.Test::Main [IP: 000a] ####
Here we see that the initial exception was raised in DoSomething at address 5 and that was caused by and earlier call from Main at address 0x000a.
Using ILDasm our code decompiles to
DoSomething.IL
.method private hidebysig static int32 DoSomething(int32 x) cil managed
{
// Code size 10 (0xa)
.maxstack 2
.locals init ([0] int32 CS$1$0000)
IL_0000: nop
IL_0001: ldc.i4.s 15
IL_0003: ldarg.0
IL_0004: div
IL_0005: stloc.0
IL_0006: br.s IL_0008
IL_0008: ldloc.0
IL_0009: ret
} // end of method Test::DoSomething
Remember I said that the IP address is one more than the address of the offending IL instruction, so in our case the IP was address 5 we look at address 4 and see a div instruction, so this is the IL instruction that caused the exception, so why?
Like normal we follow the stack trace and we take a look at Main, the stack trace says we need to look at IP 0x000a, one less than that is 0x0009.
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size 27 (0x1b)
.maxstack 8
IL_0000: nop
IL_0001: ldc.i4.5
IL_0002: call int32 StackTraceDemo.Test::DoSomething(int32)
IL_0007: pop
IL_0008: ldc.i4.0
IL_0009: call int32 StackTraceDemo.Test::DoSomething(int32)
IL_000e: pop
IL_000f: ldstr "Done"
IL_0014: call void [Microsoft.SPOT.Native]Microsoft.SPOT.Debug::Print(string)
IL_0019: nop
IL_001a: ret
} // end of method Test::Main
Add address 0x0009 we see this is our second call to DoSomething, that makes sense and just before that the arguments to the function call would have been loaded to the stack. We see the following just before the operation
IL_0008: ldc.i4.0
This is loading the value 0 onto the stack, yip, we are passing a 0 to the function which is the root of our problem.
Like I said a rather contrived and very very simple example, other scenarios involving variables etc. or a little more complex, but not so complex that we cannot follow the same process to identify the source of the issue. Fortunately the IL will still have the variable names associated with the code etc.
Sometimes this helps because if you have a complex expression that is blowing up, normally you only know that on that line something is going wrong, while at the IL level the expression is broken down into separate pieces and you have a fair chance at matching the IL to a specific part of the expression that is causing the exception, this can get quite complex with the compiler optimizations but once you get a handle on reading IL it is not that tough.
Hope this helps in the meantime…