關於PDB與EXE/DLL 檔案的匹配問題(轉)
阿新 • • 發佈:2019-01-27
1. 靜態檢查
windbg 除錯工具包中有一個工具symchk.exe, 選項很多, 下面一個簡單的用法可以檢查一個 test.exe能不能找到與它匹配的PDB:
這是成功的情形. 下面來個失敗的作為對比:
2. 如果已經在windbg內部, 可以通過下面的命令檢查
最後一行說 MATCH, 肯定沒問題.
3. 在windbg中(在VS中不行), 如果你100%確信原始碼沒有任何改動, 只不過被重新編譯了一下.
可以通過 .symopt +40 來關閉對GUID的強行檢查. 從而load一個不匹配的PDB.
4. 除了1中提到的工具, 還有一個叫chkmatch 的工具, 在
http://www.debuginfo.com/download/chkmatch.zip
可以下載, 該工具不僅可以檢查是否匹配, 還可以把不匹配的強制改為匹配, 也就是說EXE/DLL和PDB中的GUID相同, 這樣在VS中就可以使用了, 當然, 高度危險, 後果自負.
5. 在VS中的空心圓
我同事把那種設定了斷點之後, 沒有設定成功, 出現的紅色圓圈叫做空心圓問題.
此類問題有兩個可能的原因:
(A) 的確PDB不匹配
(B) 時機還不到, 有些原始檔對應的module本身還沒有被load, 對應的PDB更不會被load了.
(C) 程式碼被優化掉了
對於(B)的情況, 在windbg中也同樣會出現斷點貌似設定不對的情況.
對於是(A)還是(B)的判斷, 在VS中, 可以開啟Module 視窗, 這個視窗對診斷此類問題很有幫助. 在Debug選單下, 有些VS2005 安裝之後, 在DEBUG選單下找不到這個選單項, 不要驚慌, 它只是沒出現在選單項而已, 通過tools-customize可以找回它.
這個Module視窗中, 清楚地列出當前被除錯的程序中, 有哪些module, 每個module的pdb 情況, 你還可以手工load一個module對應的symbol檔案, 可以檢視symbol檔案的細節.
在這個視窗中, 一個可能會令你迷惑的地方是: 對於mixed module, 它會被列出兩次, 一次為native, 一次為.NET
6 關於5中的(C)的情況, 程式碼被優化掉了, 有幾個應對辦法:
(I) 如果可以, 重新編譯, 關閉優化, 我個人的經驗和習慣是, 永遠不開啟優化, 除非: 有證據表明某處有效能問題, 或在為RISC CPU寫程式, 此類指令集的效能高度依賴於是否優化.
(II) 對於.NET 程式, 你儘早會碰到即使關閉了編譯優化, 也仍然被提示說不能evaluate 表示式, 或斷點設不上的問題, 這是另一種優化. JIT, 關閉它可以通過以下一個不廣為人知的辦法:
若模句是 test.exe
在它同一目錄下, 產生一個test.ini的檔案. 內容固定如下:
[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0
這會禁用JIT優化, 條件是, 下次啟動程式時才會生效.
7. bash指令碼(cygwin下測試通過) 得到GUID
# $1: exe/dll/pdb file
# $2: the target string
# $#: the offset of guid to $2
function get_guid()
{
exe_fname="$1"
guid_mark_string=$2
guid_offset=$3
regex="$(echo -n $guid_mark_string | od -t x1 | sed 's/[^ /t]* /?//;s/ ///n/g')"
byte_offset=$(od -v -t x1 $exe_fname | sed 's/[^ /t]* /?//;s/ //n/g; /^$/d' |
grep -b -P "$regex" | head -1 | sed 's/:.*//')
od -v -t x1 -j $((byte_offset/3+ guid_offset)) $exe_fname -N 16 |
head -1 | sed 's/[^ /t]* //'
}
function get_guid_from_module()
{
get_guid $1 "RSDS" 4
}
function get_guid_from_pdb()
{
get_guid $1 "/LinkInfo" -20
}
windbg 除錯工具包中有一個工具symchk.exe, 選項很多, 下面一個簡單的用法可以檢查一個 test.exe能不能找到與它匹配的PDB:
這是成功的情形. 下面來個失敗的作為對比:
2. 如果已經在windbg內部, 可以通過下面的命令檢查
最後一行說 MATCH, 肯定沒問題.
3. 在windbg中(在VS中不行), 如果你100%確信原始碼沒有任何改動, 只不過被重新編譯了一下.
可以通過 .symopt +40 來關閉對GUID的強行檢查. 從而load一個不匹配的PDB.
4. 除了1中提到的工具, 還有一個叫chkmatch 的工具, 在
http://www.debuginfo.com/download/chkmatch.zip
可以下載, 該工具不僅可以檢查是否匹配, 還可以把不匹配的強制改為匹配, 也就是說EXE/DLL和PDB中的GUID相同, 這樣在VS中就可以使用了, 當然, 高度危險, 後果自負.
5. 在VS中的空心圓
我同事把那種設定了斷點之後, 沒有設定成功, 出現的紅色圓圈叫做空心圓問題.
此類問題有兩個可能的原因:
(A) 的確PDB不匹配
(B) 時機還不到, 有些原始檔對應的module本身還沒有被load, 對應的PDB更不會被load了.
(C) 程式碼被優化掉了
對於(B)的情況, 在windbg中也同樣會出現斷點貌似設定不對的情況.
對於是(A)還是(B)的判斷, 在VS中, 可以開啟Module 視窗, 這個視窗對診斷此類問題很有幫助. 在Debug選單下, 有些VS2005 安裝之後, 在DEBUG選單下找不到這個選單項, 不要驚慌, 它只是沒出現在選單項而已, 通過tools-customize可以找回它.
這個Module視窗中, 清楚地列出當前被除錯的程序中, 有哪些module, 每個module的pdb 情況, 你還可以手工load一個module對應的symbol檔案, 可以檢視symbol檔案的細節.
在這個視窗中, 一個可能會令你迷惑的地方是: 對於mixed module, 它會被列出兩次, 一次為native, 一次為.NET
6 關於5中的(C)的情況, 程式碼被優化掉了, 有幾個應對辦法:
(I) 如果可以, 重新編譯, 關閉優化, 我個人的經驗和習慣是, 永遠不開啟優化, 除非: 有證據表明某處有效能問題, 或在為RISC CPU寫程式, 此類指令集的效能高度依賴於是否優化.
(II) 對於.NET 程式, 你儘早會碰到即使關閉了編譯優化, 也仍然被提示說不能evaluate 表示式, 或斷點設不上的問題, 這是另一種優化. JIT, 關閉它可以通過以下一個不廣為人知的辦法:
若模句是 test.exe
在它同一目錄下, 產生一個test.ini的檔案. 內容固定如下:
[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0
這會禁用JIT優化, 條件是, 下次啟動程式時才會生效.
7. bash指令碼(cygwin下測試通過) 得到GUID
# $1: exe/dll/pdb file
# $2: the target string
# $#: the offset of guid to $2
function get_guid()
{
exe_fname="$1"
guid_mark_string=$2
guid_offset=$3
regex="$(echo -n $guid_mark_string | od -t x1 | sed 's/[^ /t]* /?//;s/ ///n/g')"
byte_offset=$(od -v -t x1 $exe_fname | sed 's/[^ /t]* /?//;s/ //n/g; /^$/d' |
grep -b -P "$regex" | head -1 | sed 's/:.*//')
od -v -t x1 -j $((byte_offset/3+ guid_offset)) $exe_fname -N 16 |
head -1 | sed 's/[^ /t]* //'
}
function get_guid_from_module()
{
get_guid $1 "RSDS" 4
}
function get_guid_from_pdb()
{
get_guid $1 "/LinkInfo" -20
}