Синтаксис адреса и диапазона адресов

Существует несколько способов указать адреса в отладчике.

Адреса обычно являются виртуальными, за исключением случаев, когда в документации конкретно указан другой тип адреса. В пользовательском режиме отладчик интерпретирует виртуальные адреса в соответствии с каталогом страницы текущего процесса. В режиме ядра отладчик интерпретирует виртуальные адреса в соответствии с каталогом страницы процесса, который задается контекстом процесса . Можно также напрямую задать контекст адреса в пользовательском режиме. Дополнительные сведения о контексте адреса в пользовательском режиме см. в разделе .context (Set User-Mode Address 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 имеет значение +0x108 от начала TEB. Затем определите адрес памяти этого расположения.

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

Дополнительные сведения о двух вычислителях выражений см. в разделе Вычисление выражений.

Вы также можете указать адрес в приложении, указав исходное имя исходного файла и номер строки. Дополнительные сведения о том, как указать эти сведения, см. в разделе Синтаксис исходной строки.

Диапазоны адресов

Диапазон адресов можно указать по паре адресов или по адресам и количеству объектов.

Чтобы указать диапазон по паре адресов, укажите начальный и конечный адрес. Например, следующий пример представляет собой диапазон в 8 байт, начиная с адреса 0x00001000.

0x00001000  0x00001007

Чтобы указать диапазон адресов по адресу и количеству объектов, укажите аргумент address, букву L (в верхнем или нижнем регистре) и аргумент значения. Адрес указывает начальный адрес. Значение указывает количество объектов для проверки или отображения. Размер объекта зависит от команды . Например, если размер объекта составляет 1 байт, в следующем примере используется диапазон 8 байт, начиная с адреса 0x00001000.

0x00001000  L8

Однако если размер объекта имеет двойное слово (32 бита или 4 байта), следующие два диапазона дают 8-байтовый диапазон.

0x00001000  0x00001007
0x00001000  L2

Описатель диапазона размеров L

Существует два других способа указать значение (описатель диапазона размеровL):

  • L?Размер (с вопросительным знаком) означает то же, что И размер L, за исключением того, что L?Размер удаляет автоматическое ограничение диапазона отладчика. Как правило, диапазон ограничен в 256 МБ, так как большие диапазоны являются типографическими ошибками. Если вы хотите указать диапазон, превышающий 256 МБ, необходимо использовать L?Синтаксис размера .

  • L-Size (с дефисом) указывает диапазон длины Size, который заканчивается на заданном адресе. Например, 80000000 L20 задает диапазон от 0x80000000 до 0x8000001F, а 800000000 L-20 — диапазон от 0x7FFFFFE0 до 0x7FFFFFFF.

Некоторые команды, запрашивающие диапазоны адресов, принимают в качестве аргумента один адрес. В этом случае команда использует некоторое число объектов по умолчанию для вычисления размера диапазона. Как правило, этот синтаксис разрешен командами, для которых диапазон адресов является окончательным параметром. Точный синтаксис и размер диапазона по умолчанию для каждой команды см. в справочных разделах для каждой команды.

Пример диапазона памяти для поиска

Сначала мы определим адрес регистра указателя инструкции rip с помощью средства оценки выражений MASM.

0:000> ? @rip 
Evaluate expression: 140720561719153 = 00007ffc`0f180771

Затем мы будем выполнять поиск, начиная с 00007ffc'0f180771, для 100000 с помощью команды s (Search Memory). Мы указываем диапазон для поиска с помощью 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-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 (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 Имя Типы адресов
% квартира 32-разрядные адреса (также 16-разрядные селекторы, указывающие на 32-разрядные сегменты) и 64-разрядные адреса в 64-разрядных системах.
& virtual 86 Адреса в реальном режиме. Только на основе x86.
# plain Адреса в реальном режиме. Только на основе x86.

Разница между простым и виртуальным режимами 86 заключается в том, что обычный 16-разрядный адрес использует значение сегмента в качестве селектора и ищет дескриптор сегмента. Но виртуальный адрес 86 не использует селекторы и вместо этого сопоставляется непосредственно с меньшим размером 1 МБ.

Если вы обращаетесь к памяти через режим адресации, который не является текущим режимом по умолчанию, можно использовать префиксы режима адреса, чтобы переопределить текущий режим адреса.

Аргументы адреса

Аргументы address указывают расположение переменных и функций. В следующей таблице объясняется синтаксис и значение различных адресов, которые можно использовать в CDB и KD.

Синтаксис Значение

offset

Абсолютный адрес в виртуальном пространстве памяти с типом, соответствующим текущему режиму выполнения. Например, если текущий режим выполнения составляет 16 бит, смещение равно 16 битам. Если режим выполнения является 32-разрядным сегментированием, смещение будет 32-разрядным сегментированием.

&Смещение [[ segment:]]

Реальный адрес. x86 и x64.

%segment:[смещение]]

Сегментированные 32-разрядный или 64-разрядный адрес. x86 и x64.

%[[ смещение]]

Абсолютный адрес (32-разрядная или 64-разрядная версия) в виртуальной памяти. x86 и x64.

смещение name[[ +| ]]

Неструктурированный 32-разрядный или 64-разрядный адрес. Имя может быть любым символом. offset задает смещение. Это смещение может быть любым режимом адреса, который указывает его префикс. Нет префикса указывает адрес режима по умолчанию. Смещение можно указать как положительное (+) или отрицательное (−).

Используйте команду dg (селектор отображения), чтобы просмотреть сведения о дескрипторов сегментах.

См. также:

Чтобы отобразить сведения о памяти, используйте команду !address .

Для поиска в памяти используйте команду s (Search Memory).

Чтобы отобразить содержимое памяти, используйте команду d, da, db, dc, dd, dD, df, dp, dq, du, dw (display Memory).

Сведения о том, как просматривать и изменять память с помощью окна памяти, см. в статье Использование окна памяти.