Windows Error Reporting and CLR integration

Windows Error Reporting (WER) monitors and collects information on crashes and hangs on Windows platforms newer that Windows XP. The information collected can be sent to a server for investigation (read more in my previous WER article).

When creating reports, WER generates some parameters to bucket-ize the failures. Since the OS doesn’t know anything about managed applications, CLR integrates WER and adds these parameters to create correct buckets:

- AppName - The filename of the EXE (e.g., “Explorer.exe”);

- AppVer – Assembly version number for an managed EXE (major.minor.build.revision) or the PE header version number (e.g. “2.0.40220.13”) for unmanged

- AppStamp - The timestamp on the executable.

- AsmAndModName – Assembly and module name if the module is part of a multi-module assembly (e.g., “MyAssembly+MyModule.dll”)

-  AsmVer - Managed assembly version number of the faulting assembly (major.minor.build.revision)

- ModStamp - The timestamp of the faulting module.

- MethodDef - MethodDef token for the faulting method, after stripping off the high byte.

- Offset - The IL offset of the faulting instruction.

- ExceptionType - The name of the type of the most-inner exception, with "Exception" removed from the end, if present. (E.g., "System.AccessViolation")

For example, I have a managed app (TestWERDefaultCategorizationAndDumps) that crashed. A report was created with these parameters:

Problem signature

Problem Event Name: CLR20r3

Problem Signature 01: XFU1LOPV1B5JQH0HBYGNH00TXWMZP45M

Problem Signature 02: 1.0.0.0

Problem Signature 03: 49833e70

Problem Signature 04: TestWERDefaultCategorizationAndDumps

Problem Signature 05: 1.0.0.0

Problem Signature 06: 49833e70

Problem Signature 07: 1 -> methodDesc

Problem Signature 08: 16 -> offset

Problem Signature 09: System.ArgumentNullException -> exception type

OS Version: 6.0.6001.2.1.0.256.4

Locale ID: 1033

 

So the application crashed because a System.ArgumentNullException was unhandled. If we attach the debugger to the application (windbg –pn TestWERDefaultCategorizationAndDumps if the application is running or windbg TestWERDefaultCategorizationAndDumps to start the app under debugger), we can use the offset and the methodDesc to find out what happened. First, we need to load sos (.loadby sos mscorwks) and then we can use !token2ee Module MethodDesc to find out the method that threw. To determine the methodDesc, append 060000 to the number in the report.

0:000> !token2ee TestWERDefaultCategorizationAndDumps 06000001

Module: 0000064280012e20 (TestWERDefaultCategorizationAndDumps.exe)

Token: 0x0000000006000001

MethodDesc: 0000064280013580

Name: TestWERDefaultCategorizationAndDumps.Program.ThrowUnhandledException()

JITTED Code Address: 00000642801504b0

 

So the function that threw the exception is ThrowUnhandledException in class Program (TestWERDefaultCategorizationAndDumps.Program.ThrowUnhandledException). Once we know the method desc, we can dump the IL of the method and see what line failed:

0:000> !dumpil 0000064280013580

ilAddr = 0000000000eb2050

IL_0000: nop

IL_0001: ldstr "Thow Argument Null Exception"

IL_0006: call System.Console::WriteLine

IL_000b: nop

IL_000c: ldstr "test"

IL_0011: newobj System.ArgumentNullException::.ctor

IL_0016: throw

The report says the offset is 16, so we look at IL_0016 and we find our throw. If we take a look at the code, it all makes sense:

static void ThrowUnhandledException()

{

    Console.WriteLine("Thow Argument Null Exception");

    throw new ArgumentNullException("test");

}