我想我不需要强调在调试时拥有有效的PDB文件有多重要。通常,PDB文件是由调试器静默加载的,并且您很高兴在modules窗口中看到解析的所有符号。不幸的是,您还可能遇到调试器找不到匹配符号的情况。其原因可能与断开的互联网连接或更复杂的签名不匹配一样微不足道。在本文中,我将向您展示如何在调试之前检查符号文件,以及如何从中提取源文件信息。由于有不同的方法(和工具)来操作符号文件,我将介绍我所知道的那些。
下载给定PE文件的PDB文件
由于PDB文件格式是微软的秘密,所以我介绍的所有工具都只是API的包装器。要处理PDB文件,我们首先需要获取它们。让我们列出能帮助我们的工具。
symchk.exe
符号检查器(Symchk.exe)是一个应用程序,它将可执行文件与符号文件进行比较,以验证匹配的符号是否可用。Symchk也可以用于填充符号缓存。它可以从PE文件(exe,dll)、转储文件和进程中读取符号信息。它还支持递归目录搜索和批处理文件。
我们将从加载kernel32.dll库的符号开始:
c:WindowsSystem32>echo %_NT_SYMBOL_PATH%
SRV*C:SymbolsMSS*http://referencesource.microsoft.com/symbols;SRV*C:SymbolsMSS*http://msdl.microsoft.com/download/symbols
c:WindowsSystem32>symchk /v /os kernel32.dll
[SYMCHK] Searching for symbols to c:WindowsSystem32kernel32.dll in path SRV*C:SymbolsMSS*http://referencesource.microsoft.com/symbols;SRV*C:SymbolsMSS*http://msdl.microsoft.com/download/symbols
DBGHELP: Symbol Search Path: SRV*C:SymbolsMSS*http://referencesource.microsoft.com/symbols;SRV*C:SymbolsMSS*http://msdl.microsoft.com/download/symbols
[SYMCHK] Using search path "SRV*C:SymbolsMSS*http://referencesource.microsoft.com/symbols;SRV*C:SymbolsMSS*http://msdl.microsoft.com/download/symbols"
DBGHELP: No header for c:WindowsSystem32kernel32.dll. Searching for image on disk
DBGHELP: c:WindowsSystem32kernel32.dll - OK
SYMSRV: C:SymbolsMSSkernel32.pdb9B30FD7CD6B44975BF34B43B6EF668212kernel32.pdb not found
SYMSRV: http://referencesource.microsoft.com/symbols/kernel32.pdb/9B30FD7CD6B44975BF34B43B6EF668212/kernel32.pdb not found
SYMSRV: kernel32.pdb from http://msdl.microsoft.com/download/symbols: 704453 bytes - copied
DBGHELP: kernel32 - public symbols
C:SymbolsMSSkernel32.pdb9B30FD7CD6B44975BF34B43B6EF668212kernel32.pdb
[SYMCHK] MODULE64 Info ----------------------
[SYMCHK] Struct size: 1680 bytes
[SYMCHK] Base: 0x0000000078D20000
[SYMCHK] Image size: 1175552 bytes
[SYMCHK] Date: 0x4e21213b
[SYMCHK] Checksum: 0x0012386d
[SYMCHK] NumSyms: 0
[SYMCHK] SymType: SymPDB
[SYMCHK] ModName: kernel32
[SYMCHK] ImageName: c:WindowsSystem32kernel32.dll
[SYMCHK] LoadedImage: c:WindowsSystem32kernel32.dll
[SYMCHK] PDB: "C:SymbolsMSSkernel32.pdb9B30FD7CD6B44975BF34B43B6EF668212kernel32.pdb"
[SYMCHK] CV: RSDS
[SYMCHK] CV DWORD: 0x53445352
[SYMCHK] CV Data: kernel32.pdb
[SYMCHK] PDB Sig: 0
[SYMCHK] PDB7 Sig: {9B30FD7C-D6B4-4975-BF34-B43B6EF66821}
[SYMCHK] Age: 2
[SYMCHK] PDB Matched: TRUE
[SYMCHK] DBG Matched: TRUE
[SYMCHK] Line nubmers: FALSE
[SYMCHK] Global syms: FALSE
[SYMCHK] Type Info: FALSE
[SYMCHK] ------------------------------------
SymbolCheckVersion 0x00000002
Result 0x00030001
DbgFilename
DbgTimeDateStamp 0x4e21213b
DbgSizeOfImage 0x0011f000
DbgChecksum 0x0012386d
PdbFilename C:SymbolsMSSkernel32.pdb9B30FD7CD6B44975BF34B43B6EF668212kernel32.pdb
PdbSignature {9B30FD7C-D6B4-4975-BF34-B43B6EF66821}
PdbDbiAge 0x00000002
[SYMCHK] [ 0x00000000 - 0x00030001 ] Checked "c:WindowsSystem32kernel32.dll"
SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1
正如您在详细模式(/v开关)中看到的,您收到了很多关于symchk正在做什么的信息。我们甚至可以读取它使用的符号API(dbghelp消息)。/os开关通知symchk打印输出消息中符号文件的完整路径。运行此命令后,kernel32.pdb文件应该在符号存储中。如果您想索引整个System32目录,您需要使用/r开关,它通知symchk递归地遍历提供的目录并下载找到的所有文件的符号,eg. symchk /r /v c:windowssystem32*.dll
让我们尝试加载notepad.exe进程的符号:
c: empsymtest>tasklist /FI "IMAGENAME eq notepad.exe"
Image Name PID Session Name Session# Mem Usage
========================= ======== ================ =========== ============
notepad.exe 2264 Console 1 6 036 K
c: empsymtest>symchk /ip 2264 /s SRV*.*http://msdl.microsoft.com/download/symbols
SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 26
使用/ip开关,我们可以只提供进程ID,symchk将为进程中加载的所有模块下载符号文件。在这个例子中,我们还使用了/s开关,它为symchk提供它应该使用的符号路径(如果设置了,则覆盖symchk的_NT_SYMBOL_PATH)。在我们的例子中,我们将符号文件从Microsoft公共服务器下载到当前目录。运行此命令后,此目录的列表如下所示:
c: empsymtest>tree .
Folder PATH listing
Volume serial number is 00000002 C622:C13F
C:TEMPSYMTEST
├───advapi32.pdb
│ └───6AEFDCFF7F2A429B8532CD2BFDDF85D12
├───CLBCatQ.pdb
│ └───60B9D310C472440BA13F66BFF0FC39E32
├───comctl32.pdb
│ └───943BA638A2CD4D88A1C7E7418EAF796C1
├───comdlg32.pdb
│ └───631B57376F8549FDB2E7A8AB3D2D1FDF2
├───cryptbase.pdb
│ └───F03E074BB9E74C9F9BBFB0E42EF3A0AB2
├───dwmapi.pdb
│ └───8683ED0C3DBE4053883EC22FD9B4F2102
├───gdi32.pdb
│ └───FB9403C3B1304DA192C4D0E3485E25ED2
├───imm32.pdb
│ └───98F27BA5AEE541ECBEE00CD03AD50FEE2
├───kernel32.pdb
│ └───9B30FD7CD6B44975BF34B43B6EF668212
├───kernelbase.pdb
│ └───61044362232B410AA600843CEBFD11612
...
另一个有趣的开关是(/id),它使您能够调试转储文件。symchk.exe的另一个伟大功能是称为清单文件的东西。清单文件包含有关必须下载的所有符号的信息。然后,可以使用/om开关运行symchk,该开关将生成清单文件,而无需下载任何符号。然后,可以将清单文件复制到具有Internet连接的任何计算机上,并使用/im开关下载符号文件。下面的代码片段显示了一个使用示例:
c: empsymtest>symchk /om notepad-symbols.man /ip 2264
SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 26
c: empsymtest>type notepad-symbols.man
notepad.pdb,36CFD5F9888C4483B522B9DB242D84782,1
notepad.exe,4a5bc9b335000,1
ntdll.pdb,6192BFDB9F04442995FFCB0BE95172E12,1
ntdll.dll,4ce7c8f91a9000,1
kernel32.pdb,9B30FD7CD6B44975BF34B43B6EF668212,1
kernel32.dll,4e21213b11f000,1
kernelbase.pdb,61044362232B410AA600843CEBFD11612,1
KernelBase.dll,4e21213c6c000,1
...
c: empsymtest>symchk /im notepad-symbols.man /s SRV*.*http://msdl.microsoft.com/download/symbols
SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 52
dbh.exe
这个工具是DbgHelp.dll库的包装器,它揭示了几乎所有的功能。我们将只看一个使用示例,因此如果您想更深入地了解Windows帮助的调试工具。当以模块名作为参数运行dbh.exe时,它将自动下载符号文件。因此,只要调用dbh c: windowssystem32kernel32.dll info,您就可以下载符号文件(使用了_NT_SYMBOL_PATH环境变量),并打印有关该文件及其PE文件(kernel32.dll)的信息:
c: emp>dbh c:windowssystem32kernel32.dll info
SizeOfStruct : 0x690
BaseOfImage : 0x1677721664x
ImageSize : 0x1000000
TimeDateStamp : 0x4e21213b
CheckSum : 0x12386d
NumSyms : 0x0
SymType : SymPdb
ModuleName : kernel32
ImageName : c:windowssystem32kernel32.dll
LoadedImageName : c:windowssystem32kernel32.dll
LoadedPdbName : C:SymbolsMSSkernel32.pdb9B30FD7CD6B44975BF34B43B6EF668212kernel32.pdb
CVSig : 0x53445352
CVData : kernel32.pdb
PdbSig : 0x0
PdbSig70 : 0x9b30fd7c, 0xd6b4, 0x4975, 0xbf, 0x34, 0xb4, 0x3b, 0x6e, 0xf6, 0x68, 0x21
PdbAge : 0x2
PdbUnmatched : false
DbgUnmatched : false
LineNumbers : false
GlobalSymbols : false
TypeInfo : false
SourceIndexed : false
PublicSymbols : true
MachineType : X64
如果您想查看有关加载的PDB文件的详细信息,请使用-n开关。要更改默认符号路径(或覆盖符号路径设置),请使用-s:开关。
dumpbin.exe
您可能会惊讶于这个工具出现在这里,但是您是否注意到它的/PDBPATH[:VERBOSE]开关?在kernel32.dll库中发出dumpbin/pdbpath:verbose将导致从公共符号存储下载PDB文件:
c: empsymtest>dumpbin /pdbpath:verbose c:windowssystem32kernel32.dll
Microsoft (R) COFF/PE Dumper Version 10.00.40219.01
Copyright (C) Microsoft Corporation. All rights reserved.
Dump of file c:windowssystem32kernel32.dll
File Type: DLL
PDB file 'c:windowssystem32kernel32.pdb' checked. (File not found)
PDB file 'c: empsymtestkernel32.pdb' checked. (File not found)
PDB file found at 'C:SymbolsMSSkernel32.pdb9B30FD7CD6B44975BF34B43B6EF668212kernel32.pdb'
Summary
2000 .data
A000 .pdata
6E000 .rdata
8000 .reloc
1000 .rsrc
9B000 .text
从源服务器下载源代码
srctool.exe
这个工具非常有趣,因为它允许您检查PDB文件中索引的源文件,并最终提取它们。使用-r开关,您可以检查PDB文件中哪些源代码路径是硬编码的
c: emp>srctool -r ConsoleApplication1.pdb
D:labsymbols-labsymbolsConsoleApplication1Program.cs
D:labsymbols-labsymbolsConsoleApplication1AdvertQuickView.cs
没有任何开关,SRCooT将检查PDB文件中的源服务器流(如果存在)和将执行以提取源文件的打印命令,例如:
c: emp>srctool ConsoleApplication1.pdb
[D:labsymbols-labsymbolsConsoleApplication1Program.cs] cmd: cmd /c svn.exe cat "svn://localhost/test2/Program.cs@1" --non-interactive --username admin --password admin > "
[D:labsymbols-labsymbolsConsoleApplication1AdvertQuickView.cs] cmd: cmd /c svn.exe cat "svn://localhost/test2/AdvertQuickView.cs@1" --non-interactive --username admin --password admin > "
ConsoleApplication1.pdb: 2 source files are indexed
要运行命令并提取源文件,只需在上面的调用中添加-x开关。此外,还可以使用-d开关指定要将源文件提取到的目录(默认情况下是当前目录)。
pdbstr
如果希望更好地控制源服务器流,可以检查pdbstr命令。借助它,您可以读取和更新PDB文件中的源服务器信息。源服务器流实际上是一个带有预定义节的文本块(可以在这里找到更多信息)。您可以通过发布以下内容来转储其内容:
c: emp>pdbstr -r -p:ConsoleApplication1.pdb -s:srcsrv > stream.txt
stream.txt文件应包含如下内容:
SRCSRV: ini ------------------------------------------------
VERSION=1
INDEXVERSION=2
VERCTRL=Subversion
DATETIME=Thu Nov 17 13:31:46 2011
SRCSRV: variables ------------------------------------------
SVNUSER=admin
SVNPASS=admin
SVN_EXTRACT_TARGET=%targ%\%fnbksl%(%var3%)\%var4%\%fnfile%(%var1%)
SVN_EXTRACT_CMD=cmd /c svn.exe cat "%var2%%var3%@%var4%" --non-interactive --username %svnuser% --password %svnpass% > "
%svn_extract_target%"
SRCSRVTRG=%SVN_extract_target%
SRCSRVCMD=%SVN_extract_cmd%
SRCSRV: source files ---------------------------------------
D:labsymbols-labsymbolsConsoleApplication1Program.cs*svn://localhost/*test2/Program.cs*1
D:labsymbols-labsymbolsConsoleApplication1AdvertQuickView.cs*svn://localhost/*test2/AdvertQuickView.cs*1
SRCSRV: end ------------------------------------------------
c: emp>pdbstr -w -p:ConsoleApplication1.pdb -s:srcsrv -i:stream.txt
Pdbstr不会为您提取源代码文件,而是从源流内容中提取,您可以很容易地在哪里找到它们。这将结束我们的PDB工具列表-我希望您会发现它很有用。