Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ДП.docx
Скачиваний:
11
Добавлен:
23.09.2019
Размер:
4.64 Mб
Скачать

3.2.4 Общие приемы отладки драйвера

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

3.2.4.1 Установка фиксированных точек прерывания

При использовании интерактивных отладчиков найдется не так много причин устанавливать фиксированные точки прерывания внутри кода драйвера. Тем не менее, это можно сделать, если воспользоваться двумя функциями [3.5]:

  • VOID DbgBreakPoint();

  • VOID KdBreakPoint();

Вызов KdBreakPoint представляет из себя макроопределение, которое определяет условную компиляцию с целью выполнить вызов DbgBreakPoint. Это макроопределение не выполняет данного вызова, если выполнена релизная (без отладочных инструкций) сборка драйвера. Windows дает фатальный сбой с сообщением КМОDE_EXCEPTION_NOT_HANDLED в том случае, если драйвер применил фиксированную точку прерывания (через упомянутые вызовы), но в этот момент клиент отладки был недоступен. Если драйвер добрался до такой точки прерывания, и не оказалось отладчика то драйвер «виснет». В некоторых случаях, ситуация может быть выправлена запуском отладчика на хост-компьютере [3.5].

3.2.4.2 Промежуточный вывод на экран

Делать сообщения из недр отлаживаемого кода при помощи функций печати (вывода на экран) — это метод с давними и славными традициями. Его иногда называют «генерацией промежуточного вывода». Фактически, нет таких ошибок, которые нельзя было бы найти, если применить такой метод в достаточном объеме.

И хотя данный метод не так ныне распространен, как отладка с использованием точек прерывания в интерактивных отладчиках, тем не менее, он может быть очень полезен при поисках сбоев, связанных с временными затруднениями драйвера (на­пример, ошибках или сбоях в последовательности событий, связанных с устройст­вом). Для генерации промежуточных сообщений используются две функции − DbgPrint и KdPrint [3.5]. Обе функции посылают форматированные строки, созданные на целевом компьютере, отладчику WinDbg, работающему на хост-компьютере.

Вызов KdPrint на самом деле является макроопределением и превращается в пус­тышку (невыполняемый участок) в релизной сборке драйвера (free build).

3.2.4.3 Сохранение отладочного кода в исходном тексте драйвера

Хорошим приемом в деле доводки драйвера является сохранение отладочных фрагментов кода на их месте, даже если для потребителя была собрана релизная версия (версия без отладочных инструкций). Все это несложно сделать при по­мощи директив условной компиляции, и при возврате к выявлению более глубо­ких ошибок и повторному тестированию этот прием окажет отличную поддержку.

Утилита BUILD использует символ времени компиляции DBG, который может быть использован при составлении условно компилируемых фрагментов. В отла­дочной версии этому символу присвоено значение 1, в релизной версии значение DBG равно 0. При внесении отладочного кода в драйвер следует ограничивать его рамками директив условной компиляции типа #if DGB и #endif [3.5].

3.2.4.4 Перехват некорректных условий

Разработчик драйвера, как и всякий разработчик, создает свой продукт, отталки­ваясь от некоторых изначальных допущений. Важно лишь, чтобы они не были бес­почвенными или чрезмерно оптимистическими. В том случае, если возникают не­которые сомнения в условиях работы некоторых важных участков кода драйвера, лучше подстраховаться. Например, предполагая, что некий фрагмент кода, будет вызван только на определенном уровне IRQL, автор закладывает потенциальную возможность будущих сбоев (если данные ожидания не будут оправданы) [3.5].

Для того чтобы перехватить эти непредусмотренные отклонения, следует при­менять несложный прием: такие допущения должны проверяться во время выпол­нения, хотя бы в отладочной сборке драйвера. Макроопределения ASSERT и ASSERTMSG помогут решить эту задачу:

  • ASSERT( Expression );

  • ASSERTMSG( Message, Expression );

В случае если выражение Expression, рассмотренное как логическое, будет равно FALSE, макроопределение ASSERT произведет запись сообщения в командное окно WinDbg, подключенного на хост-компьютере для проведения отладки. Это сообще­ние содержит исходный код выражения, значение которого оказалось равным FALSE, имя файла (в котором был исходный текст данного фрагмента) и номер стро­ки, где было вызвано макроопределение ASSERT. Затем предлагается сделать выбор, сделать ли прерывание в месте данного макроопределения ASSERT, игнорируя при­чину остановки, либо прервать процесс или поток, в котором «сработал» ASSERT (что, впрочем, совершенно аналогично применению ASSERT в Visual Studio).

Макроопределение ASSERTMSG демонстрирует точно такое же поведение, с той лишь разницей, что в сообщение включается содержимое Message (являющееся строкой) [3.5].

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

Кроме того, в основе упомянутых выше макроопределений лежит использова­ние функции RtlAssert, которая во релизных (т.е. не отладочных) версиях Windows превраща­ется в пустышку. Следовательно, чтобы наблюдать последствия ошибок в макро­определениях ASSERT и ASSERTMSG следует тестировать драйвер под отладочной версией Windows [3.5].