Запись основного цикла отладчика
Отладчик использует функцию 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); } |