Отладка драйвера для windows

Разработка и отладка простейшего драйвера

Для того чтобы начать разрабатывать драйверы устройств Windows на компьютере дол жен быть установлен пакет Windows DDK (Driver Development Kit) фирмы Microsoft, желатель но последней версии (на момент написания книги таковой являлась версия 2003 SP1). Этот пакет включает все необходимые средства для разработки и отладки драйверов. Кроме того, нужно иметь под рукой хороший компилятор C/C++ (подойдет бесплатная версия Microsoft Visual Studio Express Edition) для разработки приложения, используемого при тестировании драйвера. Поскольку для драйвера потребуется отладчик, то в качестве такого можно вы брать DebugView (www.microsoft.com), который, несмотря на свою простоту, довольно удобен в работе.

Этапы компиляции и сборки драйвера в Windows DDK довольно хорошо описаны во мно гих источниках, поэтому я не буду на этом останавливаться подробно. Давайте сразу перей дем к разработке нашего первого драйвера, который, вообще говоря, ничего не будет делать, а только выводить строки с сообщениями, которые можно будет перехватывать в нашем от ладчике. Таким образом, мы посмотрим, как создать работоспособный драйвер и научимся

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

В качестве первого примера разработаем драйвер «виртуального» устройства Test, кото рый «ничего» не делает, а только выводит в окно отладчика текстовую строку о выполненной операции.

Вот исходный текст нашего простейшего драйвера:

#define NT_DEVICE_NAME L»\\Device\\Test»

#define DOS_DEVICE_NAME L»\\DosDevices\\Test»

Test_Unload (IN PDRIVER_OBJECT DriverObject)

DbgPrint(«%s»,»Test: UNLOADING!\n»); RtlInitUnicodeString(&DosDeviceName, DOS_DEVICE_NAME); IoDeleteSymbolicLink(&DosDeviceName); IoDeleteDevice(DriverObject->DeviceObject);

Test_Create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

DbgPrint(«%s», «Test: CREATED!\n»);

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

Test_Close(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

DriverEntry(IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath)

PDEVICE_OBJECT DeviceObject; UNICODE_STRING NtDeviceName; UNICODE_STRING DosDeviceName; NTSTATUS status;

DO_DEVICE_INITIALIZING; DeviceObject->Flags |= DO_BUFFERED_IO;

DriverObject->MajorFunction[IRP_MJ_CLOSE] = Test_Close; DriverObject->DriverUnload = Test_Unload;

В начало листинга нужно включить файл заголовка ntddk.h, в котором определены все не обходимые функции. Далее мы определяем две строковые константы в формате UNICODE. Здесь мы должны уточнить некоторые нюансы. Строка NT_DEVICE_NAME указывает имя устрой ства, к которому будет обращаться наш драйвер, таким, каким оно должно быть в пространстве имен операционной системы. Здесь возникает проблема: приложение пользователя не может использовать функцию CreateFile() с данным именем, поскольку, в силу исторических обстоя тельств, нужно указывать другой путь, определенный в константной строке DOS_DEVICE_NAME. Ничего трагического в этом нет, и мы может просто связать, или по другому, сделать ссылку из DOS_DEVICE_NAME на NT_DEVICE_NAME, после чего все будет работать нормально.

Вспомним, что каждый драйвер обрабатывает только те пакеты запросов, которые про

граммист для него определил. В нашем случае мы создали драйвер «виртуального» устрой

ства Test, который обрабатывает только запросы IRP_MJ_CREATE, IRP_MJ_CLOSE и отдельно Unload. Функция Unload выгружает драйвер из системы и обрабатывается несколько иным способом, чем пакеты запросов (в WDM драйверах эта функция вообще не используется).

Проанализируем исходный текст функции обработчика IRP_MJ_CREATE:

Test_Create(IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp)

DbgPrint(«%s», «Test: CREATED!\n»);

Irp->IoStatus.Status = STATUS_SUCCESS; IoCompleteRequest(Irp, IO_NO_INCREMENT); return STATUS_SUCCESS;

Первое – все функции обработчики пакетов запросов принимают два параметра – адрес структуры DEVICE_OBJECT устройства и адрес пакета запроса PIRP. Оба параметра содержат поля, которые функция может использовать при обработке запроса.

Функция DbgPrint – это специальная функция, предназначенная для вывода информации в отладчик. Эта функция используется только для трассировки программного кода и может быть перехвачена только в отладчике, таком, например, как DebugView. В функции Testdrv_Create также ничего существенного не делается. В поле Status пакета запроса заносится значение STATUS_SUCCESS, которое затем будет возвращено приложению как свидетельство успешно выполненной операции. Функция IoCompleteRequest завершает обработку пакета запроса. Сама функция возвращает значение STATUS_SUCCESS.

Точно так же работает и функция Testdrv_Close, которая, по запросу приложения (функ

ция WINAPI CloseHandle()) закрывает дескриптор устройства.

Функция Testdrv_Unload удаляет символическую ссылку на устройство, о которой мы упо

минали ранее (IoDeleteSymbolicLink()) и удаляет устройство из системы (IoDeleteDevice()).

Мы уже упоминали о функции DriverEntry, которая вызывается операционной системой при инициализации драйвера устройства. Функции передается ссылка на структуру DriverObject, со зданной для нее операционной системой (первый параметр) и указатель на ключ данного драйвера в системном реестре (в записях этого ключа можно хранить или из записей извле кать при необходимости какие то дополнительные параметры). Эта функция последовательно выполняет такие шаги (которые являются стандартными для этого класса драйверов):

Читайте также:  Arch linux rolling release

1) инициализируется константная строка с именем устройства в пространстве имен си

2) создается программный объект описания устройства при помощи функции IoCrea teDevice(). Если объект устройства создать не удалось, функция заканчивает работу с ошибкой, код которой передается в переменной status, а сам объект устройства удаляется;

3) инициализируется константная строка с именем устройства в пространстве имен,

доступном пользовательской программе (функция RtlInitUnicodeString(&DosDevice Name, DOS_DEVICE_NAME));

4) создается символическая ссылка DOS имени на имя из пространства имен операци

онной системы для доступа к устройству из приложения пользователя (функция status

5) устанавливаются флаги устройства;

6) определяются функции обработчики пакетов запроса.

Поместим исходный текст драйвера в файл test.c и сохраним его. Теперь в каталог, где находится файл, поместим еще два файла:

С их помощью компилятор создаст (если нет ошибок в исходном тексте) файл драйвера устройства с именем test.sys. Смысл записей в этих файлах я объяснять не буду – это все есть в документации. Вы можете просто взять любую пару этих файлов из каталогов, куда помеще ны примеры, и изменить имя файла в sources следующим образом:

# The sources for the test device driver: TARGETNAME=test

TARGETPATH=obj TARGETTYPE=DRIVER INCLUDES=..\

После этого выберите консоль для запуска компилятора в среде Windows DDK, например, Windows XP Checked Build Environment и перейдите в каталог, где находятся ваши рабочие файлы. Затем наберите команду

Если в исходном тексте файла test.c нет ошибок, то файл будет откомпилирован успешно

Вид окна отладчика DebugView

Естественно, что для отладки драйвера можно использовать и другие отладчики, имею

щиеся в Интернете.

Таким образом, мы знаем, как написать и отладить простейший, ничего не делающий драйвер. Теперь посмотрим, каким образом можно считывать или записывать данные в уст ройство ввода вывода. Первое, что нужно определить при разработке такого драйвера – указать, в каких областях памяти должны находиться данные для записи чтения. Чтение за пись данных довольно сложные процедуры с точки зрения операций, которые выполняет опе рационная система, но мы рассмотрим упрощенный вариант обмена данными между данны ми и приложением.

Для обмена данными мы использовать метод буферизации, когда данные, которые долж ны быть переданы приложению или которые должны быть прочитаны, приложением предва рительно помещаются в специально выделенную системой область памяти (системный бу

фер) и только затем обрабатываются приложением или драйвером. Далее, мы должны выде лить для самого драйвера область памяти, где будут находиться прочитанные или записыва емые данные. Для относительно небольшого объема данных можно воспользоваться облас тью расширения устройства (Device Extension) – областью памяти, которая может быть выде лена драйверу при его создании и которая является неперемещаемой. Для того чтобы система могла выделить драйверу область памяти из расширения в исходный текст драйвера нужно внести некоторые изменения.

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

typedef struct _MY_DEVICE_EXTENSION

Здесь определена структура с одной 32 битовой целочисленной переменной L1. Посколь ку требуется всего 4 байта памяти, то система (гипотетически) могла бы выделить эти 4 байта, но, поскольку память выделяется блоками с учетом выравнивания для увеличения быстро действия, то, скорее всего, выделенный объем будет больше. Кроме того, при создании объекта устройства в функции IoCreateDevice в качестве второго параметра должен зада ваться размер области расширения, например:

status = IoCreateDevice(DriverObject, sizeof(MY_DEVICE_EXTENSION),

Здесь вторым параметром функции IoCreateDevice является sizeof (MY_DEVICE_ EXTENSION).

Какие функции используются для операций записи чтения? Что касается приложения пользователя, то мы уже рассматривали этот вопрос. Напомню, что приложение может запи сать данные в дескриптор устройства с помощью функции WINAPI WriteFile(), а прочитать дан ные с помощью функции ReadFile(). Есть и универсальная функция DeviceIoControl(), позволя ющая выполнять как чтение, так и запись данных.

Для манипуляций с данными в драйвере устройства можно использовать одну из функций ядра вида RtlXXX. Очень часто используется функция RtlMoveMemory(), которая перемещает данные из системной области памяти в область памяти драйвера (при записи данных в уст ройство) и наоборот, из области памяти драйвера в системный буфер (при чтении данных из устройства).

При обмене данными приложения и устройства обычно используются пакеты запроса

IRP_MJ_READ, IRP_MJ_WRITE и IRP_MJ_DEVICE_CONTROL. При этом для драйвера должен быть указан тип обмена данными (буферизованный или небуферизованный) в функции DriverEntry. Во всех наших примерах мы будем использовать буферизованный обмен данны

ми, поэтому после успешного создания объекта устройства функцией IoCreateDevice нужно указывать оператор

Читайте также:  Windows не видит флешку с линукс

Еще один важный момент, касающийся операций ввода вывода (чтения записи): Нельзя пытаться выполнять какие либо операции с устройством в функции DriverEntry! Она вызыва ется системой единственный раз при инициализации драйвера устройства и после выполне ния будет выгружена из памяти! Все операции обмена данными в драйвере выполняются при поступлении пакетов запросов посредством соответствующих функций в массиве указателей IRP_MJ_XXX.

И, наконец, последнее перед тем, как перейти к практике – в наших последующих приме рах мы будем для обмена данными использовать функцию DeviceIoControl, для которой Ме неджер ввода вывода операционной системы формирует пакет IRP_MJ_DEVICE_CONTROL.

Источник: Магда Ю. С. Компьютер в домашней лаборатории. – М.: ДМК Пресс, 2008. – 200 с.: ил.

2.6 Отладка драйверов

2.6 Отладка драйверов

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

Если, например, разрабатывать драйвер под ОС Linux, то ситуация там может быть немного хуже: в этой ОС вообще нет какой-либо возможности отлаживать драйвера, кроме как воспользоваться отладчиком gdb. Но в таком случае надо перекомпилировать ядро системы специальным образом и станцевать еще несколько подобных танцев с бубном. Поэтому зачастую отладка сводится к вызову функций printk, которые в великом множестве раскиданы по всему ядру системы.

К счастью, хоть в этом Windows имеет преимущества. Для того, чтобы можно было отлаживать драйвера, отладчик должен сам работать в нулевом кольце защиты. Естественно, разработка такой программы является чрезвычайно сложной задачей, поэтому таких отладчиков на сегодняшний день известно всего два: WinDbg (поставляется с пакетом DDK) и SoftIce (входит в состав NuMega DriverStudio). SoftIce считается одним из лучших отладчиков для Windows всех типов. Это надежный, мощный и довольно удобный в использовании инструмент. SoftIce может применяться для различных целей: для отладки драйверов и приложений пользователя, для просмотра информации о системе и т.п. Мы рассмотрим, как применять SoftIce для отладки драйверов устройств.

Будучи установленным в Win98, SoftIce прописывает в Autoexec.bat строку вида: c:Progra

Т.е. SoftIce загружается после загрузки DOS и сам грузит Windows. При работе Windows SoftIce активизируется лишь при каком-нибудь системном исключении или в точке останова, заданной программистом в драйвере. Также вызвать SoftIce можно, нажав Ctrl+D. На экране появляется окно отладчика.

Пока окно SoftIce активно, вся деятельность ОС замирает; именно сейчас можно безболезненно отлаживать драйвера.

Окно SoftIce разбито на несколько окон. Обычно в центре видно окно кода, над ним – окно регистров процессора и в самом низу – окно сообщений. Перемещаться в пределах окна можно, используя клавиши управления курсором или мышь.

В самом низу окна SoftIce расположена командная строка. SoftIce не имеет графического интерфейса, и все команды управления отладчиком вводятся в командной строке. SoftIce имеет довольно неплохую систему помощи. Перечень команд выдается по команде help. Наверное, самая важная команда — это команда выхода из SoftIce. Для этого нужно нажать клавишу F5 или дать команду Х (регистр не имеет значения).

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

Но, естественно, программисту мало простого чтения сообщений, посланных драйвером. Для эффективной отладки любой программы надо установить точку останова (breakpoint), просмотреть значения регистров. К счастью, SoftIce предоставляет такую возможность.

Универсальной точкой останова является использование прерывания INT 3. Как и в ОС MS-DOS, в Windows INT 3 также является прерыванием отладки. Для этого в тексте драйвера, где необходимо установить breakpoint, необходимо вставить следующий код:

При этом присходит вызов прерывания INT 3.

Но по умолчанию SoftIce не реагирует на INT 3. Для того, чтобы по этому прерыванию активизировался отладчик, необходимо вызвать SoftIce и дать команду:

Теперь при вызове INT 3 произойдет этого кода в отладчике. Для отключения режима отладки по INT 3 следует дать команду SET I3HERE OFF.

После того, как наш драйвер в SoftIce, мы можем контролировать выполнение программы при помощи команд:

шаг на следующую строку в окне кода;

выполнить одну инструкцию процессора (трассировка);

перейти на указанный адрес;

продолжить выполнение программы (выход из SoftIce).

Если драйвер был скомпилирован в отладочной конфигурации, то на экране будет виден текст драйвера, написанный на С++.

Читайте также:  Windows copy newest file

SoftIce также может просматривать значения переменных пользователя. Для того, чтобы открыть/закрыть окно просмотра переменных (Watch), надо дать команду WW или нажать Alt+F4. Добавить/убрать переменную для просмотра можно при по– мощи команды WATCH.

Это основные команды, применяемые для отладки драйверов устройств в SoftIce. А в общем, этот отладчик имеет огромное количество функциональных возможностей и его полное описание пославляется с программой и занимает порядка двухсот страниц.

Надеюсь, это руководство было для Вас интересно. Если даже не интересно — то, надеюсь, Вы узнали что-то новое для себя.

Зайти на мою домашнюю страничку

С уважением — Александр Тарво.

Читайте также

Отладка

Отладка Один из худших сеансов отладки за всю мою карьеру случился в 1972 году. Терминалы, подключенные к бухгалтерской системе профсоюза грузоперевозчиков, зависали один-два раза в день. Сознательно воспроизвести ошибку было невозможно. Ошибка не отдавала предпочтений

Типы драйверов

Типы драйверов Драйверы различаются по возможностям, которые они предоставляют, а также по тому, каким образом обеспечивается к ним доступ и управление. Можно рассматривать три основные типа драйверов: Символьные драйверы Этот тип драйверов обеспечивает работу с

1.7 Иерархия драйверов систем хранения и типы драйверов

1.7 Иерархия драйверов систем хранения и типы драйверов Как описывалось в предыдущем разделе, Windows NT основана на архитектуре, в которой драйверы формируют многоуровневую иерархию. Преимущество такой архитектуры состоит в расширяемости архитектуры и возможности

Установка драйверов

Установка драйверов Если вы думаете, что сразу же после установки Windows вы можете начинать работу – вы крупно ошибаетесь. И когда после многочисленных перезагрузок и настроек ваши глаза узреют ласковый пейзаж Рабочего стола Windows – не спешите устанавливать программы. Пока

Обновление драйверов устройств

Обновление драйверов устройств Чтобы обновить драйвер устройства, нажмите кнопку Обновить. В результате на экране откроется окно, изображенное на рис. 3.13. Рис. 3.13. Обновление драйвераВы можете выполнять обновление драйвера как в ручном, так и в автоматическом режиме

2.2.11. Отладка CGI

2.2.11. Отладка CGI Страницу HTML с результатом, сгенерированную по запросу мы модем увидеть выполнив CGI приложение. Для этого требуется (персональный) Web сервер. По этому я написал небольшую программу отладки, используя Delphi 2.01 и NetManage HTML

4-й шаг. Отладка

4-й шаг. Отладка По мере усложнения программ вероятность появления ошибок в работе (ошибок выполнения) растет экспоненциально. После обнаружения такой ошибки главной задачей становится выявление причины ошибки и устранение проблемы. Одним словом, это отладка.В небольших

5.1.7. Отладка

5.1.7. Отладка Команда ipcs выдает информацию о взаимодействии процессов, включая сведения о совместно используемых сегментах (для этого следует задать флаг -m). Например, в показанном ниже случае сообщается о том, что используется один такой сегмент, с номером 1627649:% ipcs -m———

Отладка

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

8.4. Отладка

8.4. Отладка Когда программа не делает того, чего от нее ждут, главной проблемой становится отыскание ошибки (или ошибок). Всегда легче найти ошибку в какой-нибудь части программы (или в отдельном модуле), чем во всей программе. Поэтому следует придерживаться следующего

Ошибки драйверов

Ошибки драйверов Пожалуй, одной из главных причин, приводящей к нестабильности работы Windows ХР, является недостаточно продуманное и небезопасное использование драйверов установленных и подключенных устройств. Чаще всего это касается драйверов принтера и

Ошибки драйверов

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

Отладка

Отладка Инструкция отладки является средством условной компиляции. Она записывается так:debug instruction; instruction; . endВ файле управления (Ace-файле) для каждого класса можно включить или отключить параметр debug. При его включении все инструкции отладки данного класса выполняются,

Установка драйверов

Установка драйверов Теперь подробно разберем то, что нужно сделать при проверке кабеля в магазине, а затем и при подключении телефона к своему домашнему компьютеру.Подключение телефона к компьютеру проще всего начать с чтения «Руководства пользователя» к data-кабелю или

Установка драйверов

Установка драйверов Что делать теперь? Теперь вставьте диск с драйверами от материнской платы и установите их. Обычно при этом будут установлены драйверы звуковой, сетевой платы и некоторые дополнительные драйверы.В процессе установки драйверов потребуется

Обновление драйверов

Обновление драйверов Установка последних версий драйверов – эффективное средство для повышения стабильности работы компьютера и устранения неполадок. Существуют два основных способа обновления драйверов: использование службы обновления Windows Vista и поиск на сайте

Оцените статью