Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье описывается использование синтаксиса выражений C++ с средствами отладки Windows.
Отладчик принимает два различных типа числовых выражений: выражения C++ и выражения сборщика макросов Майкрософт (MASM). Каждое из этих выражений соответствует собственным правилам синтаксиса входных и выходных данных.
Дополнительные сведения об использовании каждого типа синтаксиса см. в статье "Оценка выражений" и команда "Оценить выражение".
Средство синтаксического анализа выражений C++ поддерживает все формы синтаксиса выражений C++. Синтаксис включает все типы данных, включая указатели, числа с плавающей запятой и массивы, а также все унарные и двоичные операторы C++.
Окна "Контрольные " и "Локальные" в отладчике всегда используют средство оценки выражений C++.
В следующем примере команда ?? evaluate C++ expression отображает значение регистра указателя команд.
0:000> ?? @eip
unsigned int 0x771e1a02
Для определения размера структур можно использовать функцию C++ sizeof
.
0:000> ?? (sizeof(_TEB))
unsigned int 0x1000
Задайте для вычислителя выражений значение C++
Используйте оценщик .expr choose expression, чтобы увидеть оценщик выражений по умолчанию и изменить его на C++.
0:000> .expr
Current expression evaluator: MASM - Microsoft Assembler expressions
0:000> .expr /s c++
Current expression evaluator: C++ - C++ source expressions
После изменения вычислителя выражений по умолчанию можно использовать команду для отображения выражений C++. В следующем примере отображается значение регистра указателя инструкции.
0:000> ? @eip
Evaluate expression: 1998461442 = 771e1a02
Дополнительные сведения о ссылке на регистр @eip
см. в разделе Синтаксис регистра.
В этом примере шестнадцатеричное значение 0xD добавляется в регистр eip.
0:000> ? @eip + 0xD
Evaluate expression: 1998461455 = 771e1a0f
Регистры и псевдорегистры в выражениях C++
В выражениях C++ можно использовать регистры и псевдорегистры. Перед регистрацией или псевдорегистром необходимо добавить знак @.
Средство оценки выражений автоматически выполняет правильный приведение. Фактические регистры и псевдорегистры с целочисленным значением приводятся к ULONG64
. Все адреса приведены к PUCHAR
, $thread
приведен к ETHREAD*
, $proc
приведен к EPROCESS*
, $teb
приведен к TEB*
, и $peb
приведен к PEB*
.
В этом примере отображается TEB.
0:000> ?? @$teb
struct _TEB * 0x004ec000
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x004ec02c Void
+0x030 ProcessEnvironmentBlock : 0x004e9000 _PEB
+0x034 LastErrorValue : 0xbb
+0x038 CountOfOwnedCriticalSections : 0
Нельзя изменить регистр или псевдорегистр с помощью оператора присваивания или побочного эффекта. Для изменения этих значений необходимо использовать команду r registers .
В следующем примере устанавливается псевдорегистр на значение 5, после чего это значение отображается.
0:000> r $t0 = 5
0:000> ?? @$t0
unsigned int64 5
Дополнительные сведения о регистрах и псевдорегистрирующих регистрах см. в разделе Register синтаксис и синтаксис псевдорегистрирующего регистра.
Числа в выражениях C++
Числа в выражениях C++ интерпретируются как десятичные числа, если они не указаны другим способом. Чтобы указать шестнадцатеричное целое число, добавьте 0x перед числом. Чтобы указать восьмеричное целое число, добавьте 0 (ноль) перед числом.
Радикс отладчика по умолчанию не влияет на способ ввода выражений C++. Вы не можете напрямую ввести двоичное число, кроме как когда вы вкладываете выражение MASM в выражение C++.
Шестнадцатеричное 64-разрядное значение можно ввести в формате xxxx'xxxx. Вы также можете опустить серьезный акцент ('). Оба формата создают одно и то же значение.
Можно использовать суффиксы L
, U
и I64
с целыми значениями. Фактический размер создаваемого числа зависит от суффикса и введенного числа. Дополнительные сведения об этой интерпретации см. в справочнике по языку C++.
Выходные данные вычислителя выражений C++ сохраняют тип данных, указанный правилами выражений C++. Однако при использовании этого выражения в качестве аргумента для команды всегда выполняется приведение. Например, вам не нужно приведение целых значений к указателям, когда они используются в качестве адресов в аргументах команд. Если значение выражения не может быть допустимо приведено к целому числу или указателю, возникает синтаксическая ошибка.
Префикс 0n
(десятичный) можно использовать для некоторых выходных данных, но он не подходит для ввода выражений на C++.
Символы и строки в выражениях C++
Вы можете ввести символ, окружив его одними кавычками ('). Разрешены стандартные escape-символы C++.
Строковые литералы можно вводить, окружая их двойными кавычками ("). Вы можете использовать \" в качестве escape-последовательности в такой строке. Однако строки не имеют значения для вычислителя выражений.
Символы в выражениях C++
В выражении C++ каждый символ интерпретируется в соответствии с типом. В зависимости от того, к чему относится символ, он может интерпретироваться как целое число, структура данных, указатель функции или любой другой тип данных. Синтаксическая ошибка возникает, если используется символ, который не соответствует типу данных C++ ( например, немодифицированному имени модуля) в выражении C++ .
Вы можете использовать серьезный акцент (') или апостроф (') в имени символа, только если добавить имя модуля и восклицательный знак перед именем символа. При добавлении разделителей < и > после имени шаблона можно добавлять пробелы между этими разделителями.
Если символ может быть неоднозначным, можно добавить имя модуля и восклицательный знак (!) или только восклицательный знак перед символом. Чтобы указать, что символ должен быть локальным, опустить имя модуля и включить знак доллара и восклицательный знак ($!) перед именем символа. Дополнительные сведения о распознавании символов см. в разделе "Синтаксис символов" и "Сопоставление символов".
Структуры в выражениях C++
Оценщик выражений C++ приводит псевдорегистры к соответствующим типам. Например, $teb
преобразуется в TEB*
.
0:000> ?? @$teb
struct _TEB * 0x004ec000
+0x000 NtTib : _NT_TIB
+0x01c EnvironmentPointer : (null)
+0x020 ClientId : _CLIENT_ID
+0x028 ActiveRpcHandle : (null)
+0x02c ThreadLocalStoragePointer : 0x004ec02c Void
+0x030 ProcessEnvironmentBlock : 0x004e9000 _PEB
+0x034 LastErrorValue : 0xbb
+0x038 CountOfOwnedCriticalSections : 0
В следующем примере отображается идентификатор процесса в структуре TEB, показывающий использование указателя на элемент ссылочной структуры.
0:000> ?? @$teb->ClientId.UniqueProcess
void * 0x0000059c
Операторы в выражениях C++
Скобки можно использовать для переопределения правил приоритета.
Если вы заключаете часть выражения C++ в скобки и добавляете два знака (@@) перед выражением, выражение интерпретируется в соответствии с правилами выражений MASM. Нельзя добавить пробел между двумя знаками at и открывающей скобкой. Окончательное значение этого выражения передается в средство оценки выражений C++ в качестве значения ULONG64. Вы также можете указать средство оценки выражений с помощью @@c++( ... )
или @@masm( ... )
.
Типы данных указываются как обычные на языке C++. Символы, указывающие массивы ([ ]), элементы указателя (->), элементы UDT (.) и члены классов (::) распознаются. Поддерживаются все арифметические операторы, включая операторы присваивания и операторы с побочными эффектами. Однако вы не можете использовать операторы new
, delete
и throw
, и фактически не можете вызвать функцию.
Арифметика указателя поддерживается и смещения масштабируются правильно. Обратите внимание, что невозможно добавить смещение в указатель функции. Если необходимо добавить смещение в указатель функции, сначала приведите смещение к указателю символа.
Как и в C++, при использовании операторов с недопустимыми типами данных возникает синтаксическая ошибка. Средство синтаксического анализа выражений C++ отладчика использует немного более расслабленные правила, чем большинство компиляторов C++, но все основные правила применяются. Например, нельзя сместить значение, не являющееся целым числом.
Можно использовать следующие операторы. Операторы в каждой ячейке имеют приоритет над операторами в нижних ячейках. Операторы в одной ячейке имеют одинаковый приоритет и анализируются слева направо.
Как и в C++, оценка выражений заканчивается, когда его значение известно. Это окончание позволяет эффективно использовать такие выражения, как ?? myPtr && *myPtr
.
Приведение ссылочных и типовых данных
Оператор | Значение |
---|---|
Выражение // Комментарий | Игнорировать весь последующий текст |
Класс :: Член | Член класса |
Класс ::~Элемент | Член класса (деструктор) |
:: Имя | Глобальный |
Структура . Поле | Поле в структуре |
Указатель ->Поле | Поле в указанной структуре |
Имя [целое число] | Подстрочный индекс массива |
LValue ++ | Инкремент (после вычисления) |
LValue -- | Декремент (после оценки) |
dynamic_cast<тип>(Значение) | Typecast (всегда выполняется) |
static_cast<тип>(Значение) | Typecast (всегда выполняется) |
reinterpret_cast<тип>(Значение) | Typecast (всегда выполняется) |
const_cast<тип>(Значение) | Typecast (всегда выполняется) |
Операции со значениями
Оператор | Значение |
---|---|
(тип) Ценность | Typecast (всегда выполняется) |
sizeofзначение | Размер выражения |
sizeof( тип ) | Размер типа данных |
++ LValue | Инкремент (перед оценкой) |
-- LValue | Декремент (перед оценкой) |
~ Ценность | Битовое дополнение |
! Ценность | НЕ (Boolean) |
Ценность | Унарный минус |
+ Ценность | Унарный плюс |
& LValue | Адрес типа данных |
Ценность | Разыменовать |
Структура . указателя | Указатель на элемент структуры |
Указатель -> * Указатель | Указатель на элемент ссылочной структуры |
Арифметика
Оператор | Значение |
---|---|
Значение | Умножение |
Ценность / Ценность | Подразделение |
Ценность % Ценность | Модуль |
Ценность + Ценность | Дополнение |
Ценность - Ценность | Вычитание |
Ценность<<Ценность | Сдвиг влево по битам |
Ценность>>Ценность | Побитовый сдвиг вправо |
Ценность<Ценность | Меньше (сравнение) |
Ценность<= значение | Меньше или равно (сравнение) |
Ценность>Ценность | Больше, чем (сравнение) |
Ценность>= значение | Больше или равно (сравнение) |
Ценность == Ценность | Равно (сравнение) |
Значение != Значение | Не равно (сравнение) |
Значение и Значение | Битовое И |
Ценность ^ Ценность | Побитовое XOR (исключающее ИЛИ) |
Ценность | Ценность | Битовое ИЛИ |
Значение && Значение | Логическое AND |
Ценность || Ценность | Логическое ИЛИ |
В следующих примерах предполагается, что псевдорегистры установлены, как показано ниже.
0:000> r $t0 = 0
0:000> r $t1 = 1
0:000> r $t2 = 2
0:000> ?? @$t1 + @$t2
unsigned int64 3
0:000> ?? @$t2/@$t1
unsigned int64 2
0:000> ?? @$t2|@$t1
unsigned int64 3
Задание
Оператор | Значение |
---|---|
LValue = Ценность | Назначать |
LValue *= Ценность | Умножить и присвоить |
LValue /= Ценность | Деление и назначение |
LValue %= Ценность | Модуло и назначение |
LValue += Ценность | Добавление и назначение |
LValue -= Ценность | Вычитание и назначение |
LValue<<= значение | Смена влево и назначение |
LValue>>= значение | Сдвиг вправо с присваиванием |
LValue &= Value | И и назначение |
LValue |= Ценность | ИЛИ и назначение |
LValue ^= Ценность | XOR и присвоение |
Оценка
Оператор | Значение |
---|---|
Значение ? Значение : Значение | Условная оценка |
Значение , Значение | Оценка всех значений, а затем отмена всех, кроме самого правого значения |
Макросы в выражениях C++
Макросы можно использовать в выражениях C++. Перед макросами необходимо добавить знак номера (#).
Можно использовать следующие макросы. Эти макросы имеют те же определения, что и макросы Microsoft Windows с тем же именем. Макросы Windows определены в Winnt.h
.
Макрос | Возвращаемое значение |
---|---|
#CONTAINING_RECORD(адрес, тип, поле) | Возвращает базовый адрес экземпляра структуры, учитывая тип структуры и адрес поля в структуре. |
#FIELD_OFFSET(Тип, поле) | Возвращает смещение байтов именованного поля в известном типе структуры. |
#RTL_CONTAINS_FIELD(структура, размер, поле) | Указывает, включает ли заданный размер байтов требуемое поле. |
#RTL_FIELD_SIZE(Тип, поле) | Возвращает размер поля в структуре известного типа, не требуя типа поля. |
#RTL_NUMBER_OF(Массив) | Возвращает количество элементов в массиве статического размера. |
#RTL_SIZEOF_THROUGH_FIELD(Тип, поле) | Возвращает размер структуры известного типа, вплоть до указанного поля. |
В этом примере показано использование #FIELD_OFFSET
макроса для вычисления смещения байтов в поле в структуре.
0:000> ?? #FIELD_OFFSET(_PEB, BeingDebugged)
long 0n2
См. также
Выражения MASM и выражения C++