公用和私人符號
當連結器建置完整大小的 .pdb 或 .dbg 符號檔時,它包含兩個不同的資訊集合:私用符號資料和公用符號資料表。 這些集合與其包含的專案清單不同,以及它們儲存有關每個專案的資訊。
私人符號資料包含下列專案:
函式
全域變數
區域變數
使用者定義結構、類別和資料類型的相關資訊
來源檔案的名稱,以及該檔案中對應至每個二進位指令的行號
公用符號資料表包含較少的專案:
函式 (,但宣告 為靜態) 的函式除外
指定為 extern 的全域變數 (,以及跨多個物件檔顯示的任何其他全域變數)
一般規則是公用符號表包含從一個來源檔案到另一個來源檔案可存取的專案。 只有一個物件檔案中可見的專案,例如 靜態 函式、只在單一原始程式檔內全域的變數,以及區域變數-- 不包含在公用符號資料表中。
這兩個資料集合也會因每個專案所包含的資訊而有所不同。 下列資訊通常會包含在 私 用符號資料中的每個專案:
專案的名稱
虛擬記憶體中專案的位址
每個變數、結構和函式的資料類型
每個函式的參數類型和名稱
每個區域變數的範圍
與每個原始程式檔中每一行相關聯的符號
用於存取堆疊之每個函式的框架指標省略 (FPO) 記錄
另一方面, 公用 符號表只會儲存其中每個專案的相關下列資訊:
項目的名稱。
其模組之虛擬記憶體空間中專案的位址。 對於函式,這是其進入點的位址。
框架指標省略 (每個函式的 FPO) 記錄。
可能包含稱為裝飾的符號前置詞/尾碼。
公用符號資料可視為私用符號資料的子集,有兩種方式:它包含較短的專案清單,也包含每個專案的資訊較少。 例如,公用符號資料完全不包含區域變數。
每個區域變數只會包含在私用符號資料中,其位址、資料類型和範圍。 另一方面,私用符號資料和公用符號資料表都包含函式,但私人符號資料包含函式名稱、位址、FPO 記錄、輸入參數名稱和類型,以及輸出類型,公用符號資料表只包含函式名稱、位址和 FPO 記錄。
私人符號資料和公用符號資料表之間有一個其他差異。 公用符號資料表中的許多專案都有以前置詞、尾碼或兩者 裝飾 的名稱。 這些裝飾是由 C 編譯器、C++ 編譯器和 MASM 組合器所新增。 一般前置詞包括一系列底線或字串 __imp_ ( 指定匯入的函式) 。 一般尾碼包括一或多個符號 ( @ ) 後面接著位址或其他識別字串。 連結器會使用這些裝飾來厘清符號,因為函式名稱或全域變數名稱可能會在不同的模組之間重複。 這些裝飾是公用符號資料表是私用符號資料子集的一般規則例外。
完整符號檔和等量符號檔
完整的符號檔同時包含私用符號資料和公用符號資料表。 這種檔案有時稱為 私人符號檔,但此名稱會誤導,因為這類檔案同時包含私用和公用符號。
等量符號檔是較小的檔案,只包含公用符號表,或者在某些情況下,只有公用符號表的子集。 此檔案有時稱為 公用符號檔。
建立完整和等量符號檔
如果您使用 Visual Studio 建置二進位檔,您可以建立完整或移除的符號檔。 如需建置等量符號的資訊,請參閱 /PDBSTRIPPED (Strip Private Symbols) 。
使用 BinPlace 工具,您可以從完整符號檔建立等量符號檔。 使用最常見的 BinPlace 選項時, (-a -x -s -n) ,等量符號檔會放在 -s 參數之後所列的目錄中,而完整符號檔會放在 -n 參數之後所列的目錄中。 當 BinPlace 移除符號檔時,會提供相同的簽章和其他識別資訊,以移除和完整版本的檔案。 這可讓您使用任一版本進行偵錯。 如需 BinPlace 的詳細資訊,請參閱 BinPlace。
使用 PDBCopy 工具,您可以藉由移除私人符號資料,從完整符號檔建立移除的符號檔。 PDBCopy 也可以移除公用符號資料表的指定子集。 如需詳細資訊,請參閱 PDBCopy。
使用 SymChk 工具,您可以判斷符號檔是否包含私人符號。 如需詳細資訊,請參閱 SymChk。
在偵錯工具中檢視公用和私人符號
您可以使用 WinDbg、KD 或 CDB 來檢視符號。 當其中一個偵錯工具可以存取完整的符號檔時,它會同時包含私用符號資料中所列的資訊,以及公用符號資料表中所列的資訊。 公用符號資料包含符號裝飾。
存取私人符號時,一律會使用私人符號資料,因為這些符號不會包含在公用符號資料表中。 這些符號永遠不會裝飾。
.symopt (設定符號選項) 命令可用來控制符號選項,以決定偵錯工具如何使用公用和私用符號。 例如,此命令會開啟符號偵錯資訊。
.symopt+ 0x80000000
下列選項會變更偵錯工具中使用公用和私用符號的方式。
當 [SYMOPT_UNDNAME ] 選項開啟時,當顯示公用符號的名稱時,不會包含裝飾。 此外,搜尋符號時會忽略裝飾。 當此選項關閉時,會在顯示公用符號時顯示裝飾,並在搜尋中使用裝飾。 任何情況下都不會裝飾私人符號。 此選項預設會在所有偵錯工具中開啟。
當 SYMOPT_PUBLICS_ONLY 選項開啟時,會忽略私用符號資料,而且只會使用公用符號資料表。 此選項預設會在所有偵錯工具中關閉。
當 [SYMOPT_NO_PUBLICS ] 選項開啟時,會忽略公用符號資料表,並單獨搜尋和符號資訊使用私用符號資料。 此選項預設會在所有偵錯工具中關閉。
當SYMOPT_AUTO_PUBLICS選項處於 ( ,且SYMOPT_PUBLICS_ONLY和SYMOPT_NO_PUBLICS都關閉) ,則會在私人符號資料中執行第一個符號搜尋。 如果找到所需的符號,搜尋就會終止。 如果沒有,則會搜尋公用符號表。 由於公用符號資料表包含私用資料中的符號子集,因此通常會忽略公用符號資料表。
當SYMOPT_PUBLICS_ONLY、SYMOPT_NO_PUBLICS和SYMOPT_AUTO_PUBLICS選項全部關閉時,每次需要符號時,都會搜尋私人符號資料和公用符號資料表。 不過,當在這兩個位置找到相符專案時,會使用私用符號資料的相符專案。 因此,此實例中的行為與開啟SYMOPT_AUTO_PUBLICS相同,不同之處在于使用 SYMOPT_AUTO_PUBLICS 可能會導致符號搜尋稍微加快。
以下是 使用命令 x (檢查符號) 三次的範例。 第一次使用預設符號選項,因此會從私用符號資料取得資訊。 請注意,這包括陣列 typeString之位址、大小和資料類型的相關資訊。 接下來,會使用 .symopt+ 4000 命令,導致偵錯工具忽略私用符號資料。 當 x 命令再次執行時,會使用公用符號表;這次沒有 typeString的大小和資料類型資訊。 最後,會使用 .symopt- 2 命令,這會導致偵錯工具包含裝飾。 在最後一次執行 x 命令時,會顯示函式名稱的裝飾版本 _typingString。
0:000> x /t /d *!*typingstring*
00434420 char [128] TimeTest!typingString = char [128] ""
0:000> .symopt+ 4000
0:000> x /t /d *!*typingstring*
00434420 <NoType> TimeTest!typingString = <no type information>
0:000> .symopt- 2
0:000> x /t /d *!*typingstring*
00434420 <NoType> TimeTest!_typingString = <no type information>
使用 DBH 工具檢視公用和私人符號
另一種檢視符號的方式是使用 DBH 工具。 使用 /?
選項顯示說明選項。
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>dbh /?
dbh dbghelp shell
usage: dbh [-n] [-c] [-d] [-?] [-??] [-p] [targetmodule] [command]
[-n] display noisy symbol spew
[-d] use decorated publics
[-p:XXXX] attaches to process ID XXXX
[-s:SSSS] set symbol path to SSSS
[-c] callbacks return false
[targetmodule] load symbols for specified module
[command] execute command and exit
[-?] display these usage instructions
[-??] display detailed usage instructions
使用 Tlist 之類的工具來列出進程識別碼,以及附加至現有進程的 -p 選項。
C:\Program Files (x86)\Windows Kits\10\Debuggers\x64>dbh -p:4308
DBH 會使用與偵錯工具相同的符號選項。 如同偵錯工具,DBH預設SYMOPT_PUBLICS_ONLY和SYMOPT_NO_PUBLICS關閉,預設會開啟SYMOPT_UNDNAME和SYMOPT_AUTO_PUBLICS。 這些預設值可由命令列選項或 DBH 命令覆寫。
以下是使用 DBH 命令 增益集 414fe0 三次的範例。 第一次使用預設符號選項,因此資訊取自私人符號資料。 請注意,這包括函式 fgets位址、大小和資料類型的相關資訊。 接下來,會使用命令符號 +4000,這會導致 DBH 忽略私人符號資料。 當 addr 414fe0 再次執行時,會使用公用符號資料表;這次沒有函式 fget的大小和資料類型資訊。 最後,會使用命令符號 -2,這會導致 DBH 包含裝飾。 當 addr 414fe0 在此最後一次執行時,會顯示函式名稱的裝飾版本 _fgets。
pid:4308 mod:TimeTest[400000]: addr 414fe0
fgets
name : fgets
addr : 414fe0
size : 113
flags : 0
type : 7e
modbase : 400000
value : 0
reg : 0
scope : SymTagNull (0)
tag : SymTagFunction (5)
index : 7d
pid:4308 mod:TimeTest[400000]: symopt +4000
Symbol Options: 0x10c13
Symbol Options: 0x14c13
pid:4308 mod:TimeTest[400000]: addr 414fe0
fgets
name : fgets
addr : 414fe0
size : 0
flags : 0
type : 0
modbase : 400000
value : 0
reg : 0
scope : SymTagNull (0)
tag : SymTagPublicSymbol (a)
index : 7f
pid:4308 mod:TimeTest[400000]: symopt -2
Symbol Options: 0x14c13
Symbol Options: 0x14c11
pid:4308 mod:TimeTest[400000]: addr 414fe0
_fgets
name : _fgets
addr : 414fe0
size : 0
flags : 0
type : 0
modbase : 400000
value : 0
reg : 0
scope : SymTagNull (0)
tag : SymTagPublicSymbol (a)
index : 7f