Gdi Debug From The Windows NT Source Code Leak
Gdi Debug From The Windows NT Source Code Leak
Gdi Debug From The Windows NT Source Code Leak
Ori Gershony
13/08/1998 02:16:00
Table of Contents
Table of Contents.................................................................................................2
Introduction........................................................................................................3
Random things that are good to know…..................................................................3
Bugchecks and access violations............................................................................4
Alpha Debugging..................................................................................................5
Alpha .cod Files...................................................................................................8
Critical Section Timeout........................................................................................9
Pool/Virtual Memory problems.............................................................................13
Debugger Handy Hints™.....................................................................................13
GDI Debugger Extensions....................................................................................15
Example Debugging session with DDraw surfaces...................................................31
A couple of hints for debugging Hydra...................................................................37
How to Debug Bugcheck AB (SESSION_HAS_VALID_PAGES)...................................38
Introduction
This document contains a series of hints that are particularly useful for debugging GDI
problems. It is not intended as a general introduction to NT kernel mode debugging,
nor is it intended to be a replacement to newcomer.doc. Below is a list of places you
can go to obtain more information:
http://ntstress – The NtStress homepage. Lots of useful information and links including
NT debugging documentation (both user mode and kernel mode), bugcheck references,
list of owners for pooltags and list of owners for NT components.
http://ntbld – The NT build lab homepage. This page contains the beginner’s
introduction to NT, in addition to other useful build related information.
Inside Windows NT, Second Edition by David Solomon is a very useful book to read
(particularly chapter 5 on the memory manager).
idw\srch.exe is a useful front end to an index server which indexes the entire NT
codebase. It allows you to quickly search for where functions are defined and used
(useful for other components you’re not familiar with).
.cod files: show the assembly code generated for blocks of source code. To
generate, go to the directory containing the sources file (usually the daytona
directory), and type “nmake foo.cod” (to generate .cod file for foo.cxx)
When building code or .cod files set NTDEBUG=cvp for checked build or set
NTDEBUG= for free build.
Single proc x86 test machines will ALWAYS report bad checksum/timestamp for
win32k.sys. You can ignore IF you unassemble a few functions and verify that the
symbols look good.
Trying to connect to a remote when the domain servers are down or access is
denied: net use \\machinename\ipc$ /u:\\machinename\Administrator “”
where machine name is the name of the debugger machine. If the administrator
password is not NULL (happends very rarely), you can obtain it from the machine
owner.
In the debugger, “;$” can be used to start a comment. Use it often to identify
values, memory locations, etc. It is most useful when scrolling back in the session
trying to remember which of the hex numbers is the specific surface pointer you’re
looking for, etc.
A bugcheck occurs when the system encounters an unrecoverable error and cannot
continue to run. Programmatically, this is accomplished via a call to KeBugCheckEx.
The first argument to KeBugCheckEx is the bugcheck code, which describes the failure.
The other arguments are sometimes used to provide additional information. The file
\nt\private\genx\ntos\nls\bugcodes.txt contains a list of all the bugchecks along with
explanations of the causes.
One common cause of bugchecks is accessing invalid memory. This can lead to
bugcheck 50 (PAGE_FAULT_IN_NONPAGED_AREA), or bugcheck 3B
(SYSTEM_SERVICE_EXCEPTION), or sometimes bugcheck A
(IRQL_NOT_LESS_OR_EQUAL – specifically, this one happens when drivers try to
access pageable memory when their IRQL level is too high). When an access violation
happens, the operating system generates a trap frame describing the CPU state at the
time of the failure (i.e. the values of the registers). The !trap debugger extension helps
to interpret this information, though the usage details are slightly different between x86
and alpha.
x86 – Type “kv” to get the trap frame number, and then “!trap <trap frame number>”
to view the trap frame
kd> kv
ChildEBP RetAddr Args to Child
f3e90df0 804255b7 00000003 00000000 00000000 ntoskrnl!RtlpBreakWithStatusInstruction (FPO:
[1,0,0])
f3e90e20 804258bd 00000003 c03dff0c 80014d90 ntoskrnl!KiBugCheckDebugBreak+0x31(FPO: [Non
Fpo]
f3e91180 8043d271 00000050 f7fc3000 00000000 ntoskrnl!KeBugCheckEx+0x111(FPO: [NonFpo]
f3e911c0 80457cf3 00000000 f7fc3000 00000000 ntoskrnl!MmAccessFault+0x54d(FPO: [NonFpo]
f3e911c0 80450773 00000000 f7fc3000 00000000 ntoskrnl!KiTrap0E+0xc3 (FPO: [0,0] TrapFrame @
f3e911d8)
f3e91254 a011a6ce e22d0068 f7fc3000 00000172 ntoskrnl!memmove+0x33(FPO: [NonFpo]
f3e91278 a00384b8 00000038 f3e91730 00000000 win32k!vSrcCopyS16D16Identity+0x49(FPO: [Non
Fpo]
f3e91468 a004de9b e22cb010 e125acd8 00000000 win32k!EngCopyBits+0x488(FPO: [NonFpo]
f3e91674 f7fdd51e f3e91700 e1260008 00000000 win32k!EngStretchBlt+0x65b(FPO: [NonFpo]
f3e91a60 a00dcc79 e20fbd78 e216dcf8 00000000 mga64!DrvStretchBlt+0x65e (FPO: [EBP
0xe20fbd78] [11,235,4])
e20fbd78 16050674 e125b000 e125a008 000000b9 win32k!EngStretchBltROP+0x311(FPO: [NonFpo]
kd> !trap f3e911d8
eax=f7fc3172 ebx=e22d0068 ecx=0000005c edx=00000002 esi=f7fc3000 edi=e22d0068
eip=80450773 esp=f3e9124c ebp=f3e91254 iopl=0 nv up ei pl nz na pe nc
vip=0 vif=0
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010202
ErrCode = 00000000
80450773 f3a5 rep movsd
Alpha – Type “kb” to view the stack trace. The trap frame number is the Callee-SP
value of the exception handling routine (the one immediately following the routine that
caused the exception—this is sometimes ntoskrnl!KiMemoryManagementException).
Then type “!trap <trap frame number>” as you would in the x86 case.
EXAMPLE HERE
Alpha Debugging
Alpha debugging is usually a bit more difficult than x86 debugging, mostly because
arguments are passed in registers instead of on the stack. Here is some information
that might be useful while debugging Alpha machines.
Register usage:
a0-a5: The first 6 arguments in a function call are stored in registers a0-a5. When
calling a c++ method, the this pointer is passed in register a0 (i.e. register a1 contains
argument 1, etc.). In contrast, on the x86 arguments are passed on the stack, but the
this pointer is passed in ecx.
This is sometimes difficult and not always possible, but can be done effectively most of
the time with a little bit of work. One of the following heuristics works most of the
time:
(and since the saved register hasn’t changed since the move happened, the value
you see on the stack is the one that was passed in the argument register)
Example:
kb
CalleeSP Arguments to Callee Call Site
edc7ec90 : 00000001 00000001 81a90000 00000001 ntkrnlmp!DbgBreakPoint+0x4
edc7ec90 : 00000001 00000001 81a90000 00000001 win32k!DoRip+0x38
edc7eca0 : 00000001 00000001 81a90000 00000001 win32k!PDEVOBJ__vAssertDynaLock+0xe8
edc7ecb0 : 00000001 00000001 81a90000 00000001 win32k!PDEVOBJ__ppfn+0x38
edc7ecd0 : 00000001 00000001 81a90000 00000001 win32k!BRUSHOBJ_pvGetRbrush+0x44
edc7ecf0 : 00000001 00000001 81a90000 00000001 mga!DrvBitBlt+0x678
edc7f0d0 : 00000001 00000001 81a90000 00000001 mga!DbgBitBlt+0x84
edc7f120 : 00000001 00000001 81a90000 00000001 win32k!OffBitBlt+0x110
edc7f1a0 : 00000001 00000001 81a90000 00000001 win32k!MulBitBlt+0x52c
edc7f300 : 00000001 00000001 81a90000 00000001 win32k!GrePatBltLockedDC+0x2ac
edc7f390 : 00000001 00000001 81a90000 00000001 win32k!GrePolyPatBltInternal+0x28c
edc7f4e0 : 00000001 00000001 81a90000 00000001 win32k!NtGdiFlushUserBatch+0x210
edc7f5c0 : 00000001 00000001 81a90000 00000001 ntkrnlmp!KiSystemServiceRepeat+0x8c
0257f460 : 00000001 00000001 81a90000 00000001 gdi32!SelectObject+0x320
0257f490 : 00000001 00000001 81a90000 00000001 user32!xxxBNPaint+0x314
0257f4e0 : 00000001 00000001 81a90000 00000001 user32!ButtonWndProcWorker+0xcf4
0257f590 : 00000000 00000001 81a90000 00000001 user32!_fnDWORD+0x2c
0257f5b0 : 00000000 00000001 81a90000 00000001 ntdll!KiUserCallbackDispatcher+0x20
0257f5f0 : 00000000 00000001 81a90000 00000001 user32!UpdateWindow+0x58
0257f600 : 00000000 00000001 81a90000 00000001 user32!DialogBox2+0x208
BOOL DrvBitBlt(
SURFOBJ* psoDst,
SURFOBJ* psoSrc,
SURFOBJ* psoMsk,
CLIPOBJ* pco,
XLATEOBJ* pxlo,
RECTL* prclDst,
POINTL* pptlSrc,
POINTL* pptlMsk,
BRUSHOBJ* pbo,
POINTL* pptlBrush,
ROP4 rop4)
{ ... }
0: kd> u mga!DbgBitBlt+0x840x40
mga!DbgBitBlt+0x44:
ef1c31a4 : a11e0050 ldl t7,50(sp)
ef1c31a8 : a0de0058 ldl t5,58(sp)
ef1c31ac : a09e0060 ldl t3,60(sp)
ef1c31b0 : a05e0068 ldl t1,68(sp)
ef1c31b4 : a01e0070 ldl v0,70(sp)
ef1c31b8 : a21e0030 ldl a0,30(sp)
ef1c31bc : a23e0034 ldl a1,34(sp)
ef1c31c0 : a25e0038 ldl a2,38(sp)
0: kd> u
mga!DbgBitBlt+0x64:
ef1c31c4 : a27e003c ldl a3,3c(sp)
ef1c31c8 : a29e0040 ldl a4,40(sp)
ef1c31cc : a2be0044 ldl a5,44(sp)
ef1c31d0 : b51e0000 stq t7,0(sp)
ef1c31d4 : b4de0008 stq t5,8(sp)
ef1c31d8 : b49e0010 stq t3,10(sp)
ef1c31dc : b45e0018 stq t1,18(sp)
ef1c31e0 : b41e0020 stq v0,20(sp)
0: kd> u
mga!DbgBitBlt+0x84:
ef1c31e4 : d35f6f96 bsr ra,ef19f040 mga!DrvBitBlt
ef1c31e8 : 243fef1c ldah t0,10e4(zero)
ef1c31ec : b01e0030 stl v0,30(sp)
ef1c31f0 : 20217b78 lda t0,7b78(t0)
ef1c31f4 : 47e0d410 bis zero,#6,a0
ef1c31f8 : 22210010 lda a1,10(t0)
ef1c31fc : d35f979c bsr ra,ef1a9070 mga!DebugPrint
ef1c3200 : a01e0030 ldl v0,30(sp)
0: kd> dd edc7f0d0+0x30 l1
edc7f100 e17f6018
0: kd> dd edc7f0d0+0x34 l1
edc7f104 00000000
0: kd> dd edc7f0d0+0x38 l1
edc7f108 00000000
As can be seen from the dissasembled code, the arguments are loaded from the stack
for mga!DbgBitBlt before the call to mga!DrvBitBlt. Examining the contents of the stack
yields the values for the arguments.
Using the same stack trace, we try to get the argument to PDEVOBJ__ppfn.
PFN PDEVOBJ::ppfn(ULONG i)
{...}
0: kd> kb
CalleeSP Arguments to Callee Call Site
edc7ec90 : 00000001 00000001 81a90000 00000001 ntkrnlmp!DbgBreakPoint+0x4
edc7ec90 : 00000001 00000001 81a90000 00000001 win32k!DoRip+0x38
edc7eca0 : 00000001 00000001 81a90000 00000001 win32k!PDEVOBJ__vAssertDynaLock+0xe8
edc7ecb0 : 00000001 00000001 81a90000 00000001 win32k!PDEVOBJ__ppfn+0x38
edc7ecd0 : 00000001 00000001 81a90000 00000001 win32k!BRUSHOBJ_pvGetRbrush+0x44
edc7ecf0 : 00000001 00000001 81a90000 00000001 mga!DrvBitBlt+0x678
edc7f0d0 : 00000001 00000001 81a90000 00000001 mga!DbgBitBlt+0x84
edc7f120 : 00000001 00000001 81a90000 00000001 win32k!OffBitBlt+0x110
edc7f1a0 : 00000001 00000001 81a90000 00000001 win32k!MulBitBlt+0x52c
edc7f300 : 00000001 00000001 81a90000 00000001 win32k!GrePatBltLockedDC+0x2ac
edc7f390 : 00000001 00000001 81a90000 00000001 win32k!GrePolyPatBltInternal+0x28c
edc7f4e0 : 00000001 00000001 81a90000 00000001 win32k!NtGdiFlushUserBatch+0x210
edc7f5c0 : 00000001 00000001 81a90000 00000001 ntkrnlmp!KiSystemServiceRepeat+0x8c
0257f460 : 00000001 00000001 81a90000 00000001 gdi32!SelectObject+0x320
0257f490 : 00000001 00000001 81a90000 00000001 user32!xxxBNPaint+0x314
0257f4e0 : 00000001 00000001 81a90000 00000001 user32!ButtonWndProcWorker+0xcf4
0257f590 : 00000000 00000001 81a90000 00000001 user32!_fnDWORD+0x2c
0257f5b0 : 00000000 00000001 81a90000 00000001 ntdll!KiUserCallbackDispatcher+0x20
0257f5f0 : 00000000 00000001 81a90000 00000001 user32!UpdateWindow+0x58
0257f600 : 00000000 00000001 81a90000 00000001 user32!DialogBox2+0x208
0: kd> u win32k!BRUSHOBJ_pvGetRbrush+0x440x20
win32k!BRUSHOBJ_pvGetRbrush+0x24:
de0a58c4 : d346cad6 bsr ra,de258420 win32k!DoRip
de0a58c8 : a0090004 ldl v0,4(s0)
de0a58cc : 221e0010 lda a0,10(sp)
de0a58d0 : 47e19411 bis zero,#c,a1
de0a58d4 : f4000017 bne v0,de0a5934 win32k!BRUSHOBJ_pvGetRbrush+94
de0a58d8 : a0490034 ldl t1,34(s0)
de0a58dc : a042001c ldl t1,1c(t1)
de0a58e0 : b05e0010 stl t1,10(sp)
0: kd> dd 0xedc7ecd0+0x10 l1
edc7ece0 e2141088
Dissasembling the calling routine yields the a0 register which contains the this pointer
for the PDEVOBJ and the a1 register which contains 0xC.
An alternative method is to trace what happens to the argument after the call.
0: kd> u win32k!PDEVOBJ__ppfn
win32k!PDEVOBJ__ppfn:
de1dff60 : 23deffe0 lda sp,20(sp)
de1dff64 : 422595a1 cmpeq a1,#2c,t0
de1dff68 : b53e0000 stq s0,0(sp)
de1dff6c : 4225b5a0 cmpeq a1,#2d,v0
de1dff70 : b75e0008 stq ra,8(sp)
de1dff74 : 47f10409 bis zero,a1,s0
de1dff78 : b21e0010 stl a0,10(sp)
de1dff7c : f4200007 bne t0,de1dff9c win32k!PDEVOBJ__ppfn+3c
This shows the s0 register being stored on the local stack at offset 0. Dumping the data
at this point yields the value 0xC for the argument.
The Alpha compiler will also produce .cod files, but they’re a little more effort to parse.
The third section is the Machine Code Listing and represents an exact dump of
the assembler output from the compiler with one or two register substitutions
not done (it appears to be those relevant to named identifiers). This section is
characterized by the page headers containing “Machine Code Listing”, date and
compiler version. There are 5 basic columns – the first is the hex opcode, the
second the hex offset from the beginning of the routine and the third is the asm
op/label. The fourth column shows the register substitutions for the symbolic
names in the asm op in column 3. The fifth column has the source code line
number. Note this file is more than 80 characters wide so you may have to scroll
your editor to see the last column.
The last section starts with the header “Routine Base”.
Produce an appropriate .cod file for the code you’re debugging – make sure it’s checked
or free to match the code on the machine you’re debugging.
Subtract the address of the asm instruction from the start address of the routine to get
the instruction offset. Search section 3 of the .cod file for the routine and find the offset
in column 2. Double check to see that the asm ops in the debugger match what you see
in the .cod file at that point. Go to column 5 (the last column) and find the nearest
source line number. Search for this line number in the source file or section 1 of the
.cod file.
For example suppose you computed the offset of the instruction to be 0x34
You find the appropriate routine in section 3 of the .cod file and the line looks
something like this:
First you verify that you are indeed looking for an ldl t2, 8(a0) and the surrounding asm
code also matches the debugger output. You then go to line 55 in the source to find the
appropriate source code line. Note the source code line number is decimal and the
offset is hex.
There are also links between the other sections. The .loc statements in the annotated
asm section (section 2) specify the source line from which that asm statement was
compiled. Again on the far right there are source line numbers linking with section 1.
Section 2 and 3 can be linked by matching asm ops or by following identical label
specifiers common to both sections.
And there at hsemDevLock is the value for the lock we were looking at. Let’s find the
process of the thread holding the lock.
kd> !locks 80861b28
So this tells us the application in question, if that’s useful. From the thread’s stack
trace, we find the code that’s blocked. In this case, we also had weird symbol problems.
kd> u f290147e
f290147e f6c402 test ah,0x2
f2901481 75f9 jnz f290147c
f2901483 ffb3bc000000 push dword ptr [ebx+0xbc]
We’re looking at a 3-instruction spinlock-type loop. Make sure that this thread is getting
CPU time by jumping to the start of the loop again.
kd> g f290147c
f290147c 66ed in ax,dx
Right, so we have a spinlock that isn’t terminating, waiting on some hardware register.
kd> kb
ChildEBP RetAddr Args to Child
f7514224 f2901882 e2180848 e2011e78 f7514248 0xf290147c
f2bc8000 3300 ( 12 kb) f60 ( 3 kb) mouclass.sys Thu Sep 03 22:57:07 1998
f2890000 6ee0 ( 27 kb) fc0 ( 3 kb) NDProxy.SYS Fri Sep 04 00:13:08 1998
f2be0000 5660 ( 21 kb) c20 ( 3 kb) EFS.SYS Thu Sep 03 22:59:50 1998
f2ca8000 2e20 ( 11 kb) a60 ( 2 kb) flpydisk.sys Thu Sep 03 22:56:41 1998
f2d10000 0 ( 0 kb) 0 ( 0 kb) Fs_Rec.SYS Header Paged Out
f2dca000 0 ( 0 kb) 0 ( 0 kb) Null.SYS Header Paged Out
f2dcb000 0 ( 0 kb) 0 ( 0 kb) Beep.SYS Header Paged Out
f2cb8000 28a0 ( 10 kb) 9a0 ( 2 kb) vga.sys Thu Sep 03 23:00:28 1998
f2dcc000 520 ( 1 kb) 740 ( 1 kb) mnmdd.SYS Thu Sep 03 23:00:28 1998
f2c08000 4420 ( 17 kb) 960 ( 2 kb) Msfs.SYS Thu Sep 03 23:00:43 1998
f28c0000 7de0 ( 31 kb) dc0 ( 3 kb) Npfs.SYS Thu Sep 03 23:00:36 1998
f28d0000 d2a0 ( 52 kb) 10a0 ( 4 kb) wdmaud.sys Thu Sep 03 22:58:41 1998
f82ca000 1f2a0 ( 124 kb) 1f60 ( 7 kb) Fastfat.SYS Thu Sep 03 23:00:35 1998
f28e0000 d580 ( 53 kb) fa0 ( 3 kb) Cdfs.SYS Fri Sep 04 00:12:13 1998
f2cf4000 25e0 ( 9 kb) d00 ( 3 kb) dump_scsiport.sys Thu Sep 03 22:57:02 1998
f28f0000 b060 ( 44 kb) 1e80 ( 7 kb) dump_aic78xx.sys Thu Sep 03 22:56:14 1998
a0000000 160d60 (1411 kb) 1c9c0 ( 114 kb) win32k.sys Thu Sep 03 23:02:37 1998
f8236000 0 ( 0 kb) 0 ( 0 kb) atmfd.dll Header Paged Out
f2900000 0 ( 0 kb) 0 ( 0 kb) s3legacy.dll Header Paged Out
f2d12000 1420 ( 5 kb) 700 ( 1 kb) rasacd.sys Fri Sep 04 00:16:46 1998
f2c78000 26c0 ( 9 kb) ca0 ( 3 kb) TDI.SYS Fri Sep 04 00:15:48 1998
f7cca000 2e680 ( 185 kb) 4b00 ( 18 kb) tcpip.sys Fri Sep 04 00:16:17 1998
f2af8000 6a40 ( 26 kb) ea0 ( 3 kb) msgpc.sys Fri Sep 04 00:13:02 1998
f2b10000 5180 ( 20 kb) ee0 ( 3 kb) wanarp.sys Thu Aug 27 19:41:40 1998
f7caa000 1cc60 ( 115 kb) 24e0 ( 9 kb) netbt.sys Fri Sep 04 00:17:03 1998
f7c93000 14600 ( 81 kb) 1b00 ( 6 kb) afd.sys Fri Sep 04 11:29:45 1998
f2bf0000 67c0 ( 25 kb) c80 ( 3 kb) netbios.sys Fri Sep 04 00:17:10 1998
f29c0000 8760 ( 33 kb) 1260 ( 4 kb) sysaudio.sys Thu Sep 03 22:58:46 1998
f2d48000 0 ( 0 kb) 0 ( 0 kb) ParVdm.SYS Header Paged Out
f7c2d000 1e040 ( 120 kb) 2e40 ( 11 kb) rdbss.sys Fri Sep 04 00:11:56 1998
f7afd000 4c720 ( 305 kb) 85e0 ( 33 kb) mrxsmb.sys Fri Sep 04 00:12:03 1998
f79d5000 327c0 ( 201 kb) 4aa0 ( 18 kb) srv.sys Fri Sep 04 00:12:14 1998
f2b88000 4f00 ( 19 kb) ba0 ( 2 kb) termdd.sys Fri Sep 04 00:17:11 1998
f79bd000 2380 ( 8 kb) 860 ( 2 kb) spud.sys Sat Aug 22 14:05:50 1998
f7657000 f680 ( 61 kb) 1740 ( 5 kb) ipsec.sys Fri Sep 04 00:16:33 1998
f7221000 12f40 ( 75 kb) 8ce0 ( 35 kb) kmixer.sys Thu Sep 03 22:58:39 1998
f6ca9000 84e0 ( 33 kb) 2d20 ( 11 kb) swmidi.sys Thu Sep 03 22:58:41 1998
TOTAL: 5fe260 (6136 kb) e3e40 ( 911 kb) ( 0 kb 0 kb)
Looking at our current address, 0xf290147c, we can see it’s in s3legacy.dll. Later, when
the symbols magically reappeared, we found it was s3legacy!vPutBits+0x1a.
Much useful information can be gained by knowing the global variables in win32k.sys
0: kd> dd win32k!gpdispinfo l1
a016aa5c a02a1370
0: kd> !dso DISPLAYINFO a02a1370
*** Extension DLL(1912 Free) does not match target system(0 Checked)
Structure DISPLAYINFO 0xa02a1370 Size: 0x54
(000) e13a01c8 hDev (004) e198a968 pmdev
(008) 00000000 hDevInfo (00c) 0101006f hdcScreen
(010) 01010070 hdcBits (014) 02010103 hdcGray
(018) 01050104 hbmGray (01c) 00000140 cxGray
(020) 00000012 cyGray (024) e1a03b48 pdceFirst
(028) 00000000 pspbFirst (02c) 00000001 cMonitors
(030) a02a1920 pMonitorPrimary (034) a02a1920 pMonitorFirst
(038) 00000000 rcScreen (048) 05040073 hrgnScreen
(04c) 0060 dmLogPixels (04e) 0008 BitCountMax
(050) 00000003 BIT FIELDS
(050) (0) 1 fDesktopIsRect:1 (050) (1) 1 fAnyPalette:1
Another useful one to know is Win32k!gpentHmgr which is the handle manager pointer.
The declaration is ENTRY *gpentHmgr.
bp win32k!gremoveto “kb”
Dereference a pointer:
dd poi(esp)+4
(“poi” is short for “pointer” and dereferences the specified value. This particular
example if useful for showing the routine’s arguments from the stack if you’re at the
beginning of the routine.)
bp win32k!gremoveto “j poi(esp+4) == 0; g”
(This particular example will break if GreMoveTo is called with the first argument set to
NULL.)
If you want to do more than 1 thing, at the break point you can use ';'
bp win32k!gremoveto “kb;dd esp l5;g”
This lets debugger output a stack trace, its parameter (5 = 1 return address + 4
parameters), then go, when we hit gremoveto.
if (first parameter == 0) {
take stack trace;
dump registers;
} else {
take stack trace;
go;
}
bp win32k!gremoveto “j poi(esp+4) == 0 'kb;r' ; 'kb;g' ”
The first parameter is esp+4 (unless you are debugging on 64bits NT in which case it’s
esp+8).
And if the function is defined as '_fastcall', the function parameter will not be in stack,
so you can not use this way.
wt
(“wt” works only if you’re currently at the beginning of a routine, or are at the “call”
statement calling into a routine. It will provide a complete list of all the routines called
by your routine, as well as the instruction counts. This is surprisingly useful for
performance work, or to see what lower-level functions are being called.)
0:000> sx
ct break on create thread disabled
et break on exit thread disabled
ld break on load DLL disabled
av break on access violation enabled
dz break on divide by zero enabled
ip break on in page io error enabled
i2 break on in page io error 2nd chance enabled
3c break on gui app exit disabled
cc handle controlc enabled
eh break on C++ EH exception notify
ch = break on closing bad handle enabled
pf profiling DLL disabled
* break on default exception disabled
For example, if you want to break in debugger, when process loads DLL, you can do.
0:000> sx e ld
to disable ...
0:000> sx d ld
If you want to break in debugger, when some one writes DWORD data into address
0x12345678.
0:000> ba w 4 0x1234567
'w' means break on 'write', you also can use 'r' to break when the address being read.
'4' means 4bytes access (DWORD access), you also can use '1' for byte access and '2'
for word access.
The ba command sets a hardware breakpoint which turns out to be very useful for
debugging terminal server.
This command sets an execution breakpoint in NtGdiBitblt. The ‘e’ is for execution
(breaks when a fetch is attempted to that address) and the 1 is to break on the first
occurance.
ba e1 win32k!NtGdiBitblt
Note that in Terminal server it is possible for any win32k.sys to break at that location.
To determine if the server (console) stopped here, use the global variable G_fConsole
or gbRemoteSession.
For more info on debugging Hydra (Terminal Server) see the Hydra debugging hints
section below and the section on Bugcheck AB.
All the extensions have been modified to support an optional -? help switch. If the -?
flag is present anywhere in the list of arguments, all others are ignored and the help is
displayed.
cache
cache [?] PTR
dumps a CACHE structure at PTR.
fontexts.cxx
cr
cr [?] hrgn|prgn
Checks a REGION.
gdiexts.cxx
dbli
dbli [?] BLTINFO_PTR
Displays the contents of the BLTINFO structure pointed to by BLTINFO_PTR.
dblt
dblt [?] BLTREC_PTR
Takes a pointer to a BLTRECORD.
Appears to be something to do with blitting stuff to the screen.
gdiexts.cxx
dca
Syntax:
dca [?] PTR
The dca extension dumps the DCATTR structure pointed to by PTR. This structure contains a
lot of information about the DC and each DC has a pointer to a DCATTR.
Example:
This example follows on from the ddc example.
kd> !gdikdx.ddc 1aa
V 2.0 Dump DC 0x1aa:
PidOwner = 0x3f8
hdc = 0xb0101aa
pdcattr = 0x01330c5c
pdcLevel = 0xa20bea38(30)
psurf = 0xa206e6e8
ppdev = 0xa2015368
dctype = 0x00000001 = DCTYPE_MEMORY
prgnVis = 0xa206d648
sizl (22, 946)
erclClip (0, 0), (22, 946)
erclWindow (0, 0), (22, 946)
erclBounds (0, 0), (0, 0)
kd> !gdikdx.dca 0x01330c5c
DC_ATTR
address
[1330c5c] pvLDC 0x1
[1330c60] ulDirty_ 0x6f400
DIRTY_STYLESTATE
DC_BRUSH_DIRTY
DC_PEN_DIRTY
DC_DIBSECTION
DC_LAST_CLIPRGN_VALID
? 0x60000
[1330c64] hbrush 0x101c910
[1330c6c] crBackgroundClr 0xffffffff
[1330c70] ulBackgroundClr 0x6f3bc
[1330c74] crForegroundClr 0x4ec9346e
[1330c78] ulForegroundClr 0x4ec82d24
[1330c8c] iCS_CP 0x3300702d
[1330c90] iGraphicsMode 1140865126 = GM_?
[1330c94] jROP2 0x43 = R2_?
[1330c95] jBkMode 95 = BKMODE_?
[1330c96] jFillMode 84 = ?FILLMODE
[1330c97] jStretchBltMode 89 = ?STRETCHMODE
[1330cb8] lIcmMode 0x6f4cc
[1330cbc] hcmXform 0x6f278
[1330cc0] hColorSpace 0x67061dd0
[1330cc8] IcmBrushColor 0
[1330ccc] IcmPenColor 0x7
[1330c98] ptlCurrent 1996506448 120
[1330ca0] ptfxCurrent 0 0
[1330c90] iGraphicsMode 1140865126 = GM_?
[1330ca8] lBkMode 0 = BKMODE_?
[1330cac] lFillMode 455284 = ?
[1330cb0] lStretchBltMode 2013326435 = ?
[1330cd0] flTextAlign 0x6f2b8 = TA_NOUPDATECP | TA_LEFT | TA_?
[1330cd4] lTextAlign 0x77fab467 = TA_UPDATECP | TA_CENTER | TA_TOP
[1330cd8] lTextExtra 455458
[1330cdc] lRelAbs 71
[1330ce0] lBreakExtra 1728315392
[1330ce4] cBreak 1728453812
[1330ce8] hlfntNew 0x67061dd0
[1330dc0] iMapMode 0x6f3ac
[1330cb4] flFontMapper 0x20
MM_?
[1330dc4] dwLayout 2012647452
[1330dc8] lWindowOrgx 2012355808
[1330dcc] ptlWindowOrg 1 455612
[1330dd4] szlWindowExt 16867784 120
[1330ddc] ptlViewportOrg 2579792 455608
[1330de4] szlViewportExt 16892586 393216
[1330dec] flXform 0x6f3b8
DEVICE_TO_PAGE_INVALID
DEVICE_TO_WORLD_INVALID
WORLD_TRANSFORM_SET
INVALIDATE_ATTRIBUTES
PTOD_EFM11_NEGATIVE
PTOD_EFM22_NEGATIVE
PAGE_TO_DEVICE_SCALE_IDENTITY
PAGE_XLATE_CHANGED
PAGE_EXTENTS_CHANGED
WORLD_XFORM_CHANGED
0x275d50 bad flags
[1330cec] mxWorldToDevice !gdikdx.mx 1330cec
[1330d28] mxDeviceToWorld !gdikdx.mx 1330d28
[1330d64] mxWorldToPage !gdikdx.mx 1330d64
[1330df0] szlVirtualDevicePixel 2579792 2579792
[1330df8] szlVirtualDeviceMm 455656 0
[1330e00] ptlBrushOrigin 74 74
[1330e08] VisRectRegion 455656 455608 16783348 8
Source:
fontexts.cxx
dcl
Syntax:
dcl [?] PTR
Dumps a DCLEVEL structure at PTR.
Example:
This example follows on from the ddc example.
kd> !gdikdx.ddc 1aa
V 2.0 Dump DC 0x1aa:
PidOwner = 0x3f8
hdc = 0xb0101aa
pdcattr = 0x01330c5c
pdcLevel = 0xa20bea38(30)
psurf = 0xa206e6e8
ppdev = 0xa2015368
dctype = 0x00000001 = DCTYPE_MEMORY
prgnVis = 0xa206d648
sizl (22, 946)
erclClip (0, 0), (22, 946)
erclWindow (0, 0), (22, 946)
erclBounds (0, 0), (0, 0)
kd> !gdikdx.dcl 0xa20bea38
DCLEVEL
address
[a20bebe4] pSurface 0xa206e6e8
[a20bea38] hpal 0x188000b
[a20bea3c] ppal 0xa2001f48
[a20bebe8] sizl 22 946
[a20bea48] lSaveDepth 1
[a20bea50] hdcSave 0
[a20bea5c] pbrFill 0xa2001788
[a20bea60] pbrLine 0xa20011c8
[a20bea68] hpath 0
[a20bea40] pColorSpace 0xa2002848
[a20bea44] lIcmMode 0
[a20bea6c] flPath 0
[a20bea70] laPath !gdikdx.la a20bea70
[a20bea90] prgnClip 0
[a20bea94] prgnMeta 0
[a20bea98] ca !gdikdx.ca a20bea98
[a20beab0] flFontState 0
[a20beab4] ufi
[a20beae8] fl 0
[a20beaec] flbrush 0
[a20beaf0] mxWorldToDevice !gdikdx.mx a20beaf0
[a20beb2c] mxDeviceToWorld !gdikdx.mx a20beb2c
[a20beb68] mxWorldToPage !gdikdx.mx a20beb68
[a20beba4] efM11PtoD +16.000000
[a20bebac] efM22PtoD +16.000000
[a20bebb4] efDxPtoD +0.000000
[a20bebbc] efDyPtoD +0.000000
[a20bebc4] efM11_TWIPS +0.000000
[a20bebcc] efM22_TWIPS +0.000000
[a20bebd4] efPr11 +0.000000
[a20bebdc] efPr22 +0.000000
Source:
fontexts.cxx
dco
Syntax:
dco [?] clipobj
Dumps a CLIPOBJ.
Example:
Continues on from hdc example.
kd> !gdikdx.dco a20bef68
**** CLIPOBJ STRUCTURE AT 0xa20bef68 ****
iUniq = 0
rclBounds = 0 0 0 0
iDComplexity = 0
DC_TRIVIAL
iFComplexity = 0
??????????
iMode = 0
TC_RECTANGLES
fjOptions = 0
Source:
gdikdx.cxx
ddc
Syntax:
ddc [?hadefgstvux] hdc
Optional Flags:
? and h display the help.
a Attrib
d Draw
e Extend
f Font
g Global
s Saved
t Text
v Verbose
u User
x XForm
This extension dumps the DC (Device Context) information from an hdc (handle to a DC).
Example:
kd> !dumpobj p 3f8 DC_TYPE
object list for DC type objects owned by PID 0x3f8
I, handle, Lock, sCount, pid, pv, objt, unique, Flags, pUser, Tlock
16d, e01016d, 0, 0, 3f8, a2055a08, DC, e01, 4, 00dd054c, 00dd054c
16f, c01016f, 0, 0, 3f8, a2194008, DC, c01, 0, 00dd0388, 00dd0388
170, 7010170, 0, 0, 3f8, a2062008, DC, 701, 0, 00dd0000, 00dd0000
173, a010173, 0, 0, 3f8, a20c6008, DC, a01, 0, 00dd0710, 00dd0710
175, 1010175, 0, 0, 3f8, a20d3008, DC, 101, 0, 00dd01c4, 00dd01c4
181, b010181, 0, 0, 3f8, a205da08, DC, b01, 4, 00dd08d4, 00dd08d4
18a, 301018a, 0, 0, 3f8, a206ba08, DC, 301, 4, 00dd0c5c, 00dd0c5c
18b, 301018b, 0, 0, 3f8, a20c6a08, DC, 301, 4, 00dd0a98, 00dd0a98
18f, 201018f, 0, 0, 3f8, a20c7a08, DC, 201, 0, 01330388, 01330388
195, 4010195, 0, 0, 3f8, a20634a8, DC, 401, 0, 01330000, 01330000
1aa, b0101aa, 0, 0, 3f8, a20bea08, DC, b01, 4, 01330c5c, 01330c5c
1ac, 20101ac, 0, 0, 3f8, a20e95c8, DC, 201, 4, 00dd0e20, 00dd0e20
1ad, 20101ad, 0, 0, 3f8, a206d008, DC, 201, 4, 01330710, 01330710
1af, 30101af, 0, 0, 3f8, a206e008, DC, 301, 4, 013308d4, 013308d4
1b0, 30101b0, 0, 0, 3f8, a206ea08, DC, 301, 4, 01330a98, 01330a98
Total objects = 15
kd> !ddc 1aa
V 2.0 Dump DC 0x1aa:
PidOwner = 0x3f8
hdc = 0xb0101aa
pdcattr = 0x01330c5c
pdcLevel = 0xa20bea38(30)
psurf = 0xa206e6e8
ppdev = 0xa2015368
dctype = 0x00000001 = DCTYPE_MEMORY
prgnVis = 0xa206d648
sizl (22, 946)
erclClip (0, 0), (22, 946)
erclWindow (0, 0), (22, 946)
erclBounds (0, 0), (0, 0)
Source:
gdiexts.cxx
dddglobal
Syntax:
dddglobal [?ha] some_expression
Example:
This example continues from the dddsurface example.
kd> !gdikdx.dddglobal 0xe1939960
EDD_DIRECTDRAW_GLOBAL structure at 0xE1939960:
VOID* dhpdev 0x0
DWORD dwReserved1 0x0
DWORD dwReserved2 0xf8300000
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocalList 0x0
EDD_SURFACE* peSurface_LockList 0x0
FLONG fl 0x0
ULONG cSurfaceLocks 0x0
PKEVENT pAssertModeEvent 0x0
LONGLONG llAssertModeTimeout 0x40
EDD_SURFACE* peSurfaceCurrent 0x0
EDD_SURFACE* peSurfacePrimary 0x0
BOOL bSuspended 0x0
HDEV hdev 0x0
LONG cDriverReferences 0x100
DWORD dwNumHeaps 0x10
VIDEOMEMORY* pvmList 0x7e0
DWORD dwNumFourCC 0x1f
DWORD* pdwFourCC 0x0
DD_HALINFO HalInfo
DD_CALLBACKS CallBacks
DD_SURFACECALLBACKS SurfaceCallBacks
DD_PALETTECALLBACKS PaletteCallBacks
Source:
gdikdx.cxx
dddlocal
dddlocal [?ha] some_expression
Dumps some direct draw stuff.
gdikdx.cxx
dddsurface
Syntax:
dddsurface [?haruln] ddsurfobj
Dumps a direct draw surface object
Optional parameter:
? and h display the help.
a All
r Private
u Public
l Locks
n DdNext
kd> !gdikdx.dh 21030204
Entry from ghmgr for handle 0x21030204:
&pent = a016743c
pent = a0180000
move() = 1
pobj/hfree = 0xe1939908
ObjectOwner = 0x01400000
pidOwner = 0x140
ShareCount = 0x0
lock = UNLOCKED
puser = 0x0
objt = 0x3
usUnique = 0x2103
fsHmgr = 0x0
hHmgr = 0x21030204
cExcluLock = 0x00000001
tid = 0x80648690
This is DD_SURFACE_TYPE
kd> !gdikdx.dddsurface 0xe1939908
EDD_SURFACE structure at 0xE1939908:
PDD_SURFACE_GLOBAL lpGbl 0xe1939960
PDD_SURFACE_MORE lpMore 0xe1939954
DWORD dwFlags 0x2000
DDRAWISURF_HASPIXELFORMAT
DWORD ddsCaps.dwCaps 0x20005000
DDSCAPS_TEXTURE
DDSCAPS_VIDEOMEMORY
DDCOLORKEY ddckCKSrcBlt/Overlay 0x0:0x0
DDCOLORKEY ddckCKDestBlt/Overlay 0x0:0x0
PDD_ATTACHLIST lpAttachList 0x0
PDD_ATTACHLIST lpAttachListFrom 0x0
DWORD dwMipMapCount 0x0
EDD_VIDEOPORT* peVideoPort 0x0
HBITMAP hbmGdi 0x46050168
DWORD dwOverlayFlags 0x0
DWORD dwBlockSizeX 0x0
DWORD dwBlockSizeY 0x0
FLATPTR fpVidMem 0xf8300000
LONG lPitch 0x200
LONG xHint 0x2aa
LONG yHint 0x14aeaa
DWORD wWidth 0x100
DWORD wHeight 0x100
DWORD (global) dwReserved1 0xe11d8c48
DWORD (local) dwReserved1 0x0
DDPIXELFORMAT ddpfSurface
DWORD dwSize (should be 0x20) 0x20
DWORD dwFlags 0x40
DDPF_RGB
DWORD dwFourCC 0x0
DWORD dwRGB/YUV/ZBuffer/AlphaBitCount 0x10
DWORD dwRBitMask/dwYBitMask 0xf800
DWORD dwGBitMask/dwUBitMask 0x7e0
DWORD dwBBitMask/dwVBitMask 0x1f
DWORD dwRGB/YUVAlphaBitMask 0x0
EDD_SURFACE* peSurface_DdNext 0xe187c0c8
EDD_SURFACE* peSurface_LockNext 0x0
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal 0xe128e550
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal 0xe11f7b28
FLONG fl 0x8c
DD_SURFACE_FLAG_DRIVER_CREATED
DD_SURFACE_FLAG_CREATE_COMPLETE
ULONG iVisRgnUniqueness 0x312
BOOL bLost FALSE
HANDLE hSecure 0x0
ERECTL rclLock: (0, 0, 256, 256)
ULONG cLocks 0x1
HDC hdc 0x0
Source:
gdiexts.cxx
ddib
!ddib [?] [w W] [h H] [f filename] [b Bits] [y Byte_Width] [p palbits palsize] pBits
This extension creates and dumps a DIB to a .bmp file on disk.
The bad news is that all the numbers must be in hex the good news is you can pass
expressions like ebx+4 for width or height, etc.
The syntax is a bit tricky, but bear with me I'm working on it.
w, h, f, b and pBits are required parameters, y and p optional. If the y option is
omitted, the byte width for a scanline is computed from the Width and Bits parameters.
The brackets [] above can be reordered, but the contents must remain in the same order.
pBits must be the last parameter.
Make sure the filename specified for the f option is a public share and is writeable by the
machine running the debugger. If you specify a local file, it will be local to the machine
running the debugger which is not necessarily the machine running your remote.
Example:
Here's an example (relevant info is highlighted):
kd> ba e1 win32k!NtGdiSetDIBitsToDeviceInternal
kd> g
win32k!NtGdiSetDIBitsToDeviceInternal:
a00e9793 55 push ebp
kd> kb
ChildEBP RetAddr Args to Child
f8159d1c 80456894 43010224 00000000 00000000 win32k!NtGdiSetDIBitsToDeviceInternal
Lets dump the parameters for NtGdiSetDIBitsToDeviceInternal so we can get the bitmap pointer
and dimensions:
kd> dd f8159d1c
f8159d1c 00000287 80456894 43010224 00000000
f8159d2c 00000000 00000020 00000020 00000000
f8159d3c 00000000 00000000 00000020 67aa3ad0
f8159d4c 000c2ce8 00000000 00000400 00000428
f8159d5c 00000001 00000000 00000000 00000000
f8159d6c 00000000 00000000 00000000 00000000
f8159d7c 00000000 00000000 00000000 00000000
f8159d8c 00000000 00000000 00000000 00000023
Now lets dump the LPBITMAPINFO structure so we can find the palette:
kd> dd c2ce8
000c2ce8 00000028 00000020 00000020 00080001
000c2cf8 00000000 00000400 00000000 00000000
000c2d08 00000000 00000000 00000000 00800000
000c2d18 00008000 00808000 00000080 00800080
000c2d28 00008080 00c0c0c0 00c0dcc0 00a6caf0
000c2d38 00040404 00080808 000c0c0c 00111111
000c2d48 00161616 001c1c1c 00222222 00292929
000c2d58 00555555 004d4d4d 00424242 00393939
kd> !\\asecchia\nt\release\nt\mstools\gdikdx.ddib w 20 h 20 f
\\asecchia\TestStuff\one.bmp b 8 p c2ce8+28 100 67aa3ad0
input:
pbits: 67AA3AD0
width: 32
height: 32
bwidth: 32
cdepth: 8
pPal: 000C2D10
palentries: 256
filename: \\asecchia\TestStuff\one.bmp
writing the palette
kd>
Source:
gdiexts.cxx
devft
devft [?]
Equivalent to pft win32k!gpPFTDevice
fontexts.cxx
dgdev
dgdev [?m] gdev
gdikdx.cxx
dh
Syntax:
dh [?] object_handle
Dumps information about the object for a given object handle. For instance it includes the
locked status of the object.
The handle must be in hex.
Example:
kd> !gdikdx.dumpobj p 3f8 RGN_TYPE
object list for RGN type objects owned by PID 0x3f8
I, handle, Lock, sCount, pid, pv, objt, unique, Flags, pUser, Tlock
1a3, f80401a3, 0, 0, 3f8, a2061da8, RGN, f804, 0, 00de0060, 00de0060
Total objects = 1
kd> !gdikdx.dh 1a3
Entry from ghmgr for handle 0x000001a3:
&pent = a0204c10
pent = a0c00000
move() = 1
pobj/hfree = 0xa2061da8
ObjectOwner = 0x03f80000
pidOwner = 0x3f8
ShareCount = 0x0
lock = UNLOCKED
puser = 0xde0060
objt = 0x4
usUnique = 0xf804
fsHmgr = 0x0
hHmgr = 0xf80401a3
cExcluLock = 0x00000000
tid = 0x80a99870
This is RGN_TYPE
Source:
gdiexts.cxx
dhelf
dhelf [?] HANDLE
Obsolete: superseeded by helf.
fontexts.cxx
dht
Syntax:
dht [?] object_handle
Displays the handle type.
The handle must be in hex.
Example:
This example is a continuation of the example in dh.
kd> !gdikdx.dht 1a3
Handle: 1a3
Index | UNIQUE | STOCK | CLI TYPE | SRV TYPE
01a3 | 00 | 0 | ( 0) | DEF ( 0)
Source:
gdiexts.cxx
difi
difi [?] PTR
Obsolete: superseeded by ifi.
fontexts.cxx
dispcache
dispcache [?]
Equivalent to pdev y win32k!ghdev
fontexts.cxx
dldev
dldev [?] [f] [F forcenum] ldev
f forces the display even if the ldev is invalid.
F forces the display of forcenum records.
both force options stop if a cycle is detected in the linked list.
gdiexts.cxx
dpbrush
dpbrush [?] pbrush|hbrush
dump a brush.
gdiexts.cxx
dpdev
Syntax:
dpdev [?habdDfgmnpR] pdev
Optional Flags:
? and h display the help
a All
b Brush
d Dev info (case sensitive)
D Display only (case sensitive)
f Font
g GDI info
m Mode
n Pattern
p Pointer
R recursive (case sensitive)
This extension dumps the PDEV structure.
Example:
This example conintues from the ddc example.
kd> !gdikdx.ddc 1aa
V 2.0 Dump DC 0x1aa:
PidOwner = 0x3f8
hdc = 0xb0101aa
pdcattr = 0x01330c5c
pdcLevel = 0xa20bea38(30)
psurf = 0xa206e6e8
ppdev = 0xa2015368
dctype = 0x00000001 = DCTYPE_MEMORY
prgnVis = 0xa206d648
sizl (22, 946)
erclClip (0, 0), (22, 946)
erclWindow (0, 0), (22, 946)
erclBounds (0, 0), (0, 0)
kd> !gdikdx.dpdev 0xa2015368
ppdev = 0xa2015368
ppdevNext = 0xa2011008
flags = 0x40045
PDEV_DISPLAY
PDEV_SOFTWARE_POINTER
PDEV_GOTFONTS
PDEV_DRIVER_PUNTED_CALL
cPdevRefs = 82
cPdevOpenRefs = 1
pldev = 0xa2013488
dhpdev = 0xa2016000
hSpooler = 0x80a3e390
pSurface = 0xa201ccc8
ppalSurf = 0xa20152c8
peDirectDrawGlobal = 0xa20158b0
pSpriteState = 0xa20153a8
pDesktopId = 0x1
pGraphicsDevice = 0xa2002728
ppdevParent = 0xa2015368
hsemDevLock = 0x8097cbe8
ptlOrigin = 0, 0
apfn = 0xa2015ea0
Source:
gdiexts.cxx
dpeb
dpeb [?w]
w indicates a W32PROCESS structure.
process.cxx
dppal
Syntax:
dppal [?] pal
Dumps the palette.
Example:
kd> !gdikdx.dppal 0xa2075628
EPALOBJ structure at 0xa2075628:
FLONG flPal 0x501
PAL_INDEXED
PAL_DC
PAL_FREE
ULONG cEntries 0x100
ULONG ulTime 0x11d
HDC hdcHead 0x0
HDEVPPAL hSelected 0xa2015368
ULONG cRefhpal 0x0
ULONG cRefRegular 0x0
PTRANSLATE ptransFore 0x0
PTRANSLATE ptransCurrent 0x0
PTRANSLATE ptransOld 0x0
ULONG ulRGBTime 0x0
PRGB555XL pRGBClate 0x0
PAL_ULONG apalColor 0xa207567c
Issues:
This extension does not work on handles only on a pointer. If you have a PALOBJ handle,
use !gdikdx.dh on the handle and dump the pobj field with this extension.
Source:
gdiexts.cxx
dpo
dpo [?] pathobj
dump pathobj
gdiexts.cxx
dpso
Syntax:
dpso [?] surfobj
Dumps a surface object.
Example:
This example continues from the ddc example.
kd> !gdikdx.ddc 1aa
V 2.0 Dump DC 0x1aa:
PidOwner = 0x3f8
hdc = 0xb0101aa
pdcattr = 0x01330c5c
pdcLevel = 0xa20bea38(30)
psurf = 0xa206e6e8
ppdev = 0xa2015368
dctype = 0x00000001 = DCTYPE_MEMORY
prgnVis = 0xa206d648
sizl (22, 946)
erclClip (0, 0), (22, 946)
erclWindow (0, 0), (22, 946)
erclBounds (0, 0), (0, 0)
kd> !gdikdx.dpso 0xa206e6e8
Check for handle from ghmgr for handle 0xa206e6e8:
DHSURF dhsurf 0x0
HSURF hsurf 0x30501be
DHPDEV dhpdev 0x0
HDEV hdev 0xa2015368
SIZEL sizlBitmap.cx 0x16
SIZEL sizlBitmap.cy 0x3b2
ULONG cjBits 0x58b0
PVOID pvBits 0x1510000
PVOID pvScan0 0x1515898
LONG lDelta 0xffffffe8
ULONG iUniq 0x1fa
ULONG iBitmapFormat 0x3, BMF_8BPP
USHORT iType 0x0, STYPE_BITMAP
USHORT fjBitmap 0x4
BMF_DONTCACHE
FLONG flags 0x4000000
API_BITMAP
PPALETTE ppal 0xa20c8768
HDC hdc 0xb0101aa
ULONG cRef 0x1
HPALETTE hpalHint 0x0
SIZEL sizlDim (0x0, 0x0)
Source
gdiexts.cxx
dpw32
dpw32 [?] [process]
defaults to current process if process is omitted.
process.cxx
dr
Syntax:
dr [?] hrgn|prgn
Dumps a REGION. A REGION is an object which has a variable size the pscnHead points to the
SCAN object which is the start of the variable sized data.
Example:
kd> !gdikdx.dumpobj p 3f8 RGN_TYPE
object list for RGN type objects owned by PID 0x3f8
I, handle, Lock, sCount, pid, pv, objt, unique, Flags, pUser, Tlock
1a3, f80401a3, 0, 0, 3f8, a2061da8, RGN, f804, 0, 00de0060, 00de0060
Total objects = 1
kd> !gdikdx.dr 1a3
hHmgr, 0xf80401a3
cExLock 0
tid, 0x80a99870
sizeObj 0xa8
sizeRgn 0x70
cRefs 0
cScans 3
rcl {175 113 775 513}
pscnHead 0xa2061df0
pscnTail 0xa2061e18
Rectangle #0 { 175, 113, 775, 513 }
Issues:
The value reported by pscnHead has been corrected. It used to be off by 0x10.
Source:
gdiexts.cxx
dsprite
dsprite [?ha] some_expression
Dumps some direct draw stuff
gdiexts.cxx
dspritestate
dspritestate [?ha] some_expression
gdiexts.cxx
dstro
Obsolete: superseeded by stro.
fontexts.cxx
dteb
dteb [?] [TEB]
defaults to current thread if TEB is omitted.
process.cxx
dumphmgr
Syntax:
dumphmgr [?]
Dumps the contents of the handle manager. The handle manager is created when the graphics
engine is initialized and is used to track all the GDI objects in the system. On Hydra
systems, there is one handle manager per session.
Example:
kd> !gdikdx.dumphmgr
Loaded gdikdx extension DLL
Max handles out so far 516
Total Hmgr: Reserved memory 2097152 Committed 20480
handles, (objects)
TYPE current maximum allocated LookAside LAB Cur LAB Max
DEF_TYPE 18, 0 0, 0 0, 0 0 0 0
DC_TYPE 81, 0 0, 0 0, 0 0 0 0
DD_DRAW_TYPE 0, 0 0, 0 0, 0 0 0 0
DD_SURF_TYPE 0, 0 0, 0 0, 0 0 0 0
RGN_TYPE 28, 0 0, 0 0, 0 0 0 0
SURF_TYPE 144, 0 0, 0 0, 0 0 0 0
CLIOBJ_TYPE 0, 0 0, 0 0, 0 0 0 0
PATH_TYPE 0, 0 0, 0 0, 0 0 0 0
PAL_TYPE 25, 0 0, 0 0, 0 0 0 0
ICMLCS_TYPE 1, 0 0, 0 0, 0 0 0 0
LFONT_TYPE 48, 0 0, 0 0, 0 0 0 0
RFONT_TYPE 0, 0 0, 0 0, 0 0 0 0
PFE_TYPE 86, 0 0, 0 0, 0 0 0 0
PFT_TYPE 0, 0 0, 0 0, 0 0 0 0
ICMCXF_TYPE 0, 0 0, 0 0, 0 0 0 0
ICMDLL_TYPE 0, 0 0, 0 0, 0 0 0 0
BRUSH_TYPE 85, 0 0, 0 0, 0 0 0 0
D3D_HANDLE_TYPE 0, 0 0, 0 0, 0 0 0 0
DD_VPORT_TYPE 0, 0 0, 0 0, 0 0 0 0
SPACE_TYPE 0, 0 0, 0 0, 0 0 0 0
DD_MOTION_TYPE 0, 0 0, 0 0, 0 0 0 0
META_TYPE 0, 0 0, 0 0, 0 0 0 0
EFSTATE_TYPE 0, 0 0, 0 0, 0 0 0 0
BMFD_TYPE 0, 0 0, 0 0, 0 0 0 0
VTFD_TYPE 0, 0 0, 0 0, 0 0 0 0
TTFD_TYPE 0, 0 0, 0 0, 0 0 0 0
RC_TYPE 0, 0 0, 0 0, 0 0 0 0
TEMP_TYPE 0, 0 0, 0 0, 0 0 0 0
DRVOBJ_TYPE 0, 0 0, 0 0, 0 0 0 0
DCIOBJ_TYPE 0, 0 0, 0 0, 0 0 0 0
SPOOL_TYPE 0, 0 0, 0 0, 0 0 0 0
TOTALS 498, 0 0, 0 0, 0 0 0 0
cUnused objects 18
cUnknown objects 0 0
Issues:
Need to investigate why this sometimes takes so long to run.
This routine assumes a handle manager is present on Hydra systems the win32k.sys is often
paged out and the handle manager is not accessible. Under these circumstances this extension
will produce garbage output and may render the debugger unusable.
Source:
gdiexts.cxx
dumpobj
Syntax:
dumpobj [?ls] [p pid] object_type
Optional flags:
p pid specifies a given PID.
l checks lock status.
s provides data in a summary format.
This extension dumps all the objects of a given type. You can restrict the output to objects
owned by a particular process with the p option.
Valid object_type values are as follows. Note that only the first few appropriate characters
are compared so DC is the same as DC_TYPE or DCOBJ.
DEF
DC
LDB
PDB
RGN
SURF
CLIENTOBJ
PATH
PAL
FD
LFONT
RFONT
PFE
PFT
IDB
XLATE
BRUSH
D3D_HANDLE
CACHE
SPACE
DBRUSH
META
EFSTATE
BMFD
VTFD
TTFD
RC
TEMP
DRVOBJ
DCIOBJ
SPOOL
Example:
This example continues from the example in dumphmgr.
Dump all the RGN_TYPE objects in the handle table.
kd> !gdikdx.dumpobj RGN_TYPE
object list for RGN type objects owned by ALL PIDs
I, handle, Lock, sCount, pid, pv, objt, unique, Flags, pUser, Tlock
a, 104000a, 0, 0, 0, a2001008, RGN, 104, 0, 00000000, 00000000
38, 1040038, 0, 0, 0, a201c8e8, RGN, 104, 0, 00000000, 00000000
3d, 204003d, 0, 0, 0, a20227c8, RGN, 204, 0, 00000000, 00000000
3e, 104003e, 0, 0, 0, a2022888, RGN, 104, 0, 00000000, 00000000
3f, 104003f, 0, 0, 0, a2022948, RGN, 104, 0, 00000000, 00000000
40, 1040040, 0, 0, 0, a206c1e8, RGN, 104, 0, 00000000, 00000000
41, 1040041, 0, 0, 0, a2022708, RGN, 104, 0, 00000000, 00000000
42, 1040042, 0, 0, 0, a2022648, RGN, 104, 0, 00000000, 00000000
43, 1040043, 0, 0, 0, a2024f48, RGN, 104, 0, 00000000, 00000000
44, 1040044, 0, 0, 0, a2024e88, RGN, 104, 0, 00000000, 00000000
45, 1040045, 0, 0, 0, a2024dc8, RGN, 104, 0, 00000000, 00000000
46, 1040046, 0, 0, 0, a2024d08, RGN, 104, 0, 00000000, 00000000
47, 1040047, 0, 0, 0, a2024c48, RGN, 104, 0, 00000000, 00000000
48, 1040048, 0, 0, 0, a2024b88, RGN, 104, 0, 00000000, 00000000
49, 1040049, 0, 0, 0, a2024ac8, RGN, 104, 0, 00000000, 00000000
4a, 104004a, 0, 0, 0, a2024a08, RGN, 104, 0, 00000000, 00000000
4b, 104004b, 0, 0, 0, a2024948, RGN, 104, 0, 00000000, 00000000
4c, 104004c, 0, 0, 0, a2024888, RGN, 104, 0, 00000000, 00000000
4d, 104004d, 0, 0, 0, a20247c8, RGN, 104, 0, 00000000, 00000000
4e, 104004e, 0, 0, 0, a2025008, RGN, 104, 0, 00000000, 00000000
4f, 104004f, 0, 0, 0, a206f648, RGN, 104, 0, 00000000, 00000000
50, 1040050, 0, 0, 0, a2025e88, RGN, 104, 0, 00000000, 00000000
51, 1040051, 0, 0, 0, a2051d08, RGN, 104, 0, 00000000, 00000000
52, 1040052, 0, 0, 0, a205d648, RGN, 104, 0, 00000000, 00000000
119, b040119, 0, 0, b0, a20bc688, RGN, b04, 0, 00900018, 00900018
11b, 604011b, 0, 0, 98, a20e7648, RGN, 604, 0, 00640018, 00640018
1a3, db0401a3, 0, 0, 3f8, a2061da8, RGN, db04, 0, 00de0060, 00de0060
1e2, a0401e2, 0, 0, 4a4, a20fab08, RGN, a04, 0, 00c00018, 00c00018
Total objects = 28
Dump all the RGN_TYPE objects specific to pid 0x4a4
kd> !gdikdx.dumpobj p 4a4 RGN_TYPE
object list for RGN type objects owned by PID 0x4a4
I, handle, Lock, sCount, pid, pv, objt, unique, Flags, pUser, Tlock
1e2, a0401e2, 0, 0, 4a4, a20fab08, RGN, a04, 0, 00c00018, 00c00018
Total objects = 1
Source:
gdiexts.cxx
e
e [?] address [count]
dumps a FLOAT
fontexts.cxx
ebrush
Syntax:
ebrush [?] pbrush|hbrush
Dumps an EBRUSH structure.
Example:
kd> !gdikdx.ebrush 0xa20c97e8
EBRUSHOBJ at 0xa20c97e8
iSolidColor 0x101001f5
pvRbrush 0xa0c01f50
pengbrush1 0x0
crRealize 0x0
_ulSurfPalTime 0x0
_ulDCPalTime 0x80000014
crCurrentText1 0xaf
crCurrentBack1 0xde00c0
pca 0x0
psoTarg1 0x0
palSurf1 0x1
palDC1 0x0
_pbrush 0x4
flattrs = B_IS_NULL
flattrs = B_NEED_BK_COLOR
_ulUnique 0x4
Issues:
Only works with a pointer. If you have a handle use !gdikdx.dh and dump the pobj field with
this extension.
Source:
gdiexts.cxx
ef
ef [?] address [count]
dumps an EFLOAT
fontexts.cxx
elf
elf [?] PTR
dumps a LOGFONTW structure at PTR
fontexts.cxx
fdm
fdm [?] PTR
dumps an FD_DEVICEMETRICS structure at PTR.
fontexts.cxx
ffv
ffv [?] PTR
dumps a FONTFILEVIEW structure at PTR.
fontexts.cxx
fh
fh [?] PTR
dumps a FONTHASH structure at PTR.
fontexts.cxx
fo
fo [?acfhwxy] pointer to FONTOBJ
a maximal dump
c cache
x transform data
? this message
f font
h FONTOBJ header
w FD_GLYPHSET
y Glyph Memory Usage
If no switches are supplied, h is assumed.
fontexts.cxx
fv
fv [?] PTR
dumps a FILEVIEW structure at PTR.
fontexts.cxx
gb
gb [?] [g|m] [h] address
? this message
h print header
m print monochrome bitmap
g print 4bpp bitmap
If no flags are supplied, m h assumed.
If m and g are supplied together, m is assumed.
fontexts.cxx
gdata
gdata [?] PTR
dumps a GLYPHDATA structure at PTR.
fontexts.cxx
gdf
gdf [?] PTR
dumps a GLYPHDEF structure at PTR.
fontexts.cxx
gp
gp [?] PTR
dumps a GLYPHPOS structure at PTR.
fontexts.cxx
gs
gs [?] PTR
dumps an FD_GLYPHSET structure at PTR.
fontexts.cxx
hb
hb [?] PTR
dumps a HASHBUCKET structure at PTR.
fontexts.cxx
hdc
Syntax:
hdc [?gltf] HANDLE
Optional Flags:
? help
g general
l dclevel
t dcattr
f font information
Example:
This example continues the example in dumpobj.
kd> !gdikdx.dumpobj p 3f8 DC_TYPE
object list for DC type objects owned by PID 0x3f8
I, handle, Lock, sCount, pid, pv, objt, unique, Flags, pUser, Tlock
16d, e01016d, 0, 0, 3f8, a2055a08, DC, e01, 4, 00dd054c, 00dd054c
16f, c01016f, 0, 0, 3f8, a2194008, DC, c01, 0, 00dd0388, 00dd0388
170, 7010170, 0, 0, 3f8, a2062008, DC, 701, 0, 00dd0000, 00dd0000
173, a010173, 0, 0, 3f8, a20c6008, DC, a01, 0, 00dd0710, 00dd0710
175, 1010175, 0, 0, 3f8, a20d3008, DC, 101, 0, 00dd01c4, 00dd01c4
181, b010181, 0, 0, 3f8, a205da08, DC, b01, 4, 00dd08d4, 00dd08d4
18a, 301018a, 0, 0, 3f8, a206ba08, DC, 301, 4, 00dd0c5c, 00dd0c5c
18b, 301018b, 0, 0, 3f8, a20c6a08, DC, 301, 4, 00dd0a98, 00dd0a98
18f, 201018f, 0, 0, 3f8, a20c7a08, DC, 201, 0, 01330388, 01330388
195, 4010195, 0, 0, 3f8, a20634a8, DC, 401, 0, 01330000, 01330000
1aa, b0101aa, 0, 0, 3f8, a20bea08, DC, b01, 4, 01330c5c, 01330c5c
1ac, 20101ac, 0, 0, 3f8, a20e95c8, DC, 201, 4, 00dd0e20, 00dd0e20
1ad, 20101ad, 0, 0, 3f8, a206d008, DC, 201, 4, 01330710, 01330710
1af, 30101af, 0, 0, 3f8, a206e008, DC, 301, 4, 013308d4, 013308d4
1b0, 30101b0, 0, 0, 3f8, a206ea08, DC, 301, 4, 01330a98, 01330a98
Total objects = 15
kd> !gdikdx.hdc 1aa
DC
address
[a20bea24] ppdev_ 0xa2015368
[a20bea18] dhpdev_ 0xa2016000
[a20bea2c] flGraphicsCaps_ 0x21550c
GCAPS_ALTERNATEFILL
GCAPS_WINDINGFILL
GCAPS_OPAQUERECT
GCAPS_MONO_DITHER
GCAPS_ASYNCMOVE
GCAPS_DITHERONREALIZE
0x14000 BAD FLAGS
[a20bedb4] hdcNext_ 0
[a20bedb8] hdcPrev_ 0
[a20bedbc] erclClip 0 0 22 946
[a20bedd4] erclWindow 0 0 22 946
[a20bede4] erclBounds_ 0 0 0 0
[a20bedf4] erclBoundsApp_ 0 0 0 0
[a20bee04] prgnAPI_ 0
[a20bee08] prgnVis_ 0xa206d648
[a20bee0c] prgnRao_ 0
[a20befec] ipfdDevMax_
[a20bee10] ptlFillOrigin 0 0
[a20bee18] eboFill_
[a20bee68] eboLine_
[a20beeb8] eboText_
[a20bef08] eboBackground_
[a20bef58] hlfntCur_ 0
[a20bef5c] flSimulationFlags_ 0
0x14000 BAD FLAGS
[a20bef60] lEscapement_ 0
[a20bef64] prfnt_ 0
[a20befe4] pPFFList 0
[a20bef68] co_ !gdikdx.dco a20bef68
[a20bea34] pDCAttr 0x1330c5c
[a20bebf0] dcattr !gdikdx.dca a20bebf0
[a20bea38] dclevel !gdikdx.dcl a20bea38
[a20beff0] ulCopyCount_ 4294967295
[a20beff4] pSurfInfo 0
[a20bea1c] dctp_ 1 DCTYPE_MEMORY
[a20bea20] fs_ 0
Source:
fontexts.cxx
helf
helf [?] HANDLE
dumps a LOGFONTW structure with handle HANDLE.
fontexts.cxx
help
help
Displays an overview of all the debugger extensions in gdikdx.dll
help.cxx
hpfe
dumping a PFE using a handle makes no sense, so this is not implemented.
fontexts.cxx
ifi
ifi [?] PTR
dumps an IFIMETRICS structure at PTR.
fontexts.cxx
la
la [?] PTR
dumps a LINEATTRS structure at PTR.
fontexts.cxx
mx
mx [?] PTR
dumps a MATRIX structure at PTR.
fontexts.cxx
pdev
pdev [?ofy] PTR
dumps a PDEV structure at PTR.
y glyph memory usage
o memory addresses
f functions hooked
fontexts.cxx
pfe
pfe [?] PTR
dumps a PFE structure at PTR.
fontexts.cxx
pff
pff [?] PTR
dumps a PFF structure at PTR.
fontexts.cxx
pft
pft [?] PTR
dumps a PFT structure at PTR.
fontexts.cxx
pubft
pubft [?]
Equivalent to pft win32k!gpPFTPublic.
fontexts.cxx
pvtft
pvtft [?]
Equivalent to pft win32k!gpPFTPrivate.
fontexts.cxx
rgnlog
rgnlog [?] nnn [s1] [s2] [s3] [s4]
Dumps the last nnn rgnlog entries.
gdiexts.cxx
stats
stats [?]
Displays some statistics.
gdiexts.cxx
stro
stro [?ehp] address
h displays the header information
p displays the glyph position
e far east assumes h
fontexts.cxx
tm
tm [?] PTR
dumps a TEXTMETRIC structure at PTR.
fontexts.cxx
tmwi
tmwi [?] PTR
dumps a TMW_INTERNAL structure at PTR.
fontexts.cxx
tstats
tstats [?] [binsize]
binsize is in the range [1..50] and defaults to 1
fontexts.cxx
xo
xo [?] PTR
dumps an EXFORMOBJ structure at PTR.
fontexts.cxx
So we look at dwDdBltViaGdi():
DWORD
dwDdBltViaGdi(
EDD_SURFACE* peSurfaceDest,
EDD_SURFACE* peSurfaceSrc,
DD_BLTDATA* pBltData
)
!gdikdx.dh e1939908
Loaded gdikdx extension DLL
Entry from ghmgr for handle 0xe1939908:
&pent = a016743c
pent = a0180000
move() = 0
pobj/hfree = 0x0100a9de
ObjectOwner = 0x0006f3e0
pidOwner = 0x6
ShareCount = 0x73e0
lock = LOCKED
puser = 0x10017f4
objt = 0x6
usUnique = 0xf3b0
fsHmgr = 0x0
hHmgr = 0x00000000
cExcluLock = 0x00000001
tid = 0x0006f3bc
This is LO_PEN_TYPE
This is not very useful so we check out the next routine up the stack, NtGdiDdBlt
DWORD
APIENTRY
NtGdiDdBlt(
HANDLE hSurfaceDest,
HANDLE hSurfaceSrc,
PDD_BLTDATA puBltData
)
kd> !gdikdx.dddsurface 0xe1939908
EDD_SURFACE structure at 0xE1939908:
PDD_SURFACE_GLOBAL lpGbl 0xe1939960
PDD_SURFACE_MORE lpMore 0xe1939954
DWORD dwFlags 0x2000
DDRAWISURF_HASPIXELFORMAT
DWORD ddsCaps.dwCaps 0x20005000
DDSCAPS_TEXTURE
DDSCAPS_VIDEOMEMORY
DDCOLORKEY ddckCKSrcBlt/Overlay 0x0:0x0
DDCOLORKEY ddckCKDestBlt/Overlay 0x0:0x0
PDD_ATTACHLIST lpAttachList 0x0
PDD_ATTACHLIST lpAttachListFrom 0x0
DWORD dwMipMapCount 0x0
EDD_VIDEOPORT* peVideoPort 0x0
HBITMAP hbmGdi 0x46050168
DWORD dwOverlayFlags 0x0
DWORD dwBlockSizeX 0x0
DWORD dwBlockSizeY 0x0
FLATPTR fpVidMem 0xf8300000
LONG lPitch 0x200
LONG xHint 0x2aa
LONG yHint 0x14aeaa
DWORD wWidth 0x100
DWORD wHeight 0x100
DWORD (global) dwReserved1 0xe11d8c48
DWORD (local) dwReserved1 0x0
DDPIXELFORMAT ddpfSurface
DWORD dwSize (should be 0x20) 0x20
DWORD dwFlags 0x40
DDPF_RGB
DWORD dwFourCC 0x0
DWORD dwRGB/YUV/ZBuffer/AlphaBitCount 0x10
DWORD dwRBitMask/dwYBitMask 0xf800
DWORD dwGBitMask/dwUBitMask 0x7e0
DWORD dwBBitMask/dwVBitMask 0x1f
DWORD dwRGB/YUVAlphaBitMask 0x0
EDD_SURFACE* peSurface_DdNext 0xe187c0c8
EDD_SURFACE* peSurface_LockNext 0x0
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal 0xe128e550
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocal 0xe11f7b28
FLONG fl 0x8c
DD_SURFACE_FLAG_DRIVER_CREATED
DD_SURFACE_FLAG_CREATE_COMPLETE
ULONG iVisRgnUniqueness 0x312
BOOL bLost FALSE
HANDLE hSecure 0x0
ERECTL rclLock: (0, 0, 256, 256)
ULONG cLocks 0x1
HDC hdc 0x0
EDD_SURFACE* peSurfacePrimary 0x0
BOOL bSuspended 0x0
HDEV hdev 0x0
LONG cDriverReferences 0x100
DWORD dwNumHeaps 0x10
VIDEOMEMORY* pvmList 0x7e0
DWORD dwNumFourCC 0x1f
DWORD* pdwFourCC 0x0
DD_HALINFO HalInfo
DD_CALLBACKS CallBacks
DD_SURFACECALLBACKS SurfaceCallBacks
DD_PALETTECALLBACKS PaletteCallBacks
Next we dump the hdev from the DDraw global structure to get at the surface.
kd> !gdikdx.dpdev 0xe128e008 [ANDREWGO 4:52 PM]
ppdev = 0xe128e008
ppdevNext = 0xe1286008
flags = 0x40045
PDEV_DISPLAY
PDEV_SOFTWARE_POINTER
PDEV_GOTFONTS
PDEV_DRIVER_PUNTED_CALL
cPdevRefs = 69
cPdevOpenRefs = 1
pldev = 0xe128d1c8
dhpdev = 0xe19a5000
hSpooler = 0x8070b930
pSurface = 0xe189f628
ppalSurf = 0xe18ea568
peDirectDrawGlobal = 0xe128e550
pSpriteState = 0xe128e048
pDesktopId = 0x1
pGraphicsDevice = 0xe128a848
ppdevParent = 0xe128e008
hsemDevLock = 0x806723c8
ptlOrigin = 0, 0
apfn = 0xe128eb20
At this point we need to find out what the CPU was doing when it died. First we use kv
to get the trapframe and then use !trap to find out the state of the CPU when it
bugchecked.
kd> kv
ChildEBP RetAddr Args to Child
f65d651c 80425185 00000003 00000001 00000000 ntoskrnl!RtlpBreakWithStatusInstruction (FPO: [1,0,0])
f65d654c 8042548b 00000003 c03e5d40 80007ae0 ntoskrnl!KiBugCheckDebugBreak+0x31(FPO: [NonFpo]
f65d68ac 8043d5dc 00000050 f9750000 00000001 ntoskrnl!KeBugCheckEx+0x111(FPO: [NonFpo]
f65d68ec 80458183 00000001 f9750000 00000000 ntoskrnl!MmAccessFault+0x54e(FPO: [NonFpo]
f65d68ec 80450723 00000001 f9750000 00000000 ntoskrnl!KiTrap0E+0xc3 (FPO: [0,0] TrapFrame @ f65d6904)
f65d6980 a011a19a f9750000 000d7558 00000200 ntoskrnl!memmove+0x33(FPO: [NonFpo]
f65d69a4 a0037f56 00000100 a0037ace e1291a58 win32k!vSrcCopyS16D16Identity+0x49(FPO: [NonFpo]
f65d6b94 a00f1383 e1291a58 e1980438 00000000 win32k!EngCopyBits+0x488(FPO: [NonFpo]
f65d6bc8 a00f16eb e1939908 f94d5f10 e1291a48 win32k!dwDdBltViaGdi+0x194(FPO: [NonFpo]
f65d6d50 80454ed4 21030204 0c0301bf 0006f4b4 win32k!NtGdiDdBlt+0x31b(FPO: [NonFpo]
f65d6d50 77eac661 21030204 0c0301bf 0006f4b4 ntoskrnl!KiSystemService+0xc4 (FPO: [0,0] TrapFrame @ f65d6d64)
0006f5f8 74676a14 01428818 00000000 01428918 0x77eac661 [Stdcall: 20]
kd> !trap f65d6904
eax=000d7758 ebx=f9750000 ecx=00000080 edx=00000000 esi=000d7558 edi=f9750000
eip=80450723 esp=f65d6978 ebp=f65d6980 iopl=0 nv up ei pl nz ac po nc
vip=0 vif=0
cs=0008 ss=0010 ds=0023 es=0023 fs=0030 gs=0000 efl=00010216
ErrCode = 00000002
80450723 f3a5 rep movsd
We see from the !trap that we were trying to move some memory from 0x 000d7558 to
0xf9750000 (esi to edi)
Base Code Size Data Size Driver Name Creation Time
...
[stuff deleted]
...
a0000000 160fa0 (1411 kb) 1ca00 ( 114 kb) win32k.sys Sat Sep 05 05:14:56 1998
f721c000 378e0 ( 222 kb) c280 ( 48 kb) atmfd.dll Tue Sep 08 12:17:17 1998
f28d0000 d980 ( 54 kb) cc0 ( 3 kb) igfxdll.dll Wed Sep 09 10:26:21 1998
f2d28000 1420 ( 5 kb) 700 ( 1 kb) rasacd.sys Sat Sep 05 05:24:44 1998
f2ce0000 26c0 ( 9 kb) ca0 ( 3 kb) TDI.SYS Sat Sep 05 05:23:49 1998
f653e000 16c00 ( 91 kb) 1320 ( 4 kb) nbf.sys Sat Sep 05 05:24:12 1998
f6527000 14600 ( 81 kb) 1b00 ( 6 kb) afd.sys Sat Sep 05 05:24:55 1998
f2b20000 67c0 ( 25 kb) c80 ( 3 kb) netbios.sys Sat Sep 05 05:25:07 1998
f64b5000 1e040 ( 120 kb) 2e40 ( 11 kb) rdbss.sys Sat Sep 05 05:20:36 1998
f646b000 327c0 ( 201 kb) 4aa0 ( 18 kb) srv.sys Sat Sep 05 05:20:40 1998
f63c5000 4c720 ( 305 kb) 85e0 ( 33 kb) mrxsmb.sys Sat Sep 05 05:20:37 1998
f6098000 a7c40 ( 671 kb) 4360 ( 16 kb) igfxd3d.dll Wed Sep 09 10:26:23 1998
TOTAL: 5ad2a0 (5812 kb) b7600 ( 733 kb) ( 0 kb 0 kb)
To be sure we go and check out the fpVidMem field in the DDraw surface we dumped
earlier.
kd> dd 0xf8300000
f8300000 00000000 00000000 00000000 00000000
f8300010 00000000 00000000 00000000 00000000
f8300020 00000000 00000000 00000000 00000000
f8300030 00000000 00000000 00000000 00000000
f8300040 00000000 00000000 00000000 00000000
f8300050 00000000 00000000 00000000 00000000
f8300060 00000000 00000000 00000000 00000000
f8300070 00000000 00000000 00000000 00000000
This memory is accessible, so we go and find out why we’re not accessing 0xf8300000.
We dump the local ddraw structure from the surface same surface.
kd> !gdikdx.dddlocal 0xe11f7b28
EDD_DIRECTDRAW_LOCAL structure at 0xE11F7B28:
FLATPTR fpProcess 0x1450000
EDD_DIRECTDRAW_GLOBAL* peDirectDrawGlobal 0xe128e550
EDD_SURFACE* peSurface_DdList 0xf94d5f10
EDD_DIRECTDRAW_LOCAL* peDirectDrawLocalNext 0x0
FLONG fl 0x1
HANDLE UniqueProcess 0x140
PEPROCESS Process 0x81c78190
kd>? 0x1450000+0xf8300000
Evaluate expression: 109772800 = 0xf9750000
It seems that the memory location we’re accessing is the sum of the fpVidMem and
fpProcess fields. The destination surface is marked as DDSCAPS_VIDEOMEMORY, yet its
fpVidMem has a value of 0xf8300000. When DDSCAPS_VIDEOMEMORY is set, the start
of the user-mode mapping for the surface should be peDirectDrawLocal->fpProcess +
peSurface->fpVidMem, which in this case is 0xf9750000 - and we died trying to write to
this very address.
It appears that either that the surface’s fpVidMem is wrong (it should be less than the
total amount of video memory if the type is DDSCAPS_VIDEOMEMORY), or that the
surface is really DDSCAPS_SYSTEMMEMORY (which might be, since there’s memory at
0xf8300000). Could be a driver thing - what’s a “igfxdll.dll” driver?
In this case the igfxdll.dll is a new Intel 740 driver which very likely is the source of this
bug.
To test if a remote machine is running Hydra do a dd MiHydra. If the value is 1 then the
system is a Hydra system.
Hydra systems have multiple copies of win32k.sys (one for each session). Generally if a
system fails on a routine, the relevant win32k for the session will be in memory and
debugging can proceed as normal. If the failure still has the win32k paged out and you
need access to win32k variables and routines, there’s not much you can do.
If you’re trying to test some routine, using the debugger can be a bit difficult - having
more than one win32k means that normally the win32k is paged out.
Breaking into a machine that’s running normally will usually result in this problem:
kd> !reload
Unable to read header for win32k.sys at a0000000
Unable to read header for atmfd.dll at a0790000
Unable to read header for mga64.dll at a0230000
It will be impossible to set break points in win32k routines using the bp command
because the debugger cannot find the correct win32k (and in fact it’s not paged in).
Also the standard gdi debugger extensions won’t behave as expected. Because the
win32k is paged out, the handle manager is inaccessible. The problem is that the
extensions aren’t able to detect this and this can cause random behavior:
kd> !gdikdx.dumphmgr
Loaded gdikdx extension DLL
Max handles out so far 2686470268
Total Hmgr: Reserved memory 2097152 Committed 67702784
The command above caused the debugger to become unusable while it tried to get 2.6
billion handles! Again, you needn’t worry about this if you’re debugging a failure in
some win32k routine, because the relevant win32k.sys should be paged in.
kd> ba e1 win32k!NtGdiLineTo
sets a hardware breakpoint stopping the system inside any win32k that has it’s
execution point reach NtGdiLineTo. At the point it breaks, win32k will be loaded into
memory and debugging can proceed as normal. However, you don’t know whether
you’re debugging a terminal session or the main console session.
kd> dd win32k!G_fConsole l1
a01fd61c 00000001
G_fConsole is a Boolean variable set to TRUE (1) when the win32k context is not a
hydra session.
kd> dd win32k!gbRemoteSession l1
a021082c 00000000
This variable is simply a zero based count indicating how many copies of win32k have
been loaded before this one. The main session (console) has a gbRemoteSession of 0.
For more information about debugging Hydra see “How to Debug Bugcheck AB
(SESSION_HAS_VALID_PAGES)” below, or contact clupu in connection with stack traces
in checked builds.
SalimC kindly contributed the following info on how to debug this bugcheck that occurs
when a hydra session leaks memory.
A major difference between Hydra 4 and NT 5 is that win32k.sys is now responsible for cleaning
up all its paged and non-paged pool allocations at session exit. If the memory manager detects
that win32k has leaked any memory it raises a bugcheck AB (SESSION_HAS_VALID_PAGES).
KeBugCheckEx (SESSION_HAS_VALID_PAGES,
(ULONG_PTR)MmSessionSpace->SessionId,
MmSessionSpace->PagedPoolBytes,
MmSessionSpace->NonPagedPoolBytes,
MmSessionSpace->NonPagedPoolAllocations + MmSessionSpace-
>PagedPoolAllocations);
e.g The following debugger dump shows that the sessionId is 1 and we leak 0x2140 bytes of
Paged Pool and 0x0 btes of NonPagedPool across two allocations.
0x000000ab 0x00000001,0x00002140,0x00000000,0x00000002
| | | | |
BugCode -------+ | | | |
| | | |
SessionID ------------------+ | | |
| | |
Paged Bytes Leaked ---------------------+ | |
| |
Non-paged Bytes Leaked -------------------------------+ |
|
Total Allocations Leaked -----------------------------------------+
For Hydra the win32k Paged pool allocations come out of a region of memory which is specific
to each session whereas the non-paged pool allocations come out of the system wide non-
paged pool. This means that at session exit we can sweep the session specific paged pool
allocation memory range and figure out if there any valid pages left. However this cannot be
done for non-paged pool since there is no way identify which non-paged pool allocations belong
to which session. So if you hit a bugcheck AB where the NonPagedPoolBytes field is non zero
there is not much you can do at that point (See the section below on turning on Pool tracking).
As of build 2007, Win32k now has built-in tracking of allocations (even on free builds). CLupu's
e-mail below explains what options are available:
There are several levels of tracing controlled from the registry under the following key:
HKLM\System\CurrentControlSet\Control\Session Manager\SubSystems\Pool
if this key doesn't exist default settings are used for each of the following key.
1. HeavyRemoteSession REG_DWORD
default: 1
if this is non zero or the key doesn't exist then pool tracing is on for remote sessions of
win32k.sys.
2. HeavyConsoleSession REG_DWORD
default: 0
if this is non zero then pool tracing is on for console sessions of win32k.sys. it the key
doesn't exist then pool tracing is off for the main session.
3. StackTraces REG_DWORD
default:
- 1 for remote sessions
- 0 for the main session
if non zero then a stack trace record will be saved for every pool allocation made.
4. KeepFailRecords REG_DWORD
default: 32
if non zero then win32k.sys will keep a list of the last x allocations that failed (tag +
stack trace). Use !dpa -f to dump the stack traces of the failed allocations
4. UseTailString REG_DWORD
default: 0
if non zero for every pool allocation there will be a string attached to the end of the
allocation to catch some specific type of memory corruption.
5. KeepFreeRecords REG_DWORD
default: 32
the number will specify how many free pointers will be kept in a list so we can
differentiate when we call ExFreePool between a totally bogus value and a pointer that
was already freed.
6. AllocationIndex REG_DWORD
7. AllocationsToFail REG_DWORD
If AllocationIndex is non zero then win32k counts the pool allocations made and will
start failing from allocation AllocationIndex a number of AllocationsToFail allocations.
This is useful during boot time when a user mode test cannot call
Win32PoolAllocationStats to fail pool allocations.
cornel
With win32k allocation tracking you can use the user kernel debugger extension to dump the
allocation information as follows:
0: kd>!dpa -ts
If the user debugger extensions aren't available, then you can manually debug paged pool
leaks. You first dump the page table entries for the paged-pool memory allocations. To
determine the address location where the PTEs are located, dump mmsessionspace and add
32mb to the value, then do a !pte on the result. That's the start address to dump PTEs.
For x86 (non-3G mode) this address is 0xc0288000. For Alpha the address is 0xc01c0000.
In the above dump you can see that all the pte entries are 0x00000300 (0x000000c0 for Alpha)
which means that they have already been freed. However two entries (c0288bc0+0x4) and
(c0288d50+0x8) still have valid pages.
Do a !pte on each page table entry to find the address of the page with valid pool allocations.
0: kd> !pte c0288bc0+0x4
Do a !pool on the page address to dump the pool allocations on that page
As you can see we are leaking two allocations with tags Gdbr and Gebr. Once you know the
tags, grep in w32\ntgdi\gre and w32\ntuser\kernel directories for the tag string in reserver order
i.e do a 'findstr /i rbeG *'. Generally the tags starting with the letter 'G' are in GDI and those
starting with letter 'U' are in the user code.