In this post I'll try to clarify some small details, that are related to debugging a user-mode process (focusing on a UMDF driver) using a kernel-mode debugger. So, the setup is that we have a test computer, where the UMDF echo driver is running and another computer, where windbg is running and we're using it as a kernel-mode debugger. A first thing to do in our case would be to see what modules are loaded:
kd> lmstart end module name81800000 81b95000 nt (export symbols) ntkrnlmp.exeUnloaded modules:85dac000 85db4000 drmkaud.sys85ce8000 85cf5000 crashdmp.sys82a05000 82a10000 dump_ataport.sys85d94000 85d9c000 dump_atapi.sys85c27000 85c38000 dump_dumpfve.sys8d618000 8d632000 serial.sys88020000 88029000 kbdhid.sys88e52000 88e65000 i8042prt.sys88e63000 88e78000 WUDFRd.sys880aa000 880b0000 nothing.sys
Ok, that's interesting. Just with a first a look it seems that only the kernel is loaded and that there are a few unloaded modules. This view is deceiving, though. Let's reload symbols and try again:
kd> .reload /fConnected to Windows Vista 6000 x86 compatible target, ptr64 FALSELoading Kernel Symbols........................Loading User SymbolsLoading unloaded module list..........kd> lmstart end module name81800000 81b95000 nt (pdb symbols) c:\Debuggers\sym\ntkrnlmp.pdb\E556D3F077BB42BB83B132247BE9C4942\ntkrnlmp.pdb81b95000 81bc9000 hal (pdb symbols) c:\Debuggers\sym\halmacpi.pdb\AE84FF5D9CEE4D64927E629F756036841\halmacpi.pdb82004000 82012000 PCIIDEX (pdb symbols) c:\Debuggers\sym\pciidex.pdb\0A98C6B81AB842C483351BCA042A9B1A1\pciidex.pdb82012000 82019000 intelide (pdb symbols) c:\Debuggers\sym\intelide.pdb\BFCA935B0A6B47C2AA4B9F25100409F11\intelide.pdb82019000 82029000 mountmgr (pdb symbols) c:\Debuggers\sym\mountmgr.pdb\6F08CCFAE97F4F139853B1769DAB0CF31\mountmgr.pdb82029000 82038000 volmgr (pdb symbols) c:\Debuggers\sym\volmgr.pdb\3C43C06A961143719A6DF9F0B2A9699C1\volmgr.pdb82038000 8205d000 pci (pdb symbols) c:\Debuggers\sym\pci.pdb\A5E895C861984D7393087EB0459E7FE01\pci.pdb... [output has been truncated] ...
94b78000 94b8c680 WUDFRd (pdb symbols) c:\Debuggers\sym\WUDFRd.pdb\D92A3D77AEBE4FFE8EE42628096819371\WUDFRd.pdb
Ok, this seems more promising. The symbols have been loaded and we now see many more modules. We also see that the reflector (WUDFRd) is loaded. However, where is our UMDF driver? Now it's time to go back to some theory. The UMDF driver is actually a user-mode process. When you break into a kernel-mode debugger, you just break into an arbitrary process. Which one? The !process command will show us.
kd> !processPROCESS 818eff00 SessionId: none Cid: 0000 Peb: 00000000 ParentCid: 0000 DirBase: 00122000 ObjectTable: 85800178 HandleCount: 593. Image: Idle VadRoot 00000000 Vads 0 Clone 0 Private 0. Modified 215. Locked 0. DeviceMap 00000000 Token 858037d8 ElapsedTime 00:00:00.000 UserTime 00:00:00.000 KernelTime 00:00:00.000 QuotaPoolUsage[PagedPool] 0 QuotaPoolUsage[NonPagedPool] 0 Working Set Sizes (now,min,max) (4, 50, 450) (16KB, 200KB, 1800KB) PeakWorkingSetSize 0 VirtualSize 0 Mb PeakVirtualSize 0 Mb PageFaultCount 0 MemoryPriority BACKGROUND BasePriority 0 CommitCharge 0 THREAD 818efac0 Cid 0000.0000 Teb: 00000000 Win32Thread: 00000000 RUNNING on processor 0So, I'm debugging the idle thread. Now it's time to switch to the echo driver. In order to do that, we need to find all the process and search for wudfhost.exe.
kd> !process 0 0 WUDFHost.exePROCESS 85709738 SessionId: 0 Cid: 0624 Peb: 7ffde000 ParentCid: 03d8 DirBase: 1ba3d000 ObjectTable: 93a5cd40 HandleCount: 161. Image: WUDFHost.exe
Ok, now that I've found the process that I need to connect to, I need to switch to it. However, it's not enough just to do a
.process 85709738
This would just tell windbg to change just the debugger context, i.e. show what's going on in that process (e.g. the stack), however remain in the context of the idle process. If we put breakpoints, then they will be set in the idle process and NOT in the process that we want to debug! We need to do a context switch to that process.
So, one way to do this is:
kd> .process /i 85709738You need to continue execution (press 'g' <enter>) for the context to be switched. When the debugger breaks in again, you will be in the new process context.kd> gBreak instruction exception - code 80000003 (first chance)nt!RtlpBreakWithStatusInstruction:818356e8 cc int 3
However, as my friend Patrick (the debugging guru) told me: with the /i switch you have to think about the possible traps of releasing the system for the context switch to happen. After you press "g", you have to wait for the windows scheduler to do the context switch. And while the process is being brought in to context, you also have to think you’re releasing the system. On a single hardware thread execution machine, switching in to the process context won’t cause any issues (hopefully), but what about when you get in to an SMP / Multicore environment? The context switch happens and the flagged process is locked, so nothing is scheduled from that process, but what about all those other threads in queue?
So, the best option here is to do
kd> .process /r /p 85709738
In this case, the debugger does the context switch immediately (as opposed to the windows scheduler) and there is no waiting time.
Anyway, now we're in the correct context. Let's see what's loaded:
kd> lmstart end module name00f60000 00f86000 WUDFHost (pdb symbols) c:\Debuggers\sym\WUDFHost.pdb\AEC9577097EE46CAAE1D12CDA87064E61\WUDFHost.pdb73c80000 73c87000 WUDFEchoDriver (export symbols) WUDFEchoDriver.dll73d00000 73d50000 WUDFx (pdb symbols) c:\Debuggers\sym\WUDFx.pdb\A416B8E3114F4EA4BE1EAC879505D2771\WUDFx.pdb74460000 74491000 WUDFPlatform (pdb symbols) c:\Debuggers\sym\WUDFPlatform.pdb\2BA7585C1C874EBBB9B082D649DFD80F1\WUDFPlatform.pdb
[... snip ...]8270d000 8271f000 WUDFPf (pdb symbols) c:\Debuggers\sym\WUDFPf.pdb\98F0D4EDE42944CF8C87B11DD7985EC41\WUDFPf.pdb94b78000 94b8c680 WUDFRd (pdb symbols) c:\Debuggers\sym\WUDFRd.pdb\D92A3D77AEBE4FFE8EE42628096819371\WUDFRd.pdb
Ok, now I can see my echo driver (WUDFEchoDriver.dll). If the symbols are not loaded, then a .reload /f would fix everything. Of course, if there are many WudfHost.exe processes that are running (i.e. you are using many UMDF drivers), then you might have to search for your driver (i.e. WUDFEchoDriver.dll) in the list of loaded modules and if it's not there, then you'll have to switch to another instance of WudfHost.exe.
Now it's time to do some debugging. The UMDF extension is called wudfext. Let's try and see, if it's loaded:
kd> !wudfext.helpThe call to LoadLibrary(wudfext) failed, Win32 error 0n2 "The system cannot find the file specified."Please check your debugger configuration and/or network access.
No it's not... Ok, let's see what's loaded:
kd> .chainExtension DLL search Path: c:\Debuggers\WINXP;c:\Debuggers\winext;c:\Debuggers\winext\arcade;c:\Debuggers\pri;c:\Debuggers;c:\Debuggers\winext\arcade;Extension DLL chain: c:\Debuggers\winext\wdfkd: image 6.0.6001.16470, API 1.0.0, built Sun Feb 25 04:47:28 2007 [path: c:\Debuggers\winext\wdfkd.dll] dbghelp: image 6.7.0004.0, API 6.0.6, built Thu Mar 15 10:39:24 2007 [path: c:\Debuggers\dbghelp.dll] ext: image 6.7.0004.0, API 1.0.0, built Thu Mar 15 10:39:14 2007 [path: c:\Debuggers\winext\ext.dll] exts: image 6.7.0004.0, API 1.0.0, built Thu Mar 15 10:38:51 2007 [path: c:\Debuggers\WINXP\exts.dll] kext: image 6.7.0004.0, API 1.0.0, built Thu Mar 15 10:38:58 2007 [path: c:\Debuggers\winext\kext.dll] kdexts: image 6.0.6001.16470, API 1.0.0, built Thu Mar 15 10:58:28 2007 [path: c:\Debuggers\WINXP\kdexts.dll]
I know that my extension is in the WDK at, C:\WinDDK\6001\bin\x86\wudfext.dll. Let's load it:
kd> !load C:\WinDDK\6001\bin\x86\wudfext.dllkd> .chainExtension DLL search Path: c:\Debuggers\WINXP;c:\Debuggers\winext;c:\Debuggers\winext\arcade;c:\Debuggers\pri;c:\Debuggers;c:\Debuggers\winext\arcadeExtension DLL chain: C:\WinDDK\6001\bin\x86\wudfext.dll: image 6.0.6001.17138, API 1.0.0, built Thu Jan 17 23:39:16 2008 [path: C:\WinDDK\6001\bin\x86\wudfext.dll] c:\Debuggers\winext\wdfkd: image 6.0.6001.16470, API 1.0.0, built Sun Feb 25 04:47:28 2007 [path: c:\Debuggers\winext\wdfkd.dll] dbghelp: image 6.7.0004.0, API 6.0.6, built Thu Mar 15 10:39:24 2007 [path: c:\Debuggers\dbghelp.dll] ext: image 6.7.0004.0, API 1.0.0, built Thu Mar 15 10:39:14 2007 [path: c:\Debuggers\winext\ext.dll] exts: image 6.7.0004.0, API 1.0.0, built Thu Mar 15 10:38:51 2007 [path: c:\Debuggers\WINXP\exts.dll] kext: image 6.7.0004.0, API 1.0.0, built Thu Mar 15 10:38:58 2007 [path: c:\Debuggers\winext\kext.dll] kdexts: image 6.0.6001.16470, API 1.0.0, built Thu Mar 15 10:58:28 2007 [path: c:\Debuggers\WINXP\kdexts.dll]
Ok, it seems to be loaded. Let's try and use it:
It's not working! Why's that? Notice that .chain mentions wudfext.dll with the full path, whereas everything else just uses the filename without the extension. Let's try the full name:
kd> !C:\WinDDK\6001\bin\x86\wudfext.dll.helpHelp for host process debug extension: umdevstacks [flags] - This dumps all the device stacks in the host process. umdevstack <address> [flags] - This dumps detailed info on each device stack. umirps - This dumps UM Irps in the host process.[... the rst of the output is truncated ...]
Ok, so it's loaded indeed. If I try and use an extension directly, then it works:
kd> !umirpsNumber of pending IRPS: 0x0#### CWudfIrp Current Type UniqueId KernelIrp---- ---------------- ----------------------------------- ---------------- ---------However, if there are extensions with the same name (e.g. !help) in other files, this is a problem. Let's make it easier to use:
kd> !unload C:\WinDDK\6001\bin\x86\wudfext.dllUnloading C:\WinDDK\6001\bin\x86\wudfext.dll extension DLLkd> .extpath+ C:\WinDDK\6001\bin\x86Extension search path is: c:\Debuggers\WINXP;c:\Debuggers\winext;c:\Debuggers\winext\arcade;c:\Debuggers\pri;c:\Debuggers;c:\Debuggers\winext\arcade;C:\WinDDK\6001\bin\x86kd> !load wudfext
kd> .chainExtension DLL search Path:c:\Debuggers\WINXP;c:\Debuggers\winext;c:\Debuggers\winext\arcade;c:\Debuggers\pri;c:\Debuggers;c:\Debuggers\winext\arcade;C:\WinDDK\6001\bin\x86Extension DLL chain: wudfext: image 6.0.6001, API 1.0.0, built Thu Jan 17 23:39:16 2008 [path: C:\WinDDK\6001\bin\x86\wudfext.dll]kd> !wudfext.helpHelp for host process debug extension: umdevstacks [flags] - This dumps all the device stacks in the host process. umdevstack <address> [flags] - This dumps detailed info on each device stack. umirps - This dumps UM Irps in the host process.[... the rest of the output is truncated ...]
Ok, so now it works. As a final note, just remember that the UMDF extension should be from the same WDK as the UMDF framework, e.g. if you're using UMDF 1.7 RC1, then wudfext should be 1.7 RC1. The driver can be compiled with any framework version (as long as the major version of UMDF on the machine is the same as the one that the driver was compiled with and the minor version of the running UMDF is greater or equal to the driver's). So, the UMDF extension doesn't have to be the same as the version of the framework that the driver was compiled with.