因為是剛剛啟動程式(main函數還沒有機會執行),可以檢視源代碼了解要設定斷點的地方。設定斷點可以使用bp、bu和bm來做,其中bp可以根據函數名、指令位址以及源代碼檔案位址來設定斷點。
bp指令是在設定斷點過程用的比較多的一個指令,下面的表格示範了它的簡單用法:
指令格式
示例
說明
bp 函數名
bp Usage
在函數Usage的入口中斷程式的執行。
bp 指令位址
bp 010113c0
在執行位址在010113c0的指令前中斷程式的執行。
bp `源檔案位址`
bp `nativedebug.cpp:21`
在源代碼nativedebug.cpp的第21行設定斷點,請注意符号“`”(感歎号鍵左邊的反引号)。
#
# 沒有輸出結果,正所謂沒有消息就是好消息,如果斷點成功設定,
# windbg不會顯示任何資訊。
如果在設定斷點時,出現類似下面的消息:
bp UsageA
# 輸出結果
Bp expression 'UsageA' could not be resolved, adding deferred bp
那麼有兩個檢查步驟,第一是檢查符号檔案是否正确加載,第二步是檢查設定斷點的函數名是否真的存在于程式當中。
第一步,檢查符号檔案是否正确加載,可以使用lm指令檢視已加載子產品的詳細資訊,例如在上面的例子中,我們相信UsageA指令應該在子產品nativedebug.exe中,可以執行下面的指令來檢視nativedebug子產品的詳細資訊(請注意子產品名是緊跟在vm選項後面的,沒有空格,沒有字尾名,也沒有蛀牙):
lm vmnativedebug
start end module name
# 注意下面這一行裡面的private pdb symbols,說明我們已經加載了正确的符号檔案。
# 至于private的含義,會在以後的文章裡面講到。
01000000 0101b000 nativedebug C (private pdb symbols) D:\Debuggers\sym\nativedebug.pdb\E873A517513C4CC9BA5C805D1A709F206\nativedebug.pdb
Loaded symbol image file: nativedebug.exe
# Image path指明了子產品加載的路徑,在64位機器上調試程式的時候,
#這個資訊是蠻有用的 。因為你需要知道一些系統子產品是在system32還是
# SysWow64檔案夾裡加載的。
Image path: nativedebug.exe
Image name: nativedebug.exe
Timestamp: Sat Feb 20 20:05:20 2010 (4B7FD000)
CheckSum: 00000000
ImageSize: 0001B000
Translations: 0000.04b0 0000.04e4 0409.04b0 0409.04e4
順便說一下,因為nativedebug是我們自己編譯的,有一些版本方面的資訊在編譯的時候沒有加進去。如果你檢視一個Windows自帶的子產品的詳細資訊的話,你可能會看到類似下面的輸出:
lm vmntdll
775f0000 7772c000 ntdll (pdb symbols) D:\Debuggers\sym\ntdll.pdb\F0164DA71FAF4765B8F3DB4F2D7650EA2\ntdll.pdb
Loaded symbol image file: ntdll.dll
Image path: ntdll.dll
Image name: ntdll.dll
Timestamp: Tue Jul 14 09:09:47 2009 (4A5BDADB)
CheckSum: 0014033F
ImageSize: 0013C000
# 子產品的版本号,如果你的程式象微軟的産品那樣有多個版本,而且需要對多個
# 版本提供技術支援的話,下面的資訊對于找到正确版本的符号檔案非常非常非常
# 重要。
File version: 6.1.7600.16385
Product version: 6.1.7600.16385
File flags: 0 (Mask 3F)
# 子產品要求的子系統
File OS: 40004 NT Win32
File type: 2.0 Dll
File date: 00000000.00000000
Translations: 0409.04b0
CompanyName: Microsoft Corporation
ProductName: Microsoft® Windows® Operating System
InternalName: ntdll.dll
OriginalFilename: ntdll.dll
ProductVersion: 6.1.7600.16385
# 下面隻顯示了已釋出的産品的資訊,版本号已經在前面的注釋裡介紹過了。
# win7_rtm的意思是目前的子產品是從win7_rtm這個源代碼分支裡編譯出來的。
# 版本分支的概念在團隊軟體産品開發過程中是一個平常的做法,大部分版本
# 控制軟體都支援代碼分支的做法。這個過程解釋起來有點複雜,現在你需要
# 知道的是,如果你現在工作的公司沒有采取版本分支的做法,那麼祝賀你,
# 至少在尋找符号檔案的過程裡,你會比較輕松(不需要考慮分支的影響),
# 雖然會在後面釋出高品質的軟體産品你的團隊會死的比較難看。
# 如果你工作的公司正在采取版本分支的做法的話,那麼你一定要在正确的分支
# 下尋找對應版本的符号檔案,否則你會死的很難看。
# 另外,下面一行的輸出裡還有一個重要的資訊沒有顯示,那就是子產品是否為調試版
# ,還是釋出版。與軟體分支一樣,如果考慮進去,也是一樣無法加載到正确的
# 符号檔案的。
# 如果使用類似微軟的方法編譯軟體,會在後面的文章中講到。
FileVersion: 6.1.7600.16385 (win7_rtm.090713-1255)
FileDescription: NT Layer DLL
# 這個嘛,地球人都知道。
LegalCopyright: © Microsoft Corporation. All rights reserved.
既然知道符号檔案已經被正确加載,那麼下一步就是确認設定的函數名是否存在于子產品中,可以使用x指令來檢查符号檔案儲存的名字資訊—就是函數名呀,全局變量名之類的資訊。如果直接調用x指令,windbg會顯示子產品裡面所有的名字。一般都是使用x加上一個比對模式來查找指定的名字在子產品中是否已定義。比如,為了檢查UsageA這個名字在nativedebug.exe子產品中是否已定義,可以執行下面的指令來檢視(感歎号前面是告訴x指令要在哪一個子產品中查找名字,感歎号後面就是要查找的名字):
x nativedebug!UsageA
# 輸出結果—沒有輸出結果
如果x沒有找到指定的名字,就不會輸出任何資訊,否則,會有類似下面的輸出:
x nativedebug!Usage
# 輸出結果,前面的位址是函數入口在記憶體中的位址,而後面則顯示了函數的聲明資訊。
010113c0 nativedebug!Usage (void)
X指令允許你在查找過程中使用通配符進行比對,例如,在我們的示例程式中,被用來執行轉換的“函數”_ttol不是一個真實的函數,而是一個宏。下面是這個宏的定義:
#ifdef _UNICODE
# define _ttol _wtol
#else
# define _ttol atol
#endif
而宏是在編譯期間就被編譯器擴充,并不會被加到符号檔案中去,是以如果你試圖使用bp指令在_ttol入口設定斷點的話,是會失敗的。是以你可以使用類似下面的通配符來查找正确的函數名:
x MSVCR90D!*tol*
# 輸出結果(注意黃色高亮的名字)
65cd1bb0 MSVCR90D!__STRINGTOLD (struct _LDOUBLE *, char **, char *, int)
65d47c80 MSVCR90D!_ld12told (struct _LDBL12 *, struct _LDOUBLE *)
65cd1900 MSVCR90D!_atoldbl (struct _LDOUBLE *, char *)
65cd6790 MSVCR90D!_wcstol_l (wchar_t *, wchar_t **, int, struct localeinfo_struct *)
65cd4400 MSVCR90D!strtol (char *, char **, int)
65d4bac0 MSVCR90D!__mtold12 (char *, unsigned int, struct _LDBL12 *)
65cd5030 MSVCR90D!_tolower_l (int, struct localeinfo_struct *)
65cd6300 MSVCR90D!wcstol (wchar_t *, wchar_t **, int)
65ca0d50 MSVCR90D!atol (char *)
65cd4940 MSVCR90D!_strtol_l (char *, char **, int, struct localeinfo_struct *)
65ca12d0 MSVCR90D!_wtol (wchar_t *)
65d4a980 MSVCR90D!__wstrgtold12_l (struct _LDBL12 *, wchar_t **, wchar_t *, int, int, int, int, struct localeinfo_struct *)
65d544e0 MSVCR90D!_ftol (void)
65cd5010 MSVCR90D!_tolower (int)
65cd5210 MSVCR90D!tolower (int)
65ca12f0 MSVCR90D!_wtol_l (wchar_t *, struct localeinfo_struct *)
65d48fd0 MSVCR90D!__dtold (struct _LDOUBLE *, double *)
65ce3c30 MSVCR90D!_mbctolower_l (unsigned int, struct localeinfo_struct *)
65d48dc0 MSVCR90D!__STRINGTOLD_L (struct _LDOUBLE *, char **, char *, int, struct localeinfo_struct *)
65cd17f0 MSVCR90D!_atoldbl_l (struct _LDOUBLE *, char *, struct localeinfo_struct *)
65ce3d80 MSVCR90D!_mbctolower (unsigned int)
65ca0d70 MSVCR90D!_atol_l (char *, struct localeinfo_struct *)
65d38670 MSVCR90D!__lc_strtolc (struct tagLC_STRINGS *, char *)
65cdd8e0 MSVCR90D!CPtoLCID (int)
65d47d40 MSVCR90D!__strgtold12_l (struct _LDBL12 *, char **, char *, int, int, int, int, struct localeinfo_struct *)
65c6109c MSVCR90D!_imp__FileTimeToLocalFileTime = <no type information>
在上面的輸出,可以看到atol和_wtol在msvcr90d.dll這個子產品中都定義了,而我們現在不是很确定當時程式編譯的時候,_UNICODE這個宏是否被定義了。是以我們即可以采用一個笨方法,就是使用bp指令在atol和_wtol兩個函數入口上都設定斷點,運作看看到底程式會中斷在哪一個函數上。
或者,可以使用bm指令,bm指令相當于bp指令的擴充,允許使用者使用一個通配符設定斷點。例如:
bm *tol*
# 輸出結果 – Windbg會在所有比對的函數入口上設定斷點。
# 很多,的确很多,是以請慎用bm指令。
4: 65cd1bb0 @!"MSVCR90D!__STRINGTOLD"
5: 65d47c80 @!"MSVCR90D!_ld12told"
6: 65cd1900 @!"MSVCR90D!_atoldbl"
7: 65cd6790 @!"MSVCR90D!_wcstol_l"
8: 65cd4400 @!"MSVCR90D!strtol"
9: 65d4bac0 @!"MSVCR90D!__mtold12"
10: 65cd5030 @!"MSVCR90D!_tolower_l"
11: 65cd6300 @!"MSVCR90D!wcstol"
12: 65ca0d50 @!"MSVCR90D!atol"
13: 65cd4940 @!"MSVCR90D!_strtol_l"
14: 65ca12d0 @!"MSVCR90D!_wtol"
15: 65d4a980 @!"MSVCR90D!__wstrgtold12_l"
16: 65d544e0 @!"MSVCR90D!_ftol"
17: 65cd5010 @!"MSVCR90D!_tolower"
18: 65cd5210 @!"MSVCR90D!tolower"
19: 65ca12f0 @!"MSVCR90D!_wtol_l"
20: 65d48fd0 @!"MSVCR90D!__dtold"
21: 65ce3c30 @!"MSVCR90D!_mbctolower_l"
22: 65d48dc0 @!"MSVCR90D!__STRINGTOLD_L"
23: 65cd17f0 @!"MSVCR90D!_atoldbl_l"
24: 65ce3d80 @!"MSVCR90D!_mbctolower"
25: 65ca0d70 @!"MSVCR90D!_atol_l"
26: 65d38670 @!"MSVCR90D!__lc_strtolc"
27: 65cdd8e0 @!"MSVCR90D!CPtoLCID"
28: 65d47d40 @!"MSVCR90D!__strgtold12_l"
設定好斷點後,可以使用bl指令(breakpoint list)來檢視已經設定好的斷點:
bl
# 第一列是斷點的編号;
# 第二列,e表示(enabled),u表示(unresolved),是以如果那一列的值為e,則說明
# 斷點是啟用狀态,如果為d表示(disabled),則表示禁用狀态。如果有u,則基本上
# 說明這個斷點是沒有設定成功的,雖然windbg會在後續加載每一個子產品的時候,都嘗試
# 根據那個名字設定斷點;
# 後面幾列,放在後面的文章講。
0 e 010113c0 0001 (0001) 0:**** nativedebug!Usage
1 eu 0001 (0001) (UsageA)
# 這個斷點沒有設定正确
2 eu 0001 (0001) (`22`)
4 e 65cd1bb0 0001 (0001) 0:**** MSVCR90D!__STRINGTOLD
5 e 65d47c80 0001 (0001) 0:**** MSVCR90D!_ld12told
6 e 65cd1900 0001 (0001) 0:**** MSVCR90D!_atoldbl
7 e 65cd6790 0001 (0001) 0:**** MSVCR90D!_wcstol_l
8 e 65cd4400 0001 (0001) 0:**** MSVCR90D!strtol
9 e 65d4bac0 0001 (0001) 0:**** MSVCR90D!__mtold12
10 e 65cd5030 0001 (0001) 0:**** MSVCR90D!_tolower_l
11 e 65cd6300 0001 (0001) 0:**** MSVCR90D!wcstol
12 e 65ca0d50 0001 (0001) 0:**** MSVCR90D!atol
13 e 65cd4940 0001 (0001) 0:**** MSVCR90D!_strtol_l
14 e 65ca12d0 0001 (0001) 0:**** MSVCR90D!_wtol
15 e 65d4a980 0001 (0001) 0:**** MSVCR90D!__wstrgtold12_l
16 e 65d544e0 0001 (0001) 0:**** MSVCR90D!_ftol
17 e 65cd5010 0001 (0001) 0:**** MSVCR90D!_tolower
18 e 65cd5210 0001 (0001) 0:**** MSVCR90D!tolower
19 e 65ca12f0 0001 (0001) 0:**** MSVCR90D!_wtol_l
20 e 65d48fd0 0001 (0001) 0:**** MSVCR90D!__dtold
21 e 65ce3c30 0001 (0001) 0:**** MSVCR90D!_mbctolower_l
22 e 65d48dc0 0001 (0001) 0:**** MSVCR90D!__STRINGTOLD_L
23 e 65cd17f0 0001 (0001) 0:**** MSVCR90D!_atoldbl_l
24 e 65ce3d80 0001 (0001) 0:**** MSVCR90D!_mbctolower
25 e 65ca0d70 0001 (0001) 0:**** MSVCR90D!_atol_l
26 e 65d38670 0001 (0001) 0:**** MSVCR90D!__lc_strtolc
27 e 65cdd8e0 0001 (0001) 0:**** MSVCR90D!CPtoLCID
28 e 65d47d40 0001 (0001) 0:**** MSVCR90D!__strgtold12_l
在上面的輸出中,可以看到斷點1和2是無效的斷點,是以可以使用bc(breakpoint clear)這個指令删除掉這兩個斷點:
bc 1
# 沒有輸出結果—沒有消息就是好消息
bc 2
是以在前面的bm指令中,設定了太多的斷點,為了避免在不必要的函數上中斷,我們既可以使用bc指令将它們删掉,也可以使用bd(breakpoint disabled)指令将其禁用。因為指令實在太多,是以我們可以使用一個小技巧—使用一個範圍來禁用一批斷點:
bd 4-10
# 沒有輸出結果—沒有消息就是好消息,
# 這個指令将從斷點4到斷點10的所有斷點都禁用了。
bd和bc指令的文法是一樣的,既可以根據指定的範圍禁用或删除一批斷點,也可以根據指定的通配符來操作一批斷點,還可以使用一種稀奇古怪的文法來操作斷點(這個稀奇古怪的文法會在後面的文章中講到)。
本文轉自 donjuan 部落格園部落格,原文連結:http://www.cnblogs.com/killmyday/archive/2010/02/28/1675135.html ,如需轉載請自行聯系原作者