使用符號進行偵錯

本文提供如何在偵錯程式中最佳使用符號的高階概觀。 它說明如何使用 Microsoft 符號伺服器,以及如何設定及使用您自己的私人符號伺服器。 這些最佳做法可協助您提升對問題進行偵錯的有效性和能力,即使計算機上未找到與問題相關的所有符號和可執行檔也一般。

符號

有許多不同類型的符號可供偵錯。 它們包括 CodeView 符號、COFF、DBG、SYM、PDB,甚至是從二進位檔匯出數據表產生的導出符號。 本白皮書只討論 VS.NET 和 PDB 格式符號,因為它們是最新的慣用格式。 默認會針對使用 Visual Studio 編譯的項目產生它們。

產生發行可執行檔的 PDB 檔案不會影響任何優化,或大幅改變產生的檔案大小。 一般而言,唯一的差異是路徑,而 PDB 檔案的檔名會內嵌在可執行檔中。 基於這個理由,您應該一律產生 PDB 檔案,即使您不想將檔案隨附於可執行檔也一樣。

如果使用 /Zi 或 /ZI (產生 PDB 資訊) 編譯程式參數來建置專案,以及 /DEBUG (產生偵錯資訊) 連結器參數,就會產生 PDB 檔案。 編譯程式產生的 PDB 檔案會合併並寫入單一 PDB 檔案,而該檔案會放在與可執行檔相同的目錄中。

根據預設,PDB 檔案包含下列資訊:

  • 公用符號(通常是所有函式、靜態和全域變數)
  • 負責可執行檔中程式代碼區段的物件檔案清單
  • 框架指標優化資訊 (FPO)
  • 局部變數和數據結構的名稱和類型資訊
  • 原始程式檔和行號資訊

如果您擔心使用 PDB 檔案資訊協助他們反向工程可執行檔,您也可以使用 /PDBSTRIPPED:filename 連結器選項來產生去除的 PDB 檔案。 如果您有想要從中移除私用資訊的現有 PDB 檔案,您可以使用稱為 pdbcopy 的工具,這是 Windows 偵錯工具的一部分。

根據預設,已移除的 PDB 檔案包含下列資訊:

  • 公用符號(通常只有非靜態函式和全域變數)
  • 負責可執行檔中程式代碼區段的物件檔案清單
  • 框架指標優化資訊 (FPO)

這是允許可靠偵錯所需的最小資訊。 最低資訊也會讓您難以取得原始原始原始程式碼的任何其他資訊。 由於產生已移除的 PDB 檔案和一般 PDB 檔案,因此您可以將移除的版本提供給可能需要有限偵錯功能但保留完整 PDB 機密的使用者。 請注意, /PDBSTRIPPED 會產生第二個較小的 PDB 檔案,因此當您產生組建以廣泛散發時,請務必使用正確的 PDB 檔案。 對於一般專案,一般 PDB 的大小可能只有幾 MB,但 PDB 的等量版本可能只有幾百 KB。

使用符號進行偵錯

當您偵錯已當機的應用程式時,調試程式會嘗試在導致當機的堆疊上顯示函式。 如果沒有 PDB 檔案,調試程式就無法解析函式名稱、其參數,或任何儲存在堆疊上的局部變數。 如果您偵錯 32 位可執行檔,在某些情況下,您甚至無法取得沒有符號的可靠堆疊追蹤。 有時候可以查看堆疊上的原始值,並找出哪些值可能是傳回位址,但這些值很容易與函式參考或數據混淆。

如果使用省略框架指標 (/Oy) 優化來編譯目前堆疊上的函式,而且如果符號不存在,調試程式就無法可靠地判斷呼叫目前函式的函式。 這是因為沒有 PDB 所包含的框架指標優化 (FPO) 資訊,調試程式無法依賴框架指標緩存器 (EBP) 指向儲存的前一個框架指標,以及父函式的傳回位址。 相反地,它猜測。 有時它得到正確。 然而,它經常會出錯,這可能會產生誤導。 如果您看到遺漏符號或未載入任何符號的警告,如下列範例所示,請勿信任該點的堆疊。

SWPerfTest.exe!TextFunction(... ...)    Line 59    C++
d3dx9d.dll!008829b5()
[Frames below may be incorrect and/or missing, no symbols loaded for d3dx9d.dll]
SWPerfTest.exe!main(int argc=, const char * * argv=)  Line 328 + 0x12 bytes     C++
SWPerfTest.exe!__mainCRTStartup() Line 716 + 0x17 bytes    C
kernel32.dll!@BaseThreadInitThunk@12() + 0x12 bytes
ntdll.dll!__RtlUserThreadStart@8() + 0x27 bytes

在許多情況下,您可以繼續在沒有符號的情況下進行偵錯,因為問題位於具有精確符號的位置,而且您不需要在呼叫堆疊中進一步查看函式。 即使呼叫堆疊中的連結庫沒有可用的 PDB,只要它們是以框架指標進行編譯,調試程式就應該能夠在父函式上正確猜測。 從 Windows XP Service Pack 2 開始,所有 Windows DLL 和可執行文件都會停用 FPO 進行編譯,因為它可讓偵錯更精確。 停用 FPO 也可讓取樣分析工具在運行時間逐步執行堆疊,而效能影響最小。 在 Windows XP SP2 之前的 Windows 版本上,所有作業系統二進位檔都需要符合包含 FPO 資訊的符號檔,才能允許精確的偵錯和分析。

如果您偵錯 64 位原生可執行檔,則不需要符號檔來產生有效的堆疊追蹤,因為 x64 操作系統和編譯程式的設計不需要它們。 不過,您仍然需要符號檔來擷取函式名稱、呼叫參數和局部變數。

不過,某些案例特別難以在沒有符號的情況下進行偵錯。 例如,如果您對建置 PDB 檔案的程式進行偵錯,而且當您在 DLL 中沒有符號的函式回呼中當機,您將無法看到哪個函式造成回呼,因為您將無法譯碼堆疊。 如果未提供 PDB,或未在舊的作業系統元件中提供 PDB,則經常會在第三方連結庫中發生此情況。 回呼通常會在訊息傳遞、列舉、記憶體配置或例外狀況處理期間發生。 在沒有精確堆疊的情況下對這些函式進行偵錯可能會令人沮喪。

若要可靠地偵錯在不同計算機上產生的迷你傾印,或在您不擁有的程式代碼中損毀,請務必能夠存取迷你傾印中所參考可執行檔的所有符號和二進制檔。 如果符號和二進位檔可從符號伺服器取得,調試程式會自動取得它們。 如需迷你傾印的詳細資訊,請參閱 損毀傾印分析 白皮書。

取得您需要的符號

Visual Studio 和其他 Microsoft 調試程式,例如 WinDbg,通常會在您建置應用程式並在自己的電腦上進行偵錯時,設定為正常運作。 如果您需要將可執行檔提供給其他人,如果您的電腦上有多個版本的 DLL 或 .exe 檔案,或者如果您想要準確地偵錯使用 Windows 或其他連結庫的應用程式,例如 DirectX,則需要瞭解調試程式如何尋找和載入符號。 調試程式會使用使用者指定的符號搜尋路徑,該路徑位於Visual Studio中的Options\Debugging\Symbols 或 _NT_SYMBOL_PATH 環境變數中。 一般而言,調試程式會在下列位置搜尋相符的 PDB:

  • DLL 或可執行檔內部指定的位置

    如果您已在計算機上建置 DLL 或可執行檔,連結器預設會將相關聯 PDB 檔案的完整路徑和檔名放在 DLL 或可執行檔內。 當您偵錯時,調試程式會先檢查符號檔是否存在於 DLL 或可執行檔中指定的位置。 這很有幫助,因為您一律有可在計算機上編譯之程式代碼的符號。

  • 可能與 DLL 或可執行檔位於相同資料夾中的 PDB。

  • 任何本機符號快取資料夾。

  • 任何局域網路檔案共享符號伺服器。

  • 任何因特網符號伺服器,例如 Microsoft 符號伺服器。

若要確定您擁有正確偵錯所需的所有 PDB,請安裝適用於 Windows 的偵錯工具。 您可以在適用於 Windows 的偵錯工具中找到 32 和 64 位版本。

隨此套件一起安裝的實用工具是 symchk.exe。 它有助於識別遺漏或不正確的符號。 此工具具有大量的潛在命令列選項。 以下是兩個較實用且常用的方法。

檢查相同資料夾中的指定 DLL 或 .exe 檔案和 PDB 是否相符

"c:\Program Files\Debugging Tools for Windows\symchk" testing.dll /s .

SYMCHK: FAILED files = 0
SYMCHK: PASSED + IGNORED files = 1

/s . 選項會告知 symchk 只尋找目前資料夾中的符號,而不是在任何符號伺服器中尋找符號。

檢查一組資料夾中的所有 DLL 和可執行檔是否都有相符的 PDB

"c:\Program Files\Debugging Tools for Windows\symchk" *.* /r

/r 選項會將符號設定為以遞歸方式周遊資料夾,以檢查所有可執行檔是否有相符的 PDB。 如果沒有 /s 選項,symchk 會使用目前的_NT_SYMBOL_PATH來搜尋任何私人或本地伺服器上的符號,或在 Microsoft 符號伺服器上搜尋符號。 符號工具只會搜尋可執行檔的符號(.exe、.dll 和類似專案)。 您無法使用通配符搜尋非可執行檔的符號。

symchk 的運作方式

當連結器產生 .dll、可執行檔和 PDB 檔案時,它會在每個檔案中儲存相同的 GUID。 工具會使用 GUID 來判斷指定的 PDB 檔案是否符合 DLL 或可執行檔。 如果您使用資源編輯器或複製保護編碼,或變更其版本資訊來變更 DLL 或可執行檔,GUID 就會更新,而且調試程式無法載入 PDB 檔案。 基於這個理由,請務必避免在連結器建立 DLL 或可執行文件之後操作 DLL 或可執行檔。

您也可以使用隨附 VS.NET 的 DUMPBIN 公用程式來顯示所搜尋的符號路徑,並查看是否找到符合指定 DLL 或可執行檔的符號檔。 例如:

DUMPBIN /PDBPATH:VERBOSE filename.exe

符號伺服器

符號伺服器是多個可執行檔和符號檔版本的存放庫。 它包含符號檔本身,或相關聯符號檔的指標。 偵錯工具瞭解如何使用符號伺服器,並可以使用它們來搜尋遺漏或未知的符號。

您也可以從 Microsoft 符號伺服器取得 DLL 和可執行檔。 這可讓您偵錯當機,並檢查電腦上可能不存在之作業系統檔案的程式碼。 如果偵錯工具遇到用於偵錯之系統上不存在的可執行檔或 DLL,它會自動從 Microsoft 符號伺服器要求符號和二進位檔複本。 如果您要偵錯具有許多版本的元件,例如 msvcrt.dll,而且您需要檢查電腦上不存在之版本的程式碼,這會很有説明。 這也有助於偵錯在與用於偵錯之系統不同的作業系統上產生的迷你傾印。

Microsoft 在其外部可存取的符號伺服器上,發佈所有作業系統和其他轉散發元件的所有 PDB 檔案,例如 DirectX SDK。 這可讓您輕鬆地偵錯使用這些 DLL 或可執行檔的應用程式。 您可以使用 Microsoft 符號伺服器來解析符號,以及電腦上建置之元件的任何本機符號。

您可以將電腦設定為使用 Microsoft 符號伺服器,這可讓您存取所有 Microsoft 符號檔。 您也可以為公司、小組或網路設定私人符號伺服器,以用來儲存您正在處理之專案的多個舊版,或提供您從 Microsoft 符號伺服器使用之符號的本機快取。

若要使用符號伺服器,請在稱為 _NT_SYMBOL_PATH 的環境變數中指定搜尋路徑。 偵錯工具和新式工具,例如 WinDbg、NTSD 或 Visual Studio,會自動使用此路徑來搜尋符號。

當偵錯工具搜尋符號時,它會先在本機搜尋。 然後它會在符號伺服器上查看。 當找到相符的符號時,它會將符號檔傳輸至本機快取。 一般 DLL 或可執行檔的符號大小從 1 到 100 MB 不等。 因此,如果您要偵錯包含許多 DLL 的進程,可能需要一些時間才能解析所有符號,並將其傳輸至本機快取。

使用 Microsoft 符號伺服器

Microsoft 符號伺服器可讓您取得所有最新的符號,包括已修補或更新檔案的符號。 Microsoft 符號伺服器位於 https://msdl.microsoft.com/download/symbols

您可以使用下列其中一種方式來存取符號伺服器:

  • 直接輸入伺服器位址。 在 Visual Studio 中,從 [ 工具] 功能表選擇 [ 選項 ], 然後選擇 [偵錯 ],然後選擇 [ 符號 ]。

  • 使用環境變數_NT_SYMBOL_PATH。 我們建議使用此方法。

    這可供所有偵錯工具使用。 Visual Studio 也會使用它,並在 Visual Studio 開啟時讀取和解碼。 因此,如果您變更它,則需要重新開機 Visual Studio。

    此環境變數可讓您指定多個符號伺服器,例如內部私人符號伺服器。 它也可讓您指定本機快取目錄,以針對您在內部和網際網路上查閱的所有符號儲存 PDB。

_NT_SYMBOL_PATH變數的語法如下:

srv*[local cache]*[private symbol server]*https://msdl.microsoft.com/download/symbols

將 [本機快取] 取代為您要在其中儲存所使用之任何符號的快取的目錄名稱,例如 %SYSTEMROOT%\Symbols 或 c:\symbols。

[私人符號伺服器] 是選擇性的。 它可以指向位於您網路上的符號伺服器,也可以指向由小組、產品群組或公司共用的符號伺服器。

若要將 Microsoft 符號伺服器與符號的本機快取搭配使用,若要加速透過網際網路存取,請使用下列_NT_SYMBOL_PATH設定:

srv*c:\symbols*https://msdl.microsoft.com/download/symbols

您可以在隨 Microsoft Debugging Tools for Windows 套件一起安裝的說明檔中找到_NT_SYMBOL_PATH的其他選項。

不使用符號的可執行檔可以增加使用符號伺服器啟動偵錯工具所需的時間。 這是因為偵錯工具會在每次嘗試載入可執行檔時查詢符號伺服器。 因此,最好一律要求所有元件的符號。

可能無法要求每個元件的符號,例如,視訊驅動程式可能會在您的進程空間中有 DLL,而且 Microsoft 符號伺服器上提供所需的 PDB 檔案。 在此情況下,當您啟動偵錯會話時,會有一小段延遲。

若要避免即使是這個小型延遲,您也可以執行偵錯工具一次,從 Microsoft 符號伺服器本機快取所有符號。 然後,修改您的_NT_SYMBOL_PATH以移除 Microsoft 符號伺服器。 除非可執行檔變更,否則檢查沒有符號的可執行檔不需要透過網際網路進行查詢,因為您有來自 Microsoft 符號伺服器之所有符號的本機快取複本。

手動取得符號

如果您已正確設定偵錯工具,它會自動從本機快取或符號伺服器載入它所需的任何符號。 如果您想要只取得單一可執行檔或可執行檔資料夾的符號,您可以使用 symchk 。 例如,如果您想要將 Windows System 資料夾中 d3dx9_30.dll 檔案的符號下載到目前目錄,您可以使用下列命令:

"c:\Program Files\Debugging Tools for Windows\symchk" c:\Windows\System32\d3dx9_30.dll /oc \.

符號工具 具有許多其他用途。 如需詳細資訊,請參閱 symchk /? ,或查看適用于 Windows 的 Microsoft 偵錯工具檔。

設定符號伺服器

設定符號伺服器非常簡單。 基於下列原因,它很有用:

  • 若要節省頻寬,或加快公司、小組或產品的符號解析速度。 網路本機檔案共用上的內部符號伺服器會快取外部符號伺服器的任何參考,例如 Microsoft 符號伺服器。 許多人員可以同時快速存取本機或內部符號伺服器。 因此,它會節省重複符號要求可以建立的頻寬和延遲。
  • 儲存舊組建、版本或應用程式外部版本的符號。 藉由將這些組建的符號儲存在可輕鬆存取的符號伺服器上,您可以在任何具有偵錯工具和本機符號伺服器連線的電腦上偵錯當機和問題。 如果您偵錯未自行建置的可執行檔所產生的迷你傾印,也就是由另一位程式設計人員或組建電腦所產生的組建,這會特別有用。 如果這些組建的符號儲存在符號伺服器上,您將會有可靠且精確的偵錯。
  • 若要讓符號保持在最新狀態。 更新元件時,例如 Windows Update 或 DirectX SDK 修改的 OS 元件,您仍然可以使用所有最新的符號進行偵錯。

在您自己的區域網路上設定符號伺服器就像在伺服器上建立檔案共用一樣簡單,並為使用者提供存取共用的完整許可權,以建立檔案和資料夾。 此共用應在 Windows Server 2003 等伺服器作業系統上建立,因此無法同時存取共用的人員數目不受限制。

例如,如果您在 \\mainserver\symbols 上設定檔案共用,則小組的成員會將_NT_SYMBOL_PATH設定為下列專案:

Srv*c:\symbols*\\mainserver\symbols*https://msdl.microsoft.com/download/symbols

當擷取符號時,檔案和資料夾會出現在 \\mainserver\symbols 共用目錄,以及 c:\symbols 目錄中的個別快取中。

這通常是設定和使用您自己的符號伺服器或 Microsoft 符號伺服器時所涉及的所有專案。

將符號新增至符號伺服器

若要在符號伺服器共用上新增、刪除或編輯檔案,請使用 symstore.exe 工具。 此工具是適用于 Windows 套件的 Microsoft 偵錯工具的一部分。 符號伺服器、符號存放區工具和索引符號的完整檔包含在 Windows 套件的偵錯工具中。

您可能會想要將符號直接新增至您自己的符號伺服器,做為建置程式的一部分,或將符號提供給整個小組供協力廠商程式庫或工具使用。 將符號新增至符號伺服器檔案共用的程式稱為索引符號。 索引符號有兩種常見方式。 符號檔可以複製到符號伺服器。 或者,符號位置的指標可以複製到符號伺服器。 如果您有包含舊組建的封存資料夾,您可能會想要為已存在於共用上的 PDB 檔案編制索引,而不是複製符號。 因為符號有時大小可能為數十 MB,因此建議您事先規劃在開發期間封存專案的所有組建所需的空間。 如果您只編制符號指標的索引,當您移除舊組建或變更檔案共用的名稱時,可能會遇到問題。

例如,若要以遞迴方式將 c:\dxsym\Extras\Symbols 中的所有符號編制成從 2006 年 10 月 DirectX SDK 取得到名為 \\mainserver\symbols 的符號伺服器檔案共用,您可以使用下列命令:

"c:\Program Files\Debugging Tools for Windows\symstore" add /f "C:\dxsym\Extras\Symbols\*.pdb"
/s \\mainserver\symbols /t "October 2006 DirectX SDK " /r

/t 「comment」 參數可用來將描述新增至新增符號的交易。 在符號上執行系統管理工作時,這非常有用。

最佳做法

  • 為您的小組、公司或產品設定您自己的符號伺服器檔案共用。
  • 將_NT_SYMBOL_PATH設定為指向本機快取、指向私人符號伺服器,以及指向 Microsoft 符號伺服器。
  • 如果偵錯工具無法載入您要偵錯之元件的符號,請連絡元件的擁有者以要求符號,至少是已移除的 PDB。
  • 針對產生的每個組建,設定自動化建置系統,以在私人符號伺服器上為符號編制索引。 請確定您散發的組建是此程式所產生的組建。 這可確保符號一律可用於偵錯問題。
  • 設定符號伺服器,以允許偵錯工具直接從 Visual Source 保管庫 或 Perforce 型原始檔控制系統存取特定模組的原始程式碼。 如果已發行版本本的遊戲的原始程式檔資訊和符號已編制索引,則有權存取符號伺服器的開發人員可以完整針對回報的問題進行來源層級偵錯,而不會在其開發電腦上保留組建環境或舊版的原始程式檔。 若要設定符號伺服器以允許編制來源檔案資訊的索引,請參閱來源伺服器檔。