1. 程式人生 > >關於PDB與EXE/DLL 檔案的匹配問題(轉)

關於PDB與EXE/DLL 檔案的匹配問題(轉)

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
}