Tracing LoadLibrary

There are many reasons why a DLL might fail to load.

Often, it's not the DLL you're interested in that has a problem, but on of its dependencies. However, figuring out what's going on can be difficult if you don't know how to go about it.

You can get access to ntdll!LdrpDebugFlags, which is nominally a private variable ("loader private debug flags"), but is very convenient to access. It's a DWORD-sized value that controls debugger output.

For our purposes setting it to non-zero is good enough, so in windbg for example you would run ed ntdll!LdrpDebugFlags 1, and in Visual Studio you can do something similar from a Watch window.

The workflow to troubleshoot this is typically as follows.

The three most common errors are the following.

There are often errors "along the way", especially around probing for files. Usually searching for "ERROR" from the bottom of the debug spew is a good starting heuristic. You'll usually end up in a line similar to this one.

0150:040c @ 00148593 - LdrpProcessWork - ERROR: Unable to load DLL: "blargh.dll", Parent Module: "C:\foo.dll", Status: 0xc0000135

In this particular case, 0xc0000135 is STATUS_DLL_NOT_FOUND - an indication that "blargh.dll" was required by "C:\foo.dll", but the loader couldn't find it.

The last time I went down this rabbit hole was to troubleshoot some dependencies on a missing USER32.dll, when the library should have referenced an apiset by linking with an umbrella library. Using dumpbin /imports helped me realize that I had functions set up to be resolved from USER32.dll rather than ext-ms-win-rtcore-ntuser-window-l1-1-0.dll. But that's another story for another day.

Happy loader tracing!

Tags:  cppdebugging

Home