MS-DOS для программиста© Александр Фролов, Григорий ФроловТом 19, М.: Диалог-МИФИ, 1995, 253 стр. 3.12. Обработка критических ошибокОперационная система MS-DOS позволяет программам устанавливать собственный обработчик критических ошибок аппаратуры. Мы уже говорили о том, что вектор 0000h:0090h, соответствующий прерыванию INT 24h , содержит адрес обработчика критических ошибок. Этот обработчик получает управление от операционной системы, когда драйвер какого-либо устройства обнаруживает ошибку аппаратуры. Обратите внимание на то, что обработчик критических ошибок не вызывается при работе с диском через прерывания INT 25h или INT 26h. Тем более, он не вызывается при работе с диском на уровне прерывания INT 13h . При запуске программы операционная система MS-DOS копирует адрес обработчика в префикс сегмента программы PSP, а после завершения работы программы - восстанавливает его из PSP. Стандартный обработчик MS-DOS выводит на экран сообщение: Abort, Retry, Ignore, Fail? Если ваша программа должна сама обрабатывать ошибки аппаратуры, она может установить свой собственный обработчик критических ошибок. Анализ регистровКогда обработчик получает управление, регистры
процессора содержат информацию, необходимую для
определения причины и места появления ошибки:
Обработчик критических ошибок не должен пользоваться функциями MS-DOS с кодами, большими чем 0Ch (из-за того, что функции MS-DOS не реентерабельны). Программа обработки критических ошибок может вывести на экран сообщение об ошибке и запросить оператора о необходимых действиях. Ей разрешено также получить дополнительную уточняющую информацию об ошибке с помощью функции 59h прерывания INT 21h или узнать версию MS-DOS с помощью функции 30h этого же прерывания. Дополнительная информация об устройстве, в котором произошла ошибка, может быть получена с использованием адреса заголовка драйвера устройства, который передается операционной системой при вызове обработчика в регистрах BP:SI. Анализ стекаДля определения номера функции MS-DOS, в которой
произошла критическая ошибка,
программа-обработчик может выполнить анализ
стека. Когда обработчик получает управление,
стек имеет следующую структуру:
Выполнив анализ регистра AH, можно определить номер функции MS-DOS, при вызове которой произошла ошибка, а зная содержимое остальных регистров - и все параметры этой функции. Код действияПосле выполнения всех необходимых действий
программа обработки критических ошибок должна
возвратить в регистре AL код действия, которое
должна выполнить операционная система для
обработки данной ошибки:
При открытии файлов с помощью функции 6Ch программа может заблокировать вызов обработчика критических ошибок. Функции библиотеки Borland C++Для составления программы обработки критических ошибок вы можете воспользоваться языком ассемблера или функциями стандартной библиотеки Borland C++ с именами _dos_getvect , _dos_setvect , _chain_intr . Однако лучше всего использовать специально предназначенные для этого функции _harderr , _hardresume и _hardretn . _harderrФункция _harderr предназначена для установки нового обработчика критических ошибок, она имеет следующий прототип: void _harderr (void (far *handler)()); Параметр handler - указатель на новую функцию обработки критических ошибок. _hardresumeФункция _hardresume и описанная ниже функция _hardretn должны быть использованы в обработчике критических ошибок, установленном функцией _harderr . Функция _hardresume возвращает управление операционной системе, она имеет прототип: _hardresume (int result); Параметр result может иметь следующие значения (в
соответствии с необходимыми действиями):
Эти параметры описаны в файле dos.h. _hardretnФункция _hardretn возвращает управление непосредственно программе, передавая ей код ошибки, определяемый параметром функции error: void _hardretn (int error); При этом программа получает код ошибки error после возврата из вызванной ей функции MS-DOS. Если ошибка произошла при выполнении функции с номером, большим чем 38h, дополнительно устанавливается флаг переноса. Если номер функции был меньше указанного значения, в регистр AL записывается величина FFh. Функция обработки критических ошибокФункция обработки критических ошибок handler имеет следующие параметры: void far handler(unsigned deverror, unsigned errcode, unsigned far *devhdr); Первый параметр - код ошибки устройства. Он равен содержимому регистра AX при вызове обработчика прерывания INT 24h . Аналогично, параметр errcode соответствует содержимому регистра DI - код ошибки. Третий параметр devhdr - это указатель на заголовок драйвера устройства (передаваемый в регистрах BP:SI). Программа CRITERRДля демонстрации использования функций установки обработчика критических ошибок приведем программу, которая пытается создать каталог на диске А:. Эта программа сама обрабатывает критические ошибки, запрашивая у оператора информацию о необходимых действиях. Листинг 3.8. Файл criterr\criterr.cpp // Эту программу можно запускать только из командной // строки. При запуске из интегрированной среды // Borland C++ возможен конфликт с используемым в этих // средах обработчиком критических ошибок #include <stdio.h> #include <conio.h> #include <stdlib.h> #include <direct.h> #include <string.h> #include <dos.h> #include <bios.h> void far hhandler(unsigned deverr, unsigned doserr, unsigned far *hdr); void _bios_str(char *p); int main() { // Устанавливаем обработчик критических ошибок _harderr (hhandler); // Моделируем критическую ошибку. // Выполняем попытку создать каталог на диске А:. // Если мы "забудем" вставить в дисковод // дискету, будет вызван обработчик // критической ошибки printf("\nВставьте (или не вставляйте) " "дискету в дисковод A:" "\nи нажмите любую клавишу...\n"); getch(); // Создаем каталог if(mkdir ("a:\\test_ctl")) { printf("\nОшибка при создании каталога"); return(-1); } else { // Удаляем только что созданный каталог rmdir ("a:test_ctl"); } return 0; } // Новый обработчик критических ошибок #pragma argsused void far hhandler(unsigned deverr, unsigned doserr, unsigned far *hdr) { int ch; static char buf[200]; // Выводим сообщение о критической ошибке sprintf(buf,"\n\r" "\n\rКод ошибки устройтсва: %04.4X" "\n\rКод ошибки DOS: %d" "\n\r\n\r" "\n\rВыполняемые действия:" "\n\r 0 - повторить" "\n\r 1 - отменить" "\n\r 2 - завершить" "\n\r----> ?", deverr, doserr); _bios_str(buf); // Вводим ответ с клавиатуры ch = _bios_keybrd(_KEYBRD_READ) & 0x00ff; _bios_str("\n\r"); switch(ch) { case '0': // Пытаемся повторить операцию default: _hardresume (_HARDERR_RETRY); case '2': // Завершаем работу программы _hardresume (_HARDERR_ABORT); case '1': // Возврат в DOS с кодом ошибки _hardretn (doserr); } } // Программа для вывода строки символов на экран // с помощью функции BIOS 0Eh void _bios_str(char *ptr) { union REGS inregs, outregs; inregs.h.ah = 0x0e; for(; *ptr; ptr++) { inregs.h.al = *ptr; int86(0x10, &inregs, &outregs); } } |