First you get the Console Debugger, then you get the power, then you get the woman…

Alrighty, here’s the situation. You deploy some code to a production or test environment and when you run it up for the first time it crashes. You spin up DebugView and you see this bad boy in the log:

[3820] System.AggregateException: One or more errors occurred. ---> System.Reflection.ReflectionTypeLoadException: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more information.

This is one of the most annoying exceptions to see on production box, especially when you don’t have access to a debugger. With a debugger you can inspect the LoaderExceptions collection and see exactly what assembly it is after but without one your options are somewhat limited.

Your simplest solution is to enable the Fusion log in order to identify binding issues. This method is described in Back to Basics: Using Fusion Log Viewer to Debug Obscure Loader Errors by Scott Hanselman. After some messing around with registry keys and scouring through log files you will get some information like:


*** Assembly Binder Log Entry (26/07/2013 @ 6:26:36 AM) ***

The operation failed.
Bind result: hr = 0x80070002. The system cannot find the file specified.

The more advanced route involves “saying hello to my little friend”. The Console Debugger.

To install the debugger download the Windows SDK setup and when executing the installer just choose the Debugging Tools:

Features

Once we have installed the CDB we can simply run it up against the problem executable and it will start spewing out debug information like so:


C:\Program Files\Windows Kits\8.0\Debuggers\x86>cdb "c:\Program Files\TestApp\TestApp.exe"

Microsoft (R) Windows Debugger Version 6.2.9200.20512 X86
Copyright (c) Microsoft Corporation. All rights reserved.

CommandLine: "c:\Program Files\TestApp\TestApp.exe"
Symbol search path is: *** Invalid ***
****************************************************************************
* Symbol loading may be unreliable without a symbol search path. *
* Use .symfix to have the debugger choose a symbol path. *
* After setting your symbol path, use .reload to refresh symbol locations. *
****************************************************************************
Executable search path is:
ModLoad: 012d0000 0137c000 TestApp.exe
ModLoad: 770b0000 771ec000 ntdll.dll
ModLoad: 71cc0000 71d0a000 C:\Windows\SYSTEM32\MSCOREE.DLL
ModLoad: 760a0000 76174000 C:\Windows\system32\KERNEL32.dll
ModLoad: 752f0000 7533b000 C:\Windows\system32\KERNELBASE.dll
(8e0.1100): Break instruction exception - code 80000003 (first chance)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for ntdll.dll -
eax=00000000 ebx=00000000 ecx=002ffab0 edx=770f7094 esi=fffffffe edi=00000000
eip=7715054e esp=002ffacc ebp=002ffaf8 iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
ntdll!LdrVerifyImageMatchesChecksum+0x633:
7715054e cc int 3
0:000>

Then we tell the CDB to break on all CLR exceptions and tell it to continue debugging.


0:000> sxe clr
0:000> g
ModLoad: 759e0000 75a80000 C:\Windows\system32\ADVAPI32.dll
ModLoad: 76370000 7641c000 C:\Windows\system32\msvcrt.dll
ModLoad: 75670000 75689000 C:\Windows\SYSTEM32\sechost.dll
ModLoad: 75ff0000 76091000 C:\Windows\system32\RPCRT4.dll
ModLoad: 71b60000 71bc7000 C:\Windows\Microsoft.NET\Framework\v4.0.30319\mscoreei.dll
ModLoad: 757c0000 75817000 C:\Windows\system32\SHLWAPI.dll
ModLoad: 756a0000 756ee000 C:\Windows\system32\GDI32.dll
ModLoad: 77210000 772d9000 C:\Windows\system32\USER32.dll
ModLoad: 75660000 7566a000 C:\Windows\system32\LPK.dll

When we break on the next exception we simply load the SOS Debugging Extension so we can have a little look inside the CLR exception:


0:000> !loadby sos clr

Then we can dump the call stack of the exception:


0:000> !clrstack
PDB symbol for clr.dll not loaded
OS Thread Id: 0x1100 (0)
Child SP IP Call Site
002ff0d8 752f812f [HelperMethodFrame: 002ff0d8]
002ff128 63cf4119 System.Resources.ManifestBasedResourceGroveler.HandleResourceStreamMissing(System.String)
002ff150 63f6990b System.Resources.ManifestBasedResourceGroveler.GrovelForResourceSet(System.Globalization.CultureInfo,
System.Collections.Generic.Dictionary`2<System.String,System.Resources.ResourceSet>, Boolean, Boolean, System.Threading.
StackCrawlMark ByRef)
002ff1c0 6363cf75 System.Resources.ResourceManager.InternalGetResourceSet(System.Globalization.CultureInfo, Boolean, Boo
lean, System.Threading.StackCrawlMark ByRef)
002ff228 6363cd31 System.Resources.ResourceManager.InternalGetResourceSet(System.Globalization.CultureInfo, Boolean, Boo
lean)
002ff244 63c364c7 System.Resources.ResourceManager.GetObject(System.String, System.Globalization.CultureInfo, Boolean)
002ff294 63675bc9 System.Resources.ResourceManager.GetObject(System.String)
002ff298 007e1493 DevExpress.Skins.SkinManager.RegisterBySkinInfo(System.Reflection.Assembly, System.String, Boolean)
002ff2e4 007e12e6 DevExpress.Skins.SkinManager.RegisterAssembly(System.Reflection.Assembly)
002ff2f8 007e086d TestApp.Program.LoadAllSkins()
002ff340 007e00f2 TestApp.Program.Main(System.String[])
002ff5b8 641d21bb [GCFrame: 002ff5b8]

Or even print the exception itself:


0:000> !printexception
Exception object: 01fb33a4
Exception type: System.Resources.MissingManifestResourceException
Message: Could not find any resources appropriate for the specified culture or the neutral culture. Make sure
"InfoBlob.resources" was correctly embedded or linked into assembly "Themes" at compile time, or that all the sat
ellite assemblies required are loadable and fully signed.
InnerException: <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80131532

However this isn’t the exception we are looking for so we continue to run the process and inspect the exceptions until we find the AggregateException that is causing the problem:


First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=08dced50 ebx=00000005 ecx=00000005 edx=00000000 esi=08dcedfc edi=0633e268
eip=752f812f esp=08dced50 ebp=08dceda0 iopl=0 nv up ei pl nz ac pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000216
KERNELBASE!RaiseException+0x54:
752f812f c9 leave
0:014> !printexception
Exception object: 027d06b8
Exception type: System.Reflection.ReflectionTypeLoadException
Message: Unable to load one or more of the requested types. Retrieve the LoaderExceptions property for more inf
ormation.
InnerException: <none>
StackTrace (generated):
<none>
StackTraceString: <none>
HResult: 80131602

Now that we have the exception we can simply dump the object with !dumpobj and the address of the object it gave you in !printexception:


0:014> !dumpobj 027d06b8
Name: System.Reflection.ReflectionTypeLoadException
MethodTable: 637082d8
EEClass: 6344aa18
Size: 92(0x5c) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
MT Field Offset Type VT Attr Value Name
6371fba0 400004b 4 System.String 0 instance 00000000 _className
637203e8 400004c 8 ...ection.MethodBase 0 instance 00000000 _exceptionMethod
6371fba0 400004d c System.String 0 instance 00000000 _exceptionMethodString
6371fba0 400004e 10 System.String 0 instance 027d0818 _message
637141f8 400004f 14 ...tions.IDictionary 0 instance 00000000 _data
6371fe00 4000050 18 System.Exception 0 instance 00000000 _innerException
6371fba0 4000051 1c System.String 0 instance 00000000 _helpURL
6371f7dc 4000052 20 System.Object 0 instance 00000000 _stackTrace
6371f7dc 4000053 24 System.Object 0 instance 00000000 _watsonBuckets
6371fba0 4000054 28 System.String 0 instance 00000000 _stackTraceString
6371fba0 4000055 2c System.String 0 instance 00000000 _remoteStackTraceString
63722b6c 4000056 3c System.Int32 1 instance 0 _remoteStackIndex
6371f7dc 4000057 30 System.Object 0 instance 00000000 _dynamicMethods
63722b6c 4000058 40 System.Int32 1 instance -2146232830 _HResult
6371fba0 4000059 34 System.String 0 instance 00000000 _source
6371ac20 400005a 44 System.IntPtr 1 instance 0 _xptrs
63722b6c 400005b 48 System.Int32 1 instance -532462766 _xcode
636da490 400005c 4c System.UIntPtr 1 instance 0 _ipForWatsonBuckets
636d9a7c 400005d 38 ...ializationManager 0 instance 027d0904 _safeSerializationManager
636d6e1c 40010ec 50 System.Object[] 0 instance 027cf09c _classes
636d6e1c 40010ed 54 System.Object[] 0 instance 027d06a4 _exceptions

As we are really interested in the LoaderExceptions we need to dump the array of exception at the address specified in the previous step:


0:014> !dumparray 027d06a4
Name: System.Exception[]
MethodTable: 636d6e1c
EEClass: 63459698
Size: 20(0x14) bytes
Array: Rank 1, Number of elements 1, Type CLASS
Element Methodtable: 6371fe00
[0] 027cff6c

In this case the array had one item in it and we now have the address of this object to dump:


0:014> !dumpobj 027cff6c
Name: System.IO.FileNotFoundException
MethodTable: 63714ae0
EEClass: 63451e34
Size: 96(0x60) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
Fields:
MT Field Offset Type VT Attr Value Name
6371fba0 400004b 4 System.String 0 instance 00000000 _className
637203e8 400004c 8 ...ection.MethodBase 0 instance 00000000 _exceptionMethod
6371fba0 400004d c System.String 0 instance 00000000 _exceptionMethodString
6371fba0 400004e 10 System.String 0 instance 027d044c _message
637141f8 400004f 14 ...tions.IDictionary 0 instance 00000000 _data
6371fe00 4000050 18 System.Exception 0 instance 00000000 _innerException
6371fba0 4000051 1c System.String 0 instance 00000000 _helpURL
6371f7dc 4000052 20 System.Object 0 instance 00000000 _stackTrace
6371f7dc 4000053 24 System.Object 0 instance 00000000 _watsonBuckets
6371fba0 4000054 28 System.String 0 instance 00000000 _stackTraceString
6371fba0 4000055 2c System.String 0 instance 00000000 _remoteStackTraceString
63722b6c 4000056 3c System.Int32 1 instance 0 _remoteStackIndex
6371f7dc 4000057 30 System.Object 0 instance 00000000 _dynamicMethods
63722b6c 4000058 40 System.Int32 1 instance -2147024894 _HResult
6371fba0 4000059 34 System.String 0 instance 00000000 _source
6371ac20 400005a 44 System.IntPtr 1 instance 0 _xptrs
63722b6c 400005b 48 System.Int32 1 instance -532462766 _xcode
636da490 400005c 4c System.UIntPtr 1 instance 0 _ipForWatsonBuckets
636d9a7c 400005d 38 ...ializationManager 0 instance 027cffcc _safeSerializationManager
6371fba0 4002021 50 System.String 0 instance 00000000 _maybeFullPath
6371fba0 400203d 54 System.String 0 instance 027cf2d4 _fileName
6371fba0 400203e 58 System.String 0 instance 027cf36c _fusionLog

Then we want to find the address of the exception message. This address is found in the Value column and we once again use !dumpobj to look at its contents:


0:014> !dumpobj 027d044c
Name: System.String
MethodTable: 6371fba0
EEClass: 63458bb0
Size: 362(0x16a) bytes
File: C:\Windows\Microsoft.Net\assembly\GAC_32\mscorlib\v4.0_4.0.0.0__b77a5c561934e089\mscorlib.dll
String: Could not load file or assembly 'TestApp.Common, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null' or
one of its dependencies. The system cannot find the file specified.
Fields:
MT Field Offset Type VT Attr Value Name
63722b6c 4000103 4 System.Int32 1 instance 174 m_stringLength
63721fbc 4000104 8 System.Char 1 instance 43 m_firstChar
6371fba0 4000105 8 System.String 0 shared static Empty
>> Domain:Value 004111b0:01f81228 <<

We now know the specific assembly it was looking for and had recorded in its LoaderExceptions property. You now know which assembly to include and you’re looking more baller than LeBron.

As mentioned earlier in this post, there are alternative ways to find missing dependencies at runtime but the potential uses of the Console Debugger as a lightweight debugging platform are limitless.

Leave a Reply

Your email address will not be published. Required fields are marked *