地址和地址範圍語法
有數種方式可以在調試程式中指定位址。
位址通常是 虛擬位址,但文件特別指出另一種位址時除外。 在使用者模式中,調試程式會根據目前進程的頁面目錄來解譯虛擬位址。 在核心模式中,調試程式會根據進程內容所指定的進程頁面目錄來解譯虛擬位址。 您也可以直接設定 使用者模式地址內容。 如需使用者模式位址內容的詳細資訊,請參閱 .context(設定使用者模式位址內容)。
在MASM運算式中,您可以使用 poi 運算符來取值任何指標。 例如,如果位址的指標0x0000008e『ed57b108 指向位址位置0x805287637256,則下列兩個命令相等。
0:000> dd 805287637256
0:000> dd poi(000000bb`7ee23108)
顯示記憶體位址範例
若要查看使用 poi 的範例,請判斷線程環境區塊的 CurrentLocale 位移 (TEB)。 使用 dx 命令來顯示 @$teb,這是虛擬緩存器範例,其中包含常見的位址,例如目前的程式計數器位置。
0:000> dx @$teb
@$teb : 0x1483181000 [Type: _TEB *]
...
[+0x108] CurrentLocale : 0x409 [Type: unsigned long]
CurrentLocale 是從 TEB 開始的 +0x108。 接下來,判斷該位置的記憶體位址。
0:000> ? @$teb + 0x108
Evaluate expression: 613867303176 = 0000008e`ed57b108
使用 poi 來取值該位址,以查看其包含 0x409 的 CurrentLocale 值。
0:000> ? poi(0000008e`ed57b108)
Evaluate expression: 1033 = 00000000`00000409
在C++調試程序表達式中,指標的行為就像C++中的指標。 不過,數位會解譯為整數。 如果您必須順從實際數位,您可能需要先轉換它,如下列範例所示。
若要嘗試這樣做,請使用 .expr 將運算式評估工具設定為 C++。
0:000> .expr /s C++
Current expression evaluator: C++ - C++ source expressions
當表達式評估工具設定為 C++時,我們可以使用 long 來轉換。
0:000> d *((long*)0x00000014`83181108 )
00000000`00000409 ???????? ???????? ???????? ????????
如需轉換數值的詳細資訊,請參閱 C++數位和運算符。
如果表達式評估工具設定為 c++,我們可以將 poi 指標包裝為 @@masm(),讓 MASM 運算式評估工具所評估的運算式只有該部分。
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
0:000> ? @@masm(poi(00000078`267d7108))
Evaluate expression: 1033 = 00000000`00000409
如需兩個表達式評估工具的詳細資訊,請參閱 評估表達式。
您也可以指定原始來源檔名和行號,以指出應用程式中的位址。 如需如何指定這項資訊的詳細資訊,請參閱 源行語法。
位址範圍
您可以透過一對位址或位址和物件計數來指定位址範圍。
若要依一組位址指定範圍,請指定起始地址和結束位址。 例如,下列範例的範圍是8個字節,從位址0x00001000開始。
0x00001000 0x00001007
若要依位址和物件計數指定位址範圍,請指定位址自變數、字母 L(大寫或小寫),以及值自變數。 位址會指定起始位址。 值會指定要檢查或顯示的物件數目。 物件的大小取決於 命令。 例如,如果物件大小為1位元組,則下列範例的範圍為8個字節,從位址0x00001000開始。
0x00001000 L8
不過,如果物件大小是雙字(32 位或 4 個字節),則下列兩個範圍各提供 8 位元組的範圍。
0x00001000 0x00001007
0x00001000 L2
L 大小範圍規範
還有兩種方式可以指定值( LSize 範圍規範):
L?大小 (含問號) 表示與 L 大小相同,但 L 除外? 大小會移除調試程式的自動範圍限制。 一般而言,範圍限製為 256 MB,因為較大的範圍是印刷錯誤。 如果您要指定大於 256 MB 的範圍,則必須使用 L? 大小 語法。
L- 大小 (含連字元) 指定長度 大小 範圍,以指定位址結尾。 例如, 80000000 L20 指定從0x80000000到0x8000001F的範圍,而 80000000 L-20 會指定從0x7FFFFFE0到0x7FFFFFFF的範圍。
某些要求位址範圍的命令接受單一位址做為自變數。 在此情況下,命令會使用一些默認物件計數來計算範圍的大小。 位址範圍是最後一個參數的命令通常允許此語法。 如需每個命令的確切語法和預設範圍大小,請參閱每個命令的參考主題。
搜尋記憶體範圍範例
首先,我們將使用MASM表達式評估工具來判斷撕裂指令指標緩存器的位址。
0:000> ? @rip
Evaluate expression: 140720561719153 = 00007ffc`0f180771
然後,我們將使用 s (Search Memory) 命令,從 00007ffc'0f180771 開始搜尋 100000。 我們會指定要使用 L100000 搜尋的範圍。
0:000> s -a 00007ffc`0f180771 L100000 "ntdll"
00007ffc`0f1d48fa 6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00 ntdll\ldrinit.c.
00007ffc`0f1d49c2 6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00 ntdll\ldrmap.c..
00007ffc`0f1d4ab2 6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63 ntdll\ldrredirec
00007ffc`0f1d4ad2 6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00 ntdll\ldrsnap.c.
...
我們也可以使用兩個記憶體位址來指定與這個相同的範圍。
0:000> s -a 0x00007ffc`0f180771 0x00007ffc`0f280771 "ntdll"
00007ffc`0f1d48fa 6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00 ntdll\ldrinit.c.
00007ffc`0f1d49c2 6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00 ntdll\ldrmap.c..
00007ffc`0f1d4ab2 6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63 ntdll\ldrredirec
00007ffc`0f1d4ad2 6e 74 64 6c 6c 5c 6c 64-72 73 6e 61 70 2e 63 00 ntdll\ldrsnap.c.
...
最後,我們可以使用 L 長度參數來向後搜尋記憶體範圍。
0:000> s -a 00007ffc`0f1d4ad2 L-100000 "ntdll"
00007ffc`0f1d48fa 6e 74 64 6c 6c 5c 6c 64-72 69 6e 69 74 2e 63 00 ntdll\ldrinit.c.
00007ffc`0f1d49c2 6e 74 64 6c 6c 5c 6c 64-72 6d 61 70 2e 63 00 00 ntdll\ldrmap.c..
00007ffc`0f1d4ab2 6e 74 64 6c 6c 5c 6c 64-72 72 65 64 69 72 65 63 ntdll\ldrredirec
Unassemble 記憶體範例
這個範例會使用 u (unassemble) 命令和 L 參數來解除組譯三個字節的程式碼。
0:000> u 00007ffc`0f1d48fa L3
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e outs dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464 je ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c ins byte ptr [rdi],dx
或指定三個字節範圍的記憶體,以取消組譯,如下所示。
0:000> u 00007ffc`0f1d48fa 00007ffc`0f1d48fd
ntdll!`string'+0xa:
00007ffc`0f1d48fa 6e outs dx,byte ptr [rsi]
00007ffc`0f1d48fb 7464 je ntdll!`string'+0x21 (00007ffc`0f1d4961)
00007ffc`0f1d48fd 6c ins byte ptr [rdi],dx
位址模式和區段支援
在 x86 型平臺上,CDB 和 KD 支援下列尋址模式。 這些模式會以其前置詞來區分。
Prefix | 名稱 | 位址類型 |
---|---|---|
% | flat | 32 位位址(也指向 32 位區段的 16 位選取器)和 64 位系統上的 64 位位址。 |
& | virtual 86 | 實際模式位址。 僅限 x86 型。 |
# | plain | 實際模式位址。 僅限 x86 型。 |
純文本和虛擬 86 模式之間的差異在於,一般 16 位位址會使用區段值做為選取器,並查閱區段描述元。 但虛擬 86 位址不會使用選取器,而是直接對應到較低的 1 MB。
如果您透過不是目前預設模式的尋址模式存取記憶體,您可以使用位址模式前置詞來覆寫目前的位址模式。
位址自變數
位址自變數會指定變數和函式的位置。 下表說明您可以在CDB和 KD 中使用的各種位址文法和意義。
語法 | 意義 |
---|---|
offset |
虛擬記憶體空間中的絕對位址,其類型會對應至目前的執行模式。 例如,如果目前的執行模式是16位,則位移為16位。 如果執行模式為32位區段,則位移為32位區段。 |
&[[ segment:]] offset |
實際位址。 x86 型和 x64 型。 |
%segment:[[ offset]] |
分段 32 位或 64 位位址。 x86 型和 x64 型。 |
%[[ offset]] |
虛擬記憶體空間中的絕對位址(32 位或64位)。 x86 型和 x64 型。 |
name[[ +|\ ]] offset |
一般32位或64位位址。 name 可以是任何符號。 offset 指定位移。 此位移可以是其前置詞所指出的任何位址模式。 沒有前置詞會指定預設模式位址。 您可以將位移指定為正值 (+) 或負值。 |
使用 dg (顯示選取器) 命令來檢視區段描述元資訊。
另請參閱
若要顯示記憶體的相關信息,請使用 !address 命令。
若要搜尋記憶體,請使用 s (Search Memory) 命令。
若要顯示記憶體的內容,請使用 d、da、db、dc、dd、dD、df、dp、dq、du、dw (Display Memory) 命令。
如需如何使用記憶體視窗檢視和編輯記憶體的資訊,請參閱 使用記憶體視窗。