來個樣例
我的符號目錄設置是:
用我們在windows下調試必須用到的ntdll.dll模塊來講下windbg加載符號文件的過程。windbg加載符號文件時,會首先根據配置的符號目錄信息,在本地符號目錄中查找對應的符號文件。一個典型的搜索過程如下:
F:\Debug_Symbol\Symbols32\
F:\Debug_Symbol\Symbols32\pingme.txt
F:\Debug_Symbol\Symbols32\flat.txt
F:\Debug_Symbol\Symbols32\index2.txt
F:\Debug_Symbol\Symbols32\ntdll.pdb\2505F15902821D2C6931BBFF1B941EBF1\ntdll.pdb
F:\Debug_Symbol\Symbols32\ntdll.pdb\2505F15902821D2C6931BBFF1B941EBF1\ntdll.pd_
F:\Debug_Symbol\Symbols32\ntdll.pdb\2505F15902821D2C6931BBFF1B941EBF1\file.ptr
首先解釋一下路徑中的那一串字母和數字混合的東西是什么玩意兒,這個字符串是編譯器根據編譯時的時間、版本、程序類型等信息生成的一個類似GUID一樣的東西(VC6編譯的符號文件其內部編號是編譯時間的絕對秒,就是 time 函數返回的32位從1970年1月1日0點開始的秒數,后面加上程序的特征,例如目標機器的類型、程序類型等;VC7.0、7.1、8.0、9.0 編譯的符號文件編號是一個 GUID,這可能是為了避免多線程同時編譯相同特征的程序引發內部編號沖突),存儲在PE文件的DebugDirecotry數據目錄指向的數據中,暫且稱之為pdb的索引串,對於每個編譯出來的文件而言它是唯一的。同名文件的不同版本,它的這個索引串也不同。
過程詳解
下面我來逐一解釋下上面看到的這個搜索過程:
- 調試器先檢查符號目錄是否存在
- 檢查符號目錄下是否存在flat.txt、pingme.txt或index2.txt。這三個文件的存在與否,決定了搜索過程中的一些細節。
如果存在pingme.txt,說明該目錄下存在自動下載的符號文件。那么windbg將按照自動下載時的存放路徑來檢查符號文件是否存在。若沒有pingme.txt,將不會采用這種路徑來搜索。具體搜索方式參考第3條。
如果存在flat.txt(即使同時也存在pingme.txt),將忽略上面這種采用pdb索引串的快捷搜索方式,只以文件名和文件類型等信息進行搜索。
如果存在index2.txt,將按照文件名稱分組進行搜索。分組方式是:使用符號文件名稱的前兩個字母最為一級目錄,符號文件的名稱作為二級目錄,符號文件的編號作為三級目錄,如此可對大量的文件進行分級索引,避免Symbols 目錄下的子目錄過多。比如以下路徑:
F:\Debug_Symbol\Symbols32\ke\kernel32.pdb\
F:\Debug_Symbol\Symbols32\nt\ntdll.pdb\
F:\Debug_Symbol\Symbols32\nt\ntkrnlpa.pdb\ - 按pdb索引搜索(要求pingme.txt存在)
對於windbg自動下載的符號文件,會以"符號目錄+符號文件名+pdb索引串+符號文件名的方式"為路徑存儲符號文件,這樣,在下次需要查找該符號時,可以直接從PE文件中取得pdb索引串,然后構造出這樣一個路徑來快速加載符號文件。這就是搜索路徑"F:\Debug_Symbol\Symbols32\ntdll.pdb\2505F15902821D2C6931BBFF1B941EBF1\ntdll.pdb"的由來。當存在pingme.txt時,將優先采用這種方式搜索。當然,自動下載符號的目錄一般會自動創建一個pingme.txt的。 - 檢查是否存在壓縮的符號文件
windbg從符號服務器下載的符號文件,有些可能是壓縮形式(文件名以_結束,需要用expand.exe解壓縮),所以windbg會檢查ntdll.pd_的存在,若存在就會將其解壓縮。file.ptr可能也是某種方式的臨時文件,暫時我無法完全解釋它。 - 以符號文件名作為文件夾名進行搜索
如果以上都沒有找到,那么就檢查符號目錄下ntdll.pdb這個文件夾是否存在,注意這里是文件夾。如果該文件夾存在,就會繼續查找F:\Debug_Symbol\Symbols32\ntdll.pdb\ntdll.pdb。若文件夾不存在,就會直接在符號目錄下查找符號文件ntdll.pdb(注意是文件)。 - 以目標文件的類型作為分類搜索
如果仍然沒有找到,那么將根據PE文件的類型(dll,exe,sys,ocx等)作為子目錄進行查找(安裝的符號文件一般是以這種路徑形式存放的)。 - 以目標文件Debug信息中指定的符號路徑進行搜索
對於我們自己編譯的驅動,通常是包含了pdb文件的全路徑的,隨便用一個編輯器打開一個sys文件都可以看到文件中出現的pdb路徑信息。 - 搜索windbg所在路徑
- 到符號服務器查找符號
如果以上都沒有找到的話,也就是說本地符號庫中無法找到匹配的符號文件,如果符號設置中允許自動到符號服務器下載符號(比如出現了"SRV*F:\Debug_Symbol\Symbols32*http://msdl.microsoft.com/download/symbols"這樣的配置),那么windbg就會根據PE文件的pdb索引串到符號服務器上查找是否有與該pdb索引串匹配的符號文件,若有,就將其下載到本地,若沒有,那就是真的沒有了,windbg將返回"ERROR: Symbol file could not be found."