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");
}