保留PDB,节省调试耗时

来源:互联网 发布:c语言编的游戏代码 编辑:程序博客网 时间:2024/06/03 14:48

转自:http://blog.163.com/hao_dsliu/blog/static/131578908201411314610310/


我们在解决Bug的时候经常遇到一些难重现的Bug。例如偶尔崩溃的问题,如果错失现场,也许花几天时间也难重现,最后不了了之。在发布后,可能在客户那里重新出现,这种Bug很让人懊恼。

如果我们能掌握一些Release模式下的调试技巧,事情就会变的简单起来。将调试时间从几天降低到数小时内。一般在程序崩溃后,可以用一些工具(典型 的:WinDbg)将其dump文件获取出来,拿到我们开发机器上进行分析。通常获取的都是Release版本的dump文件,使用 VS2008,Windbg都能打开来分析。初次打开,你会发现崩溃的调用堆栈,但是堆栈都是一堆不可识别的符号,分析难度很大,如果我们保留了模块对应的PDB文件,使用调试软件加载,就能够定位到具体的崩溃位置。

PDB知识

PDB文件是微软编译器产生出来的,专门为了调试使用的。微软的操作系统里大部分模块对应的PDB文件,都能通过微软的在线服务器下载得到:
http://msdl.microsoft.com/download/symbols

PDB中包含什么东西都?

  • Public, private, and static function addresses
  • Global variable names and addresses
  • Parameter and local variable names and offsets where to find them on the stack
  • Type data consisting of class, structure, and data definitions
  • Frame Pointer Omission (FPO) data, which is the key to native stack walking on x86
  • Source file names and their lines

调试器如何配对正确的PDB?

1. 模块的名字。例如一个模块叫XXX.DLL,调试器就会找XXX.PDB。 2. 如何判断此PDB是否和模块相对应? 调试器在编译的时候,会给XXX.DLL模块中插入一个GUID,PDB文件中也有一个GUID。这两个GUID只有相同,调试器才会加载此PDB。
GUID这个数值和机器,时间等因素有关。即便我们没有更改一行代码,每次重新编译后的此值都会变化。所以,保存当时对应的PDB尤为重要。

使用VS2008的DUMPBIN.exe工具,你就能够找到这个GUID:

>>dumpbin.exe /HEADER HelloWorld.exe

Debug Directories

Time Type Size RVA Pointer

-------- ------ -------- -------- --------

4A03CA66 cv 4A 000025C4 7C4 Format: RSDS,

{4B46C704-B6DE-44B2-B8F5-A200A7E541B0}, 1,

C:\junk\stuff\HelloWorld\obj\Debug\HelloWorld.pdb

Windbg工具包里附带了一个工具:symchk.exe.可以用来检测PDB和模块是否匹配:

symchk RinjPlay.exe /s .\

 

如果匹配:

SYMCHK: FAILED files = 0

SYMCHK: PASSED + IGNORED files = 1

 

如果不匹配:

SYMCHK: RinjPlay.exe FAILED - RinjPlay.pdb mismatched or not found

SYMCHK: FAILED files = 1

SYMCHK: PASSED + IGNORED files = 0

调试器如何查找PDB?

注:不同编译器查找的顺序可能会不同

  • 第一个地方是模块里面嵌入的绝对路径,如上面的例子:C:\junk\stuff\HelloWorld\obj\Debug\HelloWorld.pdb。(这个绝对路径可以在VS2008中去除掉,只保留pdb文件名)
  • 第二个地方是模块被加载的目录
  • 第三个地方就是调试的Symbol Path的配置路径,windbg下,一般有一个Cache目录和一个在线目录
  • 如果都找不到,宣告失败。

我们平常调试的时候,模块一般在哪儿,都将对应的pdb拷贝到相同目录下。

产生PDB文件后,模块也随之变大?

VS2008编译Release版本,默认是不产生PDB文件的。如果要产生PDB文件,需要几个步骤:

第一步,设置Debug Information Format为Program Database(/Zi),也就是给cl.exe加/Zi参数。

第二步,给link.exe 加/DEBUG参数:

经过这两个步骤后,PDB文件就产生出来了,但你会发现我们的模块也随之变大。这是因为我们打开了/DEBUG开关,Link.exe不会做任何优化,编译出的Obj中函数可能有300多个,而我们引用的可能只有5个,但/DEBUG开关打开,300的函数都会被连接进去。所以我们要告诉链接器不要 连接没有被引用的文件:
第三步,优化:

再次编译,模块大小又缩小回去了,甚至比一开始不产生PDB文件时还小。

更多内容

关于PDB以及调试技巧的更多知识,参考这里:
http://blog.163.com/hao_dsliu/blog/#m=0&t=1&c=fks_084071092095085074092080083095085085080070083094095067092


0 0