I have a crash dump and I suspect GDI leaks to be a cause of the crash
From the full crash dump is there anyway to find out the number of GDI handles used by my process when it crashed?
I have a crash dump and I suspect GDI leaks to be a cause of the crash
From the full crash dump is there anyway to find out the number of GDI handles used by my process when it crashed?
I have created a Windbg script to dump all GDI Handles from the GDI Handle table. See https://aloiskraus.wordpress.com/2016/06/25/show-gdi-handles-by-type-in-windbg/
When you dump it e.g. two times you can see what has changed there:
0:013> $$>a<"D:\GdiDump\DumpGdi.txt"
GDI Handle Table 00000000013e0000 0000000001561000
GDI Handle Count 14
DeviceContexts: 4
Regions: 2
Bitmaps: 2
Palettes: 0
Fonts: 3
Brushes: 3
Pens: 0
Uncategorized: 0
0:013> g
0:014> $$>a<"D:\GdiDump\DumpGdi.txt"
GDI Handle Table 00000000013e0000 0000000001561000
GDI Handle Count 1021
DeviceContexts: 8
Regions: 3
Bitmaps: 1003
Palettes: 0
Fonts: 3
Brushes: 4
Pens: 0
Uncategorized: 0
Here is the script
$$ Run as: $$>a<DumpGdi.txt
$$ Written by Alois Kraus 2016
$$ uses pseudo registers r0-5 and r8-r14
r @$t1=0
r @$t8=0
r @$t9=0
r @$t10=0
r @$t11=0
r @$t12=0
r @$t13=0
r @$t14=0
$$ Increment count is 1 byte until we find a matching field with the current pid
r @$t4=1
r @$t0=$peb
$$ Get address of GDI handle table into t5
.foreach /pS 3 /ps 1 ( @$GdiSharedHandleTable { dt ntdll!_PEB GdiSharedHandleTable @$t0 } ) { r @$t5 = @$GdiSharedHandleTable }
$$ On first call !address produces more output. Do a warmup
.foreach /pS 50 ( @$myStartAddress {!address @$t5} ) { }
$$ Get start address of file mapping into t2
.foreach /pS 4 /ps 40 ( @$myStartAddress {!address @$t5} ) { r @$t2 = @$myStartAddress }
$$ Get end address of file mapping into t3
.foreach /pS 7 /ps 40 ( @$myEndAddress {!address @$t5} ) { r @$t3 = @$myEndAddress }
.printf "GDI Handle Table %p %p", @$t2, @$t3
.for(; @$t2 < @$t3; r @$t2 = @$t2 + @$t4)
{
$$ since we walk bytewise through potentially invalid memory we need first to check if it points to valid memory
.if($vvalid(@$t2,4) == 1 )
{
$$ Check if pid matches
.if (wo(@$t2) == @$tpid )
{
$$ increase handle count stored in $t1 and increase step size by 0x18 because we know the cell structure GDICell has a size of 0x18 bytes.
r @$t1 = @$t1+1
r @$t4 = 0x18
$$ Access wType of GDICELL and increment per GDI handle type
.if (by(@$t2+6) == 0x1 ) { r @$t8 = @$t8+1 }
.if (by(@$t2+6) == 0x4 ) { r @$t9 = @$t9+1 }
.if (by(@$t2+6) == 0x5 ) { r @$t10 = @$t10+1 }
.if (by(@$t2+6) == 0x8 ) { r @$t11 = @$t11+1 }
.if (by(@$t2+6) == 0xa ) { r @$t12 = @$t12+1 }
.if (by(@$t2+6) == 0x10 ) { r @$t13 = @$t13+1 }
.if (by(@$t2+6) == 0x30 ) { r @$t14 = @$t14+1 }
}
}
}
.printf "\nGDI Handle Count %d", @$t1
.printf "\n\tDeviceContexts: %d", @$t8
.printf "\n\tRegions: %d", @$t9
.printf "\n\tBitmaps: %d", @$t10
.printf "\n\tPalettes: %d", @$t11
.printf "\n\tFonts: %d", @$t12
.printf "\n\tBrushes: %d", @$t13
.printf "\n\tPens: %d", @$t14
.printf "\n\tUncategorized: %d\n", @$t1-(@$t14+@$t13+@$t12+@$t11+@$t10+@$t9+@$t8)
It is unlikely since the only debugger extension gdikdx.dll tailored at gdi tasks is not actively maintained since the w2k version and i believe they stopped shipping it since not that many folks are into hacking into gdi internals - according to someone's statement i stumbled upon in a newsgroup - therefore it is no longer invested into. You're left with only a few options all of which are unfortunately about runtime troubleshooting.
You could start with a tool like nirsoft's GDIView to monitor the use of GDI resources from your app and then progress to any of the runtime instrumentation options:
P.S. could you be more specific on the actual reason of your particular crash?
Tess talks about a similar situation, perhaps this will give you a lead...
Here is an alternative script that dumps the gdi handles from GdiSharedHandleTable it can be used in live usermode / live kernelmode / dump mode it can also be used in !for_each_process command string to dump gdi handles from all running process in a kernel mode debugging
it uses a .catch block to print the summary
in kd some times the GdiSharedhandleTable page will be paged out / truncated to less than its allocation size The peb header paged out etc problems arise
so this script tries to read as much as it is possible and when a memory access violation happens leaves the catch block and prints a summary of
what it was able to salvage
btw this script is for 32 bit for 64 bit the Pseudo registers need to be adjusted as needed
r $t19=0;r $t18=0;r $t17=0;r $t16=0;r $t15=0;r $t14=0;r $t13=0;r $t12=0;
r $t0 = @@c++(@$Peb->GdiSharedHandleTable)
r $t1 = (@@c++(@$Peb->GdiSharedHandleTable) + 0xffffff )
r $t2 = 0
.catch {
.printf /D "<b>gdioffs Kaddr Pid Count Handle Type Tname
IsLive UAddr </b>\n";
.while(@$t0 < @$t1) {
.while( wo(@$t0+4) != @$tpid) {
r $t0 = @$t0+0x10 ; r $t2 = @$t2+1
}
.printf "%08x " , @$t0 ; .printf "%08x " , dwo(@$t0)
.printf "%08x " , wo(@$t0+4) ;.printf "%08x " , wo(@$t0+6)
.printf "%08x " , (wo(@$t0+8)<<0x10)+@$t2 ; .printf "%08x " , by(@$t0+a)
.if( by(@$t0+a) == 1 ) {r $t19=@$t19+1;.printf "DC "}
.elsif( by(@$t0+a) == 4 ) {r $t18=@$t18+1;.printf "Region "}
.elsif( by(@$t0+a) == 5 ) {r $t17=@$t17+1;.printf "Bitmap "}
.elsif( by(@$t0+a) == 8 ) {r $t16=@$t16+1;.printf "Pallete "}
.elsif( by(@$t0+a) == a ) {r $t15=@$t15+1;.printf "Font "}
.elsif( by(@$t0+a) == 10) {r $t14=@$t14+1;.printf "Brush "}
.elsif( by(@$t0+a) == 30) {r $t13=@$t13+1;.printf "Pen "}
.else {r $t12=@$t12+1;.printf "Unknown "}
.printf "%08x " , by(@$t0+b)
.printf "%08x\n" , dwo(@$t0+c)
r $t0 = @$t0+0x10
r $t2 = @$t2+1
}
}
r? @$t11 = @@c++(@$peb->ProcessParameters->ImagePathName.Buffer)
.printf /D "<b>Gdi Handles for %mu</b>\n", @$t11
.printf "Total Gdi Handles = %d\n", (@$t19+@$t18+@$t17+@$t16+@$t15+@$t14+@$t13+@$t12)
.printf "DC = %d\n" , @$t19 ; .printf "Font = %d\n" , @$t18
.printf "Region = %d\n" , @$t17 ; .printf "Brush = %d\n" , @$t16
.printf "Bitmap = %d\n" , @$t15 ; .printf "Pen = %d\n" , @$t14
.printf "Pallete = %d\n" , @$t13 ; .printf "Unknpown = %d\n" , @$t12
result of execution
0:000> $$>a< c:\wdscr\dumpgdi.txt
gdioffs Kaddr Pid Count Handle Type Tname ;IsLive UAddr
00472b30 fe6b5728 00000ca4 00000000 0d0102b3 00000001 DC 00000040 000e0cb0
00472be0 fdf73da8 00000ca4 00000000 420502be 00000005 Bitmap 00000040 00000000
004737b0 fddac108 00000ca4 00000000 9605037b 00000005 Bitmap 00000040 00000000
00474030 fe76eda8 00000ca4 00000000 eb050403 00000005 Bitmap 00000040 00000000
00474c90 fddde008 00000ca4 00000000 d70a04c9 0000000a Font 00000040 001fb1e8
0047ab80 fddab008 00000ca4 00000000 ba050ab8 00000005 Bitmap 00000040 00000000
0047f270 fddbcda8 00000ca4 00000000 16050f27 00000005 Bitmap 00000040 00000000
0047fef0 fdee4da8 00000ca4 00000000 cd050fef 00000005 Bitmap 00000040 00000000
004809f0 fe72eda8 00000ca4 00000000 3405109f 00000005 Bitmap 00000040 00000000
00480e50 fdda5aa8 00000ca4 00000000 0e0510e5 00000005 Bitmap 00000040 00000000
00481cf0 ffb0fda8 00000ca4 00000000 df0511cf 00000005 Bitmap 00000040 00000000
00481d70 fddb0da8 00000ca4 00000000 930511d7 00000005 Bitmap 00000040 00000000
00482020 ff4a1da8 00000ca4 00000000 d4051202 00000005 Bitmap 00000040 00000000
00482060 fddd4008 00000ca4 00000000 39051206 00000005 Bitmap 00000040 00000000
00482170 fddb6008 00000ca4 00000000 20051217 00000005 Bitmap 00000040 00000000
00483140 ff4a0008 00000ca4 00000000 4e051314 00000005 Bitmap 00000040 00000000
00483870 ff427980 00000ca4 00000000 6d051387 00000005 Bitmap 00000040 00000000
00483d80 fe7d04b0 00000ca4 00000000 bd0513d8 00000005 Bitmap 00000040 00000000
00484620 ff437eb8 00000ca4 00000000 0d101462 00000010 Brush 00000040 000f0fd8
004846a0 fddc2da8 00000ca4 00000000 d305146a 00000005 Bitmap 00000040 00000000
00484b80 fdf1a728 00000ca4 00000000 530114b8 00000001 DC 00000040 000e0ae0
Memory access error at ') != @$tpid) <-------- jumps out of catch block here
Gdi Handles for C:\Windows\system32\calc.exe
Total Gdi Handles = 21
DC = 2
Font = 0
Region = 17
Brush = 0
Bitmap = 1
Pen = 1
Pallete = 0
Unknpown = 0
© 2022 - 2024 — McMap. All rights reserved.
!handles
will list all handles in the dump, but I don't think it includes the GDI ones, only the ones listed at msdn.microsoft.com/en-us/library/ms724211(VS.85).aspx. – Basso