Глава 3. Введение в Turbo Debugger
I
Отладчик фирмы Borland - это весьма мощное средство отладки программ. Этот отладчик разрабатывался еще для DOS-программирования и ориентирован в основном на языки фирмы Borland. Существенно то, что отладчик позволяет отлаживать программу как на уровне дизассемблированных команд микропроцессора, так и на символьном уровне, т.е. с использованием текста программы. В последнем случае требуется, чтобы при трансляции в исполняемый модуль была помещена отладочная информация.
Рассмотрим, например, программу на Рис. 3.4.1. Эта программа выводит в окно типы устройств (список доступных дисков). При трансляции с помощью TASM32 добавим также ключ /zi, а при компоновке (TLINK.32.EXE) ключ -v. В этом случае в исполняемом модуле будет сохранена информация, необходимая для символьной отладки.
Тут важно иметь в виду, что для символьной отладки, т.е. с использованием текста программы, необходим не только сам исполняемый модуль и отладочная информация в нем, но и сам программный текст. Дело в том, что в исполняемом модуле хранится информация, позволяющая сопоставлять машинные коды программ и текст программы. На Рис. 4.3.1 представлено окно отладчика с загруженной отладочной информацией программы DRIV.ASM (Рис. 3.4.1). Отладчик позволяет выполнять программу в пошаговом режиме (подробнее о режимах выполнения программы см. далее в главе), видя одновременно текст программы и дизассемблированный текст, и передвигаясь по нему, видеть результат каждого шага.
На Рис. 4.3.1 представлены три наиболее часто используемых окна отладчика: окно с текстом программы (модульное окно), окно CPU, где хранится дизассемблированный текст, а также текущая информация о регистрах и флагах, и окно сообщений, которое очень важно при отладке оконных GUI-приложений.
Рассмотрим команды отладчика и возможности отладчика.
Запуск отлаживаемого приложения. Выполняется по клавише F9 или по команде RUN из меню RUN. Программа выполняется в полном объеме, если только не указана точка останова (breakpoint) на строку в окне с текстом программы или окне CPU. Точка останова устанавливается при помощи клавиши F2. Открыв окно Watch (View/ Watches), Вы можете установить там слежение за переменными, которые Вам интересны. В этом случае точки останова окажутся очень полезными.
Выполнить программу до строки, где находится курсор. Команда выполняется при помощи клавиши F4 или посредством меню. Смысл данной команды заключается в том, что, заинтересовавшись каким-либо местом программы, Вы можете выполнить программу до данной строки и посмотреть результат выполнения. Фактически это та же точка останова, но работает более оперативно. Кроме того, можно заставить выполняться программу до данного адреса (Alt+F9).
Выполнить единичную команду. Команда выполняется по нажатию клавиши F7. Если мы находимся в окне с текстом программы, то выполняется оператор соответствующего языка. Если мы находимся в окне CPU, то выполняется инструкция микропроцессора.
Рис. 4.3.1. Окна Turbo Debugger.
Выполнение команды с переходом через процедуру. Данная команда выполняется по нажатию клавиши F8. Отличается от предыдущей команды тем, что не происходит вход в процедуру, но все инструкции в процедуре выполняются автоматически.
Выполнить процедуру. Если курсор находится на команде вызова процедуры, то можно выполнить лишь одну эту процедуру командой Alt+F8.
Выполнение с задержкой. Можно заставить отладчик выполнять программу с задержкой после каждой команды (Animation) - команда Animate меню Run.
При выполнении любой из перечисленных команд также могут быть заданы опции командной строки - Run/Arguments...
Рассмотрим теперь окна, которые используются при отладке в данном отладчике. С некоторыми из них мы уже познакомились, но все равно повторимся. Показать на экране то или иное окно можно посредством меню View. Мы опишем часть наиболее важных окон.
Текст программы можно увидеть на экране, обратившись к пункту меню Module. При этом программа должна быть оттранслирована с опциями, обеспечивающими сохранение в исполняемом модуле отладочной информации. К сожалению, речь идет только о продуктах фирмы Borland: C++, Delphi, Assembler. Отладочная информация других фирм Turbo Debugger не распознает. В дальнейшем мы рассмотрим пример отладки программы, написанной на Borland C++.
Если отладочную информацию в исполняемом модуле Turbo Debugger не распознает, Вам при
отладке придется использовать окно CPU. Окно разделено на пять частей (см. Рис. 4.3.2 против
часовой стрелки):
1. Инструкции микропроцессора.
2. Сегмент данных.
3. Сегмент стека.
4. Состояние регистров.
5. Основные флаги.
Рис. 4.3.2. Окно CPU отладчика Turbo Debugger.
Окно слежения за переменными. Окно открывается через View/Watches. Щелкнув правой кнопкой мыши, мы можем по желанию добавить в окно переменные, за значением которых мы хотим наблюдать. При пошаговом выполнении программы, либо при выполнении с точками останова можно на каждом этапе контролировать значение переменных.
Окно стека. Показывает текущее состояние стека. Причем первая вызванная функция будет находиться на дне стека.
Окно точек останова. Здесь содержится информация обо всех установленных в программе точках останова. Здесь же можно добавить или установить точки останова.
Окно регистрации (Log). В нем хранится информация о происходящих в отладчике событиях.
Окно переменных. Отображает все переменные, доступные в данном месте.
Окно файлов. В этом окне можно просмотреть двоичный файл и исправить его при необходимости.
Окно отображения памяти. Дает возможность построчного просмотра памяти.
Окно сопроцессора. Данное окно отображает текущее состояние сопроцессора.
Окно истории выполнения (Execution History). Окно содержит историю выполнения программы.
Окно иерархии (Hierarchy). Выводит на дисплей иерархическое дерево для всех объектов и всех типах классов, используемых в текущем модуле. Пример окна, отображающего иерархию классов объектов, см. на Рис. 4.3.3.
Рис. 4.3.3. Пример окна Turbo Debugger, отображающего иерархию классов.
Окно потоков. Данное окно содержит информацию обо всех потоках, работающих в данный момент в программе.
Окно сообщений. С помощью данного окна можно отслеживать все сообщения, получаемые указанным окном. На Рис. 4.3.4 представлен пример использования окна сообщений. Можно выделить класс отслеживаемых сообщений или задать единичные сообщения. Кроме отслеживания, можно задать и другую реакцию — прервать выполнение, т.е. установить точку останова на определенное сообщение.
Рис. 4.3.4. Пример содержимого окна сообщений
Окно буфера обмена. С помощью данного окна можно следить за содержимым буфера обмена при выполнении программы.
II
Поговорим теперь об отладке программ, написанных на языке высокого уровня. Если при трансляции в исполняемом модуле была сохранена отладочная информация, то Turbo Debugger будет работать и с языком высокого уровня. Рассмотрим, например, простую консольную программу, демонстрирующую пузырьковую сортировку. Программа располагается на Рис. 4.3.6.
Puc. 4.3.5. Программа, расположенная на Рис. 4.3.6 в окне отладчика.
#include <windows.h> #include <stdio.h> void sort(DWORD a[], DWORD ); void main() { DWORD a[10]; DWORD j,p,k,r; randomize(); for(j=0; j<10; j++) a[j]=random(10) ; // сортировка for(k=9; k>l; k--) { r=0; for(j=0; j<k; j++) { if(a[j]>a[j+1]){ p=a[j+1] ; a[j+1]=a[j] ; a[j]=p; r=1; }; } if(r==0) break; } for(j=0; j<10; j++) printf("%lu\n",a[j]); ExitProcess(0); }
Рис. 4.3.6. Пример простой консольной программы.
На Рис. 4.3.5 показано окно отладчика Turbo Debugger с данной программой. В нижней части рисунка расположено окно Watches. В этом окне отслеживается значение элементов массива а[]. Обратившись к окну CPU, можно увидеть, как алгоритм пузырьковой сортировки, реализованный на языке Си, преобразуется в ассемблерный код.
III
Основной целью отладчика Turbo Debugger является отладка программы, имеющей отладочную информацию. Дело в том, что хотя отладчик и дизассемблирует программу, и мы можем видеть дизассемблированный код в окне CPU, такие дизассемблеры, как W32Dasm и IDA Pro намного превосходят в этой части Turbo Debugger. Отладчик же Ice, работая в нулевом кольце, также более удобен для анализа исполняемых модулей. Отладчик Turbo Debugger занимает свою нишу в отладке, но здесь он незаменим и очень удобен. В данном разделе мы намерены рассмотреть некоторые вопросы методики отладки.
Вообще процесс отладки можно разделить на четыре этапа:
- Обнаружение ошибки. Обнаружение ошибок в программе связано с тестированием программы и ее эксплуатацией.
- Поиск ее местонахождения. Данный этап часто оказывается самым трудоемким, и именно здесь может пригодиться использование отладчика. Профессиональные программисты знают, что в сложных алгоритмах найти ошибку путем простого анализа текста программы бывает очень сложно. Можно, конечно, выводить промежуточные результаты, но для этого может понадобиться слишком много таких выводов. Хороший отладчик в этом случае незаменим, поскольку может позволить отслеживать значение переменных на каждом шаге.
- Определение причины ошибки. Отбрасывая тот случай, когда причиной ошибки является неправильный
алгоритм, рассмотрим типичные ассемблерные ошибки.
- Ошибка в порядке следования операндов. Например, MOV EAX,EBX вместо MOV EBX,EAX.
- При использовании рекурсивных алгоритмов или слишком большой вложенности вызовов процедур может быть исчерпан стек.
- При вызове процедур может быть испорчено содержимое того или иного регистра.
- Неосвобождение стека при выходе из процедуры.
- Неправильное использование условных переходов - JA вместо JNA и т.п.
- Часто при организации циклических алгоритмов программисты ошибаются относительно последних значений переменных.
- Неправильная установка флага направления.
- Ошибка при определении границ переменных и массивов. Эти ошибки часто приводят к тому, что портится содержимое и других переменных.
- Неправильное преобразование из одного типа операнда к другому. Например, после загрузки MOV AL,BL используется EAX и забывается об обнулении старших байтов регистра EAX.
- Исправление ошибки. Если найденная ошибка проста и очевидна для Вас, то исправить ее не составит большого труда. Кстати, как Вы, наверное, уже поняли, Turbo Debugger не позволяет исправлять исполняемые модули. Но случаются и ситуации, когда очевидно, что данный участок программы (или процедура) выдает ошибочное значение, а на то, чтобы найти ошибку, у Вас не хватает времени - участок достаточно сложен. Иногда неправильное значение выходной информации возникает, лишь при редком сочетании входных параметров. В этом случае может быть применен простой прием: между указанным участком и остальной частью программы вставляется несколько строк, проверяющих выходную информацию и исправляющих ее, если нужно. Такой прием часто оказывается незаменим при доработке чужой программы очень большого объема, когда понять логику чужого алгоритма (да еще содержащего ошибку) бывает просто невозможно.
Forekc.ru
Рефераты, дипломы, курсовые, выпускные и квалификационные работы, диссертации, учебники, учебные пособия, лекции, методические пособия и рекомендации, программы и курсы обучения, публикации из профильных изданий