原文发表于百度空间,2010-09-07
==========================================================================
本来只是打算以回复的形式回答一下m_sunv同学关于windbg搜索符号的问题,不料写得太多,超过了评论字数,索性就更详细一点单独写一篇文章来说明一下windbg查找符号文件的问题吧~
以下所有说明以本人的符号目录设置为前提,我的符号目录设置是:
_NT_SYMBOL_PATH=D:MyLocalSymbols;D:MySysSymbols
windbg加载符号文件的过程如下(以加载testGetObj.sys的符号为例,命令是"ld testGetObj"):
windbg加载符号文件时,会首先根据配置的符号目录信息,在本地符号目录中查找对应的符号文件。比如以上命令,在本地搜索时,一个典型的搜索过程如下:
D:MyLocalSymbols
D:MyLocalSymbolspingme.txt
D:MyLocalSymbolsflat.txt
D:MyLocalSymbolsindex2.txt
D:MyLocalSymbols estGetObj.pdb7CEF954F6E0647149F7447797763E3E31 estGetObj.pdb
D:MyLocalSymbols estGetObj.pdb7CEF954F6E0647149F7447797763E3E31 estGetObj.pd_
D:MyLocalSymbols estGetObj.pdb7CEF954F6E0647149F7447797763E3E31file.ptr
D:MySysSymbolspingme.txt
D:MySysSymbols estGetObj.pdb
D:MySysSymbols estGetObj.pdb estGetObj.pdb//当上面一个路径存在时
D:MySysSymbols estGetObj.pdb
D:MySysSymbolssys estGetObj.pdb
D:MySysSymbolssymbolssys estGetObj.pdb
F:mySys estGetObjobjchki386 estGetObj.pdb
C:Program FilesDebugging Tools for Windows estGetObj.pdb
首先解释一下路径中的那一串字母和数字混合的东西是什么玩意儿,这个字符串是编译器根据编译时的时间、版本、程序类型等信息生成的一个类似GUID一样的东西(VC6编译的符号文件其内部编号是编译时间的绝对秒,就是 time 函数返回的32位从1970年1月1日0点开始的秒数,后面加上程序的特征,例如目标机器的类型、程序类型等;VC7.0、7.1、8.0、9.0 编译的符号文件编号是一个 GUID,这可能是为了避免多线程同时编译相同特征的程序引发内部编号冲突),存储在PE文件的DebugDirecotry数据目录指向的数据中,暂且称之为pdb的索引串,对于每个编译出来的文件而言它是唯一的。同名文件的不同版本,它的这个索引串也不同。
下面我来逐一解释下上面看到的这个搜索过程:
1、先检查符号目录是否存在
这个很好解释,符号目录都不存在的话,搜索自然无从谈起
2、检查符号目录下是否存在flat.txt、pingme.txt或index2.txt
这三个文件的存在与否,决定了搜索过程中的一些细节。
如果存在pingme.txt,说明该目录下存在自动下载的符号文件。那么windbg将按照自动下载时的存放路径来检查符号文件是否存在。若没有pingme.txt,将不会采用这种路径来搜索。具体搜索方式参考第3条。
如果存在flat.txt(即使同时也存在pingme.txt),将忽略上面这种采用pdb索引串的快捷搜索方式,只以文件名和文件类型等信息进行搜索。
如果存在index2.txt,将按照文件名称分组进行搜索。分组方式是:使用符号文件名称的前两个字母最为一级目录,符号文件的名称作为二级目录,符号文件的编号作为三级目录,如此可对大量的文件进行分级索引,避免Symbols 目录下的子目录过多。比如以下路径:
D:MyLocalSymbolskekernel32.pdb
D:MyLocalSymbols
t
tdll.pdb
D:MyLocalSymbols
t
tkrnlpa.pdb
3、按pdb索引搜索(要求pingme.txt存在)
对于windbg自动下载的符号文件,会以"符号目录+符号文件名+pdb索引串+符号文件名的方式"为路径存储符号文件,这样,在下次需要查找该符号时,可以直接从PE文件中取得pdb索引串,然后构造出这样一个路径来快速加载符号文件。这就是搜索路径"D:MyLocalSymbols estGetObj.pdb7CEF954F6E0647149F7447797763E3E31 estGetObj.pdb"的由来。当存在pingme.txt时,将优先采用这种方式搜索。当然,自动下载符号的目录一般会自动创建一个pingme.txt的。
4、检查是否存在压缩的符号文件
windbg从符号服务器下载的符号文件,有些可能是压缩形式(文件名以_结束,需要用expand.exe解压缩),所以windbg会检查testGetObj.pd_的存在,若存在就会将其解压缩。file.ptr可能也是某种方式的临时文件,暂时我无法完全解释它。
5、以符号文件名作为文件夹名进行搜索
如果以上都没有找到,那么就检查符号目录下testGetObj.pdb这个文件夹是否存在,注意这里是文件夹。如果该文件夹存在,就会继续查找D:MySysSymbols estGetObj.pdb estGetObj.pdb。若文件夹不存在,就会直接在符号目录下查找符号文件testGetObj.pdb(注意是文件)。
6、以目标文件的类型作为分类搜索
如果仍然没有找到,那么将根据PE文件的类型(dll,exe,sys,ocx等)作为子目录进行查找(安装的符号文件一般是以这种路径形式存放的)。
7、以目标文件Debug信息中指定的符号路径进行搜索
对于我们自己编译的驱动,通常是包含了pdb文件的全路径的,随便用一个编辑器打开一个sys文件都可以看到文件中出现的pdb路径信息。
8、搜索windbg所在路径
这个没什么说的,在windbg所在路径下进行搜索。
9、到符号服务器查找符号
如果以上都没有找到的话,也就是说本地符号库中无法找到匹配的符号文件,如果符号设置中允许自动到符号服务器下载符号(比如出现了"SRV*D:MyLocalSymbols*http://msdl.microsoft.com/download/symbols"这样的配置),那么windbg就会根据PE文件的pdb索引串到符号服务器上查找是否有与该pdb索引串匹配的符号文件,若有,就将其下载到本地,若没有,那就是真的没有了,windbg将返回"ERROR: Symbol file could not be found."
了解了以上过程,现在回答提出的问题就简单了。
Q:不同系统的同名符号文件放在同一个符号目录里,会对windbg查找符号文件有影响吗?
A:有没有影响,取决于符号文件“放置”的方式,即这个符号文件是如何到符号目录中的。
如果是从微软官网下载的符号安装包,以ntfs.sys为例,安装到目录D:MyLocalSymbols,那么其完整路径将是:
D:MyLocalSymbolssys
tfs.pdb
显然,如果将不同系统的符号包安装在同一个文件夹,那么因为路径重复问题,同名的符号文件很有可能被覆盖,那么就只能存储一个有效的符号文件,而不能并存,想要并存的话就得安装到不同的文件夹,并将这些文件夹都添加到_NT_SYMBOL_PATH环境变量中。
如果你安装的符号文件不在同一个目录里,那也许还可以并存。
如果是windbg自动从符号服务器下载的服务,那么不同系统的同名文件之间是没有影响的。举个例子,WinXP有ntfs.sys,Win7也有ntfs.sys,这两个ntfs.sys显然是不一样的,那么这两个同名文件的同名符号文件在符号目录中是怎么放的呢?
在我的系统上,两个ntfs.pdb的实际位置如下:
D:MyLocalSymbols
tfs.pdbCF3F539EE3B2408887756DD42D7E53442
tfs.pdb
D:MyLocalSymbols
tfs.pdbDEF98FCD9F6340F6B23B65421A08CFD72
tfs.pdb
可以看到,这两个ntfs.pdb都位于D:MyLocalSymbols
tfs.pdb目录下,但是按照pdb索引放在了不同的子文件夹里,当Windbg搜索时,自会按照pdb索引进行优先搜索,并不会有冲突问题。
Q:我把符号文件放在符号目录里一个叫abc的子文件夹下,为什么windbg就找不到了?
A:结合上面说明的windbg搜索符号文件的过程就知道了,windbg不可能无缘无故地去到符号目录下一个叫abc的文件夹里进行搜索,能进行那么多处搜索已经是考虑得很全面了,难道你指望windbg知道符号目录下一个叫abc(或者其它一个没有任何规律和来由的名字)的目录里存储着你要找的符号文件?显然是不可能的!出于搜索效率考虑,windbg不可能去枚举符号目录中的每一个符号文件来进行检查匹配,所以找不到就不足为怪了。如果你是程序员,让你来解决搜索符号这个问题,在兼顾效率的同时还要尽可能全面,我想你也不会想着到某一个不知来历的子目录下去搜索我们要找的文件吧?所以,符号文件该怎么放就怎么放,我们就不要去难为windbg了嘛~~