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

MS-DOS для программиста

© Александр Фролов, Григорий Фролов
Том 18, М.: Диалог-МИФИ, 1995, 254 стр.

[Назад] [Содеожание] [Дальше]

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

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

Прикладная программа не вызывает драйвер напрямую, а делает это через функции прерывания MS-DOS, поэтому вам придется очень долго "добираться" до программы прерывания драйвера. Малейшие ошибки в программе инициализации могут привести к невозможности завершения загрузки операционной системы.

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

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

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

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

В листинге 6.2 вы найдете исходный текст функции ntrace, а также исходный текст небольшой com-программы, которая вызывает эту функцию.


Листинг 6.2. Файл ntrace\ntrace.asm


@@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

  .MODEL tiny
  .CODE
  .STARTUP
  
  mov ax, 1234h
  mov bx, 5678h
  call ntrace

  .EXIT 0

;==============================================
; Функция выводит на экран содержимое
; всех регистров и приостанавливает выполнение
; программы до тех пор, пока пользователь не
; нажмет на любую клавишу.
; После возвращения из процедуры
; все регистры восстанавливаются.
;==============================================
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 аt address ','$'
hit_msg db 13,10,'Press 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

;==============================================
; Преобразование байта в два символа
; AL - преобразуемый байт
; DX - его символьное представление
;==============================================
Byte_to_hex proc near
  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

Для ассемблирования и редактирования этой программы используйте пакетный файл, приведенный в листинге 6.3.


Листинг 6.3. Файл ntrace\mk.bat


tasm ntrace
tlink ntrace /t

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

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

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

push	ax
mov	ax,0
int	16h
pop	ax

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

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

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

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

И еще одно замечание.

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

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

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

[Назад] [Содеожание] [Дальше]