Запись основного цикла отладчика
Отладчик использует функцию WaitForDebugEvent в начале своего основного цикла. Эта функция блокирует отладчик, до тех пор, пока не произойдет событие отладки. Когда событие отладки происходит, система приостанавливает все потоки в отлаживаемом процессе и уведомляет отладчик о событии.
Отладчик может взаимодействовать с пользователем, или обрабатывать состояние отлаживаемого процесса, используя функции GetThreadContext, GetThreadSelectorEntry, ReadProcessMemory, SetThreadContext и WriteProcessMemory. GetThreadSelectorEntry возвращает запись таблицы дескрипторов для заданного селектора и потока. Отладчики используют запись таблицы дескрипторов, чтобы преобразовать адрес относительно начала сегмента в адрес линейного виртуального адреса. Функции ReadProcessMemory и WriteProcessMemory требуют линейных виртуальных адресов.
Отладчики часто читают в памяти отлаживаемого процесса и записывают в память, которая содержит инструкции кэша команд. После того, как инструкции запишутся, отладчик вызывает функцию FlushInstructionCache, чтобы исполнить кэшируемые команды.
Отладчик использует функцию ContinueDebugEvent в конце своего основного цикла. Эта функция позволяет отлаживаемому процессу продолжить исполнять код.
Пример ниже использует функции WaitForDebugEvent и ContinueDebugEvent, чтобы проиллюстрировать, как простой отладчик программы может быть организован.
DEBUG_EVENT DebugEv; // информация о событиях отладки
DWORD dwContinueStatus = DBG_CONTINUE; // продолжение исключения
for(;;)
{
// Ожидание произошедшего события отладки. Второй параметр
// указывает, что функция не возвращает значение до тех пор,
// пока не произойдет событие отладки.
WaitForDebugEvent(&DebugEv, INFINITE);
// Обработка кода события отладки.
switch (DebugEv.dwDebugEventCode)
{
case EXCEPTION_DEBUG_EVENT:
// Обработка кода исключения. При обработке
// исключительных ситуаций, не забудьте установить
// параметр состояния продолжения (dwContinueStatus).
// Это значение используется функцией ContinueDebugEvent.
switch (DebugEv.u.Exception.ExceptionRecord.ExceptionCode)
{
case EXCEPTION_ACCESS_VIOLATION:
// Первый случай: Передать это в систему.
// Последний случай: Показать на экране
// соответствующую ошибку.
break;
case EXCEPTION_BREAKPOINT:
// Первый случай: Показать на экране текущую
// команду и значения регистров.
break;
case EXCEPTION_DATATYPE_MISALIGNMENT:
// Первый случай: Передать это в систему.
// Последний случай: Показать на экране
// соответствующую ошибку.
break;
case EXCEPTION_SINGLE_STEP:
// Первый случай: Обновить показанные
// на экране текущие команду и значения
// регистров.
break;
case DBG_CONTROL_C:
// Первый случай: Передать это в систему.
// Последний случай: Показать на экране
// соответствующую ошибку.
break;
default:
// Обработка других исключений.
break;
}
case CREATE_THREAD_DEBUG_EVENT:
// Как требуется, проверьте или измените регистры потока
// функциями GetThreadContext и SetThreadContext;
// и приостановите и возобновите исполнение кода
// потока функциями SuspendThread и ResumeThread.
break;
case CREATE_PROCESS_DEBUG_EVENT:
// Как требуется, проверьте или измените регистры
// начального потока процесса функциями GetThreadContext
// и SetThreadContext; прочтите из и запишите в
// виртуальную память процесса функциями ReadProcessMemory
// и WriteProcessMemory; и приостановите и возобновите
// исполнение кода потока функциями SuspendThread и
// ResumeThread. Убедитесь, что закрыли дескриптор
// процесса загрузочного модуля функцией CloseHandle.
break;
case EXIT_THREAD_DEBUG_EVENT:
// Покажите на экране код завершения потока.
break;
case EXIT_PROCESS_DEBUG_EVENT:
// Покажите на экране код завершения процесса.
break;
case LOAD_DLL_DEBUG_EVENT:
// Прочтите отладочную информацию включенную в недавно
// загруженную DLL. Убедитесь, что закрыли дескриптор
// загруженной DLL функцией CloseHandle.
break;
case UNLOAD_DLL_DEBUG_EVENT:
// Покажите на экране сообщение, что DLL была выгружена.
break;
case OUTPUT_DEBUG_STRING_EVENT:
// Покажите на экране выводимую строку отладки.
break;
}
// Возобновим исполнение кода потока, который сообщает
// о событии отладки.
ContinueDebugEvent(DebugEv.dwProcessId, DebugEv.dwThreadId,
dwContinueStatus);
}
|