windbg调试基础

#工作空间 [Workspace]

工作空间被用来描述和存储一个调试项目的属性、参数以及调试器设置等信息,其功能类似于集成开发环境的项目文件。

具体包括:调试会话状态(断点、打开的源文件、用户定义的别名等)、调试器设置(符号文件路径、源文件路径、可执行映像文件路径等)和窗口布局状态

0. 基础工作空间 [base workspace]

未载入任何的调试文件时使用默认的启动环境。存放位置:HKEY_CURRENT_USER\Software\Microsoft\Windbg\WorkspacesDefault二进制值。

1. User、Kernel、Dump、Explicit工作空间

存放在HKEY_CURRENT_USER\Software\Microsoft\Windbg\Workspaces的各子键中(如下图)

子键UserKernelDump用来保存用户态调试、内核态调试、调试转储文件时,使用【Save Workspace】方式时默认的保存路径。

子键Explicit则用来记录使用【Save Workspace as】方式保存的命名工作空间。

对于【Attach to a Process】的方式,会使用User下的Default二进制值作为其工作空间,之后对工作空间所作的修改也会写到该字段中。

windbg调试基础_第1张图片

注:有时会发现没有某个子键,这是因为windbg还没使用过该调试方式。

2. 其他说明

(1) windbg还提供另外一种保存方式【Save WorkSpace to File】,作用跟上面两种的方式差不多,

     只不过把工作空间以文件的形式保存到磁盘里,那么用户就可以通过U盘或其它方式把工作空间的环境移植到其它机器上使用。

(2) 调试目标最后的工作空间为:基础工作空间其对应工作空间求并所得的环境。

(3) 用windbg打开目标可执行文件【Open Executable】,若有默认的工作空间文件(在子键User下),会自动打开其对应默认的的工作空间文件。

     要使用子键Explicit下目标文件的工作空间,必须先提前【Open WorkSpace】,然后再打开目标可执行文件。

(4) 在载入调试目标后改变了工作空间并保存,并不改变windbg的基础工作空间,只改变调试目标对应的工作空间;

     而只有在windbg还没载入任何调试目标时改变并保存才会影响基础工作空间。

#符号 [Symbol]

调试者接触的二进制数据以及汇编代码,如果没有符号表文件的帮助,就无法知道这些数据代表什么变量、函数。

符号(symbol) :函数和变量的别名,编译器通过符号修饰(Name Decoration)和 函数签名(Function Signature)来实现全局唯一性。

函数符号含有返回值,函数名,函数参数等函数所有信息;变量符号含有类型和名称信息。

通过不同的编译选项,编译器可以生成两种截然不同的信息集合:私有符号(private symbol)公有符号(public symbol)

私有符号(private symbol)包含完整的调试信息,编译选项:/Zi或/ZI。

windbg调试基础_第2张图片

公共函数和变量:在多个的编译单元(源代码文件)中可见的函数和变量。

私有函数和变量:用于描述除公共函数和变量以外的所有函数和变量,包括静态函数、静态和局部变量、函数参数)。

因此,为了能更方便读懂二进制数据和汇编语言,需要获取符号表文件,在windbg下使用的符号表文件一般是.PDB文件。  

客户端软件存在于exe/dll中,这些二进制文件会调用操作系统的dll,这两部分二进制文件的符号表文件都需要获取。

客户端软件自己的符号表文件在构建程序的过程中产生;而操作系统dll的符号表文件可以通过设置windbg,根据需要自动从微软符号服务器上下载。

#pdb(program Database )

0. pdb中包含的内容

符号表

函数和变量符号到地址的映射表(map文件实际就是一个文本格式的符号表)。

源文件和代码行信息

二进制指令到代码源文件代码行的映射表。

类型信息

用于存储每一个函数和变量的类型信息。对于变量或函数参数,类型信息能够告诉调试器是整型还是字符串类型,或是用户自定义类型。

对于函数,类型信息记载了参数的个数、调用转换和返回值的类型。

FPO(frame pointer omission, 帧指针省略)

 

对于做了FPO优化的函数,FPO信息保存了一些数据来帮助调试器确定函数堆栈帧的大小,

帮助调试器查找函数的参数和本地变量,甚至在帧指针无效时也能工作。

如果没有FPO信息,调试器无法正确显示被优化的程序的调用堆栈。

编辑和继续执行信息

用于帮助Visual Studio在调试时实现编辑和继续执行的功能

在过去的十年中,微软使用了几种不同的格式(COFF、CodeView和应用的最广泛的PDB格式)来存放调试信息。

格式

是否有文档

存储

公共函数和变量

私有函数和变量

源文件和代码行信息

类型信息

FPO信息

编辑和继续执行信息

COFF

微软可移植可执行和通用对象文件格式规范

可执行文件中

+

-

+

-

+

-

CodeView

部分

Microsoft Symbol and Type Information

可执行文件中

或.DBG文件中

+

+

+

+

+

-

Program Database

微软没有提供程序数据库格式的文档,只提供特殊的编程接口DbgHelp 和DIA来访问它。
目前有两个版本,第一版(PDB2.0)为VC6.0所用,第二版(PDB 7.0)被VS采用。
PDB 7.0不能向上兼容,也就是说:VC6.0不能读取PDB 7.0格式。

.PDB文件中

+

+

+

+

+

+

1. 在vc6下配置生成PDB文件

vc6的Debug配置,会在编译时生成私有符号pdb文件;Release可通过如下配置来达到这一目的:

(1) 选择Project->Setting菜单,打开工程设置对话框

(2) 在“Setting For:” 中选择 “Win32 Release”(只设置Release版本即可,因为Debug版本默认生成PDB文件)

(3) 选择标签页 “C/C++” ,在 “Debug info” 中选择 “Line Numbers Only”(如果选择Program Database则包含更多的符号信息)

(4) 选择标签页 “Link” ,勾选 “Generate debug info”

(5) 在标签页 “Link” 中,选择 “Category->Customize”,在这里填写PDB文件的生成路径

论是Debug还是Release配置,VC6.0的Link选项需要将/pdbtype:sept改为/pdbtype:con, 否则生成的pdb文件中将不包含如自定义结构体,类等信息

更多关于vc6和vs的pdb编译和链接选项信息,请参考:Windows程序调试系列: 使用VC++生成调试信息

2. 为vs下Release配置生成PDB文件

(1) 配置C/C++ >General>Debug Information Format 为 “Program Database(/Zi)”

(2) 配置C/C++ >Optimization>Optimization 为”Disabld(/Od)”

(3) 配置Linker>Debugging>Generate Debug Info 为”Yes/(DEBUG)”

3.在windbg下使用PDB文件

启动windbg后,选择 【Symbol File Path】,弹出 “Symbol Search Path” 对话框,输入存放PDB文件的路径。可以输入多个路径,路径之间使用分号进行分隔。

如果此时正在调试程序,则对话框中的 “reload” 选择框是可以选择的,勾选后点击“确定”。

4.使用Windows符号表服务器

为了方便调试,需要获取Windows系统DLL的符号表文件。微软公司提供了可以通过Internet访问的符号表服务器。

经过设置,在调试过程中,windbg调试器会从符号表服务器自动下载调试所需的PDB文件,非常方便。

设置方法: 在 【Symbol Search Path】 对话框中加入下面的路径:srv*D:\SystemSymbols*http://msdl.microsoft.com/download/symbols

其中: D:\SystemSymbols为存放符号的下载目录

windbg调试基础_第3张图片

windbg调试基础_第4张图片

注148C58F3D11e000为对应版本dbghelp.dll的PE头中记录的时间日期戳和映像大小的组合(字节数)

windbg调试基础_第5张图片

timestamp与日期时间的在线转换工具:http://tool.chinaz.com/Tools/unixtime.aspx

注2:6B19F261EE434AF59623D1791CE5A7D72为对应版本dbghelp.pdb的guid

另外,也可以使用windbg提供的symchk.exe工具提前下载某个dll及某个目录下所有dll的pdb文件到本地

"C:\Program Files\Debugging Tools for Windows (x86)\symchk.exe" c:\windows\system32\user32.dll /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols  //下载user32.dll的pdb到c:\symbols目录中
"C:\Program Files\Debugging Tools for Windows (x86)\symchk.exe" c:\windows\system32\ /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols //下载system32下所有dll的pdb到c:\symbols目录中
"C:\Program Files\Debugging Tools for Windows (x86)\symchk.exe" /r c:\windows\system32\ /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols  //递归子目录下载system32下所有dll的pdb到c:\symbols目录中

5. 设置_NT_SYMBOL_PATH环境变量

设置系统环境变量“_NT_SYMBOL_PATH”,Visual Studio、windbg、SysinternalsSuite工具集的ProcessExplorer、ProcessMonitor等都会将该环境变量下的路径添加到自己的Symbol File Path中

windbg调试基础_第6张图片

6.建立自己的符号表服务器

通过为产品建立自己的符号表服务器,就不需要关心复杂的版本问题。在调试过程中,windbg可以根据二进制文件(exe/dll)的哈希值,在符号表服务器上自动查找正确版本的PDB。

(1)建立一个共享文件夹,比如 “ \\server\symbols” ,然后将所有的PDB文件上传到此处

(2)使用下面的命令上传符号表文件

symstore add /r /f D:\MyOutput\chess.exe /s \\server\symbols /t "chess" /v "exe" /c "version build"

symstore add /r /f D:\MyOutput\chess.pdb /s \\server\symbols /t "chess" /v "pdb" /c "version build"

symstore add /r /f D:\MyOutput\chess.map /s \\server\symbols /t "chess" /v "map" /c "version build"

symstore 是windbg附带的一个exe文件,存放于windbg安装目录下。需包含2个文件:symstore.exe、symsrv.dll

上述命令完成的功能是:将D:\MyOutput目录下的chess.exe、chess.pdb、chess.map上传到\\server\symbols目录中。

产品的名称是"chess",版本信息是"exe"、"pdb"、"map",备注说明是"version build"。

(3)在windbg的 【Symbol Search Path】对话框中添加新的路径(路径之间使用分号[;]分隔)\\server\symbols(关联一个本地缓存目录)

srv*D:\SystemSymbols*http://msdl.microsoft.com/download/symbols;srv*D:\ServerSymbols*\\server\symbols;f:\symbols

7. 查找函数符号名  -- 列出含CreateThread字样的符号名

"D:\Program Files (x86)\windbg\dbh.exe" -s:srv*D:\Symbols\ms*http://msdl.microsoft.com/Download/Symbols -d C:\Windows\SysWOW64\kernel32.dll enum *CreateThread*

windbg调试基础_第7张图片

 

 

#使用windbg

0. Attach方式

启动windbg,使用菜单【Attach to a Process】,可以选择注入到现在正在运行的某个进程中。

注入到进程中后,进程被暂停执行,windbg处于可输入命令状态,但此时当前线程为windbg产生的线程。

按g继续运行进程时,windbg会随即销毁该线程。

windbg调试基础_第8张图片

如果要观察主线程堆栈,需要切换到主线程(0号线程)(在windbg命令窗口输入这个命令,然后回车):

~0s 

当程序出现CPU占用100%的情况时,通常可以使用这种方式进行注入,然后切换到占用CPU的线程,

同时根据需要使用单步跟踪、设置断点等手段,来判断是何处的代码导致CPU100%问题。

1. Open Executable方式

使用【Open Executable】方式,可以通过windbg启动被调试程序。在这种方式下,被调试程序从启动时刻起就在调试器的监控之下。

对于一些在程序启动过程中产生的异常,可以使用这种方式进行调试。

2. Just in time Debugger 方式 (JIT)

当进程产生结构化异常时,如果进程不作处理,也没有调试器在监控这个进程,那么windows就会调用默认的调试器来调试发生异常的进程。

通过把windbg设置为Just in time Debugger,可以在任意进程发生异常时自动调用windbg来进行调试。

在注册表编辑器中修改下面的注册表项:

HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\AeDebug

HKEY_LOCAL_MACHINE\Software\Wow6432Node\Microsoft\Windows NT\CurrentVersion\AeDebug  // 注:64位系统上的32位程序使用该注册表项

Debugger键值修改为下面的取值 "D:\Tools\windbg.exe " -p %ld -e %ld

注1:将例中windbg.exe的路径替换为本机windbg绝对路径即可

注2:一般该值为:"C:\Windows\system32\vsjitdebugger.exe" -p %ld -e %ld

3. Dump文件

为了分析程序发生异常的原因,还可以借助Dump文件。

当异常发生时,把进程当前的信息保存到一个Dump文件中,再把该Dump文件发送给分析者,由分析者通过windbg进行分析。

Dump分类:

windbg调试基础_第9张图片

内核dump:(蓝屏后,由系统生成)

1. 完全内存转储。这个文件比较大,和物理内存相当,包含了程序崩溃前系统及用户模式下的所有信息。
2. 核心内存转储。这个文件大小约物理内存的三分之一,主要包含崩溃前系统内核的所有信息。一般为了分析内核错误,就选用这种文件。
3. 小内存转储(MiniDump)。保存内存前64KB的基本空间数据,主要包含crash进程及crash线程内核上下文信息,crash线程内核模式堆栈,加载的驱动和模块等信息。

windbg调试基础_第10张图片

 

如果没有禁用“Windows Error Reporting Service”服务,重启后会弹出如下对话框来显示一些蓝屏相关的信息:

windbg调试基础_第11张图片

问题签名:
  问题事件名称:	BlueScreen
  OS 版本:	6.1.7601.2.1.0.256.48
  区域设置 ID:	2052

有关该问题的其他信息:
  BCCode:	1000007e
  BCP1:	FFFFFFFFC0000005
  BCP2:	FFFFF80004CCC0E4
  BCP3:	FFFFF88004993668
  BCP4:	FFFFF88004992EC0
  OS Version:	6_1_7601
  Service Pack:	1_0
  Product:	256_1

有助于描述该问题的文件:
  C:\Windows\Minidump\060717-10280-01.dmp
  C:\Users\nicochen\AppData\Local\Temp\WER-41964-0.sysdata.xml

联机阅读隐私声明:
  http://go.microsoft.com/fwlink/?linkid=104288&clcid=0x0804

如果无法获取联机隐私声明,请脱机阅读我们的隐私声明:
  C:\Windows\system32\zh-CN\erofflps.txt

事件查看器中也记录了那次致命错误

windbg调试基础_第12张图片

 

不同信息量的minidump:

    (1)标准的minidump。包含了相对比较少的信息,适合在做在线分析:系统信息、加载的模块(DLL)信息、进程信息和线程信息。
        .dump /m c:\stardardMini.dmp(注:不指定/m和/f,/m为缺省选项

    (2) full dump。在内核模式下,生成完全内存转储;用户模式下,最好不使用(/ma和/mf是更好的选择,生成出的dump信息也更丰富一些)
        .dump /f c:\fullMini.dmp

    (3)带有尽量多选项的minidump。包括完整的内存内容、句柄、未加载的模块,等等。文件很大(本机和局域网环境适用)~
        .dump /ma c:\bigMini.dmp(注:/ma等价于/mfFhut;/m的子参数包括:a,A,f,F,h,u,t,i,p,w,d,c,r,R ).dump命令详细用法

下面列出六种生成Dump文件的方法:

(1)在产品代码中加入自动生成Dump文件功能

使用下面的函数,可以生成一个Dump文件:

BOOL MiniDumpWriteDump (
HANDLE hProcess,
DWORD ProcessId,
HANDLE hFile,
MINIDUMP_TYPE DumpType,
PMINIDUMP_EXCEPTION_INFORMATION ExceptionParam,
PMINIDUMP_USER_STREAM_INFORMATION UserStreamParam,
PMINIDUMP_CALLBACK_INFORMATION CallbackParam
);

这个函数定义在dbghelp.dll中,windbg安装目录中带有这个dll,同时在sdk子目录中提供了.h和.lib文件。
在进程捕捉结构化异常的地方,使用这个API生成一个Dump文件。

(2) 使用AdPlus生成Dump文件

windbg附带了一个AdPlus的脚本,可以用于监控进程运行情况,并且可以在发生异常时把进程信息写入到Dump文件中。
如果产品没有自动生成Dump文件的功能,可以通过使用这个工具来弥补缺陷。

通过如下命令来使用AdPlus:

cscript D:\tools\windbg\adplus.vbs -crash -pn DebugTest.exe -o D:\CrashDumps

上述命令的意思是:监控当前运行的DebugTest.exe,如果发生了结构化异常,则生成一个Dump文件到D:\CrashDumps目录中。
关于AdPlus更详细的介绍请参阅:http://support.microsoft.com/kb/286350/zh-cn

(3) 使用windbg生成Dump文件

windbg可以通过命令生成mini-Dump文件:

.dump /mfh D:\CrashDumps\mydumpfile.dmp

(4) win7任务管理器 - 进程标签页 - 创建转储文件

(5) 使用vs2010以上版本生成  在调试状态下[菜单]:调试 - 将转储另存为

(6) 第三方系统工具  如:最新版本的Process Explorer、proccump.exe命令行工具等

注意:

win32程序在64位操作系统上,需要生成dump时,应该生成32位的dump,否则windbg在获取call stack时可能出错,一些sos、psscor2等扩展无法读取dump中的数据,一些命令在获取dump中的信息也会受限。
对于32位dump,应该用x86版的windbg分析(无论是在32位还是64位操作系统上);64位dump,应该用在64位操作系统上使用x64版的windbg进行分析。

 

分析Dump文件

使用菜单【Open Crash Dump】打开Dump文件,然后打开堆栈观察窗口,此时看到的堆栈可能不是异常发生时的堆栈。

通过如下命令切换到异常发生时的堆栈:

.ecxr

为了分析异常,可以通过下面的语句来获取分析信息,帮助定位问题:

!analyze -v

#参考

http://www.debuginfo.com/resources.html

http://www.debuginfo.com/articles/debuginfomatch.html

http://www.debuginfo.com/articles/gendebuginfo.html

DbgHelp Functions: http://msdn.microsoft.com/en-us/library/ms679291(VS.85).aspx

利用VS2005进行dump文件调试

你可能感兴趣的:(windbg调试基础)