【问题标题】:Command to get GDI handle count from a crash dump从故障转储中获取 GDI 句柄计数的命令
【发布时间】:2010-12-10 06:16:47
【问题描述】:

我有一个崩溃转储,我怀疑 GDI 泄漏是导致崩溃的原因

是否可以从完整的故障转储中找出我的进程在崩溃时使用的 GDI 句柄数?

【问题讨论】:

标签: windbg


【解决方案1】:

我创建了一个 Windbg 脚本来转储 GDI 句柄表中的所有 GDI 句柄。见https://aloiskraus.wordpress.com/2016/06/25/show-gdi-handles-by-type-in-windbg/

当你转储它时,例如两次你可以看到那里发生了什么变化:

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

这是脚本

$$ 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)

【讨论】:

【解决方案2】:

这是不太可能的,因为自 w2k 版本以来,唯一针对 gdi 任务定制的调试器扩展 gdikdx.dll 没有得到积极维护,我相信他们停止发布它,因为没有多少人进入 gdi 内部 - 根据某人的声明我在新闻组中偶然发现-因此不再投资。 您只剩下几个选项,不幸的是,所有这些选项都与运行时故障排除有关。

您可以从 nirsoft 的 GDIView 之类的工具开始监控应用程序中 GDI 资源的使用情况,然后进入任何运行时检测选项:

附:您能否更具体地说明您的特定崩溃的实际原因?

【讨论】:

    【解决方案3】:

    【讨论】:

      【解决方案4】:

      这是一个从 GdiSharedHandleTable 转储 gdi 句柄的替代脚本,它可以在实时用户模式/实时内核模式/转储模式下使用 它也可以在 !for_each_process 命令字符串中使用,以在内核模式调试中从所有正在运行的进程中转储 gdi 句柄

      它使用 .catch 块来打印摘要 在 kd 中,有时 GdiSharedhandleTable 页面将被分页/截断到小于其分配大小 peb 标头分页等问题出现
      所以这个脚本尝试尽可能多地读取,当发生内存访问冲突时,会离开 catch 块并打印一个摘要 它能够挽救什么

      顺便说一句,此脚本适用于 64 位的 32 位,需要根据需要调整伪寄存器

      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
      

      执行结果

      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
      

      【讨论】:

        猜你喜欢
        • 2012-12-04
        • 2012-10-23
        • 2010-09-11
        • 1970-01-01
        • 1970-01-01
        • 2010-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多