Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Операционная система MS-DOS

© Александр Фролов, Григорий Фролов
Том 1, книги 1-2, М.: Диалог-МИФИ, 1991.

[Назад] [Содеожание]

6.8. Особенности отладки драйверов

Драйверы достаточно сложны для отладки. Это связано прежде всего с тем, что Вы не сможете использовать такие отладчики, как CodeView. На этапе инициализации драйвера (при выполнении команды инициализации) загрузка операционной системы еще не завершена, и воспользоваться обычным отладчиком невозможно.

Прикладная программа также не вызывает драйвер напрямую, а делает это через прерывания DOS. Отладчик CodeView не позволит Вам трассировать прерывание 21h, даже если Вы и сможете это сделать при помощи другого отладчика (например, отладчик Advanced Fullscreen Debugger фирмы IBM позволяет трассировать операционную систему), Вам придется очень долго "добираться" до программы прерывания Вашего драйвера.

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

Можно использовать специально подготовленную системную дискету, записать на нее отлаживаемый драйвер и загрузить операционную систему с дискеты. Если произойдет зависание системы, загрузите DOS с жесткого диска.

Можно порекомендовать следующую методику отладки драйвера.

Программа стратегии обычно очень проста и проблем не вызывает.

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

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

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

;==========================================
; Процедура выводит на экран содержимое
; всех регистров и ожидает нажатия на
; любую клавишу.
; После возвращения из процедуры
; все регистры восстанавливаются.

ntrace proc near

; Сохраняем в стеке регистры,
; содержимое которых будет изменяться

     pushf
     push ax
     push bx
     push cx
     push dx
     push ds
     push bp

     push cs
        pop  ds

        mov bp,sp

; Выводим сообщение об останове

          mov dx,offset cs:trace_msg
          @@out_str

; Выводим содержимое всех регистров

          mov ax,cs        ; cs
       call Print_word
          @@out_ch ':'
       mov ax,[bp]+14   ; ip
       call Print_word

          @@out_ch 13,10,13,10,'A','X','='
       mov ax,[bp]+10
       call Print_word

          @@out_ch ' ','B','X','='
       mov ax,[bp]+8
       call Print_word

          @@out_ch ' ','C','X','='
       mov ax,[bp]+6
       call Print_word

          @@out_ch ' ','D','X','='
       mov ax,[bp]+4
       call Print_word

          @@out_ch ' ','S','P','='
       mov ax,bp
          add ax,16
       call Print_word

          @@out_ch ' ','B','P','='
       mov ax,[bp]
       call Print_word

          @@out_ch ' ','S','I','='
       mov ax,si
       call Print_word

          @@out_ch ' ','D','I','='
       mov ax,di
       call Print_word

          @@out_ch 13,10,'D','S','='
       mov ax,[bp]+2
       call Print_word

          @@out_ch ' ','E','S','='
       mov ax,es
       call Print_word

          @@out_ch ' ','S','S','='
       mov ax,ss
       call Print_word

          @@out_ch ' ','F','='
       mov ax,[bp]+12
       call Print_word

          lea dx,cs:hit_msg
          @@out_str

; Ожидаем нажатия на любую клавишу

          mov ax,0
       int 16h

; Восстанавливаем содержимое регистров

       pop bp
       pop ds
       pop dx
       pop cx
       pop bx
       pop ax
       popf

       ret

trace_msg db 13,10,'>---- BREAK ----> At address ','$'
hit_msg db 13,10,'Hit any key...','$'

ntrace endp

;==========================================
; Процедура выводит на экран содержимое AX

Print_word proc near

        push ax
     push bx
     push dx

     push ax
     mov cl,8
     rol ax,cl
     call Byte_to_hex
     mov bx,dx
        @@out_ch bh
        @@out_ch bl

     pop ax
     call Byte_to_hex
     mov bx,dx
        @@out_ch bh
        @@out_ch bl

     pop dx
     pop bx
     pop ax
     ret
Print_word endp

Byte_to_hex proc near
;--------------------
; al - input byte
; dx - output hex
;--------------------
     push ds
     push cx
     push bx

     lea bx,tabl
     mov dx,cs
     mov ds,dx

     push ax
     and al,0fh
     xlat
     mov dl,al

     pop ax
     mov cl,4
     shr al,cl
     xlat
     mov dh,al

     pop bx
     pop cx
     pop ds
     ret

tabl db '0123456789ABCDEF'
Byte_to_hex endp

     end

Для вывода строки на экран в этой процедуре используется макро @@out_str и @@out_ch, которые определены в файле sysp.inc:

@@out_ch  MACRO c1,c2,c3,c4,c5,c6,c7,c8,c9,c10
                mov   ah,02h
                IRP   chr,<c1,c2,c3,c4,c5,c6,c7,c8,c9,c10>
                IFB   <chr>
                EXITM
                ENDIF
                mov   dl,chr
                int   21h
                ENDM
                ENDM

@@out_str MACRO
                mov   ah,9
                int   21h
                ENDM

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

Если у Вас есть отладчик Advanced Fullscreen Debugger, можно использовать его способность оставаться резидентным и вызываться по нажатию комбинации клавиш CTRL+ESC.

В интересующее Вас место драйвера поместите вызов прерывания 16h, ожидающий ввода с клавиатуры, например:

push    ax
mov     ax,0
int     16h
pop     ax

Можно сохранить в стеке и регистр флагов, если его изменение нежелательно.

После того, как драйвер повиснет на ожидании ввода, активизируйте отладчик, нажав комбинацию клавиш CTRL+ESC. Вы окажетесь в теле обработчика прерывания 16h. Выполняя программу по шагам, довольно скоро Вы достигнете выхода из этого обработчика - команды IRET. После выполнения команды IRET управление будет передано команде, следующей за командой int 16h. Эта команда (в приведенном примере - pop ax) принадлежит Вашему драйверу!

Используя известное теперь значение адреса заголовка запроса (регистры ES:BX), можно определить, какая команда выполняется драйвером, и просмотреть сам запрос.

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

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

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

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

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

[Назад] [Содеожание]