
Глава 17
Отладка резидентных программ и драйверов устройств
--------------------------------------------------

     Turbo Debugger    2.0   позволяет   отлаживать   резидентные
программы и драйверы устройств,  так же как и обычные выполняемые
файлы. Turbo Debugger сам тоже может быть запущен как резидентная
программа, и вы параллельно сможете  выполнять  команды  DOS  или
другие программы.

     Turbo Debugger  2.0  имеет  три  новые  команды меню файлов,
специально предназначенные   для   использования   при    отладке
резидентных программ   и   драйверов   устройств.   Это   команды
File|Resident, File|Symbol Load и File|Table Relocate.

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

Что такое резидентная программа (TSR)
-----------------------------------------------------------------

     TSR означает   "terminate   and   stay   resident"   ("после
завершения остается   резидентной").   Резидентными    называются
программы, которые после завершения работы остаются в оперативной
памяти. Примерами  резидентных  программ  являются   SideKick   и
SuperKey; они   все   время  находятся  в  оперативной  памяти  и
активизируются при  нажатии  соответствующих   активных   клавиш.
Другие резидентные программы активизируются из программ, выдающих
соответствующие программные прерывания.  Turbo  С  имеет  функцию
geninterrupt, генерирующую такие программные прерывания.

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

     После завершения  временной  части   резидентной   программы
запускается функция   DOS,  которая  позволяет  части  .EXE-файла
оставаться резидентной  в  оперативной  памяти  после   окончания
программы -   отсюда  и  термин  "terminate  and  stay  resident"
("после завершения  остается   резидентной").   Временная   часть
резидентной программы знает размер резидентной части,  а также ее
адрес в памяти,  и передает эту информацию DOS.  Тогда DOS делает
соответствующий участок памяти неприкосновенным,  тогда как любая
другая, не защищенная таким образом область оперативной  памяти в
любой момент может быть затерта. Таким образом, резидентная часть
программы остается в памяти, а временная может быть удалена.

     Сложность отладки резидентной программы состоит в  том,  что
требуется отладить как временную, так и резидентную ее части. При
выполнении .EXE-файла единственный  выполняемый  код  -  это  код
временной части   резидентной   программы.  Поэтому  при  обычном
запуске Turbo Debugger,  с заданием имени файла,  вы увидите лишь
временную часть   заданной   программы,  а  именно  то,  как  она
инсталлирует резидентную  часть  и  соответствующие   обработчики
прерываний. Для  отладки  резидентной  части вы должны установить
точку останова  отладчика  и  сделать   резидентным   сам   Turbo
Debugger. Ниже это описано более подробно.

Отладка резидентной программы  ----------------------------------

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

     Ниже описан процесс отладки резидентной программы:

     1. Компилируйте  или ассемблируйте резидентную программу, не
забыв включить  информацию  о  символических  именах  (отладочную
информацию). Используйте  для  этого  параметры  командной строки
TASM /ZI, TCC -v или TPC /V.

     2. При необходимости компоновки  резидентной  программы  для
включения информации о символических именах используйте опцию /v.
Для помещения символической информации  в  отдельный  файл  можно
воспользоваться опцией TDSTRIP -s,  хотя этот файл не нужен, если
отлаживается .EXE-файл.

     3. Теперь загрузим резидентную программу в Turbo  Debugger и
запустим временную  ее  часть,  используя  для  этого  как обычно
команду Run|Run.  Отладьте временную часть программы, как обычно.
После того, как выполнение временной части завершено, резидентная
часть инсталлируется  в  оперативной  памяти.   Сложность   далее
заключается в отладки резидентной части.

     4. Установите точку останова в начале резидентной части кода
при помощи F2.  При желании точки останова могут быть установлены
и в других частях резидентной части программы.

     5. Для того,  чтобы сделать резидентным сам Turbo Debugger ,
выберите команду  File|Resident.  Это  не   имеет   отношения   к
резидентности отлаживаемой   программы;   последняя  делает  себя
резидентной сама, при выполнении ее в Turbo Debugger, так же, как
и при  запуске из командной строки.  Причина,  заставляющая иметь
Turbo Debugger в качестве резидентной программы,  состоит в  том,
что это позволяет вернуться в DOS и оттуда запустить отлаживаемую
резидентную программу и начать выполнение ее резидентной части.

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

     7. Когда программа доходит до точки останова, Turbo Debugger
перехватит управление,  а  отлаживаемая  программа   окажется   в
соответствующем окне. Теперь вы можете начать отладку резидентной
части кода.  (Можно повторить вход в Turbo Debugger  из  DOS  при
помощи двойного нажатия Ctrl-Break).

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

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

     Для того, чтобы воспользоваться данным методом,

     1. Выполните  шаги  1  и 2 первого метода для компиляции или
ассемблирования вашего  кода,  также  для  того,  чтобы  вырезать
оттуда таблицу  символических  имен  и  поместить ее в .TDS-файл.
Если это  необходимо  для  вашей  прикладной   программы,   также
запустите TDSTRIP  с  опцией -c,  чтобы преобразовать резидентную
программу из .EXE-файла в .COM-файл.

     2. Запустите резидентную программу из командной  строки DOS,
введя для этого ее имя. Например, если ваша резидентная программа
называется TSR.EXE,  введите по приглашению  DOS  TSR  и  нажмите
Enter.

     3. Запустите   TDMEM,  чтобы  получить  карту  распределения
оперативной памяти  компьютера.  Отметьте  адрес  сегмента,  куда
загружена резидентная  часть  вашей программы.  Мы будем называть
этот сегмент Seg.

     4. Затем вам необходимо  определить  размер  памяти  таблицы
символических имен,  которую  Turbo  Debugger должен распределять
при его  запуске.  Для  этого  отметьте  размер   файла   таблицы
символических имен   вашей   резидентной  программы  (.TDS-файл),
выполнив для этого команду DOS DIR.
     Данный размер  представляет  собой  нижнюю  границу  размера
памяти таблицы   символических   имен,   которая   должна    быть
распределена при   загрузке  Turbo  Debugger,  поскольку,  помимо
хранимой здесь информации,  Turbo Debugger при  загрузке  таблицы
символических имен  создает еще некоторое число таблиц, временных
переменных и т.д.  Полезно распределять хотя бы  в  полтора  раза
больше памяти,  чем  занимает  .TDS-файл  на  диске,  хотя иногда
памяти требуется  больше,  а  иногда  достаточно  меньше.   Turbo
Debugger сообщает    вам,   если   таблице   символических   имен
распределено слишком мало памяти,  "Not  enough  memory  to  load
symbol table",  поэтому  с  командой  File|Symbol  Load  (которая
обсуждается тиже) нужно поэкспериментировать.

     5. Загрузите  Turbo  Debugger,   не   задавая   имя   файла,
распределив при    помощи    параметра   командной   строки   -sm
соответствующее количество памяти для таблицы символических имен.
Параметр -sm   задает  в  килобайтах  размер  распределяемой  для
таблицы символических имен  памяти.  Например,  если  вы  желаете
зарезирвировать для  таблицы  символических  имен 3К,  введите TD
-sm3 по приглашению DOS. При загрузке Turbo Debugger не задавайте
имя файла, поскольку то, что вы собираетесь отлаживать, и так уже
находится в оперативной памяти.  Исходные файлы и .TDS-файлы  для
отлаживаемой резидентной программы должны находиться в директории
по умолчанию, чтобы соответствующая символическая информация была
доступна отладчику.

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

     7. При загрузке Turbo Debugger уберите загрузочное сообщение
нажатием Esc,  загрузите  таблицу  символических имен резидентной
программы командой File|Symbol Load,  задав  соответствующее  имя
таблицы символических  имен.  При получении сообщения о том,  что
для загрузки  таблицы  символических  имен  не  хватает   памяти,
выйдите из  Turbo Debugger и перезапустите его по приглашению DOS
с большим значением аргумента -sm.

     8. Таблица символических имен содержит  набор  символических
имен, привязанных  к  относительным  адресам  памяти вашего кода.
Символическим именам  в   этой   таблице   предшествуют   символы
#имя_файла#, где  имя_файла  это  имя исходного файла резидентной
программы. Например, если ваш исходный файл называется TSR.ASM, и
содержит метку  Intr,  то  символическое имя #TSR#INTR обозначает
пдрес памяти.
     Символические имена  в  таблице  смещены  друг  от  друга на
необходимое число   байтов,   но   абсолютный    адрес    первого
символического имени не определен,  поскольку DOS может загрузить
символическое имя в адрес,  отличный от адреса, используемого при
ассемблировании. Поэтому   вы  должны  использовать  команду  для
явного определения адреса первого символического имени в памяти.

     9. Используйте команду  File|Table  Relocate  для  помещения
первого символического  имени  из  таблицы  символических  имен в
память. Таким образом, символическая информация в отладчике будет
соответствовать вашему коду.  Для этого по запросу Turbo Debugger
задайте адрес сегмента Seg вашей резидентной  программы,  который
был определен в TDMEM.
     Дизассемблированные операторы из памяти  синхронизируются  с
информацией из таблицы символических имен.  При наличии исходного
файла исходные операторы из  этого  файла  печатаются  в  той  же
строке, что и информация из таблицы символических имен.

     10. Для  перехода к сегменту оперативной памяти, содержащему
резидентную программу,  используйте команду  Goto  (Ctrl-G).  Для
этого задайте  адрес  сегмента  резидентной  программы,  а  затем
смещение 0000H, либо перейдите к конкретной символической метке в
коде.

     Далее все выполняется,  как и для первого метода,  начиная с
шага 4.

Что такое драйвер устройства
-----------------------------------------------------------------

     Драйверы устройств - это набор подпрограмм, используемых DOS
для управления    функциями    ввода/вывода    низкого    уровня.
Инсталлируемые драйверы  устройств  (по  сравнению  с встроенными
драйверами DOS) устанавливаются путем вставки в  файл  CONFIG.SYS
строк типа

     device = clock.sys

     Когда DOS  должен  выполнить  операцию  ввода/вывода  одного
символа, она сканирует скомпонованный список заголовков устройств
в поисках   устройства   с   соответствующим   логическим  именем
(например, COM1).  В  случае  драйверов   устройств,   работающих
поблочно, DOS следит за тем,  сколько таких устройств установлено
в системе,  и назначает каждому из них букву,     A  для  первого
драйвера блочного  устройства,  B  для  второго,  и  т.д.  Когда,
например, вы обращаетесь к дисководу С,  например, DOS знает, что
должен быть вызван драйвер третьего блочного устройства.

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

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

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

     Проблема с отладкой драйверов устройств состоит в том, что в
данном случае  выполняемый  .EXE-файл отсутствует,  поскольку для
правильной работы  драйвер  должен  устанавливаться  при   помощи
команды DEVICE = ДРАЙВЕР.РАСШИРЕНИЕ,  где .РАСШИРЕНИЕ - это .SYS,
.COM или .BIN.  Это означает, что отлаживаемый драйвер устройства
уже находится в оперативной памяти до запуска отладчика,  как это
требуется для  правильной  работы   драйвера.   Поэтому   большое
значение имеют    функции    загрузки    и   перемещения   таблиц
символических имен,  поскольку  они   позволяют   восстанавливать
символическую информацию  в  дизассемблированном сегменте памяти,
куда загружается драйвер устройства. Кам мы увидим далее, полезно
использовать команду File | Resident.

Отладка драйвера устройства   -----------------------------------

     Ниже показано,  как отлаживать драйверы устройств при помощи
TDREMOTE:

     1. Компилируйте или  ассемблируйте  драйвер  устройства,  не
забыв  включить  информацию  о  символических  именах (отладочную
информацию).  Используйте для этого  параметры  командной  строки
TASM /ZI, TCC -v или TPC /V.

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

     3. Введите TDSTRIP -s -c имя_файла,  где имя_файлп - это имя
отлаживаемого    драйвера,    чтобы   вырезать   оттуда   таблицу
символических имен  и  поместить  ее   в   .TDS-файл,   а   также
преобразовать существующий .EXE-файл в .COM-файл.

     TDSTRIP -s -c имя_файла

     где имя_файла  -  это имя отлаживаемого драйвера устройства.
Скопируйте .COM-файл  на удаленную систему.

     4. Модифицируйте файл CONFIG.SYS удаленной  системы, добавив
туда строку

     device = имя_файла.COM

     5. Убедитесь,   что  в  имени_файла  правильно  указан  путь
доступа к драйверу устройства.

     6. Перезпгрузите удаленную систему для того,  чтобы  драйвер
устройства был загружен.

     7. Запустите  TDDEV,  чтобы  узнать адрес в памяти удаленной
системы, куда DOS  загрузмла  ваш  драйвер  устройства.  Заметьте
адрес, в который загружен драйвер.  Сегментную часть этого адреса
мы будем обозначать как Seg.

     8. Затем вам необходимо  определить  размер  памяти  таблицы
символических  имен,  которую  Turbo Debugger должен распределять
при  его  запуске.  Для  этого  отметьте  размер  файла   таблицы
символических   имен   вашего  драйвера  устройства  (.TDS-файл),
выполнив для этого команду DOS DIR.
     Данный размер  представляет  собой  нижнюю  границу  размера
памяти таблицы   символических   имен,   которая   должна    быть
распределена при   загрузке  Turbo  Debugger,  поскольку,  помимо
хранимой здесь информации,  Turbo Debugger при  загрузке  таблицы
символических имен  создает еще некоторое число таблиц, временных
переменных и т.д.  Полезно распределять хотя бы  в  полтора  раза
больше памяти,  чем  занимает  .TDS-файл  на  диске,  хотя иногда
памяти требуется  больше,  а  иногда  достаточно  меньше.   Turbo
Debugger сообщает    вам,   если   таблице   символических   имен
распределено слишком мало памяти,  "Not  enough  memory  to  load
symbol table",  поэтому  с  командой  File|Symbol  Load  (которая
обсуждается тиже) нужно поэкспериментировать.

     9. Загрузите на удаленной системе TDREMOTE.

     10. Загрузите Turbo  Debugger,   не   задавая   имя   файла,
распределив при    помощи    параметра   командной   строки   -sm
соответствующее количество памяти для таблицы символических имен.
Параметр -sm   задает  в  килобайтах  размер  распределяемой  для
таблицы символических имен  памяти.  Например,  если  вы  желаете
зарезирвировать для  таблицы  символических  имен 3К,  введите TD
-sm3 по приглашению DOS. При загрузке Turbo Debugger не задавайте
имя файла, поскольку то, что вы собираетесь отлаживать, и так уже
находится в оперативной памяти.  Исходные файлы и .TDS-файлы  для
отлаживаемого драйвера устройства  должны находиться в директории
по умолчанию, чтобы соответствующая символическая информация была
доступна отладчику.

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

     12.При загрузке Turbo Debugger уберите загрузочное сообщение
нажатием Esc,   загрузите  таблицу  символических  имен  драйвера
устройства командой File|Symbol Load, задав  соответствующее  имя
таблицы символических  имен.  При получении сообщения о том,  что
для загрузки  таблицы  символических  имен  не  хватает   памяти,
выйдите из  Turbo Debugger и перезапустите его по приглашению DOS
с большим значением аргумента -sm.

     13.Таблица символических имен содержит  набор  символических
имен,  привязанных  к  относительным  адресам памяти вашего кода.
Символическим  именам  в  этой   таблице   предшествуют   символы
#имя_файла#,  где  имя_файла  это  имя  исходного  файла драйвера
устройства Например, если ваш исходный файл называется TSR.ASM, и
содержит  метку  Intr,  то символическое имя #TSR#INTR обозначает
пдрес памяти.
     Символические имена  в  таблице  смещены  друг  от  друга на
необходимое число   байтов,   но   абсолютный    адрес    первого
символического имени не определен,  поскольку DOS может загрузить
символическое имя в адрес,  отличный от адреса, используемого при
ассемблировании. Поэтому   вы  должны  использовать  команду  для
явного определения адреса первого символического имени в памяти.

     14. Используйте команду  File|Table Relocate  для  помещения
первого  символического  имени  из  таблицы  символических имен в
память. Таким образом, символическая информация в отладчике будет
соответствовать вашему коду.  Для этого по запросу Turbo Debugger
задайте адрес сегмента Seg вашего  драйвера  устройства,  который
был определен в TDMEM.
     Дизассемблированные операторы из памяти  синхронизируются  с
информацией из таблицы символических имен.  При наличии исходного
файла исходные операторы из  этого  файла  печатаются  в  той  же
строке, что и информация из таблицы символических имен.

     15. Установите в вашем коде необходимые точки останова.

     16. Для того, чтобы сделать резидентным сам Turbo Debugger ,
выберите  команду  File|Resident.  Это  не  имеет   отношения   к
резидентности   отлаживаемого  драйвера;  последний  делает  себя
резидентной  сам,  при  загрузке  удаленной  системы,  вследствие
команды  device  в  файле CONFIG.SYS удаленной системы.  Причина,
заставляющая  иметь  Turbo  Debugger   в   качестве   резидентной
программы,  состоит  в  том,  что это позволяет вернуться в DOS и
оттуда выполнить действия по запуску драйвера устройства.

     17. Когда вы вернетесь к  командной  строке  DOS  уддаленной
системы, сделайте   все   необходимое  для  активизации  драйвера
устройства. Например,  пошлите информацию на  управляемое  данным
драйвером устройство.

     18. Когда   программа   доходит  до  точки  останова,  Turbo
Debugger перехватит управление, а отлаживаемый драйвер окажется в
соответствующем  окне.  Теперь вы можете начать отладку его кода.
(Можно повторить вход в Turbo Debugger из DOS при помощи двойного
нажатия Ctrl-Break).


Конец сеанса отладки
-----------------------------------------------------------------

     Для того,  чтобы  завершить сеанс отладки,  выйдите из Turbo
Debugger обычным образом, выбрав команду File|Quit или нажав Alt-
X. При  отладке  резидентной  программы  она  будет автоматически
выгружена.

