Debugger commands (!drvobj, !devobj, !podev, !devstack) that make my life easier (part 1)

Over the next few days I'll talk about different debugger commands which I use to make driver development easier, especially when debugging my driver.  Today I'll talk about how to find your driver, the devices you created and any device object that any other driver has created.  The commands I'll cover today are

!drvobj
!devobj
!podev
!devstack

"!drvobj Driver Name | PDRIVER_OBJECT pointer" will list all of the devices that a driver has created.  I typically invoke this call with "!drvobj Driver Name."  For instance,

0: kd> !drvobj \Driver\i8042prt
Driver object (82158040) is for:
\Driver\i8042prt
Driver Extension List: (id , addr)

Device Object list:
8213c3d0 82153738 

Once you have a list of devices, you can pass a device pointer to either !devobj or !devstack to get more information.  !devobj will work for any type of device object and will give the device name, device extenion, current irp (for StartIo) and lot more information.

0: kd> !devobj 8213c3d0
Device object (8213c3d0) is for:
\Driver\i8042prt DriverObject 82158040
Current Irp 00000000 RefCount 0 Type 00000027 Flags 00002004
DevExt 8213c488 DevObjExt 8213c768
ExtensionFlags (0xe0000000) DOE_RAW_FDO, DOE_BOTTOM_OF_FDO_STACK,
DOE_DESIGNATED_FDO
AttachedDevice (Upper) 8213c250 \DRIVER\VERIFIER
AttachedTo (Lower) 8213c820 \DRIVER\VERIFIER
Device queue is not busy.

If the device is a pnp device object (FDO, PDO, filter, doesn't matter), !devstack will show you the entire stack of devices.  This can give you a better picture of the environment that your device is executing in.  In the following example, I am dumping the device which controsl the PS2 mouse.  Furthermore, the device stack is being verifier by driver verifier which is why you see the 2 device objects created by \Driver\VERIFIER.

0: kd> !devstack 8213c3d0
!DevObj !DrvObj !DevExt ObjectName
8213b030 \Driver\Mouclass 8213b0e8 PointerClass0
8213c250 \DRIVER\VERIFIER 8213c308
> 8213c3d0 \Driver\i8042prt 8213c488
8213c820 \DRIVER\VERIFIER 8213c8d8
822923e8 \Driver\ACPI 822b2270 00000050
!DevNode 8228f4c8 :
DeviceInst is "ACPI\PNP0F13\4&1506bb2e&0"
ServiceName is "i8042prt"

Using either !devobj or !devstack, you can get your device extension and then dump it. This is useful if you have a BSOD where you know your driver is at fault, but the callstack itself does not have any backpointers to your device or the needed context.

0: kd> dt 8213c488 i8042prt!_PORT_MOUSE_EXTENSION
+0x000 Self : 0x8213c3d0 _DEVICE_OBJECT
+0x004 InterruptObject : 0x81f44bb0 _KINTERRUPT
+0x008 InterruptSpinLock : 0
+0x00c TopOfStack : 0x8213c820 _DEVICE_OBJECT
+0x010 PDO : 0x822923e8 _DEVICE_OBJECT
[...]

Finally, if you have a pnp device object, you can see the information that power maintains on your device object by running !podev.  In the following example, I ran !podev when an Sx irp was being sent to the mouse stack (by setting a bp on i8042prt!I8xPower)

1: kd> !podev 0x8213c3d0
Device object is for:
DriverObject 82158040
Current Irp 00000000 RefCount 0 Type 00000000 AttachedDev 8213c250 DevFlags 00002004 DO_POWER_PAGABLE
Device queue is not busy.
Device Object Extension: 8213c768:
PowerFlags: 00000110 =>SystemState=0 DeviceState=1 syact
Dope: 00000000:

For instance, if your driver calls PoSetPowerState() properly for each S and D irp, the PowerFlags will indicate the current S and D state of the device (i8042prt only calls it for D irps).  PowerFlags also can tell you if there is an S or D irp active on your device (unfortunately, not the PIRP value itself which would be useful); in this case, there is an S irp active as indicated by the "sysact" output.  By continuing on and keeping the same breakpoint, I can see when a device power irp is active

1: kd> !podev 0x8213c3d0
[...]
PowerFlags: 00000410 =>SystemState=0 DeviceState=1 dvact