Visual Studio調試之斷點進階篇
文章導航
在上一篇文章Visual Studio調試之斷點基礎篇里面介紹了什么是斷點,INT 是Intel系列CPU的一個指令,可以讓程序產生一個中斷或者異常。程序中如果有中斷或者異常發生了以后,CPU會中斷程序的執行,去一個叫做IDT的部件查找處理這個中斷(或者異常)的例程(Handler)。IDT是操作系統在啟動的時候初始化的,至于IDT的細節問題,例如什么是IDT,怎樣編寫一個IDT的例程,怎樣 初始化IDT,可以去網上搜索一些資料。
總之,這里我們只要知道,CPU在執行程序指令過程中,碰到INT 3中斷程序的執行,CPU然后去IDT表里面找到處理斷點的例程入口。這個例程要做的事情就是:
1. 先看看機器里面是不是安裝了一個調試器—記住,這一步很重要,之所以重要以后的文章里面會介紹。
2. 如果機器里面沒有安裝調試器,那么操作系統就會終止程序的執行。
3. 否則操作系統啟動調試器,并將調試器附到進程上。
4. 這樣,我們才能在調試器里面檢查程序內部變量的值。
前面文章里面的INT 3 (或者DebugBreak(),或者Debugger.Break())指令是我們自己在代碼里面硬編碼進去的,因此我們在Visual Studio里,在相應的代碼行里面點一下,出現一個小紅球,也就是說Visual Studio在程序指令集某個地方動態地添加了一個INT 3指令。現在的問題來了,Visual Studio是如何在程序中正確找到插入INT 3指令的位置的?
或者更具體一些,我們在源代碼(文本文件)里面設置斷點的,Visual Studio需要把代碼行翻譯成在程序指令集中的位置。Visual Studio之所以需要做翻譯,是因為通常一行C++或者 C#代碼都會對應好幾行匯編指令。
因此,Visual Studio需要一個額外的文件來執行這個翻譯過程,這個額外的文件叫做調試符號文件(Symbols),是由編譯器生成的。Visual Studio系列的編譯器,不論是C#、VB.NET還是C++編譯器都會生成這個調試符號文件,.pdb 文件。所以如果你花一點時間看看Debug文件夾的話,你就會發現這個文件。
因此我們來看看Visual Studio支持的各種斷點,并解釋各種斷點的實現方式
條件斷點
首先我們先看看如何設置條件斷點,條件斷點有兩種,一種是根據觸發的次數來設置,另外一種是根據一條預置的條件來設置。
根據觸發次數設置
比如說,你有一個循環,循環1000次,你知道有一個BUG總是在500次之后才會出現,因此肯定希望在循環內設置一個斷點,但是前面500次都不會觸發這個斷點,否則連續按500次的F5的確不是一件輕松的差事。
根據預置條件來設置
如果你已經知道一些條件可能會引發Bug,那么根據條件來設置則最合適不過了。如下圖所示:
在“斷點條件(Breakpoint Condition)”對話框里面,只需要輸入一條正常的C#、C++或者VB.NET的語句就可以了(當然,語法是根據你項目里面的源代碼語法一致),這條語句的要求是必須返回bool值—否則就不是一個條件了。
第三個還有斷點過濾器,當你在斷點上,右鍵點擊彈出的菜單里面,會有一個“過濾(Filter)”菜單,它允許你限制將斷點僅設置在特定的線程上。這里我就不細講了,有興趣的話,可以自己寫一個多線程或者多進程程序試試這個功能。
知道斷點的原理以后,理解條件斷點應該就不會是問題了。
監視斷點(Watching Point)
有的時候,你可能需要查看程序內部一些變量的值,但是你又不希望中斷程序的執行。例如你在調試一個網絡協議棧,一個程序可能在接收數據包,你想看看數據包的格式,但如果中斷程序的執行,會導致后續的數據包丟失。
因此,我們一般的做法就是在源代碼里面加一些日志記錄代碼,這樣可以將一些變量的值記錄下來,以便后續分析。如果日志在產品發布以后還需要的話,在源代碼里面加入這些日志代碼固然是一個好主意,但是如果你只是想臨時看看一些變量的值呢?
這個時候,監視斷點就很有用了,Visual Studio的監視斷點就可以讓你做到在不修改程序源代碼的前提下,在調試器窗口中打印一些變量的值。
下圖演示了監視斷點的用法:
設置監視斷點的步驟,或者說是注意事項吧:
1. 設置一個普通的斷點
2. 右鍵單擊剛剛設置的斷點,在彈出菜單里面選擇“When Hit…”
3. 鉤選 第一個“打印一條消息(Print a message)”復選框,輸入一串文本,默認情況下,你輸入的文本會被直接打印到調試的輸出窗口里面來。除了:
a. 以$符號開頭的幾個關鍵字。比如$FUNCTION就會被替換成斷點所在的函數名。其他有一些關鍵字在“When Breakpoints Is Hit”窗口當中有詳細的說明。
b. 使用 大括號 {}包含起來的變量名,這樣的字符串會被替換成變量的值。
這下面就是監視斷點的效果,注意,你只能在Visual Studio的“輸出(Output)”窗口中查看結果。
監視斷點相對于日志記錄的好處是,你不需要改動源代碼,并且重新編譯代碼。實際上Visual Studio實現監視斷點的原理也很簡單,就是插入一個普通的斷點,斷點觸發之后處理并且打印在“When Breakpoints Is Hit”窗口輸出的表達式,最后自動恢復程序的執行。