Quality reports on the App Summary page
Microsoft provides triage dumps of your Windows Store application’s crashes and hangs through the Quality section of the App Summary page on the Dev Center - Windows Store apps portal.
Back in June 2012, the Windows Store team posted an article on this feature and the basics of debugging the dumps provided. Improving apps with Quality reports,
http://blogs.msdn.com/b/windowsstore/archive/2012/06/27/improving-apps-with-quality-reports.aspx.
This article digs further into the debugging of Windows Store application crash dump files, and explains the recent changes made to exception reporting in Windows 8.1.
The files being debugged can be obtained from the Quality page or by collecting them yourself using Windows Error Reporting (WER) or the AeDebug feature of Windows.
An example AeDebug tool is Sysinternals ProcDump. To configure crash dumping, execute the following from an elevated command prompt:
C:\>md c:\dumps
C:\>procdump.exe -ma -i c:\dumps
Windows Runtime Architecture
The Windows Runtime (WinRT API) is at the core of all Windows Store applications. Similar to how Win32 and.NET sit between the Desktop app and the kernel, the WinRT API sits between the Windows Store app and the kernel.
Image may be NSFW.
Clik here to view.
In between the WinRT API and app is a layer called the Language Projection layer. This layer projects the C++ centric concepts of WinRT, into language specific concepts.
The projection of errors through the Language Projection layer is the focus of this article.
- In WinRT, errors are modeled as IErrorInfo and IRestrictedErrorInfo interfaces.
- In CLR languages, errors are modeled as exceptions and are represented as class objects derived from System.Exception.
- In JavaScript, errors are also modeled as exceptions and are represented as JavaScript Exception (JSE) objects.
- In C/C++, errors are modeled as an interface or a pure HRESULT.
Image may be NSFW.
Clik here to view.
Because each language has a different concept on how errors are handled, the projection layer needs to use a least common denominator. For errors, that means that just an HRESULT (Error Code) and HSTRING (Error Message) are sent through the projection layer. Any addition information held by WinRT’s interface is not available in the receiving language. And conversely, any additional information held by the language’s object is not available to WinRT.
If the error becomes unhandled, the HRESULT becomes the Exception Code reported in the Exception Record (of a live debug session or dump file).
Visual Studio 2013
Opening a dump file in Visual Studio allows you to see the Exception Record via the MiniDump File Summary. The Exception Code is listed in the Dump Summary section.
Image may be NSFW.
Clik here to view.
If you Debug the application, the Exception Code‘s Description will be listed in the Output window.
Image may be NSFW.
Clik here to view.
The call stack of the Exception Record’s context is viewable in the Call Stack window. Depending on the dump’s state, the $exceptionstack pseudo variable can be used in a Watch (or Locals) window to see the stack.
Image may be NSFW.
Clik here to view.
Note, having the Private PDBs of the application will make the stack output more complete/accurate.
Debugging Tools for Windows
Using the Debugging Tools for Windows, the Exception Record can be displayed using the .exr -1 command. The Exception Code’s description can (sometimes) be looked up using the !error <code> command. The context of the exception is changed to with the .ecxr command. The stack is displayed with the k command (knL adds frame numbers and omits source line information).
0:004> .exr -1
ExceptionAddress: 722248e8 (msvcr110!Concurrency::details::_ReportUnobservedException+0x00000022)
ExceptionCode: c0000409 (Security check failure or stack buffer overrun)
ExceptionFlags: 00000001
NumberParameters: 1
Parameter[0]: 00000005
0:004> !error c0000409
Error code: (NTSTATUS) 0xc0000409 (3221226505) - The system detected an overrun of a stack-based buffer in this application. This overrun could potentially allow a malicious user to gain control of this application.
0:004> .ecxr
eax=00000001 ebx=ffffffff ecx=00000005 edx=0a6ee048 esi=13672424 edi=0546c33c
eip=722248e8 esp=02ceeef8 ebp=02ceef14 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
msvcr110!Concurrency::details::_ReportUnobservedException+0x22:
722248e8 cd29 int 29h
0:004> knL
*** Stack trace for last set context - .thread/.cxr resets it
# ChildEBP RetAddr
00 02ceeef4 00f2f6cb msvcr110!Concurrency::details::_ReportUnobservedException+0x22
WARNING: Stack unwind information not available. Following frames may be wrong.
01 02ceef14 00f2fad7 MyBadApp+0xef6cb
02 02ceef40 01122720 MyBadApp+0xefad7
03 02ceef64 011228eb MyBadApp+0x2e2720
04 02ceef70 00f3960a MyBadApp+0x2e28eb
05 02ceefb0 010cc804 MyBadApp+0xf960a
06 02ceefc0 0112108e MyBadApp+0x28c804
07 02ceeff8 72422b61 MyBadApp+0x2e108e
08 02cef034 72427e27 Microsoft_Xbox!DllGetClassObject+0x61352
09 02cef040 76095c3e Microsoft_Xbox!DllGetClassObject+0x66618
0a 02cef060 7610f497 rpcrt4!Invoke+0x2a
0b 02cef6ec 75c241f8 rpcrt4!NdrStubCall2+0x33c
0c 02cef734 75c1f58a combase!CStdStubBuffer_Invoke+0xc1
0d 02cef7c0 75b24617 combase!SyncStubInvoke+0x144
0e (Inline) -------- combase!StubInvoke+0x9a
0f 02cef8e8 75b97d8d combase!CCtxComChnl::ContextInvoke+0x222
10 02cef90c 75c24cc9 combase!DefaultInvokeInApartment+0x30
11 (Inline) -------- combase!ASTAInvokeInApartment+0x35
12 02cef9b4 75c1fdc7 combase!AppInvoke+0x5ae
13 02cefb00 75c24c71 combase!ComInvokeWithLockAndIPID+0x5ed
14 02cefb20 75b93118 combase!ComInvoke+0x153
15 02cefb30 75b97b11 combase!ThreadDispatch+0x23
16 02cefb44 75be53b5 combase!CComApartment::ASTAHandleMessage+0xe6
17 02cefb68 75ba8f22 combase!ASTAWaitContext::DispatchCallsOnExitNonBlockingProcessEventsIfAppropriate+0x9e
18 02cefb8c 75b5917e combase!ASTAWaitContext::~ASTAWaitContext+0x1a9
19 02cefb98 74acb13d combase!CoEndProcessEvents+0x37
1a 02cefbf4 00f733d7 windows_ui!Windows::UI::Core::CDispatcher::ProcessEvents+0x29ac1
1b 02cefc64 00f77f46 MyBadApp+0x1333d7
1c 02cefc94 74f6f45e MyBadApp+0x137f46
1d 02cefca0 74f6f322 twinapi_appcore!Windows::ApplicationModel::Core::CoreApplicationView::Run+0x27
1e 02cefcc0 74b1008a twinapi_appcore!<lambda_f0454c86bc54370cf843d844d6c13e00>::operator()+0xb2
1f 02cefd44 75f4a534 SHCore!_WrapperThreadProc+0xe2
20 02cefd50 77dd8f8b kernel32!BaseThreadInitThunk+0xe
21 02cefd94 77dd8f61 ntdll!__RtlUserThreadStart+0x20
22 02cefda4 00000000 ntdll!_RtlUserThreadStart+0x1b
Simple so far...
Using Visual Studio or the Debugging Tools for Windows is relatively simple when the Exception Record is associated with the call stack of the issue. This is not however always the case. It depends on what side of the projection layer the issue occurred. If the error (exception) was not handled on the language side, the exception is marshaled (projected) to the WinRT side for its exception handling. When this occurs, it starts getting very, very tricky indeed, to see what stack caused the issue...
Language Exceptions - Error Code 0xC000027B
In the initial design of the WinRT API, the projection of errors was done though a call to the RoOriginateError function. This function takes a HRESULT and HSTRING. Of note, there is no call stack captured. The limits of the RoOriginateError function were recognized and a new (associated) function was created for Windows 8.1.
The RoOriginateLanguageException function takes a HRESULT, HSTRING and a marshalable interface pointer. When RoOriginateLanguageException in called, the current call stack is captured and is passed as part of the error.
The purpose of RoOriginateLanguageException is to marshal the interface pointer so that additional language information is available on the other side of the projection layer. This behavior is achieved by using a specific exception code. Instead of the using the (user defined) HRESULT, a value of 0xC000027B is used. This error code indicates to the receiver that there is data to unmarshal. The data includes the HRESULT and HSTRING, and also the Interface pointer.
The important point to understand here is that all async exceptions raised in Windows 8.1 Windows Store apps now result in a 0xC000027B error code in the Exception Record, not the error code passed by the caller.
Debugging Language Exceptions
The Exception Record of a Language Exception contains (of note) the exception code (0xC000027B) and two parameters.
0:004> .exr -1
ExceptionAddress: 73034fec (Windows_UI_Xaml!DirectUI::ErrorHelper::ProcessUnhandledError+0x000000b8)
ExceptionCode: c000027b
ExceptionFlags: 00000001
NumberParameters: 2
Parameter[0]: 0bdaf240
Parameter[1]: 00000001
0:006> !error c000027b
Error code: (NTSTATUS) 0xc000027b (3221226107) - An application-internal exception has occurred.
The first parameter is the address of a pointer array (of unmarshalled data). The second parameter is the count of pointers in the pointer array.
So why is the need for a count? Since applications have multiple threads, it is possible for multiple threads to call RoOriginateLanguageException simultaneously. Equally, there can be a cyclic nature to the experience, where exceptions are caught and then re-thrown. Since WinRT processes the errors asynchronously, multiple errors exist regularly. The first exception in the array should be the focus of the investigation.
[Tip] Even though Microsoft publishes the private symbols for combase.dll (allowing you to view the local variables of combase!RoFailFast* functions), these locals regularly resolve to invalid addresses due to register reuse and other code flow optimizations. The pointer array in Parameter[0] is the correct place to get the address of the language exception pointer array.
Original Error Code
The first step when debugging a Language Exception is to determine the actual error code of the caller, instead of the 0xC000027B error code.
Casting an address to a pointer array of a specific type in Visual Studio is, put simply, too difficult to undertake. The easiest option is to use the Debugging Tools for Windows. Even though these tools are all command-line driven and use an obscure syntax, it is relatively easy to follow the following commands to get to the important information.
If not done already, set your symbol path to the Microsoft Public Symbol server:
0:004> .sympath SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
Symbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
Expanded Symbol search path is: srv*c:\Symbols*http://msdl.microsoft.com/download/symbols
************* Symbol Path validation summary **************
Response Time (ms) Location
Deferred SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols
Force the load of the symbols using the .reload /f command:
0:004> .reload /f
...
The next step is to display the pointer array as the original structure type. First, we need to know what structure to cast the pointer array to. Using the Parameter[0] value from .exr -1, we will generate a dt command that will display the header of the first record. We use Parameter[0] as the address in this command.
dt <Parameter[0]> combase!_STOWED_EXCEPTION_INFORMATION_HEADER*
Here’s an example:
0:004> .exr -1
ExceptionAddress: 73034fec (Windows_UI_Xaml!DirectUI::ErrorHelper::ProcessUnhandledError+0x000000b8)
ExceptionCode: c000027b
ExceptionFlags: 00000001
NumberParameters: 2
Parameter[0]: 0180cf90
Parameter[1]: 00000003
0:004> dt 0180cf90 combase!_STOWED_EXCEPTION_INFORMATION_HEADER*
0x070884a4
+0x000 Size : 0x20
+0x004 Signature : 0x53453031
The value of the Signature member (0x53453031) is converted to a string using .formats <value>.
0:006> .formats 0x53453031
Evaluate expression:
Hex: 53453031
Decimal: 1397043249
Octal: 12321230061
Binary: 01010011 01000101 00110000 00110001
Chars: SE01
Time: Wed Apr 09 04:34:09 2014
Float: low 8.46917e+011 high 0
Double: 6.90231e-315
The chars “SE01” map to a structure name of combase!_STOWED_EXCEPTION_INFORMATION_V1. It can be assumed that v2 uses a signature of “SE02” and a structure name of combase!_STOWED_EXCEPTION_INFORMATION_V2, and so on…
Now we know the type, we can again use the values from .exr -1 to generate a dt command that will display each record. We use the Parameter[0] as the address, and Parameter[1] as the count in the command. We add an “*” to the end of the type as this is an array of pointers to the type, not structures packed next to each other.
In this example, there are 3 pointers, so 3 records are displayed:
dt -a<Parameter[1]><Parameter[0]> combase!_STOWED_EXCEPTION_INFORMATION_V1*
Note, there is no space between the -a and <Parameter[1]>.
0:004> .exr -1
ExceptionAddress: 73034fec (Windows_UI_Xaml!DirectUI::ErrorHelper::ProcessUnhandledError+0x000000b8)
ExceptionCode: c000027b
ExceptionFlags: 00000001
NumberParameters: 2
Parameter[0]: 0180cf90
Parameter[1]: 00000003
0:004> dt -a30180cf90 combase!_STOWED_EXCEPTION_INFORMATION_V1*
[0] @ 0180cf90
---------------------------------------------
0x070884a4
+0x000 Header : _STOWED_EXCEPTION_INFORMATION_HEADER
+0x008 ResultCode : 80131500
+0x00c ExceptionForm : 0y01
+0x00c ThreadId : 0y000000000000000000010100111100 (0x53c)
+0x010 ExceptionAddress : 0x7721ea23 Void
+0x014 StackTraceWordSize : 4
+0x018 StackTraceWords : 5
+0x01c StackTrace : 0x06f48418 Void
+0x010 ErrorText : 0x7721ea23 "?????"
[1] @ 0180cf94
---------------------------------------------
0x071ca274
+0x000 Header : _STOWED_EXCEPTION_INFORMATION_HEADER
+0x008 ResultCode : 80131500
+0x00c ExceptionForm : 0y01
+0x00c ThreadId : 0y000000000000000000010100111100 (0x53c)
+0x010 ExceptionAddress : (null)
+0x014 StackTraceWordSize : 4
+0x018 StackTraceWords : 0x19
+0x01c StackTrace : 0x071c926c Void
+0x010 ErrorText : (null)
[2] @ 0180cf98
---------------------------------------------
0x071c922c
+0x000 Header : _STOWED_EXCEPTION_INFORMATION_HEADER
+0x008 ResultCode : 80131534
+0x00c ExceptionForm : 0y01
+0x00c ThreadId : 0y000000000000000000010100111100 (0x53c)
+0x010 ExceptionAddress : (null)
+0x014 StackTraceWordSize : 4
+0x018 StackTraceWords : 9
+0x01c StackTrace : 0x071c8224 Void
+0x010 ErrorText : (null)
The ResultCode member is 80131500 in the first two records, and 80131534 in the third record. A quick use of the !error <code> command looks up the descriptions:
0:007> !error 80131500
Error code: (HRESULT) 0x80131500 (2148734208) - <Unable to get error code text>
0:007> !error 80131534
Error code: (HRESULT) 0x80131534 (2148734260) - <Unable to get error code text>
In this case, both aren‘t well-known error codes. This is common as API specific error codes aren’t in the OS error lookup routines.
Here are some examples of known error codes, found by looking at a random selection of dumps. Some are quite common (80004003, 80004005 and 80070057) while others are quite rare:
0:004> !error 80004003
Error code: (HRESULT) 0x80004003 (2147500035) - Invalid pointer
0:004> !error 80004005
Error code: (HRESULT) 0x80004005 (2147500037) - Unspecified error
0:005> !error 8000ffff
Error code: (HRESULT) 0x8000ffff (2147549183) - Catastrophic failure
0:004> !error 80070057
Error code: (HRESULT) 0x80070057 (2147942487) - The parameter is incorrect.
0:006> !error 80073db8
Error code: (HRESULT) 0x80073db8 (2147958200) - Loading the state store failed.
0:005> !error 800f1000
Error code: (HRESULT) 0x800f1000 (2148470784) - No installed components were detected.
0:006> !error 88985004
Error code: (HRESULT) 0x88985004 (2291683332) - A font file exists but could not be opened due to access denied, sharing violation, or similar error.
Original Call Stack
Regardless of whether the error code is known or unknown, it is useful to determine the location of the issue by viewing the call stack.
Symbol Pointers
If the ExceptionForm member has a value of 0y01, the structure’s union represents a call stack.
Unlike call stacks associated with threads, where the symbol pointers are placed throughout the stack next to local variables, these symbols pointers are packed tightly at the address specified in the StackTrace member. The dpS command is used to display the call stack.
- It is important to include a limit (L) as the call stack is regularly longer than the default 10 rows displayed by dpS. The limit’s value is in the StackTraceWords member.
- Note that capital S is used (dps vs dpS) because we want to omit the first column normally displayed by dps; the location of the symbol pointer is irrelevant.
- If you aren‘t using the same bitness debugger as the target’s bitness, use ddS for StackTraceWordSize = 4, and dqS for StackTraceWordSize = 8.
0:004> dt -a3 0180cf90 combase!_STOWED_EXCEPTION_INFORMATION_V1*
[0] @ 0180cf90
---------------------------------------------
0x070884a4
+0x000 Header : _STOWED_EXCEPTION_INFORMATION_HEADER
+0x008 ResultCode : 80131500
+0x00c ExceptionForm : 0y01
+0x00c ThreadId : 0y000000000000000000010100111100 (0x53c)
+0x010 ExceptionAddress : 0x7721ea23 Void
+0x014 StackTraceWordSize : 4
+0x018 StackTraceWords : 5
+0x01c StackTrace : 0x06f48418 Void
+0x010 ErrorText : 0x7721ea23 "?????"
...
0:007> dpS 0x06f48418 L5
7723f217 combase!RoOriginateLanguageException+0x3b
72e29bfd clr!SetupErrorInfo+0x1e1
72ef27e1 clr!MarshalNative::GetHRForException_WinRT+0x7d
71981170 Windows_UI_Xaml_ni+0x291170
72b02a36 clr!COMToCLRDispatchHelper+0x28
Unicode String Pointer
If the ExceptionForm member has a value of 0y10, the structure’s union represents an error message.
The call stack is (hopefully) contained within the Unicode string pointed at by the ErrorText member. As the text is defined by the caller, the existence of a call stack text isn’t guaranteed.
0:005> dt –a1 13f117e0 combase!_STOWED_EXCEPTION_INFORMATION_V1*
[0] @ 13f117e0
---------------------------------------------
0x0471f3c0
+0x000 Header : _STOWED_EXCEPTION_INFORMATION_HEADER
+0x008 ResultCode : 8000ffff
+0x00c ExceptionForm : 0y10
+0x00c ThreadId : 0y000000000000000000010101110100 (0x574)
+0x010 ExceptionAddress : 0x0de38f7c Void
+0x014 StackTraceWordSize : 0
+0x018 StackTraceWords : 0
+0x01c StackTrace : (null)
+0x010 ErrorText : 0x0de38f7c "System.Exception.. at Windows.UI.Xaml.VisualStateManager.GoToState(Control control, String stateName, Boolean useTransitions).. at MyBadApp.Common.LayoutAwarePage.InvalidateVisualState().. at MyBadApp.Common.LayoutAwarePage.WindowSizeChanged(Object sender, WindowSizeChangedEventArgs e)"
CLR - Last Exception Object
Sometimes, the call stack retrieved from the record isn’t that useful. It may just be the call stack leading up to RoOriginateLanguageException function call, or it just might not relate to any of the code that the application author has written. In these cases, the CLR provides one more chance to understand the issue.
When the CLR throws an exception on a managed thread, the address of the exception object is kept in an (internal) per-thread variable. This address is what the !sos.pe (print exception) command reads to display the CLR Last Exception of a thread.
Note, if you use the Windows 8.1 SDK version of the Debugging Tools for Windows, SOS will be automatically loaded for you, including the download of any required DLLs. As such, it is highly suggested that you use the Windows 8.1 version.
Example #1
Looking at this example, we can see that there is a single record with an "Invalid pointer" error.
0:006> .exr -1
ExceptionAddress: 00007ffb87c46960 (twinapi_appcore!Microsoft::WRL::ComPtr<Windows::ApplicationModel::Core::UnhandledErrorDetectedEventArgs>::{dtor})
ExceptionCode: c000027b
ExceptionFlags: 00000001
NumberParameters: 2
Parameter[0]: 0000003fbc80c8a0
Parameter[1]: 0000000000000001
0:006> dt -a1 0000003fbc80c8a0 combase!_STOWED_EXCEPTION_INFORMATION_V1*
[0] @ 0000003f`bc80c8a0
---------------------------------------------
0x0000003f`bfc3c5b8
+0x000 Header : _STOWED_EXCEPTION_INFORMATION_HEADER
+0x008 ResultCode : 80004003
+0x00c ExceptionForm : 0y01
+0x00c ThreadId : 0y000000000000000000100111001000 (0x9c8)
+0x010 ExceptionAddress : 0x00007ffb`981e1f1c Void
+0x018 StackTraceWordSize : 8
+0x01c StackTraceWords : 0x18
+0x020 StackTrace : 0x0000003f`bd7ac9c0 Void
+0x010 ErrorText : 0x00007ffb`981e1f1c "???"
0:006> !error 80004003
Error code: (HRESULT) 0x80004003 (2147500035) - Invalid pointer
This is a common call stack. A CLR exception is being marshaling to the unhandled error reporting sub-system of WinRT.
0:006> dpS 0x0000003f`bd7ac9c0 L18
00007ffb`98238d27 combase!RoOriginateLanguageException+0x57
00007ffb`71e0f926 mscorlib_ni!DomainNeutralILStubClass.IL_STUB_PInvoke(Int32, System.String, IntPtr)+0xe6
00007ffb`71ff7084 mscorlib_ni!System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.RoOriginateLanguageException(Int32, System.String, IntPtr)+0x44
00007ffb`71ff6b8d mscorlib_ni!System.Runtime.InteropServices.WindowsRuntime.WindowsRuntimeMarshal.ReportUnhandledError(System.Exception)+0x12d
00007ffb`885042f4 System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x73e04
00007ffb`7ee6b915 clr!ExceptionTracker::CallHandler+0xc5
00007ffb`7ee6b80b clr!ExceptionTracker::CallCatchHandler+0x7f
00007ffb`7ee6b728 clr!ProcessCLRException+0x2e6
00007ffb`9a30a7fd ntdll!RtlpExecuteHandlerForUnwind+0xd
00007ffb`9a2b36ba ntdll!RtlUnwindEx+0x366
00007ffb`7ee6d1c0 clr!ClrUnwindEx+0x40
00007ffb`7ee6d174 clr!ProcessCLRException+0x2b2
00007ffb`9a30a77d ntdll!RtlpExecuteHandlerForException+0xd
00007ffb`9a2b29fb ntdll!RtlDispatchException+0x19b
00007ffb`9a2b2668 ntdll!RtlRaiseException+0xf0
00007ffb`976c8384 KERNELBASE!RaiseException+0x68
There is a CLR Last Exception object and the exception code of it matches the record’s code:
0:006> !sos.pe
Exception object: 0000003fa2be4830
Exception type: System.NullReferenceException
Message: Object reference not set to an instance of an object.
InnerException: <none>
StackTrace (generated):
SP IP Function
0000003FBC80D190 00007FFB1F72FC18 MyBadApp!MyBadApp.Utilities.Authentication.GetAliasFromSecurityToken()+0x18
0000003FBC80D1D0 00007FFB1F72FAC2 MyBadApp! MyBadApp.MainPage.MainPage_AuthenticateUserCompleted(System.Object, System.EventArgs)+0x82
0000003FBC80D210 00007FFB1F72F5E5 MyBadApp! MyBadApp.MainPage+<AuthenticateUser_Async>d__0.MoveNext()+0x305
0000003FBC80EE60 00007FFB724F0B31 mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(System.Object)+0x4d61d1
0000003FBC80EE90 00007FFB88490523 System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x33
StackTraceString: <none>
HResult: 80004003
In this case, you can surmise that the System.NullReferenceException exception was thrown within the MyBadApp!MyBadApp.Utilities.Authentication.GetAliasFromSecurityToken() function, and that it was unhandled.
Extraction of the CLR Last Exception object can also sometimes be done in Visual Studio. When you do a Debug with Managed Only on the dump file, the Locals window sometimes contains a pseudo variable called $exception that represents the exception.
Image may be NSFW.
Clik here to view.
The Text Visualizer of the StackTrace member allows you to see the call stack.
Image may be NSFW.
Clik here to view.
Example #2
Looking at another example, we can see that again there is a single record, this time with an "Unspecified error" exception code.
0:004> .exr -1
ExceptionAddress: 73034fec (Windows_UI_Xaml!DirectUI::ErrorHelper::ProcessUnhandledError+0x000000b8)
ExceptionCode: c000027b
ExceptionFlags: 00000001
NumberParameters: 2
Parameter[0]: 0bdaf240
Parameter[1]: 00000001
0:004> dt -a1 0bdaf240 combase!PSTOWED_EXCEPTION_INFORMATION_V1
[0] @ 0bdaf240
---------------------------------------------
0x0af64034
+0x000 Header : _STOWED_EXCEPTION_INFORMATION_HEADER
+0x008 ResultCode : 80004005
+0x00c ExceptionForm : 0y01
+0x00c ThreadId : 0y000000000000000000010010011110 (0x49e)
+0x010 ExceptionAddress : (null)
+0x014 StackTraceWordSize : 4
+0x018 StackTraceWords : 5
+0x01c StackTrace : 0x0af6302c Void
+0x010 ErrorText : (null)
0:006> !error 80004005
Error code: (HRESULT) 0x80004005 (2147500037) - Unspecified error
The call stack of the record suggests that this is associated with GetNavigationState:
0:004> dpS 0x0af6302c L5
72ec4e7d Windows_UI_Xaml!DirectUI::NavigationHistory::WritePageStackEntryToString+0x1f7fde
72ec4ef0 Windows_UI_Xaml!DirectUI::NavigationHistory::GetNavigationState+0x1f7ddf
72ccd0fa Windows_UI_Xaml!DirectUI::Frame::GetNavigationStateImpl+0x3a
72cccced Windows_UI_Xaml!DirectUI::FrameGenerated::GetNavigationState+0x2f
737d00eb Windows_UI_Xaml_ni+0x2400eb
But the CLR Last Exception object doesn’t have the same exception code as the record:
0:004> !sos.pe
Exception object: 02cb3cb8
Exception type: <Unknown>
Message: <Invalid Object>
InnerException: System.Runtime.InteropServices.COMException, Use !PrintException e2a09bc6 to see more.
StackTrace (generated):
SP IP Function
052DF6C0 07141094 MyBadApp!UNKNOWN+0x544
052DF8A4 73E0D17A mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task)+0x5e
052DF8B4 73E0D115 mscorlib_ni!System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task)+0x35
052DF8C0 071409DB MyBadApp!UNKNOWN+0xb3
052DF8CC 7458458F mscorlib_ni!System.Runtime.CompilerServices.AsyncMethodBuilderCore.<ThrowAsync>b__4(System.Object)+0x33
052DF8D4 6F9EF994 System_Runtime_WindowsRuntime_ni!System.Threading.WinRTSynchronizationContext+Invoker.InvokeCore()+0x24
StackTraceString: <none>
HResult: 80131500
0:006> !error 80131500
Error code: (HRESULT) 0x80131500 (2148734208) - <Unable to get error code text>
It does however have a nested CLR Exception object that does have the same exception code as the record. It too has a call stack that indicates GetNavigationState is having an issue.
0:004> !PrintException /d 02caf968
Exception object: 02caf968
Exception type: System.Runtime.InteropServices.COMException
Message: <Invalid Object>
InnerException: <none>
StackTrace (generated):
SP IP Function
00000000 00000001 Windows_UI_Xaml_ni!Windows.UI.Xaml.Controls.Frame.GetNavigationState()+0x2
052DF778 071411B5 MyBadApp!UNKNOWN+0x1d
052DF788 07140BF3 MyBadApp!UNKNOWN+0xa3
StackTraceString: <none>
HResult: 80004005
Summary
The asynchronous and projected nature of Windows Store applications makes them significantly harder to debug than desktop applications. Knowing the error code and call stack is just the first step in understanding the root cause of a crash in a Store application. Hopefully this blog post has made those first steps easier to undertake, and that those first steps have pointed you in the right direction.
The solutions to some of the more common issues have been talked about on episodes of Channel 9 Defrag Tools. These episodes show the code changes required to avoid the hang or crash:
Clik here to view.