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

时间:2008-09-24 14:37:39

标签: c++ windows debugging windbg

我已经意识到Windbg是一个非常强大的Windows平台和调试器。我偶尔会学到一些关于它的新知识。 Windbg用户可以分享他们的一些疯狂技能吗?

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

13 个答案:

答案 0 :(得分:28)

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

最初在这里讨论,并提供<file>参数的示例: http://blogs.msdn.com/debuggingtoolbox/archive/2008/09/17/special-command-execute-commands-from-a-customized-user-interface-with-cmdtree.aspx

实施例: alt text http://blogs.msdn.com/photos/debuggingtoolbox/images/8954736/original.aspx

答案 1 :(得分:26)

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

  • !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.2 GB的内存。
   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 )
  • 然后,如果你的对象有vtable,只需使用dps命令在DumpHeapEntries.log中寻找一些0x24字节的堆分配,以了解占用所有内存的对象的类型。
0:075> dps 3be7f7e8
3be7f7e8  00020006
3be7f7ec  090c01e7
3be7f7f0  0b40fe94 SomeDll!SomeType::`vftable'
3be7f7f4  00000000
3be7f7f8  00000000

这很俗气但它有效:)

答案 2 :(得分:19)

使用vtables查看C ++对象的堆栈时,以下命令非常方便,尤其是在使用发布版本时,很多东西都会被优化掉。

dpp esp 范围


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

windbg -z mylib.dll


使用以下命令查询GetLastError()

!GLE


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

!error error_number

答案 3 :(得分:15)

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

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

答案 4 :(得分:10)

我经常使用的“提示”会让您不必经常触摸那个讨厌的鼠标: Alt + 1

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

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

答案 5 :(得分:8)

一个词(好吧,好的,三个): DML ,即调试器标记语言

这是WinDbg的最新成员,并没有在帮助文件中记录。但是,在Windows调试工具的安装目录中的“dml.doc”中有一些文档。

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

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

现在,使用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> " }

显然,这是一个非常实用的例子,但这些东西对我来说真是无价之宝。不是在非常复杂的对象中搜寻正确的数据成员(通常需要一分钟时间以及各种演员和解除引用的技巧),所以一切都可以自动完成!

答案 6 :(得分:7)

  • .prefer_dml 1

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

  • .reload /f /o file.dll/o将覆盖您所拥有的符号的当前副本)

  • .enable_unicode 1 //将调试器的默认值切换为Unicode,因为所有Windows组件都在内部使用Unicode,这非常方便。

  • .ignore_missing_pages 1 //如果您进行了大量的内核转储分析,您会看到很多关于内存被分页的错误。此命令将告诉调试器停止抛出此警告。

别名别名...

在调试器中节省一些时间。以下是我的一些内容:

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, e.g. f explorer.exe

答案 7 :(得分:4)

另一个答案提到命令窗口和 Alt + 1 以关注命令输入窗口。有没有人发现在不使用鼠标的情况下滚动命令输出窗口很困难?

好吧,我最近使用AutoHotkey使用键盘滚动命令输出窗口而不离开命令输入窗口。

; 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提供的窗口间谍工具来首先查找实际的类名。

答案 8 :(得分:4)

基于.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}

答案 9 :(得分:3)

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

答案 10 :(得分:1)

使用WinDbg的.heap -stat命令。它有时会给你不正确的输出。相反,请使用DebugDiags内存报告。

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

答案 11 :(得分:1)

对于命令&amp;在使用调试器的简单(静态或自动化)例程中,能够将所有调试器命令在文本命令文件中运行并通过kd.exe或cdb.exe作为输入运行是非常酷的,可通过批处理脚本等

每当您需要执行相同的旧例程时运行它,而无需启动WinDbg并手动执行操作。太糟糕了,如果您不确定要查找的是什么,或者某些命令参数需要手动分析来查找/获取,这不起作用。

答案 12 :(得分:1)

托管代码的独立于平台的转储字符串,适用于x86 / x64:

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

以下是一个示例用法:

0:000> !ds 00000000023620b8

MaxConcurrentInstances