你最喜欢的Windbg提示/技巧是什么?

我已经认识到,Windbg是Windows平台的一个非常强大的debugging器,我偶尔会学到一些新的东西。 Windbg的用户可以分享一些疯狂的技能吗?

ps:我不是在寻找一个漂亮的命令,那些可以在文档中find。 如何分享有关做一些别人无法想象的事情的提示可以用windbg来完成? 例如,在windbg下运行一个进程时,可以使用某种方法来生成有关内存分配的统计信息。

我最喜欢的命令是.cmdtree <file> (未logging,但在以前的发行说明中引用)。 这可以帮助调出另一个窗口(可以停靠)来显示有用或常用的命令。 这可以帮助用户使用该工具更高效。

最初在这里讨论了<file>参数的例子: http : //blogs.msdn.com/debuggingtoolbox/archive/2008/09/17/special-command-execute-commands-from-a-customized-user -Interface与- cmdtree.aspx

示例: 替代文字http://blogs.msdn.com/photos/debuggingtoolboxhttp://img.dovov.com8954736/original.aspx

调查崩溃转储内存泄漏(因为我更喜欢UMDH实时进程)。 策略是相同types的对象都被分配相同的大小。

  • !heap -h 0命令提供给WinDbg的命令行版本cdb.exe(以获得更高的速度)以获取所有堆分配:
 "C:\Program Files\Debugging Tools for Windows\cdb.exe" -c "!heap -h 0;q" -z [DumpPath] > DumpHeapEntries.log 
  • 使用Cygwin grep的分配列表,按大小分组:
 grep "busy ([[:alnum:]]\+)" DumpHeapEntries.log \ | gawk '{ str = $8; gsub(/\(|\)/, "", str); print "0x" str " 0x" $4 }' \ | sort \ | uniq -c \ | gawk '{ printf "%10.2f %10d %10d ( %s = %d )\n", $1*strtonum($3)/1024, $1, strtonum($3), $2, strtonum($2) }' \ | sort > DumpHeapEntriesStats.log 
  • 例如,你得到一个表格,告诉我们25529270分配的0x24字节需要将近1.2GB的内存。
  8489.52 707 12296 ( 0x3000 = 12288 ) 11894.28 5924 2056 ( 0x800 = 2048 ) 13222.66 846250 16 ( 0x2 = 2 ) 14120.41 602471 24 ( 0x2 = 2 ) 31539.30 2018515 16 ( 0x1 = 1 ) 38902.01 1659819 24 ( 0x1 = 1 ) 40856.38 817 51208 ( 0xc800 = 51200 ) 1196684.53 25529270 48 ( 0x24 = 36 ) 
  • 然后,如果你的对象有vtables,只需使用dps命令在DumpHeapEntries.log中寻找一些0x24字节的堆分配来知道正在占用所有内存的对象的types。
 0:075> dps 3be7f7e8 3be7f7e8 00020006 3be7f7ec 090c01e7 3be7f7f0 0b40fe94 SomeDll!SomeType::`vftable' 3be7f7f4 00000000 3be7f7f8 00000000 

这是俗气,但它的作品:)

当使用vtables在C ++对象堆栈中查看堆栈时,下面的命令非常方便,特别是在使用发布版本进行工作的时候,有很多事情会被优化掉。

dpp esp 范围

能够加载任意PE文件作为转储是整齐的:

windbg -z mylib.dll

用以下方法查询GetLastError():

!GLE

这有助于解码常见的错误代码:

!错误error_number

我每天使用的命令几乎有60%

 dv /i /t ?? this kM (kinda undocumented) generates links to frames .frame x !analyze -v !lmi ~ 

我经常使用的“小技巧”就是让您不必经常碰触那个烦人的鼠标: Alt + 1

Alt + 1会将焦点放置在命令窗口中,以便您可以实际键入一个命令,并使向上箭头实际上在命令历史中滚动。 但是,如果您的焦点已经在可滚动的命令历史logging中,则不起作用。

Peeve:为什么在焦点位于源窗口时忽略了按键? 这不像你可以从WinDbg里面编辑源代码。 Alt + 1进行救援。

一个字(好吧,三个): DML ,即debugging器标记语言

这是WinDbg的一个相当新的补充,它没有logging在帮助文件中。 但是,Windowsdebugging工具安装目录中的“dml.doc”中有一些文档。

基本上,这是一种类似于HTML的语法,您可以将其添加到debugging器脚本进行格式化,更重要的是,可以将其链接。 您可以使用链接来调用其他脚本,甚至是相同的脚本。

我的日常工作涉及一个元build模器的维护,这个元build模器为一大块C ++软件提供通用对象和对象之间的关系。 首先,为了便于debugging,我写了一个简单的转储脚本,从这些对象中提取相关信息。

现在,使用DML,我可以添加链接到输出,允许相同的脚本再次被调用相关的对象。 这允许更快速地探索模型。

这是一个简单的例子。 假设内省下的对象有一个称为“引用”的关系到另一个对象。 r @ $ t0 = $ arg1 $$ arg1是要检查的对象的地址

 $$ dump some information from $t0 $$ allow the user to examine our reference aS /x myref @@(&((<C++ type of the reference>*)@$t0)->reference ) .block { .printf /D "<link cmd=\"$$>a< <full path to this script> ${myref}\">dump Ref</link> " } 

显然,这是一个很好的例子,但是这个东西对我来说是非常宝贵的。 而不是在非常复杂的对象中寻找正确的数据成员(通常需要花费一分钟的时间和各种铸造和解除引用的技巧),所有事情都是一键自动完成的!

  • .prefer_dml 1

    这会修改许多内置的命令(例如lm )以显示DML输出,从而允许您单击链接而不是运行命令。 非常方便…

  • .reload /f /o file.dll/o会覆盖你有的符号的当前副本)

  • .enable_unicode 1 //由于所有Windows组件都在内部使用Unicode,所以将debugging器切换为默认为string的Unicode,这非常方便。

  • .ignore_missing_pages 1如果你做了很多的内核转储分析,你会看到很多关于内存页错误的错误。 这个命令会告诉debugging器停止抛出这个警告。

别名别名别名

在debugging器中保存一段时间。 这里是我的一些:

 aS !p !process; aS !t !thread; aS .f .frame; aS .p .process /p /r aS .t .thread /p /r aS dv dv /V /i /t //make dv do your favorite options by default aS f !process 0 0 //f for find, eg f explorer.exe 

另一个答案提到了命令窗口和Alt + 1来关注命令input窗口。 有没有人发现很难滚动命令输出窗口而不使用鼠标?

那么,我最近使用AutoHotkey使用键盘滚动命令输出窗口,而不离开命令input窗口。

 ; WM_VSCROLL = 0x115 (277) ScrollUp(control="") { SendMessage, 277, 0, 0, %control%, A } ScrollDown(control="") { SendMessage, 277, 1, 0, %control%, A } ScrollPageUp(control="") { SendMessage, 277, 2, 0, %control%, A } ScrollPageDown(control="") { SendMessage, 277, 3, 0, %control%, A } ScrollToTop(control="") { SendMessage, 277, 6, 0, %control%, A } ScrollToBottom(control="") { SendMessage, 277, 7, 0, %control%, A } #IfWinActive, ahk_class WinDbgFrameClass ; For WinDbg, when the child window is attached to the main window !UP::ScrollUp("RichEdit50W1") ^k::ScrollUp("RichEdit50W1") !DOWN::ScrollDown("RichEdit50W1") ^j::ScrollDown("RichEdit50W1") !PGDN::ScrollPageDown("RichEdit50W1") !PGUP::ScrollPageUp("RichEdit50W1") !HOME::ScrollToTop("RichEdit50W1") !END::ScrollToBottom("RichEdit50W1") #IfWinActive, ahk_class WinBaseClass ; Also for WinDbg, when the child window is a separate window !UP::ScrollUp("RichEdit50W1") !DOWN::ScrollDown("RichEdit50W1") !PGDN::ScrollPageDown("RichEdit50W1") !PGUP::ScrollPageUp("RichEdit50W1") !HOME::ScrollToTop("RichEdit50W1") !END::ScrollToBottom("RichEdit50W1") 

运行此脚本后,可以使用Alt + 向上 / 向下滚动命令输出窗口的一行Alt + PgDn / PgUp来滚动一个屏幕。

注意:不同版本的WinDbg将为窗口和控件使用不同的类名,因此您可能需要使用由AutoHotkey提供的窗口间谍工具来首先查找实际的类名。

基于.NET框架版本(v2.0 / v4.0)加载SOS的脚本:

 !for_each_module .if(($sicmp( "@#ModuleName" , "mscorwks") = 0) ) {.loadby sos mscorwks} .elsif ($sicmp( "@#ModuleName" , "clr") = 0) {.loadby sos clr} 

我喜欢使用高级断点命令,例如使用断点来创build新的一次性断点。

不要使用WinDbg的.heap -stat命令。 它有时会给你不正确的输出。 而是使用DebugDiags内存报告。

有了正确的数字,你可以使用WinDbg的.heap -flt ...命令。

对于使用debugging器的命令和直接(静态或可自动化)例程,能够将所有debugging器命令在文本命令文件中运行并通过kd.exe或cdb.exe作为input运行是非常酷的,可以通过批处理脚本进行调用等。

运行,只要你需要做这个相同的旧例程,而不必启动WinDbg和手动做的事情。 太糟糕了,这不工作,当你不知道你在找什么,或者一些命令参数需要手动分析找/得到。

独立于平台的转储string,可用于x86 / x64的托pipe代码:

 j $ptrsize = 8 'aS !ds .printf "%mu \n", c+';'aS !ds .printf "%mu \n", 10+' 

以下是一个示例用法:

 0:000> !ds 00000000023620b8 MaxConcurrentInstances