アドレスとアドレス範囲の構文
デバッガーでアドレスを指定するには、いくつかの方法があります。
ドキュメントで別の種類のアドレスが特に示されている場合を除き、アドレスは通常、仮想アドレスです。 ユーザー モードでは、デバッガーは現在のプロセスのページ ディレクトリに従って仮想アドレスを解釈します。 カーネル モードでは、デバッガーはプロセス コンテキストで指定されたプロセスのページ ディレクトリに従って仮想アドレスを解釈します。 ユーザー モード アドレス コンテキストを直接設定することもできます。 ユーザー モード アドレス コンテキストの詳細については、「.context (ユーザー モード アドレス コンテキストの設定)」を参照してください。
MASM 式では、poi 演算子を使用して任意のポインターを逆参照できます。 たとえば、アドレス 0x0000008e`ed57b108 のポインターがアドレス位置 0x805287637256 を指している場合、次の 2 つのコマンドは同等です。
0:000> dd 805287637256
0:000> dd poi(000000bb`7ee23108)
メモリ アドレスの表示例
poi の使用例を見るために、スレッド環境ブロック (TEB) の CurrentLocale のオフセットを特定しましょう。 dx コマンドを使用して、現在のプログラム カウンターの場所などの共通アドレスを保持する pseudo-registers の例である @$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 を使用してそのアドレスを逆参照し、CurrentLocale 値 0x409 が格納されていることを確認します。
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
2 つの式エバリュエーターの詳細については、「式の評価」を参照してください。
元のソース ファイル名と行番号を指定することで、アプリケーション内のアドレスを指定することもできます。 この情報を指定する方法の詳細については、「ソース行の構文」を参照してください。
アドレス範囲
アドレス範囲は、アドレスのペア、またはアドレスとオブジェクト数で指定できます。
アドレスのペアで範囲を指定するには、開始アドレスと終了アドレスを指定します。 次の例は、アドレス 0x00001000 で始まる 8 バイトの範囲です。
0x00001000 0x00001007
アドレスとオブジェクト数でアドレス範囲を指定するには、address 引数、文字 L (大文字または小文字)、および value 引数を指定します。 address には、開始アドレスを指定します。 value には、検査または表示するオブジェクトの数を指定します。 オブジェクトのサイズはコマンドによって異なります。 たとえば、オブジェクト サイズが 1 バイトの場合、次の例はアドレス 0x00001000 から始まる 8 バイトの範囲になります。
0x00001000 L8
ただし、オブジェクト サイズがダブル ワード (32 ビットまたは 4 バイト) の場合、以下の 2 つの範囲はそれぞれ 8 バイトの範囲になります。
0x00001000 0x00001007
0x00001000 L2
L Size 範囲指定子
値 (LSize 範囲指定子) を指定するには、他にも 2 つの方法があります。
L?Size (疑問符付き) は、LSize と同じですが、L? サイズデバッガーの自動範囲制限を削除します。 通常、範囲の上限は 256 MB です。これより大きい範囲は入力ミスになるためです。 256 MB を超える範囲を指定する場合は、 L を使用する必要 サイズ 構文。
L- Size (ハイフン付き) は、指定したアドレスで終わる長 Size の範囲を指定します。 たとえば、80000000 L20 は 0x80000000 ~ 0x8000001F の範囲を指定し、80000000 L-20 は 0x7FFFFFE0 ~ 0x7FFFFFFF の範囲を指定します。
アドレス範囲を要求する一部のコマンドは、1 つのアドレスを引数として受け付けます。 この状況では、コマンドは既定のオブジェクト数を使用して範囲のサイズを計算します。 通常、アドレス範囲が最後のパラメーターであるコマンドでは、この構文が許可されます。 各コマンドの正確な構文と既定の範囲サイズについては、各コマンドのリファレンス トピックを参照してください。
メモリ範囲の検索例
まず、MASM 式エバリュエーターを使用して、rip 命令ポインター レジスタのアドレスを特定します。
0:000> ? @rip
Evaluate expression: 140720561719153 = 00007ffc`0f180771
次に、s (メモリ検索) コマンドを使用して、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.
...
このように 2 つのメモリ アドレスを使用して同じ範囲を指定することもできます。
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- length パラメーターを使用してメモリ範囲を逆方向に検索できます。
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
メモリ逆アセンブルの例
この例では、u (逆アセンブル) コマンドと L パラメーターを使用して、3 バイトのコードを逆アセンブルします。
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
または、次のように 3 バイトのメモリ範囲を指定して逆アセンブルします。
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 は次のアドレス指定モードをサポートしています。 これらのモードは、それぞれのプレフィックスによって区別されます。
プレフィックス | 名前 | アドレスの種類 |
---|---|---|
% | flat | 32 ビット アドレス (32 ビット セグメントを指す 16 ビット セレクターも含む) および 64 ビット システム上の 64 ビット アドレス。 |
& | 仮想 86 | リアル モード アドレス。 x86 ベースのみ。 |
# | plain | リアル モード アドレス。 x86 ベースのみ。 |
プレーン 86 モードと仮想 86 モードの違いは、プレーン 16 ビット アドレスがセグメント値をセレクターとして使用し、セグメント記述子を参照することです。 ただし、仮想 86 アドレスはセレクターを使用せず、代わりに下位 1 MB に直接マッピングします。
現在の既定モードではないアドレス指定モードを通じてメモリにアクセスする場合、アドレス モード プレフィックスを使用して現在のアドレス モードを上書きすることができます。
アドレス引数
アドレス引数は、変数や関数の位置を指定します。 次の表では、CDB および KD で使用できるさまざまなアドレスの構文と意味について説明します。
構文 | 意味 |
---|---|
オフセット |
仮想メモリ空間内の絶対アドレスで、その種類は現在の実行モードに対応します。 たとえば、現在の実行モードが 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 (メモリの検索) コマンドを使用します。
メモリの内容を表示するには、d、da、db、dc、dd、dD、df、dp、dq、du、dw (メモリ表示) コマンドを使用します。
メモリ ウィンドウを使用してメモリを表示および編集する方法については、「メモリ ウィンドウの使用」を参照してください。