I have often seen Devs trying to figure out the cause of the app crash without a memory dump. The only information that is available to analyze is the Windows Error Reporting message in the event viewer which would have “Event Name: CLR20r3” along with Watson bucket information like this.

Fault bucket , type 0

Event Name: CLR20r3

Response: Not available

Cab Id: 0

Problem signature:

P1: unhandledexception.exe

P2: 1.0.0.0

P3: 4ce1e0f1

P4: LibraryCode

P5: 1.0.0.0

P6: 4ce1e0f1

P7: 7

P8: 1f

P9: System.NullReferenceException

P10:

I will demonstrate the steps in identifying the code that caused the app to crash with the above information.Here is the explanation on the Watson Bucket items

  1. P1: unhandledexception.exe – is the Exe File Name
  2. P2:1.0.0.0 – is the Exe File assembly version number
  3. P3:4ce1e0f1- is the Exe File Stamp
  4. P4:LibraryCode- is the Faulting full assembly name
  5. P5:1.0.0.0- is the Faulting assembly version
  6. P6:4ce1e0f1- is the Faulting assembly timestamp
  7. P7:7- is the Faulting assembly method def
  8. P8:1f-  is Faulting method IL Offset within the faulting method
  9. P9:System.NullReferenceException- is Exception type that was thrown

 

Here is the LibraryCode that is mentioned in P4 of the watson bucket

[sourcecode language=”csharp” highlight=”42,43″]

using System;

namespace LibraryCode

{

public class Foo

{

public Foo()

{

Console.WriteLine(“Constructor”);

}

public void Test()

{

Console.WriteLine(“Test”);

}

public string Bar(string test)

{

var x = test;

return x.ToUpper();

}

public string Bar1(string test)

{

var x = test;

return x.ToUpper();

}

public string Bar2(string test)

{

var x = test;

return x.ToUpper();

}

public string Bar3(string test)

{

var x = test;

return x.ToUpper();

}

public string Bar4(string test)

{

int j = 10;

for (int i = 0; i < 10; i++)

{

j += i;

}

var x = test;

return x.ToUpper();

}

}

}

[/sourcecode]

And here is the code for the Main method calling the LibraryCode

[sourcecode language=”csharp”]

static void Main(string[] args)

{

var f = new Foo();

var x = Console.ReadKey();

f.Bar4(null);

}

[/sourcecode]

The most important items in the above watson bucket are 4,7 ,8 and 9. The item 4 is the assembly that was responsible for the crash which is “LibraryCode”. The item 7 is methoddef that threw the exception which is “7”. To identify the method we would have to dump the IL and here is the command to do that.

[sourcecode]

ildasm /tokens “C:tempLibraryCode.dll” /out=libcode.il

[/sourcecode]

Open the libcode.il in a text editor and look for 06000007. The methoddef starts with 06 and 7 is the hex value and when converted to decimal it is still 7 and that’s how we ended with 06000007. The IL content for the corresponding method def

.method /*06000007*/ public hidebysig instance string

Bar4(string test) cil managed

{

// Code size       42 (0x2a)

With this we know the method that caused the app to crash.

The next step is to identify the faulting IL code within the method. The IL offset that caused the exception to be thrown is 1f (decimal value is 31), and here is the IL Code

IL_001d:  ldarg.1

IL_001e:  stloc.2

IL_001f:  ldloc.2

IL_0020:  callvirt   instance string [mscorlib/*23000001*/]System.String/*01000013*/::ToUpper() /* 0A000012 */

IL_0025:  stloc.3

IL_0026:  br.s       IL_0028

Now mapping the IL code back to C# shouldn’t be hard.

And If you are like me then you would probably want to automate things , so here is doing the same using Mono Cecil

[sourcecode language=”csharp”]

AssemblyFactory.GetAssembly(@“C:TempLibraryCode.dll”)

.MainModule.Types.Cast()

.ElementAt(1)

.Methods.Cast().First(md => md.MetadataToken.RID == 7)

.Body.Instructions.Cast()

.Select (i =>

new {Offset = i.Offset,

OpCode = i.OpCode.ToString() ,

Operand = i.Operand != null ? i.Operand.ToString() : string.Empty} )

.Dump();

[/sourcecode]

Notice the above code looks for methoddef “7” which is the P7 item in the Watson bucket.The code could have just dumped 31st IL offset which is “ldloc.2” but that would not help , I like to see the entire method to figure out the cause of the exception.

And here is the output from above code.

We cannot get the call-stack for the crash with just watson buckets.