Environment Windows Server R2 64 bit. The app is compiled for x86 and running as a 32 bit app.
- lm e
This listed modules which had errors.
- reload -f
Force a reload of all modules. Noticed none of them were loading from my path.
- Hooked up SysInternals Process Monitor filtered to just my process name and just disk activity. cleared the output right before doing reload -f
NOticed it was attempting to load modules from the same directory I was running from.
- restarted the application
- !sym noisy
To noisy load symbols.
DBGHELP: SymSrv load failure: symsrv.dllDBGHELP: wntdll.pdb - file not found*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\SysWOW64\ntdll.dll -DBGHELP: ntdll - export symbolsDBGHELP: wuser32.pdb - file not found*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\syswow64\USER32.dll -DBGHELP: USER32 - export symbolsDBGHELP: System.Windows.Forms.pdb - file not found*** WARNING: Unable to verify checksum for C:\Windows\assembly\NativeImages_v2.0.50727_32\System.Windows.Forms\fedf1ba58dced4f0b3f8c457648ceed9\System.Windows.Forms.ni.dll*** ERROR: Module load completed but symbols could not be loaded for C:\Windows\assembly\NativeImages_v2.0.50727_32\System.Windows.Forms\fedf1ba58dced4f0b3f8c457648ceed9\System.Windows.Forms.ni.dllDBGHELP: System_Windows_Forms_ni - no symbols loaded
- Copied symsrv.dll into my local directory even though it is already in the app path.
- Restarted, !sym noisy, .reload
- Filter Process monitor where the path ends in symsrv.dll
Noticed the process is trying to load symsrv.dll from C:\Windows\SysWOW64\
- Copied symsrv.dll to C:\Windows\SysWOW64
- restarted, !sym noisy, .reload
Shows dbghelp.dll is loaded from c:\Windows\system32\dbghelp.dll
MSDN writes symsrv must be installed in the same directory as the copy of dbghelp.dll being loaded.
- .extpath C:\Program Files (x86)\Debugging Tools for Windows (x86)\
sets dbgeng's extension search path to where symsrv.dll is.
dbghelp.dll is still loaded from the system32 directory.
- Prior to running the debugger I set the environmental variable _NT_DEBUGGER_EXTENSION_PATH to C:\Program Files (x86)\Debugging Tools for Windows (x86)\
- Restart, .chain
dbghelp is loaded from the correct directory! but symsrv.dll is still broken :(
Looking at the stack in Process monitor shows dbgeng.dll is being loaded from C:\Windows\SysWOW64\dbgeng.dll which calls dbghelp.dll in the same directory.
Changing process monitor to filter for requests ending in dbgeng.dll shows when the program runs it is looking in the executing applications directory for the dll, not finding it, and then loading it from C:\Windows\SysWOW64\dbgeng.dll
- Head over to pinvoke.net to grab the loadlibrary signature and put it in my application.
[DllImport("kernel32", SetLastError = true)]static extern IntPtr LoadLibrary(string lpFileName);
- Call LoadLibrary from C# prior to loading my debugger and now the correct dll is bing loaded, but the debugging commands don't return any values :(
- Reading the LoadLibrary documentation and then the dll search order documentation I think calling SetDllDirectory may do what I want.
- Back to pinvoke.net to grab this signature
[DllImport("kernel32.dll", SetLastError=true)]static extern bool SetDllDirectory(string lpPathName);
- Call SetDllDirectory prior to loading up the debugger and everything now works as expected!
Here is the code:
internal static class UnsafeNativeMethods
[DllImport("kernel32.dll", SetLastError = true)]
internal static extern bool SetDllDirectory(string lpPathName);
public static class Utility
public static void ProvideWindbgInstallationDirectory(string path)
if (Directory.Exists(path) == false)
throw new DirectoryNotFoundException(path);
#warning add a check that the files we want exist. maybe even that they are the correct version?
bool setPath = UnsafeNativeMethods.SetDllDirectory(path);
if (setPath == false)
int error = Marshal.GetLastWin32Error();
throw new InvalidOperationException("Setting the installation directory failed with error code: " + error.ToString());