使用windbg觀察IA-32處理器啓用PAE後內存分頁映射關係

目的前端

    調試代碼的過程當中,在一些複雜狀況下須要查看內存數據的實際物理地址。32位windows xp sp2系統在intel處理器下默認啓用了PAE,這裏就探討一下在啓用PAE後查看實際物理地址的方法。express

原理windows

    PAE是 Physical Address Extension的縮寫,即物理地址擴展。簡單來講,就是把IA-32處理器的尋址能力從原來的4GB擴展到64GB。尋址4GB空間,要求物理地址的寬度爲32位。相似的,要尋址64GB空間,那麼物理地址的寬度就是36位。由於這個緣由,PAE又被稱爲PAE-36bit。服務器

    若是從CPU的引腳來說,那麼支持PAE的CPU原則上應該有36根地址線,但由於IA-32 CPU的前端總線是64位寬,每次可同時傳遞8個字節數據,因此CPU在訪問內存時,它老是向前端總線給出一個低3位爲0的地址,所以實際上省略了低三位地址線。這實際上也起到了將地址按8字節對齊的功效。以奔騰4 CPU爲例,它的地址線是A[35:3]#。lua

    當IA-32 CPU工做在32位模式時,軟件中使用的是32位寬的虛擬地址和線性地址,所以便產生了一個問題,如何將32位寬的線性地址翻譯爲36位寬的物理地址,尋址能力從原來的4GB擴展到64GB呢?答案是將原來的二級映射擴展爲三級映射,也就是在原來的頁目錄和頁表基礎上再增長一級,稱爲頁目錄指針表。根據單個內存頁的大小不一樣(4KB或者2MB)又分爲兩種狀況。spa

  下圖中畫出的是4KB內存頁的狀況。其中的PDPTR是Page Directory Pointer Table Register的縮寫,它是啓用PAE後CR3寄存器的別名,該寄存器中保存了頁目錄指針表所在地址。此時,32位線性地址被分割爲以下三個部分:

    * 2位(位30和位31)的頁目錄指針表索引,用來索引本地址在頁目錄指針表中的對應表項。
    * 9位(位21-29)的頁目錄表索引,用來索引本地址在頁目錄表中的對應表項。
    * 9位(位12-20)的頁表索引,用來索引本地址在頁表中的對應表項。
    * 12位(位0-11)的頁內偏移,這與之前是相同的。
翻譯

http://advdbg.org/img/inset/pae_tran_4kb.bmp
圖1 啓用PAE時將線性地址翻譯爲物理地址(4KB內存頁)(摘自IA-32手冊卷3A)
3d

    和沒有啓用PAE的4KB狀況相比,表的數量由兩張變成了三張,增長了頁目錄指針表。指針

    由於表中的地址都是物理地址,因此三張表的每一個表項都有原來的32位變爲64位,具體格式以下圖所示。
http://advdbg.org/img/inset/pae_entries.bmp
圖2 啓用PAE時的地址轉換表項格式(4KB內存頁)(摘自IA-32手冊卷3A)

    也就是說,每一個64位的表項中有24位是用來表明基地址的,這24位對應的是物理地址的高24位,低12位爲0。這意味着,頁目錄表、頁表和每一個頁的基地址都是按4KB對齊的。
調試

    2MB內存頁的情形。與未啓用PAE的狀況同樣,再也不須要頁表。以下圖所示。
http://advdbg.org/img/inset/pae_tran_2mb.bmp
圖3 啓用PAE時將線性地址翻譯爲物理地址(2MB內存頁)(摘自IA-32手冊卷3A)

調試觀察

    有了上面所說的原理,咱們須要觀察驗證一下。這裏使用windbg在Windows XP SP2系統下,利用Windows自帶的計算器程序(calc.exe)進行調試。步驟以下。

1.啓動計算器程序(calc.exe),鍵入一串數字(如123456789)以便後面觀察。

2.啓動Windbg,並附加到計算器程序上開始調試。

3.加載符號表文件,Windows的符號服務器地址爲http://msdl.microsoft.com/download/symbols,所以選中File=>Symbol File Path菜單項,加入符號路徑SRV*d:\symbols*http://msdl.microsoft.com/download/symbols,而後勾選reload框,加載調試計算器程序所需符號表。

4.在Windbg命令區輸入x calc!g*命令列出以g開頭全部符號。注意其中包含的gpszNum行。

5.在Windbg命令區輸入dd calc!gpszNum l1命令,查看該符號地址內容。我這裏該變量地址爲000b4650。

6.繼續查看地址000b4650處的內容:db 000b4650

0:002> db 000b4650
000b4650 31 00 32 00 33 00 34 00-35 00 36 00 37 00 38 00 1.2.3.4.5.6.7.8.
000b4660 39 00 2e 00 00 00 00 00-00 00 65 00 72 00 00 00 9.........e.r...

能夠看到該內存處的具體內容。下面咱們看一看如何把這個字符串地址(000b4650)翻譯爲物理地址。

1.再啓動一個Windbg實例,選中File=>Kernel Debug菜單中的local頁籤,點擊肯定進入本地內核調試模式,而後如前所述方式加載符號表。

2.列出calc進程的概況:!process 0 0 calc.exe

lkd> !process 0 0 calc.exe
PROCESS 8679f180 SessionId: 0 Cid: 1d6c Peb: 7ffd5000 ParentCid: 01fc
DirBase: 0a4c27e0 ObjectTable: e14594b0 HandleCount: 77.
Image: calc.exe

上面的DirBase即是CR3寄存器的值,即PDPTR的內容,其格式以下,能夠看出低5位爲0,頁目錄指針表起始地址是32Byte對齊的。
http://advdbg.org/img/inset/pae_pdptr.bmp

3.將要轉換的線性地址000b4650 顯示爲二進制:

lkd> .formats 000b4650
Evaluate expression:
Hex: 000b4650
Decimal: 738896
Octal: 00002643120
Binary: 00000000 00001011 01000110 01010000
Chars: ..FP
Time: Fri Jan 09 21:14:56 1970
Float: low 1.03541e-039 high 0
Double: 3.65063e-318

    根據圖1,分解爲以下4個部分:

    * 最高兩位爲0,是頁目錄指針表的索引。
    * 接下來的9位(000000 000)爲頁目錄索引,即0。
    * 再接下來的9位(01011 0100)爲頁目錄索引,即0xb4。lkd> ? 0y010110100 Evaluate expression: 180 = 000000b4
    * 最後的12位(0110 01010000)是頁內偏移,即0x650。

4.由於CR3值(0a4c27e0) 的低5位都是0,因此能夠知道計算器進程的頁目錄指針表的基地址就是0x0a4c27e0。觀察這一地址附近的內容:

lkd> !dd 0a4c27e0
# a4c27e0 22e14801 00000000 74295801 00000000
# a4c27f0 7d156801 00000000 27053801 00000000
# a4c2800 1e975801 00000000 78e36801 00000000
# a4c2810 282f7801 00000000 394f4801 00000000
# a4c2820 1b78a801 00000000 6bd8b801 00000000

每一個頁目錄指針表共有4個表項,每一個表項是8字節(64位),所以,能夠知道上面的前兩行內容是計算器進程的頁目錄指針表。

5.根據上面的分解,1b1c0aa0對應的是0號表項,即00000000`22e14801。根據圖2,位12到位35是頁目錄表基地址的高24位,所以,能夠知道對應的頁目錄表基地址是0x22e14000,觀察它的0號表項:

lkd> !dq 0x22e14000
#22e14000 00000000'3445a867 00000000'42130867
#22e14010 00000000'77246867 00000000'345c9867
#22e14020 00000000'392e1867 00000000'4830a867
#22e14030 00000000'310d4867 00000000'1c16c867
#22e14040 00000000'7a459867 00000000'00000000

可見,咱們要翻譯的線性地址對應的頁目錄表項是00000000`3445a867,其中位12到位35是頁表基地址的高24位,所以能夠知道咱們要尋找的頁表基地址是3445a000,觀察它的0xb4號表項:

lkd> !dq 0x3445a000+0xb4*8
#3445a5a0 80000000'45505867 80000000'55986867
#3445a5b0 80000000'29e47867 80000000'75008867
#3445a5c0 00000000'00000080 00000000'00000000

這樣便獲得頁表表項:80000000`45505867, 它的位12到位35是內存頁基地址的高24位,即線性地址000b4650所對應的內存頁基地址是45505000,加上頁內偏移0x650便獲得最終的物理地址,即0x45505650,顯示其內容:

lkd> !db 45505650
#45505650 31 00 32 00 33 00 34 00-35 00 36 00 37 00 38 00 1.2.3.4.5.6.7.8.
#45505660 39 00 2e 00 00 00 00 00-00 00 65 00 72 00 00 00 9.........e.r...

可見,其內容與前面使用用戶態調試器觀察的線性地址內容是一致的。

相關文章
相關標籤/搜索