1. 程式人生 > >【總結】除錯暫存器 原理與使用:DR0-DR7

【總結】除錯暫存器 原理與使用:DR0-DR7

下面介紹的知識性資訊來自intel IA-32手冊(可以在intel的開發手冊或者官方網站查到),提示和補充來自學習偵錯程式實現時的總結。
希望能給你帶去有用的資訊。

(DRx對應任意的一個除錯暫存器。LENn對應任意一個長度。Ln對應任意一個區域性置位)

DR0-DR7可以直接被讀寫操作(MOV 指令之類的,DRx可以是源運算元也可以是目的運算元)

   但是,DRx的訪問是需要一定許可權的。比如你用MOV操作的話,你需要在實地址模式,系統管理模式(smm)或者在保護模式(CPL設0).如果許可權不夠,將會在訪問DRx的時候嘗產生#GP(general-protection)異常

現在來看看DRx可以幹些什麼? 


1.設定發生斷點的地址(線性地址)
2.設定斷點的長度(1,2,4個位元組,但是執行斷點只能是1)
3.設定在除錯異常產生的地址執行的操作
4.設定斷點是否可用
5.在除錯異常產生時,除錯條件是否是可用

(以上直接翻譯自"Intel 64 and IA-32 Architectures Software Developer’s Manual" volume 3。
以下來自個人的總結。當然,也是參考intel官方資料得來的)

我們來看看除錯暫存器的一些細節資訊。
下圖很重要,後面的介紹都是針對這個圖說的。

(當然不是我畫的,是來自intel  ia-32系統結構開發手冊18章2節)。


除錯暫存器 DR0-DR3
   這四個暫存器是用來設定 斷點地址的。斷點的比對在實體地址轉換前(異常產生時,還沒有將線性地址轉換成實體地址)。由於只有0-3四個儲存地址的暫存器,所以,硬體斷點,在物理上最多隻能有4個。


除錯暫存器DR4-DR5 
   這兩個除錯暫存器有CR4的DE標記控制。如果DE置位,那麼對這兩個暫存器的訪問會導致#UD異常。如果DE置0,那麼他們就被化名為DR6-DR7(你一定會問原來的DR6-DR7怎麼辦?這個…… 我也不知道。如果你搞明白了,一定記得告訴我)
除錯暫存器DR7(控制暫存器)
   (先介紹DR7對DR6的理解有好處。)

DR7是除錯控制暫存器。控制方式嘛!繼續看:
1.  L0-L3(由第0,2,4,6位控制):對應DR0-DR3,設定斷點作用範圍,如果被置位,那麼將只對當前任務有效。每次異常後,Lx都被清零。
2.  G0-G3(由第1,3,5,7位控制):對應DR0-DR3,如果置位,那麼所有的任務都有效。每次異常後不會被清零。以確保對所有任務有效。但是,不知道為什麼,我在測試時:

設定Gn後,不能返回除錯異常給偵錯程式(如果你知道為什麼,記得告訴我)
3.  LE,GE(由第8,9位控制):這個在P6以下系列CPU上不被支援,在升級版的系列裡面:如果被置位,那麼cpu將會追蹤精確的資料斷點。LE是區域性的,GE是全域性的。(到底什麼算精確的,我也不清楚,但是,我知道如果設定了這兩個,cpu的速度會降低。我在測試中,都沒有置位。)
4.  GD(由第13位控制):如果置位,追蹤下一條指令是否會訪問除錯暫存器。如果是,產生異常。在下面的DR6裡面,你會知道他還和另外一個標誌位有點關係。
5.  R/W0-R/W3:(由第16,17,20,21,24,25,28,29位控制):這個東西的處理有兩種情況。
如果CR4的DE被置位,那麼,他們按照下面的規則處理問題:
00:執行斷點
01:資料寫入斷點
10:I/0讀寫斷點
11:讀寫斷點,讀取指令不算
如果DE置0,那麼問題會這樣處理:
00:執行斷點
01:資料寫入斷點
10:未定義
11:資料讀寫斷點,讀取指令不算
6.  LEN0-LEN3:(由第18.19.22.23.26.27.30位控制):指定記憶體操作的大小。
00:1位元組(執行斷點只能是1位元組長)
01:2位元組
10:未定義或者是8位元組(和cpu的系列有關係)
11:4位元組
除錯暫存器DR6(除錯狀態暫存器)
   這個暫存器主要是在除錯異常產生後,報告產生除錯異常的相關資訊
1.  B0-B3(DR0-DR3):DRx指定的斷點在滿足DR7指定的條件下,產生異常。那麼Bx就置位。但是,有時,即使Ln和Gn置0,也可能產生Bx被置位。這種現象可能這樣出現(提示:在p6系列處理器,REP MOVS在不斷迴圈中產生的除錯異常需要執行完了才能準確返回給除錯程序):DR0的L0,G0都置0(DR0就是一個不能產生異常的斷點了),然後在DR0指定的地址是一個REP指令的迴圈,這樣,DR0就可能在這個迴圈之後的REP指令產生的除錯異常中將B0置位
2.  BD:BD需要DR7的GD置位,才有效。BD是在下一條指令要訪問到某一個除錯暫存器的時候,被置位的。
3.  BS:單步執行模式時,被置位。單步執行是最高許可權的除錯異常。
4.  BT:在任務切換的時候,被置位。但是必須在被切換去的任務的TSS段裡面的T標記被置位的情況下才有效。在控制權被切換過去後,在執行指令前,返回除錯異常。但是,需要注意,如果除錯程式是一個任務,那麼T標記的設定肯定就衝突了。然後,導致了死迴圈(BT的這些資訊都是按照官方資料翻譯而來,由於沒有實際的操作,肯定會有理解上的出入。如果要深入的話,建議看官方資料)

有些除錯異常會將B0-B3清零。但是其他的DR6的位是不能被產生異常的程序清零的。每次除錯異常返回後,除錯程序都會先將DR6清零,再按照情況設定。以免產生不必要的錯誤。

對齊問題和64位處理器
對齊問題:
這個問題是來源於LENn的設定,如果設定4位元組,那麼必須4位元組對齊。例如:我們下4位元組的斷點,那麼DRx需要是A0000/A0004/A0008這樣的地址上。I/O地址是零擴充套件的(這個……也許意味著必須完全對齊)。因為,intel在比對地址時:用LENn的值去覆蓋DRx裡面儲存的地址的低位。你可以想到,不對齊會有什麼後果了吧。注意:執行斷點只能是1位元組。

再用圖片解釋下(當然,圖片來自intel官方資料):
(此處省略一萬字)

最後需要提醒一個小問題:資料寫入斷點設定後。是在原資料被修改後,才產生除錯異常。所以,返回異常時,原有資料已經被修改。如果想保留原有資料,需要自己提前儲存對應地址的資料。

如果想看我的測試程式,在我發的 除錯引擎 那個帖子裡面的附近裡的DBG裡面。

如果覺得有問題或有疑問的,Just let me know!