четверг, 14 мая 2009 г.

Hello Turbo Debugger :)

Теперь будем знакомится с Turbo Debagger -ОМмммм..... :)
Чтобы знакомство нашей супер программы hello.asm прошло с отладчиком хорошо, ее надо подготовить к знакомству :)
Делается это следующим образом – при ассемблировании надо добавить ключик /zi, который добавит в объектный файл отладочную информацию. Скопируем hello.asm в hello4.asm и ассемблируем следующим образом: tasm /la /zi hello4. И затем линкуем следующим образом: tlink /v hello4. Ключик /v включает в исполняемый файл информацию для отладчика.

Теперь загружаем нашу программу в Trubo Debugger командой td hello4 (перед этим следует убедится, что файл с текстом программы hello4.asm и исполняемый файл hello4.exe находятся в одной папке, так как отладчик при своей работе использует оба этих файла).
Запускаем нашу прогу под отладчиком: td hello4 и видим кадр отладчика, в котором видны два окна - окно Module с исходным текстом отлаживаемой программы и окно Watches для наблюдения за ходом изменения заданных переменных в процессе выполнения программы. Окно Watches нам пока не понадобится, и его можно убрать, щелкнув мышью по маленькому квадратику в левом верхнем углу окна, или введя команду [ALT]+[F3], предварительно сделав это окно активным. Переключение (по кругу) между окнами осуществляется клавишей [F6].

Следует заметить, что если вы писали программу в кодировке Windows (CP-1251), то вместо комментариев на русском языке увидите всякую абракадабру. Если это произошло, то можете воспользоваться плагином FarTrans для FAR manger чтобы изменить кодировку файла.
В процессе отладки программы на экран приходится выводить много дополнительных окон; они перекрываются и часто скрывают друг друга. Чтобы увидеть их все одновременно, размер окон приходится уменьшать, а сами окна перемещать по экрану. Режим изменения размеров и положения окна включается командой [Ctrl]+[F5], после чего клавиши со стрелками перемещают окно по экрану, а те же клавиши при нажатой клавише [Shift] позволяют изменять его размер. Выход из режима настройки окна осуществляется нажатием клавиши [Enter].
Начальное окно отладчика дает слишком мало информации для отладки программы. В нем можно выполнять программу по частям до местоположения курсора (клавиша [F4]) и команда за командой (клавиша [F8]); можно также с помощью окна Watches наблюдать изменения заданных полей данных. Однако для отладки программы на уровне языка ассемблера необходимо контролировать все регистры процессора, включая регистр флагов, а также, во многих случаях, поля данных вне программы (например, векторы прерываний или системные таблицы). Гораздо более информативным является "окно процессора", которое вызывается с помощью пункта Vicw>CPU верхнего меню или командой [Alt]+[V] [C].
Кроме того в стандартном размере окна помещается не слишком много информации, поэтому его лучше увеличить, выбрав Options->Display options… и далее выбрать Screen lines 43/50, а для корректного отображения табуляции установить Tab size равным 8.

Теперь открываем окно CPU (View->CPU) , видим следующее:

Медитируем и просветляемся...
Окно процессора состоит, в свою очередь, из 5 внутренних окон для наблюдения текста программы на языке ассемблера и в машинных кодах, регистров процессора, флагов, стека и содержимого памяти. С помощью этих окон можно полностью контролировать ход выполнения отлаживаемой программы. Для того чтобы можно было работать с конкретным окном, например, прокручивать его содержимое, надо сделать его активным, щелкнув по нему мышью. Перейти из окна в окно можно также с помощью клавиатуры, нажимая клавишу Tab. Посмотрим, какие сведения можно извлечь из содержимого окна процессора.
Содержимое сегментных регистров DS и ES одинаково и составляет 1547h. Как мы помним они указывают на начало PSP. Длина PSP составляет 256 байт или 100h байт или 10h параграфов. Прибавляем 10h к 1547h получаем 1557h, то есть начало сегмента кодов, что и подтверждается содержимым регистра CS. Регистр SS в результате инициализации ОС получил значение 155B. Начало стека отстоит от начала сегмента кода на 4 параграфа – 2 параграфа занимает сегмент кода (с учетом «пустых» байт) и 2 параграфа занимают данные (так же с учетом «пустых» байт). Итак CS=1557h прибавляем к нему 4 параграфа и получаем 155Bh. Как помним SP у нас содержит величину равную размеру стека, которую мы определили в программе, то есть 100h байт (256 байт десятичное) и указывает на «дно» стека. Регистр IP имеет смещение 0000 и указывает на первую исполняемую команду нашей программы (вспоминаем то, что уже знаем про точку входа в программу). В окне дампа памяти, мы естественным образом не видим наших данных, так как регистр DS еще не был инициализирован в нашей программе соответствующим значением. Это делают, как мы помним, первые две команды нашей программы. А они еще не выполнены. Скриншот сделан еще до выполнения первой команды.
Первая команда у нас имеет вид в машинном коде B85915, что соответствует команде mov ax,data. То есть в AX заносится сегментный адрес начала сегмента данных, который равен, в данном случае 1559h (не забываем, что байтики идут в обратном порядке). Давайте разберемся почему именно такое число. Сегмент данных у нас в программе определен сразу за сегментом кода. Сегмент кода у нас начинается с адреса 1557h (CS=1557h) и занимает 2 параграфа, далее за ним начинается сегмент данных. 1557h + 2h = 1559h, что мы и видим в отладчике.
Теперь попробуем разобраться с остальными значениями регистров. Содержимое всех регистров общего назначения (АХ, ВХ, СХ, DX, SI, DI и ВР) равно 0. Отсюда можно сделать вывод, что DOS, загружая программу в память, очищает регистры процессора. Однако на самом деле это совсем не так! Регистры очищает не DOS, а отладчик. При обычном запуске программы исходное содержимое регистров практически непредсказуемо, и ни в коем случае нельзя рассчитывать, что в них будут нули. Иногда можно столкнуться и с более тонким влиянием отладчика на ход выполнения программы, вплоть до того, что некоторые виды программ, например, управляющие подключенной к компьютеру аппаратурой, в отладчике будут выполняться просто неверно.
Так же мы видим в стеке по смещению 100h значение 52FB и по смещению 00FE значение 0000. Но мы же ни чего в стек не вносили! Мы то да, а вот отладчик внес эти значения для своих нужд. Еще один пример "самодеятельности" отладчика можно увидеть в окне исходного текста. Там есть странные команды add [bx+si],al. Таких команд, да еще в таком количестве, в нашей программе нет, их "придумал" отладчик, пытаясь дизассемблировать промежуток между сегментом команд и сегментом данных и сегментом данных и стеком, которые заполненны нулями. Код 0000h соответствует команде add [bx+si],al, которую и изобразил отладчик. То же самое можно сказать по поводу команд sub ch,[bp+si] – это попытка отладчика представить содержимое стека в дизассемблированном виде.
ыполним две первые команды программы, дважды нажав клавишу [F8]. Состояние программы после этой операции показано ниже:

Видно, что указатель команд получил значение 5 и показывает на очередную (еще не выполнявшуюся) команду mov AH,09h, относительный адрес которой равен 5. Сегментный регистр DS получил значение 1559h, что должно соответствовать сегментному адресу сегмента данных. Вспомним, что сегмент команд у нас занимает 11h байт и требует в памяти 2 параграфа (с учетом «пустых» байт выравнивания на границу параграфа). Сегмент команд имеет сегментный адрес 1557h, следовательно, сегментный адрес сегмента данных должен быть равен 1559h, что мы и получили.
Те регистры или флаги, которые изменили свое значение, отладчик подсвечивает белым цветом. Кроме того, следует заметить, что в отличие от отладчика debug.exe дамп памяти выводится не по целому параграфу (16 байт), а по половине параграфа (8 байт).
Итак, после выполнения двух первых команд в окне дампа памяти мы опять не увидели своих данных, так как там отобразилось содержимое памяти относительно значения в регистре ES.
Для того, чтобы вывести на экран что-либо иное, надо воспользоваться командой [Alt]+[F10], которая для каждого внутреннего окна процессора открывает дополнительное меню. Вид этого меню зависит от того, какое окне было активным в момент ввода команды.
Чаще всего приходится пользоваться первым пунктом этого меню Goto, с помощью которого можно задать любой адрес (входящий или не входящий в сегменты программы), и получить дамп этого участка. На скриншоте видно содержимое окна дампа после ввода начального адреса в виде DS:0 (тот же результат даст начальный адрес DS:msg, а так же и просто msg, так как по умолчанию сегментный адрес берется из DS). Как и следовало ожидать, по этому адресу расположено наше единственное данное - строка текста, выводимая программой на экран. Кстати, в окне дампа видно начало промежутка между сегментами (данных и стека), заполненного нулями.

Важнейшим элементом отладки программы является наблюдение значений тех или иных полей данных, особенно тех, которые заполняются программой динамически, т.е. по ходу ее выполнения. Для того чтобы вывести на экран содержимое поля данных, надо поместить курсор на имя этого поля в синем окне, начального кадра отладчика (например, msg в нашем случае) и выбрать пункт меню Data->Inspect. В появившемся окне ввода переменной можно скорректировать имя интересующего нас поля данных или ввести новое; если имя правильное достаточно нажать клавишу Enter.

В кадр отладчика будет выведено окно с характеристиками и содержимым указанной переменной. Отладчик сообщает, что переменная msg хранится в памяти по адерсу 1559:0000, т.е. имеет сегментный адрес 1559h и смещение 0000h, и описана как последовательность из 20 байт. Тут же приводятся значения всех байт нашей строки, включая их начертание на экране, а также десятичное и шестнадцатеричное представление.
В окне Inspecting можно изменить значение отображаемого поля данных. Для этого надо, сделав это окно активным и поместив курсор на отображение конкретного элемента нашего символьного массива, например элементы с индексом 0 и 18 (знак ‘-‘), ввести команду [Alt]+[F10] для открытия внутреннего меню этого окна и выбрать пункт Change. Выбрав этот пункт, мы получим окно, в котором можно ввести требуемое значение изменяемого данного. В нашем случае это символ '!', которым будет заменен символ '-'. Можно было вместо символа в одинарных кавычках ввести его шестнадцатеричный или десятичный ASCII код, если он известен (в нашем случае 21h или 33d).

Если теперь, не выходя из отладчика, выполнить программу до конца, на экран будет выведена фраза «!=* Hello World *=!», вместо фразы «-=* Hello World *=-». Для того чтобы находясь в отладчике увидеть результат работы программы, надо ввести команду [Alt]+[F5] или выбрать пункт меню Window-> User screen. Возврат в кадр отладчика осуществляется нажатием любой клавиши.
Важно понимать, что любые изменения, вносимые в текст программы в процессе работы с отладчиком, будут действовать только до конца данного сеанса (даже точнее говоря, до рестарта программы). Отладчик изменяет не файл, хранящийся на диске, а только его копию в памяти. Рестарт программы можно сделать нажав клавиши [Ctrl]+[F2] или выбрав пункт меню Run->Program reset.
Пошагово исполнять программу можно при поморщи клавиш F8 или F7. Каждая из них выполняет одно предложение программы, но различие этих команд весьма существенно: команда F7 (trace, трассировка) позволяет войти внутрь вызываемых подпрограмм, а так же выполнять циклы шаг за шагом. Команда F8 (step, шаг), наоборот, выполняет подпрограммы и циклы как одно неразрывное действие, что заметно ускоряет пошаговую отладку программы, при условии, что мы уверены, что вызываемая подпрограмма выполняется правильно.
Можно выполнить сразу целый фрагмент программы, т.е. несколько предложений. Для этого надо поместить курсор _ перед тем предложением, на котором требуется сделать остановку (или на любой символ внутри него), и нажать клавишу F4. Выполнятся все строки программы до той на которой установлен курсор, а значок ► переместится на эту строку.

2 комментария:

Анонимный комментирует...

Спасибо, добавил в закладки

-=*=- комментирует...

пожалуйста