
Приложение G
Использование отладчика Turbo Debugger с различными языками
-----------------------------------------------------------------

     В этом  приложении  собраны  некоторые  советы  по  наиболее
эффективному использованию отладчика Turbo Debugger  с различными
языками программирования.

Советы по отладке программ на языке Turbo C
-----------------------------------------------------------------

Оптимизация кода компилятором   ---------------------------------

     Если вы используете параметр -O командной строки  при работе
с  компилятором TCC или команду Options/Compiler/Optimization при
работе с интегрированной средой  разработки  для  задания  режима
генерации   оптимизированного   кода,   у  вас  могут  возникнуть
трудности при  пошаговой  отладке  отдельных  участков  исходного
текста программы. В частности, если в программе имеются вложенные
операторы if/else или несколько таких  операторов,  то  остановка
программы  при  проходе  каждого  оператора  else может оказаться
затруднительной.  Цикл  "for"  также  переформировывается   таким
образом,  что  в  некоторых  случаях  при  его  трассировке могут
возникнуть некоторые затруднения.

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

Доступ к ссылочным данным   -------------------------------------

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

     char *p, buf[80];
     for (p = buf; p < buf + sizeof(buf); p++) {
          ...
     }

     можно проверить  переменную  p  как массив символов,  выбрав
команду Range из локального меню окна проверки и введя в качестве
начального индекса 0, а в качестве числа элементов 80.

Пошаговая отладка сложных выражений    --------------------------

     Если имеется сложное выражение, например,

     if (isvalid(x)  && luseless(x)) {
          ...
     }

     может потребоваться      проверить     результат     каждого
подвыражения,  входящего в состав  данного  условного  выражения.
Если в выражении имеются вызовы функций, это можно сделать, начав
трассировку функции по клавише F7,  а затем  поместив  курсор  на
закрывающую  скобку  }  в конце данной функции и нажав клавишу F4
для того,  чтобы выполнить функцию до данной точки. Затем следует
выбрать команду Data/ Function Return,  чтобы проверить значение,
которое  будет  возвращено  данной  функцией.  Если  в   условном
выражении имеются другие вызовы функций, после этого можно нажать
клавишу  F7,  чтобы  остановить  выполнение  на   первой   строке
следующей  функции,  входящей  в условное выражение.  Затем можно
повторить  описанную   процедуру   для   проверки   возвращаемого
значения.

     Если имеется   сложное   выражение,  не  содержащее  вызовов
функций, например,

     if (x <= 5 && y[z] > 8) {
          ...
     }

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

Советы по отладке программ на языке Turbo Assembler
-----------------------------------------------------------------

Просмотр строк шестнадцатиричных данных   -----------------------

     Для просмотра построчного  шестнадцатиричного  дампа  памяти
можно  использовать команды Data|add Watch и Data|Evaluate/Modify
с модификатором формата, например, команда

     [ES:DI],20m

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

Отладка на уровне исходного текста   ----------------------------

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

     В некоторых   случаях   может   потребоваться   одновременно
просматривать исходный код  и  состояние  процессора.  Для  этого
следует открыть окно процессора, а затем в локальном меню подокна
кода установить параметр Mixed в состояние  "both"  (оба).  Таким
образом вы сможете одновременно просматривать как исходный текст,
так и байты машинного кода.  Если требуется  просматривать  байты
машинного  кода,  не  забудьте  увеличить размер окна процессора,
нажав клавишу F5.

Проверка и изменение значений регистров   -----------------------

     Наиболее очевидный  способ   изменения   значения   регистра
состоит  в его выделении курсором либо в окне процессора,  либо в
окне  регистров.  Наиболее  быстрый  способ  изменения   значения
регистра - это использование команды F10/Data/Evaluate/Modify. Вы
можете  ввести  выражение,  выполняющее   присваивание,   которое
непосредственно   модифицирует   содержимое  регистра,  например,
выражение

     SI=99

загрузит в регистр SI число 99.

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

     Alt-D E AX

отобразит значение регистра AX.

Советы по отладке программ на языке Turbo Pascal
-----------------------------------------------------------------

Пошаговое выполнение кода инициализации   -----------------------

     При загрузке программы  в  отладчик  Turbo  Debugger  маркер
выполнения    (стрелка,   направленная   вправо)   указывает   на
зарезервированное   слово   begin   в   основной   программе.   В
действительности   оператор  begin  соответствует  серии  вызовов
разделов инициализации всех модулей, которые использует программа
(предполагается,  что они имеют код инициализации). Все программы
начинаются с вызова кода инициализации модуля System.

     Если в этой точке вы нажмете F7  (активную  клавишу  команды
Run/Trace  Into),  вы  попадете  в  первый  модуль,  имеющий  код
инициализации,  который был скомпилирован в  режиме  формирования
информации   для  отладки.  Если  вы  нажмете  клавишу  F7  после
прохождения слова  end  кода  инициализации  первого  модуля,  вы
попадете  в  следующий  модуль.  В  конце  концов  вы вернетесь в
главную программу и сможете выполнить ее первый оператор.

     Если же в начале программы вы нажмете F8  (активную  клавишу
команды  Run/Step  Over),  вы  пропустите  выполнение  всего кода
инициализации  и  начнете  пошаговое  выполнение  тела   основной
программы.

Пошаговое выполнение процедур выхода   --------------------------

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

Константы   -----------------------------------------------------

     Идентификаторы констант  распознаются  только для числовых и
типизованных констант, например,

     program Test;
     const
       A = 5;
       B = Pi;
       Message = 'Testing';
       Caps = ['A'..'Z'];
       Digits : string[10] = '0123456789';
     begin
       Writeln(A);
       Writeln(B);
       Writeln(Message);
       Writeln('A' in Caps);
       Writeln(Digits);
     end.

     В этой  программе вы можете проверить A (числовую константу)
и Digits (типизованную константу),  однако не можете проверить  B
(константу   с  плавающей  точкой),  Message  и  Caps  (строковую
константу и константу-множество).

Промежуточные строки и множества в стеке   ----------------------

     Если вы используете окно  процессора,  имейте  в  виду,  что
Turbo  Debugger  автоматически  размещает  промежуточные строки и
множества в стеке. Он делает это следующим образом.

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

Искусное преобразование типов   ---------------------------------

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

     program Typecast;
     uses Dos;
     var
       TextFile : Text;
       IntFile : file of Integer;
     begin
       Assign(TextFile, 'TEXT.DTA');
       Rewrite(TextFile);
       Assign(IntFile, 'INT.DTA');
       Rewrite(IntFile);
       Close(TextFile);
       Close(IntFile);
     end.

     Теперь занесите в окно слежения следующие четыре выражения:

     IntFile
     TextFile
     FileRec(IntFile),r
     TextRec(TextFile),r

     Первые два   выражения  будут  показывать  состояния  файлов
(CLOSED,  OPEN,  INPUT, OUTPUT) и имена дисковых файлов, а вторые
два   используют   преобразование   типа   для  отображения  имен
внутренних полей и значений файловых переменных.

Советы по использованию окна процессора для программ на Паскале
-----------------------------------------------------------------

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

     - Для  ряда  подпрограмм  ввода/вывода,  например  ReadLn  и
WriteLn, часто формируется несколько вызовов на языке ассемблера.

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

     - Ряд операций (умножение значений типа logint, конкатенация
строк   и   др.)   реализуется  посредством  вызова  библиотечных
подпрограмм.

     - Литеральные  константы  (строки,  множества  и   числа   с
плавающей   точкой)   процедуры   помещаются   в   сегмент   кода
непосредственно перед точкой входа в процедуру.
