符號文件
編譯器和鏈接器在創建二進制鏡像文件(諸如exe、dll、sys)時,伴生的后綴名為(".dbg",".sym",".pdb")的包含鏡像文件編譯、鏈接過程中生成的符號信息的文件稱為符號文件。
具體來說,符號信息包括如下內容:
1 // 全局變量(類型、名稱、地址) 2 // 局部變量(類型、名稱、地址) 3 // 函數(名稱、原型、地址) 4 // 結構體類型定義
符號路徑
符號路徑是調試器尋找符號文件的方向,它可以是本地文件夾路徑、可訪問的UNC路徑、或者是符號服務器路徑。符號服務器有一套命名規則,使得調試軟件能夠正確找到需要的符號文件。為了降低網絡訪問的成本,WinDbg會將從服務器上下載到的符號文件,保存在本地緩存中,以后調試器需要符號文件的時候,先從緩存中尋找,找不到的時候再到服務器上下載。
設置符號路徑
WinDbg允許用戶指定一個或多個目錄來存放符號文件,並使用環境變量"_NT_SYMBOL_PATH"來指向這些目錄的位置。這樣WinDbg在啟動時就會自動到這些目錄中搜索相應的符號文件。對操作系統內部模塊的符號文件,你可以在微軟官方網站上下載符號文件包(現在不提供離線下載了)。但是操作系統經常升級會導致系統中很多模塊的實際版本與已經發布的符號文件無法匹配,因此,實際使用過程中最常用的方式是根據使用的模塊版本訪問微軟提供的符號服務器下載(http://msdl.microsoft.com/download/symbols)。
手動設置:
從微軟服務器下載符號文件,並將文件保存到本地目錄:"C:\Symbols"。

命令設置:
// 顯示當前的路徑設置 0:000> .sympath Symbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols Expanded Symbol search path is: srv*c:\symbols*http://msdl.microsoft.com/download/symbols // 新增路徑設置 0:000> .sympath SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols Symbol search path is: SRV*C:\Symbols*http://msdl.microsoft.com/download/symbols Expanded Symbol search path is: srv*c:\symbols*http://msdl.microsoft.com/download/symbols // 覆蓋原來的路徑設置 0:000> .sympath C:\NewSymbols Symbol search path is: C:\NewSymbols Expanded Symbol search path is: c:\newsymbols // 追加一個新路徑設置 0:000> .sympath+ C:\NewSymbols2 Symbol search path is: C:\NewSymbols;C:\NewSymbols2 Expanded Symbol search path is: c:\newsymbols;c:\newsymbols2 // 要注意的是,使用.sympath改變或新增符號路徑后,符號文件並不會自動更新,應再執行.reload命令手動更新。 0:000> .reload Reloading current modules .....
符號選項
修改符號選項可以更好的使用其它符號功能。
// 顯示當前設置:.symopt 0:000> .symopt Symbol options are 0x30236: 0x00000002 - SYMOPT_UNDNAME 0x00000004 - SYMOPT_DEFERRED_LOADS 0x00000010 - SYMOPT_LOAD_LINES 0x00000020 - SYMOPT_OMAP_FIND_NEAREST 0x00000200 - SYMOPT_FAIL_CRITICAL_ERRORS 0x00010000 - SYMOPT_AUTO_PUBLICS 0x00020000 - SYMOPT_NO_IMAGE_SEARCH // 增加選項:.symopt+ Flags 0:000> .symopt+ 1 Symbol options are 0x30237: 0x00000001 - SYMOPT_CASE_INSENSITIVE //新增加選項 0x00000002 - SYMOPT_UNDNAME 0x00000004 - SYMOPT_DEFERRED_LOADS 0x00000010 - SYMOPT_LOAD_LINES 0x00000020 - SYMOPT_OMAP_FIND_NEAREST 0x00000200 - SYMOPT_FAIL_CRITICAL_ERRORS 0x00010000 - SYMOPT_AUTO_PUBLICS 0x00020000 - SYMOPT_NO_IMAGE_SEARCH // 刪除選項:.symopt- Flags 0:000> .symopt- 1 Symbol options are 0x30236: 0x00000002 - SYMOPT_UNDNAME 0x00000004 - SYMOPT_DEFERRED_LOADS 0x00000010 - SYMOPT_LOAD_LINES 0x00000020 - SYMOPT_OMAP_FIND_NEAREST 0x00000200 - SYMOPT_FAIL_CRITICAL_ERRORS 0x00010000 - SYMOPT_AUTO_PUBLICS 0x00020000 - SYMOPT_NO_IMAGE_SEARCH
各Flage含義如下:
//值 可讀名稱 描述 0x1 SYMOPT_CASE_INSENSITIVE 符號名稱不區分大小寫 0x2 SYMOPT_UNDNAME 符號名稱未修飾 0x4 SYMOPT_DEFERRED_LOADS 延遲加載 0x8 SYMOPT_NO_CPP 關閉C++轉換,C++中的::符號將以__顯示 0x10 SYMOPT_LOAD_LINES 從源文件中加載行號 0x20 SYMOPT_OMAP_FIND_NEAREST 如果由於編譯器優化導致找不到對應的符號,就以最近的一個符號代
替之 0x40 SYMOPT_LOAD_ANYTHING 使得符號匹配的時候,匹配原則較松散,不那么嚴格。 0x80 SYMOPT_IGNORE_CVREC 忽略鏡像文件頭中的CV記錄 0x100 SYMOPT_NO_UNQUALIFIED_LOADS 只在已加載模塊中搜索符號,如果搜索符號失敗,不會自動加載新模
塊。 0x200 SYMOPT_FAIL_CRITICAL_ERRORS 不顯示文件訪問錯誤對話框。 0x400 SYMOPT_EXACT_SYMBOLS 進行最嚴格的符號文件檢查,只要有微小的差異,符號文件都不會被
加載。 0x800 SYMOPT_ALLOW_ABSOLUTE_SYMBOLS 允許從內存的一個絕對地址處讀取符號信息。 0x1000 SYMOPT_IGNORE_NT_SYMPATH 忽視在環境變量中設置的符號路徑,也忽視被調試進程的執行路徑。
也就是說,當搜索符號文件的時候,不會從這些路徑中搜索。 0x2000 SYMOPT_INCLUDE_32BIT_MODULES 讓運行在安騰系統上的調試器,也枚舉32位模塊。 0x4000 SYMOPT_PUBLICS_ONLY 僅搜索符號文件的公共(PUBLIC)符號表,忽略私有符號表。 0x8000 SYMOPT_NO_PUBLICS 不搜索符號文件的公共(PUBLIC)符號表 0x10000 SYMOPT_AUTO_PUBLICS 先搜索pdb文件的私有符號表,如果在其中找到對應的符號,就不再
搜索公共(PUBLIC)符號表,這可以加快搜索速度。 0x20000 SYMOPT_NO_IMAGE_SEARCH 不搜索鏡像拷貝 0x40000 SYMOPT_SECURE 安全模式,讓調試器盡量不影響到主機。 0x80000 SYMOPT_NO_PROMPTS 不顯示符號代理服務器的認證對話框,將導致某些時候無法訪問符號
服務器 0x80000000 SYMOPT_DEBUG 顯示符號搜索的詳細過程和信息
符號加載
WinDbg默認采用延遲模式加載符號,也就是直到符號被使用的時候,才將符號文件加載到調試器中並進行解析。
你可以使用符號選項中介紹的命令來開啟和關閉延遲加載設置。
// 關閉延遲加載 0:000> .symopt- 4 //0x00000004 = SYMOPT_DEFERRED_LOADS //開啟延遲加載 0:000> .symopt+ 4 //0x00000004 = SYMOPT_DEFERRED_LOADS
立即加載符號文件
// 立即加載指定模塊的符號文件 0:000> lm start end module name 00000000`76f00000 00000000`76ffa000 USER32 (deferred) 00000000`77000000 00000000`7711f000 kernel32 (deferred) //未加載kernel32符號文件 00000000`77120000 00000000`772c9000 ntdll (pdb symbols) c:\symbols\ntdll.pdb\6192BFDB9F04442995FFCB0BE95172E12\ntdll.pdb 00000001`3fb40000 00000001`3fd2e52d hisfans (deferred) 000007fe`fd260000 000007fe`fd2cb000 KERNELBASE (deferred) 000007fe`fd650000 000007fe`fd719000 USP10 (deferred) 000007fe`fda60000 000007fe`fdaad000 WS2_32 (deferred) 000007fe`fdab0000 000007fe`fdacf000 sechost (deferred) 000007fe`fdd30000 000007fe`fdd3e000 LPK (deferred) 000007fe`fde20000 000007fe`fdefb000 ADVAPI32 (deferred) 000007fe`fe020000 000007fe`fe091000 SHLWAPI (deferred) 000007fe`fe0a0000 000007fe`fe0a8000 NSI (deferred) 000007fe`fe230000 000007fe`fe297000 GDI32 (deferred) 000007fe`fe2a0000 000007fe`fe33f000 msvcrt (deferred) 000007fe`fe340000 000007fe`fe46d000 RPCRT4 (deferred) 000007fe`fe470000 000007fe`ff1f8000 SHELL32 (deferred) // 加載kernel32模塊符號文件 0:000> ld kernel32 Symbols loaded for kernel32
重新加載符號文件
使用.reload命令重新加載符號文件時,默認情況下,調試器不會立刻根據符號路徑重新搜索並加載新的符號文件,而是推遲到調試器下一次(再次)使用到此模塊或符號時,才會進行更新。
你可以使用/f參數(force),迫使調試器立刻搜索並重新加載新的符號文件,這樣就不會等到下一次使用時在更新。
// .reload其它參數說明 /v:將搜索過程中的詳細信息都顯示出來。 /i:不檢查pdb文件的版本信息; /l:只顯示模塊信息,內核模式下,和“lm n t”命令類似,但顯示內容比后者更多,因為包含了用戶模塊信息; /n:僅重載內核符號,不重載用戶符號; /o:強制覆蓋符號庫中的符號文件,即使版本相同; /d:用戶層模式下使用Windbg時的默認選項,重載調試器模塊列表中的所有模塊; /s:內核模式下使用Windbg時的默認選項,重載系統模塊列表中的所有模塊,另外,如果調試器在用戶模式下運行,要加載內核模塊,也必須使用/s選項,否則調試器將只會在調試器模塊列表中搜索而導致找不到內核模塊; /u:卸載指定模塊。如發現當前符號版本不對,使用/u開關先卸載之再重新加載。
驗證符號
使用.reload重新加載符號文件的時候,符號文件可能會出現不匹配的情況。可以使用下面的命令驗證一個模塊的符號文件。
0:000> !chksym ntdll _PEB ntdll.dll Timestamp: 4CE7C8F9 SizeOfImage: 1A9000 pdb: ntdll.pdb pdb sig: 6192BFDB-9F04-4429-95FF-CB0BE95172E1 age: 2 Loaded pdb is c:\symbols\ntdll.pdb\6192BFDB9F04442995FFCB0BE95172E12\ntdll.pdb ntdll.pdb pdb sig: 6192BFDB-9F04-4429-95FF-CB0BE95172E1 age: 2 MATCH: ntdll.pdb and ntdll.dll
搜索符號
全局搜索
// 格式: x [參數] [模塊!符號] // 搜索ntdll中的所有OpenProcess函數 0:000> x ntdll!*OpenProcess* 00000000`77171570 ntdll!ZwOpenProcess = <no type information> 00000000`77171570 ntdll!NtOpenProcess = <no type information> 00000000`77171610 ntdll!ZwOpenProcessTokenEx = <no type information> 00000000`771722d0 ntdll!ZwOpenProcessToken = <no type information> 00000000`77171610 ntdll!NtOpenProcessTokenEx = <no type information> 00000000`771722d0 ntdll!NtOpenProcessToken = <no type information> // 也可以加/D參數,使用DML顯示 0:000> x /D ntdll!*OpenProcess* A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 00000000`77171570 ntdll!ZwOpenProcess = <no type information> 00000000`77171570 ntdll!NtOpenProcess = <no type information> 00000000`77171610 ntdll!ZwOpenProcessTokenEx = <no type information> 00000000`771722d0 ntdll!ZwOpenProcessToken = <no type information> 00000000`77171610 ntdll!NtOpenProcessTokenEx = <no type information> 00000000`771722d0 ntdll!NtOpenProcessToken = <no type information> // 如果想知道某個函數是在哪個模塊中定義的,可以使用如下命令 0:000> x *!NtOpenProcess 00000000`77171570 ntdll!NtOpenProcess = <no type information>
附近搜索
如果知道了符號的大概地址,但不能確定確切的符號名稱,可以使用"ln"命令(List Nearest)。它根據給定的地址列出附近一定范圍內的所有符號。
// 在指定地址0x7c8179f0附近尋找符號 0:000> ln 7c8179f0 (7c8179c3) kernel32!NlsServerInitialize+0x29 | (7c8179fe) kernel32!AllocTables
。。。
