Вопросы и ответы по отладке машинного кода

Как выполнить отладку нарушений доступа при запуске программы за пределами отладчика Visual Studio?

Активируйте параметр JIT-отладка и запустите автономное выполнение программы до момента возникновения нарушения доступа. Затем в диалоговом окне Нарушение доступа можно нажать Отмена и запустить отладчик.

Как выполнить отладку нарушения доступа C++?

Если вы получаете нарушение прав доступа в строке кода, которая разыменовывает несколько указателей, может быть трудно определить указатель, который вызвал нарушение прав доступа. В Visual Studio диалоговое окно исключения явно присваивает имя указателю, вызвавшем нарушение доступа.

Например, если имеется следующий код, вы должны получить нарушение прав доступа:

#include <iostream>
using namespace std;

class ClassC {
public:
  void printHello() {
    cout << "hello world";
  }
};

class ClassB {
public:
  ClassC* C;
  ClassB() {
    C = new ClassC();
  }
};

class ClassA {
public:
  ClassB* B;
  ClassA() {
    // Uncomment to fix
    // B = new ClassB();
  }
};

int main() {
  ClassA* A = new ClassA();
  A->B->C->printHello();

}

Если вы запускаете этот код в Visual Studio, вы увидите следующее диалоговое окно исключения:

Screenshot of a Microsoft Visual Studio exception dialog, showing a read access violation for 'A->B was nullptr'. The Break button is selected.

Если не удается определить, почему указатель вызвал нарушение прав доступа, выполните трассировку кода, чтобы проверить правильность назначения указателя, ставшего причиной проблемы. Если он передается как параметр, убедитесь, что он передается правильно, и вы не создаете случайно неполную копию. Затем проверьте, не изменяются ли непреднамеренно значения где-нибудь в программе путем создания точки останова по данным для рассматриваемого указателя, чтобы убедиться, что он не изменяется в другом месте программы. Дополнительные сведения о точках останова по данным см. в разделе, посвященном точкам останова по данным, в статье Using Breakpoints.

Как определить, повреждают ли указатели адрес памяти?

Проверьте наличие повреждения кучи. Большая часть повреждения памяти связана с повреждением кучи. Используйте программу глобальных флагов (gflags.exe) или pageheap.exe. См. /windows-hardware/drivers/debugger/gflags-and-pageheap.

Чтобы найти расположение адреса памяти, выполните следующие действия.

  1. Задайте точку останова данных по адресу 0x00408000. Подробнее см. раздел Установка точки останова, действующей при изменении данных (только для машинного кода C++).

  2. При попадании в точку останова используйте окно Память для просмотра содержимого памяти начиная с адреса 0x00408000. Дополнительные сведения см. в разделе Окно "Память".

Как узнать, кто передает неправильное значение параметра?

Для решения этой проблемы сделайте следующее:

  1. Установите точку останова в начале функции.

  2. Щелкните правой кнопкой мыши точку останова и выберите пункт Условие.

  3. В диалоговом окне Условие для точек останова установите флажок Условие. См. раздел Расширенные точки останова.

  4. Введите в текстовое поле выражение, например Var==3, где Var представляет собой имя параметра, который содержит неправильное значение, а 3 — это неправильное значение, переданное параметру.

  5. Установите переключатель в положение верно и нажмите кнопку ОК.

  6. Запустите программу повторно. Точка останова заставит программу прервать выполнение на начале функции, когда параметр Var получит значение 3.

  7. Затем в окне "Стек вызовов" можно найти вызывающую функцию, чтобы перейти к ее исходному коду. Дополнительные сведения см. в разделе "Практическое руководство. Использование окна стека вызовов".

Как определить конкретный вызов функции, приведший к сбою, если таких вызовов было порядка ста?

Пример. Моя программа завершается сбоем при вызове определенной функции. CnvtV Программа, вероятно, вызывает эту функцию перед сбоем пару сотен раз. Если поставить точку останова на CnvtV, программа останавливается на каждом вызове этой функции, а этого не требуется. Непонятно, что приводит к сбойному вызову, поэтому поставить условную точку останова невозможно. Что я могу сделать?

Можно установить точку останова на функции с полем Количество обращений, равном недостижимо большому значению. В этом случае, так как предполагается, что функция CnvtV вызывается пару сотен раз, Количество обращений можно задать 1000 или более. Затем запустить программу и подождать сбоя. Когда сбой произойдет, откройте окно точек останова и просмотрите их список. Точка останова в CnvtV появилась, следом появилось заданное число попаданий и количество выполненных итераций:

CnvtV(int) (no condition) when hit count is equal to 1000 (currently 101)

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

Где можно найти коды ошибок Win32?

WINERROR. H в каталоге INCLUDE установки системы по умолчанию содержит определения кода ошибки для функций API Win32.

Кроме того, код ошибки можно посмотреть, введя код в окно Контрольные значения или в диалоговом окне Быстрая проверка. Например:

0x80000004,hr

Как сосредоточиться при пошаговом переходе по моему приложению?

Пример. У моей программы возникла проблема с активацией окна. При пошаговом выполнении программы с отладчиком не удается воспроизвести проблему, так как программа теряет фокусировку. Есть ли какой-либо способ избежать потери фокуса?

Если есть второй компьютер, используйте удаленную отладку. Можно управлять программой на удаленном компьютере, а на основном хосте запустить отладчик. Дополнительные сведения см. в разделе "Практическое руководство. Выбор удаленного компьютера".

Как отладить функции Windows API?

Чтобы задать точку останова в функции API Windows с загруженными символами NT:

  • В диалоговом окне Точка останова в функции введите имя функции вместе с именем DLL-файла, в котором эта функция находится (см. статью Оператор контекста в отладчике Visual Studio (C++)). В 32-разрядном коде используйте декорированную форму имени функции. Например, чтобы задать точку останова на MessageBeep, необходимо ввести следующее.

    {,,USER32.DLL}_MessageBeep@4
    

    Чтобы получить внутреннее имя, обратитесь к разделу Просмотр внутренних имен.

    Можно проверить внутреннее имя и просмотреть его в дизассемблированном коде. При паузе в выполнении функции в отладчике Visual Studio щелкните функцию правой кнопкой мыши в окне редактора кода или окне стека вызовов выберите К дизассемблированному коду.

  • В 64-разрядном коде можно использовать недекорированное имя.

    {,,USER32.DLL}MessageBeep
    

Следующие шаги

Дополнительные сведения об отладке машинного кода в Visual Studio см. по следующим ссылкам: