Windbg及Dump文件分析方法

2023-05-16

1.WinDbg

1.1WinDbg介绍

WinDbg全称Debugging Tools for Windows,是windows平台下的调试工具。

获取Windbg的三种途径:

(1)在Visual Studio安装时安装Windows Driver Kit(WDK)。WDK中包含WinDbg。

(2)安装Windows Software Development Kit (SDK)。SDK中包含WinDbg。下载地址

(3)如果只下载单独的WinDbg,先下载SDK,在安装过程中选择“Debugging Tools for Windows”,同时勾掉其他选择框。

1.2用户模式的WinDbg

WinDbg有两种类型:内核模式调试器和用户模式调试器。内核模式用于调试Windows内核以及驱动程序。用户模式用于调试用户程序,本文主要介绍用户模式的调试器,内核模式调试器的使用方法可在微软官网查找。

1.2.1无代码情况下调试

(1)打开WinDbg.exe

(2)在File菜单中选择Open Executable, 在 Open Executable 对话框中选择notepad.exe(C:\Windows\System32),点击Open。

(3)在底部窗口中,输入命令:

.sympath srv*

窗口将输出以下内容:

Symbol search path is: srv*

Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols

符号搜索路径指示WinDbg查找符号文件(PDB)的地方,通过符号文件调试器可以获取代码模块中的函数名称、变量名等信息。输入如下命令将通知WinDbg进行初始化搜索和加载符号文件动作:

.reload

(4)输入以下命令可查看Notepad.exe模块的符号

x notepad!*

如果看不到任何输出,在此输入.reload命令。

输入以下命令可查看Notepad.exe模块中包含main名称的符号

x notepad!*main*

窗口将输出以下内容:

00a31409          notepad!WinMain (<no parameter info>)

00a331c9          notepad!WinMainCRTStartup (<no parameter info>)

(5)输入以下命令可在notepad!WinMain上打断点:

bu notepad!WinMain

输入以下命令验证断点是否已经设置:

bl

窗口将输出以下内容:

     0 e Disable Clear  00a31409     0001 (0001)  0:**** notepad!WinMain

(6)输入以下命令运行Notepad:

g

Nopad将会运行到WinMain函数,并中断。输入以下命令可查看Notepad进程已加载模块列表:

lm

调试器窗口将输出以下内容:

start    end        module name

00a30000 00a60000   notepad    (pdb symbols)          C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\sym\notepad.pdb\BAF2EA337470437B9DF28CCDFD3EDEB22\notepad.pdb

6dfa0000 6dff1000   WINSPOOL   (deferred)            

6e1b0000 6e34e000   COMCTL32   (deferred)            

73730000 73739000   VERSION    (deferred)            

74f10000 74f1c000   CRYPTBASE   (deferred)            

74f20000 74f80000   SspiCli    (deferred)            

74f80000 74ffb000   COMDLG32   (deferred)            

75100000 75191000   OLEAUT32   (deferred)            

75300000 75f4b000   SHELL32    (deferred)            

76130000 76220000   RPCRT4     (deferred)            

76220000 762c1000   ADVAPI32   (deferred)            

76510000 76610000   USER32     (deferred)            

76640000 76687000   KERNELBASE   (deferred)            

76730000 76787000   SHLWAPI    (deferred)            

76930000 76949000   sechost    (deferred)            

76d30000 76dfc000   MSCTF      (deferred)            

76e00000 76e90000   GDI32      (deferred)            

76f30000 76f90000   IMM32      (deferred)            

770c0000 7721c000   ole32      (deferred)            

77250000 772fc000   msvcrt     (deferred)            

77350000 773ed000   USP10      (deferred)            

773f0000 773fa000   LPK        (deferred)            

77400000 77510000   kernel32   (deferred)            

77a50000 77bd0000   ntdll      (pdb symbols)          C:\Program Files (x86)\Windows Kits\10\Debuggers\x86\sym\wntdll.pdb\EA251A0A79C44D5AAF977F6875A518662\wntdll.pdb

输入以下命令可查看调用堆栈信息:

k

调试器窗口将输出以下内容:

# ChildEBP RetAddr 

00 0020fbac 00a3190e notepad!WinMain

01 0020fc3c 7741336a notepad!_initterm_e+0x1a1

02 0020fc48 77a89902 kernel32!BaseThreadInitThunk+0xe

03 0020fc88 77a898d5 ntdll!__RtlUserThreadStart+0x70

04 0020fca0 00000000 ntdll!_RtlUserThreadStart+0x1b

(7)输入以下命令再次运行Notepad:

g

(8)如果想中断Notepad的运行,可在Debug菜单中选择Break。

(9)输入以下命令可在ZwWriteFile处设置并且验证断点:

bu ntdll!ZwWriteFile

bl

(10)输入g再次运行Notepad。在Notepad窗口中输入一些文字然后在文件菜单中选择保存。运行代码将会在ZwCreateFile处中断。输入k可查看调用堆栈。

在调试器窗口左下角,命令行的左侧,显示了处理器和线程的数字。在上图中处理器数字为0,线程数字为0。下图中处理器数字为0,线程数字为19。所以,在下图中我们看到是线程19(在处理器0上运行)的堆栈。

(11)输入以下命令可查看现场0的堆栈:

~0s

k

(12)输入以下命令退出调试,并且从Notepad进程中分离:

qd

1.2.2有代码情况下调试

假设写好了以下简单的控制台程序并且已经编译完成。

...

void MyFunction(long p1, long p2, long p3)

{

         long x = p1 + p2 + p3;

         long y = 0;

         y = x / p2;

}

void main ()

{

         long a = 2;

         long b = 0;

         MyFunction(a, b, 5);

}

在这个例子中,我们假设编译好了程序(MyApp.exe),符号文件(MyApp.pdb)在C:\MyApp\x64\Debug这个路径中,程序代码在C:\MyApp\MyApp。

(1)打开WinDbg

(2)在File菜单中选择Open Executable,在Open Executable对话框中选择文件路径C:\MyApp\x64\Debug,选择MyApp.exe,点击Open。

(3)输入命令:

.sympath srv*

.sympath+ C:\MyApp\x64\Debug

.srcpath C:\MyApp\MyApp

现在WinDbg知道从何处查找程序的符号和代码。

(4)输入命令:

.reload

bu MyApp!main

g

程序将启动并发生中断,中断位置在main函数上。WinDbg显示出了代码和命令窗口。

(5)在Debug菜单中选择Step Into(或者按下F11)。继续单步调试知道进入MyFunction函数。当单步调试到代码行“y = x / p2”时,程序将会发生崩溃并且在调试器中发生中断。调试器窗口将输出以下内容:

(1450.1424): Integer divide-by-zero - code c0000094 (first chance)

First chance exceptions are reported before any exception handling.

This exception may be expected and handled.

MyApp!MyFunction+0x44:

00007ff6`3be11064 f77c2428    idiv  eax,dword ptr [rsp+28h] ss:00000063`2036f808=00000000

(6)输入命令:

!analyze -v

WinDbg将显示出问题(除0异常)的分析结果

FAULTING_IP:

MyApp!MyFunction+44 [c:\myapp\myapp\myapp.cpp @ 7]

00007ff6`3be11064 f77c2428        idiv    eax,dword ptr [rsp+28h]

EXCEPTION_RECORD:  ffffffffffffffff -- (.exr 0xffffffffffffffff)

ExceptionAddress: 00007ff63be11064 (MyApp!MyFunction+0x0000000000000044)

   ExceptionCode: c0000094 (Integer divide-by-zero)

  ExceptionFlags: 00000000

NumberParameters: 0

...

STACK_TEXT: 

00000063`2036f7e0 00007ff6`3be110b8 : ... : MyApp!MyFunction+0x44

00000063`2036f800 00007ff6`3be1141d : ... : MyApp!main+0x38

00000063`2036f840 00007ff6`3be1154e : ... : MyApp!__tmainCRTStartup+0x19d

00000063`2036f8b0 00007ffc`b1cf16ad : ... : MyApp!mainCRTStartup+0xe

00000063`2036f8e0 00007ffc`b1fc4629 : ... : KERNEL32!BaseThreadInitThunk+0xd

00000063`2036f910 00000000`00000000 : ... : ntdll!RtlUserThreadStart+0x1d

STACK_COMMAND: dt ntdll!LdrpLastDllInitializer BaseDllName ;dt ntdll!LdrpFailureData ;.cxr 0x0 ;kb

FOLLOWUP_IP:

MyApp!MyFunction+44 [c:\myapp\myapp\myapp.cpp @ 7]

00007ff6`3be11064 f77c2428        idiv    eax,dword ptr [rsp+28h]

FAULTING_SOURCE_LINE:  c:\myapp\myapp\myapp.cpp

FAULTING_SOURCE_FILE:  c:\myapp\myapp\myapp.cpp

FAULTING_SOURCE_LINE_NUMBER:  7

FAULTING_SOURCE_CODE: 

     3: void MyFunction(long p1, long p2, long p3)

     4: {

     5: long x = p1 + p2 + p3;

     6: long y = 0;

>    7: y = x / p2;

     8: }

     9:

    10: void main ()

    11: {

    12: long a = 2;

...

1.2.3调试进程

(1)在File菜单中选择Attach to a Process,或者按F6

(2)在Attach to Process对话框中选择需要调试的进程,然后点击OK

(3)调试方法和以上两个类似

2.符号

当应用程序、库、驱动或者操作系统进行链接时,链接器将会创建.exe,.dll以及一些额外的符号文件。符号文件中包含了大量程序运行时不需要用到的数据,但是在调试时这些数据会很有用。通常情况下,符号文件包含以下几个类别:

  1. 全局变量
  2. 局部变量
  3. 函数名称和相应的入口地址
  4. 框架指针省略(Frame Pointer Omission)(FPO)
  5. 代码行数信息

单个符号文件可能包含很多个符号,包括全局变量、函数名称以及很多局部变量。通常情况下,软件公司会发布两种版本的符号文件:全符号文件(包含公有符号和私有符号)和裁剪符号文件(只包含公有符号)

调试时,需要确保调试器可以访问调试对象相关联的符号文件。无论实时调试或者是调试dump文件都需要符号。调试代码时,需要加载正确的符号进入调试器。

Windows下的符号文件后缀名是.pdb。编译器和链接器控制符号的格式,Visual C++连接器将所有的符号都放到了.pdb文件中。

Windows操作系统提供了两种发布版本。小的二进制文件的免费版(或零售版)以及大的二进制文件并且包含很多调试符号的检测版(或者调试版)。每种发布版本都有其自己的符号文件。调试时,需要匹配正确的Windows版本的符号文件。

下表列出了一些列的包含标准的Windows符号树的目录:

目录

包含特定类型的符号文件

ACM

Microsoft Audio Compression Manager files

COM

Executable files (.com)

CPL

Control Panel programs

DLL

Dynamic-link library files (.dll)

DRV

Driver files (.drv)

EXE

Executable files (.exe)

SCR

Screen-saver files

SYS

Driver files (.sys)

在调试Windows内核、驱动或者应用程序时,需要访问正确的符号文件。

如果调试器在运行的时候已经连上了网络,可以直接使用微软的符号服务器。连接符号服务器的方法是使用命令.symfix(设置符号存储路径)。调试器会缓存连接的服务器上的符号文件,下次调试会自动使用本地的缓存文件。

3.Dump文件

3.1Dump文件介绍

Dump文件可分为内核Dump文件和用户模式Dump文件。本文主要讲述用户模式下Dump文件。用户模式Dump文件又可分为:完整用户模式Dump文件和Minidump文件。

(1)完整用户模式Dump文件

完整用户模式Dump文件是最基本的用户模式的dump文件。文件中包含进程的全部内存空间,程序自身镜像,句柄表,以及其他对调试器非常有用的信息。完整用户模式dump文件可以剪切成minidump文件,先将dump文件加载到调试器中,然后使用.dump(Create Dump File)命令保存一个新的minidump格式的dump文件。

注意尽管其名称有mini,但最大的minidump文件实际上包含的信息比完整的用户模式转储还多。 例如,.dump /mf.dump /ma将创建比.dump /f更大,更完整的文件。

在用户模式下,.dump /m [MiniOptions]是最佳选择。用此开关创建的转储文件的大小可以从很小到很大。通过指定适当的MiniOptions,可以精确控制所包含的信息。

(2)Minidumps

用户模式转储文件仅包含与进程关联的内存的选定部分,称为最小转储。

小型转储文件的大小和内容取决于要转储的程序和执行转储的应用程序。有时,小型转储文件很大,并且包含完整的内存和句柄表。在其他时候,它要小得多-例如,它可能仅包含有关单个线程的信息,或仅包含有关堆栈中实际引用的模块的信息。

名称“minidump”具有误导性,因为最大的minidump文件实际上比“全”用户模式转储包含更多的信息。例如,.dump /mf.dump /ma将创建比.dump /f更大,更完整的文件。 因此,建议在所有用户模式转储文件创建中使用.dump /m [MiniOptions],而不是.dump /f

如果要使用调试器创建小型转储文件,则可以准确选择要包含的信息。 一个简单的.dump /m命令将包含有关组成目标进程的已加载模块的基本信息,线程信息和堆栈信息。可以使用以下任一选项进行修改:

选项

描述

/ma

使用所有选项创建转储文件。/ma选项等同于/mfFhut。它将完整的内存数据,句柄数据,卸载的模块信息,基本内存信息和线程时间信息添加到小型转储文件中。

/mf

将完整的内存数据添加到小型转储。将包含目标应用程序拥有的所有可访问的提交页面。

/mF

将所有基本内存信息添加到小型转储。这会将流添加到小型转储,其中包含所有基本内存信息,而不仅仅是有关有效内存的信息。这使得调试器可以在调试小型转储时重建进程的完整虚拟内存布局。

/mh

将有关与目标应用程序关联的句柄的数据添加到小型转储。

/mu

将卸载的模块信息添加到小型转储。仅在Windows Server 2003和更高版本的Windows中可用。

/mt

将其他线程信息添加到minidump。这包括线程时间,调试minidump时可以使用.ttime(显示线程时间)显示该时间。

/mi

将辅助内存添加到小型转储。 辅助存储器是堆栈或后备存储器上的指针引用的任何存储器,外加围绕该地址的小区域。

/mp

将进程环境块(PEB)和线程环境块(TEB)数据添加到小型转储。 如果您需要访问有关应用程序进程和线程的Windows系统信息,这将很有用。

/mw

将所有已提交的可读写私有页面添加到小型转储中。

/md

将可执行镜像中的所有读写数据段添加到小型转储中。

/mc

在镜像中添加代码段。

/mr

从小型转储中删除堆栈的那些部分,并存储对重新创建堆栈跟踪无用的内存。局部变量和其他数据类型值也将被删除。此选项不会使minidump变小(因为这些内存部分仅被清零了),但是如果希望保护其他应用程序的隐私,则该选项很有用。

/mR

从小型转储中删除完整的模块路径。 仅包含模块名称。如果您希望保护用户目录结构的私密性,这是一个有用的选项。

/mk "FileName"

(仅Windows Vista)除了用户模式小型转储之外,还创建内核模式小型转储。内核模式小型转储将限于用户模式小型转储中存储的相同线程。FileName必须用引号引起来。

这些选项可以组合。例如,命令.dump /mfiu可用于创建相当大的小型转储,或者命令.dump /mrR可用于创建可保留用户隐私的小型转储。 有关完整语法的详细信息,请参见.dump(创建转储文件)。

3.2分析Dump文件

WinDbg可以分析用户模式的内存转储文件。在其上创建转储文件的处理器或Windows版本不需要与运行WinDbg的平台匹配。

注意:发生崩溃的程序必须和pdb文件的版本一致(同一时间编译),否则将会发生符号加载失败的情况。

分析步骤:

(1)在菜单File中选择Open Crash Dump菜单或者按下CTRL+D快捷键。当出现“Open Crash Dump”对话框时,在“File name”文本框中输入故障转储文件的完整路径和名称,或使用对话框选择正确的路径和文件名。 选择正确的文件后,单击“Open”。

(2)调试方法和1.2章节类似

A.输入 !analyze -v 命令进行自动分析

B.使用 .excr 命令定位到崩溃位置

C.使用 kp 命令查看崩溃时的堆栈信息

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Windbg及Dump文件分析方法 的相关文章

  • 如何设置 Windows 符号服务器

    我在网络上有一个备用服务器 我想用它来托管我们所有的构建符号 我已经知道如何在本地开发系统上设置符号缓存并将调试器 例如 Windbg 指向 符号文件路径 中的该路径 我认为我可以对网络上具有自己的符号缓存 例如 host symbols
  • 比较堆转储 (HPROF) 文件

    是否可以比较两个 HPROF 文件 如何 根据我的发现 您只能比较对象的直方图 为此 请转到 直方图 视图 然后单击 与另一个堆转储比较 并选择另一个 hprof 文件 Here is screenshot
  • SOS 不支持当前目标架构

    我正在尝试使用 Windbg 来研究在 x64 计算机上为我们的 x86 进程创建的挂起转储文件 这是一个 4 0 x86 应用程序 因此为了获得非托管堆栈 我必须执行以下操作 loadby sos clr load wow64exts s
  • 无法找到模块“mscorwks.dll”

    我尝试使用 winDBG 来调试转储文件 当我运行 loadby sos mscorwks dll 时 它给了我一条错误消息 无法找到模块 mscorwks dll 有没有人见过这个 如果您正在调试 NET 4 0应用程序 您需要使用以下内
  • 切换到内核转储中的用户堆栈

    有没有办法在进行事后调试时切换到内核转储中特定进程的用户模式 我记得在使用 process 命令进行实时调试时执行此操作 process也适用于内核转储 首先 您可以使用以下方式找到您的流程 process 0 0 myprocess ex
  • 如何调试在客户计算机上崩溃的 Windows 应用商店应用程序?

    我收到一位客户的支持电子邮件 说他的应用程序在启动时崩溃 他收到的只是一条类似以下的消息 应用程序名称 遇到问题您可以向 Microsoft 发送有关以下内容的信息 出了什么问题来帮助改进这个应用程序 将发送给 Microsoft 的文件
  • 内存转储比可用内存小得多

    我有一个 Tomcat 应用程序服务器 配置为在 OOM 上创建内存转储 并且以 Xmx1024M 启动 因此应该有千兆字节可供他使用 现在我找到了一个这样的转储 它只包含 260MB 的未保留内存 垃圾场怎么可能比他应有的可用大小小得多
  • GDB无法显示堆栈并显示“#1 0x0000000000000000 in ?? ()”

    我有一个多线程 C 程序 在极少数情况下会死锁 这个问题很难重现 我只能在远程机器上重现它 我想用来解决这个问题的方法是 运行程序 等待死锁 向其发送中止信号以生成核心转储 将转储复制回我的本地计算机 使用gdb来调试它 我在远程计算机上没
  • 如何识别STATUS_INVALID_CRUNTIME_PARAMETER异常

    平台是Windows 7 SP1 我最近花了一些时间调试由于代码将无效参数传递给 安全 CRT 函数之一而引起的问题 结果 我的应用程序立即中止 没有任何警告或任何内容 甚至没有崩溃对话框 起初 我尝试通过将 Windbg 附加到我的应用程
  • 如何阻止 Windbg 成为交互式调试器?

    正确的撤消方法是什么Windbg I在 Vista Win7 上 难道只是删除 HKEY LOCAL MACHINE SOFTWARE Microsoft Windows NT CurrentVersion AeDebug 中的注册表项那么
  • 如何在 WinDbg 中删除断点 ntdll!DbgBreakPoint+0x1

    我正在调试一个在将 WinDbg 设置为事后调试器时崩溃的程序 我在地址 77f7f571 设置了断点 当它被触发时 我常常得到以下信息 ERROR Symbol file could not be found Defaulted to e
  • 如何使用 SBCL 正确保存 Common Lisp 图像?

    如果我想创建我的程序的 Lisp 映像 我该如何正确地做到这一点 有什么先决条件吗 它与 QUICKLISP 配合得很好吗 现在 如果我启动 SBCL 仅预加载 QUICKLISP 并保存图像 save lisp and die core
  • 为什么windbg命令以.开头或者 !

    之间有什么区别吗 和 WinDbg 中有不同类型的命令 常规命令 例如kb适用于调试会话 例如 显示堆栈转储等 元命令以点为前缀 例如 load 元命令适用于调试器本身 例如 加载扩展 显示帮助等等 扩展命令以感叹号为前缀 例如 analy
  • WinDbg:APPLICATION_HANG_WRONG_SYMBOLS

    我对 WinDbg 还很陌生 我正在尝试找到一个导致我的应用程序无缘无故挂起的错误 我不确定我做的事情是否正确 但我知道我需要系统 dll 以及我正在调试的 exe 的符号 因此 我这样设置符号路径 srv c websymbols htt
  • 什么是 ntdll.dll!RcConsolidateFrames?

    我的转储文件中有一个如下所示的调用堆栈 我想在调用堆栈中找到我的代码 但找不到 分析我的转储的起点是什么 我的程序的链接选项是release Od msvcr120 dll abort msvcr120 dll terminate msvc
  • 生成转储并导致非托管代码崩溃?

    当我的应用程序突然崩溃时 有没有办法获得完整的故障转储 问题是 我怀疑这是由于非托管代码杀死了 net 框架本身 因此 除非在崩溃时应用程序附加了调试器 否则应用程序甚至没有机会处理崩溃 我无法附加调试器并等待 因为崩溃是随机发生的 而且我
  • 制作 SQL Server 转储并将该转储导入另一个 SQL Server 的最佳(最简单)方法

    我想从一台服务器在 SQL Server 中实现数据库导出 转储 并将该转储导入到另一台 SQL Server 中 并且不一定使用相同的架构名称 例如 如果我准备了一个数据库 其中包含用于为新客户实施新数据库的所有数据集 则该数据库名为 D
  • 什么可以解释托管堆上超过 5,000,000 个 System.WeakReference 实例?

    我一直在针对生产 ASP NET Web 应用程序运行负载测试 并且看到在堆上创建了大量 System WeakReference 在大约 15 分钟内 负载管理堆内存已飙升至大约 3GB 并且我有大约 5 000 000 个对 Syste
  • COM+ 应用程序死锁故障排除

    我正在尝试对间歇性死锁的 COM 应用程序进行故障排除 上次锁定时 我能够获取 dllhost 进程的用户模式转储并使用 WinDbg 对其进行分析 检查完所有线程和锁后 一切都归结为该线程拥有的关键部分 ChildEBP RetAddr
  • Nodejs 进程挂起,我该如何调试它或收集转储?

    我的nodejs进程在Linux上运行 现在挂起并且CPU为100 无论如何我可以调试它并找到原因吗 我需要收集转储吗 如何收集 谢谢 有一个 npm 模块叫做节点为何运行 https www npmjs com package why i

随机推荐