你最喜欢的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