Отладка с помощью GDB. Основы использования отладчика WinDbg Отладчик gdb команды

Введение

Откровенно говоря, программа GNU GDB довольно многофункциональная. Пошаговая от-лад-ка — лишь одна из ее возможностей. В этой статье я попытался описать те лишь команды GDB, которые позволяют проводить удобную пошаговую отладку программ, на-пи-сан-ных на Free Pascal.

Чтобы программу можно было отлаживать, она должна быть откомпилирована с ключом -g .

Поскольку GDB ориентирован не на Pascal, а на C и C++, то использование GDB для от-лад-ки Pascal-программ иногда сопряжено с неудобствами.

Приведу список подводных камней, обнаруженных мною и разработчиками Free Pascal (пе-ре-чис-лен-ных в user"s manual).

  1. Отладочная информация в Free Pascal генерируется в верхнем регистре. Поэтому имена всех переменных, процедур, функций при использовании GDB должны указываться БОЛЬШИМИ БУКВАМИ.
  2. GDB не воспринимает тип extended (ведь в C такого типа нет). Обойти эту неприятность можно, если, например, включить в код такие строки...
    type
    {$IFDEF DEBUG}
    dbl = double;
    {$ELSE}
    dbl = extended;
    {$ENDIF}
    ...

    var x: dbl;
    ...

  3. К элементам многомерных массивов нужно обращаться в C-шной манере, а именно, команда (gdb) print A выдаст первую строку массива A. Для просмотра требуемого элемента следует писать (gdb) print A
  4. GDB не воспринимает множества.
  5. Есть трудности с поддержкой объектов (см. user"s manual за подробностями).
  6. Есть трудности с глобально переопределенными функциями. (за подробностями см. user"s manual).
  7. При отладке процедур, функций, расположенных в разных файлах, часто возникает несоответствие — смещение строк. Та строка, которую GDB показывает текущей, таковой не является, а текущая расположена строк эдак на двадцать выше. Это приводит к большим неудобствам при пошаговой отладке. Я для себя сделал из этого такую мораль — хоть GDB и позволяет отлаживать процедуры, описанные в разных файлах, но лучше этой возможностью не пользоваться, а на время отладки все вызываемые процедуры, работа которых вас заинтересует, помещать в одном файле.

Все примеры отлаживались с использованием GNU GDB 5.0.

Запуск отладчика GDB

gdb [опции] [имя_файла | ID процесса]

После запуска видим "nice GDB logo" (если это почему-то раздражает, то опция -q поз-во-ля-ет не выводить это введение с ин-фор-ма-ци-ей об авторских правах и прочая). В следующей стро-ке приглашение
(gdb)
ждет ввода команды.

Ниже приводится краткий перечень команд GDB.

Краткую справку о любой команде можно получить, введя
(gdb) help [имя_команды, можно краткое]

Если при запуске GDB имя исполняемого файла не было указано (что следовало бы делать), то указать его можно командой file .

Команда file

(gdb) file <имя исполняемого файла, который подлежит отладке>


Для того, чтобы пролистать содержимое исходника, используйте команду list (сокращенно l ; бо льшая часть наиболее полезных ко-манд имеют сокращения). При этом под-ра-зу-ме-ва-ет-ся, что исходник расположен в том же каталоге, что и исполняемый файл. Как правило, так оно и есть.

Команда list (сокращенно l)

Пролистывает 10 строк вниз, начиная с текущей. Для пролистывания вверх следует набрать

Команда run (сокращенно r)

Запускает отлаживаемую программу под GDB. Если требуется, то после команды можно ука-зать список аргументов программы. Так-же допускается перенаправление потоков ввода и вы-во-да в другие файлы, например

(gdb) run > outfile

Если никаких точек останова не определено, то программа выполняется тихо, при этом нам со-об-ща-ет-ся:

(gdb) run
Starting program: test
Program exited normally.
(gdb)

Если же отладчик встречает точку останова, он выдает ее номер, адрес и дополнительную ин-фор-ма-цию — текущую строку, имя про-це-ду-ры, и т.п.

(gdb) r
Breakpoint 1, main () at test.pp:3
Current language: auto; currently pascal
3 x:= x + 1;
(gdb)

И ожидает ввода команды.

Остановка отладки программы

Команда kill (k). Следует запрос

(gdb) kill
Kill the program being debugged? (y or n) y
(gdb)

Здесь введено y (то есть "да"), и отладка программы прекращается. Командой run ее можно на-чать заново, при этом все точки ос-та-но-ва (breakpoints), точки просмотра (watchpoints) и точ-ки отлова (catchpoints) сохраняются.

Выход из отладчика

Команда quit (q).

(gdb) q
$

Точки останова


(gdb) help breakpoints

Точки останова — такие, когда GDB приостанавливает выполнение программы. Как уже упо-ми-на-лось, имеется 3 типа точек ос-та-но-ва:

  1. Breakpoints — точка останова как таковая. Остановка происходит, когда выполнение доходит до определенной строки, адреса или процедуры/функции.
  2. Watchpoints — точка просмотра. Выполнение программы приостанавливается, если программа обратилась к определенной переменной — либо считала ее значение, либо изменила его.
  3. Catchpoints — точка отлова. Приостановка происходит при определенном событии (например, получение сигнала). Я не буду касаться точек останова этого типа.

Определение точек останова

Breakpoint

Команда break
(gdb) break [аргумент]
или, сокращенно
(gdb) b [аргумент]
определяет точку останова. В качестве аргумента может выступать

  • номер строки . Остановка произойдет при достижении строки программы с этим номером. То, что написано в самой строке, выполняться не будет. Например (gdb) b 394 Breakpoint 1 at 0x805a650: file maeq.pas, line 394.
  • имя процедуры (функции) . Отладчик зайдет в эту процедуру и остановит выполнение программы. NB!! Имя процедуры (функции) должно быть указано БОЛЬШИМИ БУКВАМИ. Приведу пример: (gdb) b CALC Breakpoint 2 at 0x7657c7a: file maeq.pas, line 26.
  • если вызвать команду break без аргументов , то точка останова поставится на текущей строке.
  • также можно явно указывать адрес точки останова (перед адресом надо поставить знак *). Приведу лишь пример для полноты описания: (gdb) b *0x805a650 Breakpoint 3 at 0x805a650: file maeq.pas, line 394.

Допускается использование нескольких точек останова на одной строке (функции, адресе).

Watchpoint

Существуют различные виды точек просмотра, и задаются они различными командами:

  • команда watch (сокращенно wa) (gdb) wa <переменная> Выполнение программы приостанавливается всякий раз, когда значение указанной переменной изменяется.
  • команда rwatch (сокращенно rw) (gdb) rw <переменная> Выполнение приостанавливается всякий раз, когда программа считывает значение указанной переменной.
    NB!! Имя переменной должно быть указано БОЛЬШИМИ БУКВАМИ.
  • команда awatch (сокращенно aw) (gdb) aw <переменная> Выполнение приостанавливается всякий раз, когда программа обращается к указанной переменной, как для считывания, так и для записи.
    NB!! Имя переменной должно быть указано БОЛЬШИМИ БУКВАМИ.

Замечу от себя, что команды rwatch и awatch у меня почему-то капризничают — часто не ус-та-нав-ли-ва-ют точки просмотра на пе-ре-мен-ную. Зато команда watch работала всегда.

Управление точками останова

Информацию о всех установленных точках останова можно вывести командой info .

Команда info имеет много возможностей, но в данном случае воспользуемся лишь сле-дую-щим ее форматом:
(gdb) info breakpoints
или, кратко
(gdb) i b

Выводится подробная информация о всех точках останова (как breakpoints, так и watch-points), включающая - номер - breakpoint или watchpoint - активность - сколько раз прог-рам-ма натыкалась на эту точку - иные характеристики, значение которых мне не со-всем понятно

Если какая-то точка останова не нужна, то ее можно сделать неактивной с помощью ко-ман-ды disable:

(gdb) disable breakpoint <номер этой точки>

Обратно, деактивированная точка останова активируется командой enable:

(gdb) enable breakpoint <номер этой точки>

Статус точки останова — активна она или нет, легко обозреть той же командой info .

Если же точка останова не требуется вообще, то она может быть удалена насовсем.

(gdb) delete breakpoint [номер точки]

(gdb) d b [номер точки]

Ввод этой команды без аргумента удалит ВСЕ точки останова.

Возобновление выполнения, пошаговая отладка

Информацию о командах этого раздела можно получить, введя

(gdb) help running

Команда continue (c)

(gdb) с [аргумент]

Продолжает выполнение остановленной программы. Выполнение будет происходить, пока сно-ва не встретится точка останова. В ка-чест-ве аргумента может использоваться целое чис-ло N. Это укажет отладчику проигнорировать (N-1) точку останова (вы-пол-не-ние остановится на N-ой).

Команда step (s)

(gdb) s [аргумент]

Аналог действия клавиши F7 (Trace into) в IDE. Происходит выполнение программы до тех пор, пока не будет достигнута сле-дую-щая строка ее кода. При указании аргумента — це-ло-го чис-ла N, отладчик выполняет команду step N раз (если не останавливает вы-пол-не-ние из-за точек останова или по иным причинам).

Команда next (n)

(gdb) n [аргумент]

Аналог действия клавиши F8 (Step over) в IDE. В отличие от step вызов процедуры счи-та-ет-ся единой инструкцией (не заходит в вы-зы-вае-мые процедуры, функции). Аргумент N ра-бо-та-ет так же, как и для step .

Команда finish (fin)

(gdb) fin

Выполняет программу до момента выхода из текущей процедуры (функции). Если функция воз-вра-ща-ет значение, то это значение вы-во-дит-ся тоже.

Команда until (u)

Производит выполнение программы до тех пор, пока не будет достигнута строка с номером, бо ль-шим текущего. Команду until удоб-но применять при отладке циклов. Остановка про-и-зой-дет также, если программа при выполнении цикла выйдет из текущей про-це-ду-ры, функ-ции.

Команда stepi (si)

(gdb) si [аргумент]

Действие подобно step , но выполняется не строка, а ровно одна инструкция в этой строке прог-рам-мы. Аргумент N нужен, если тре-бу-ет-ся выполнить N инструкций.

Команда nexti (ni)

(gdb) ni [аргумент]

Аналогична stepi , но вызовы процедур трактуются как одна инструкция.

Управление состоянием (просмотр, изменение) переменных при отладке

Информацию о командах этого раздела можно получить, введя

(gdb) help data

Команда print (p)

(gdb) print <выражение>

Вывод текущего значения переменной (выражения). При использовании команды print имя пе-ре-мен-ной можно писать в сме-шан-ном регистре, то есть в этом случае использование боль-ших букв обязательным не является.

Часто требуется отслеживать значения нескольких переменных. Чтобы не утруждать себя мно-го-крат-ным вводом команды print , ис-поль-зуй-те команду display .

Команда display

(gdb) display [аргумент]

В качестве аргумента обычно указывают переменную или выражение. При этом указанная пе-ре-мен-ная (выражение) занесется в дис-плей, то есть станет выводиться при каждой ос-та-нов-ке программы (при попадании на точку останова, при пошаговом вы-пол-не-нии командами step и next , etc). Если вызвать display без аргументов, то GDB выдаст значения всех пе-ре-мен-ных (вы-ра-же-ний), занесенных в дисплей.

Управление списком этих переменных осуществляется аналогично точкам останова. А имен-но, команда info display

(gdb) info display

выдаст все переменные, занесенные в дисплей. Любая переменная в списке дисплея может быть дезактивирована

(gdb) disable display <номер переменной в списке дисплея>

или активирована заново

(gdb) enable display <номер переменной в списке дисплея>

Удаление переменной из списка дисплея производится командой delete или командой undisplay . Так, команда

(gdb) delete display [номер переменной в списке дисплея]

делает то же, что и

(gdb) undisplay [номер переменной в списке дисплея]

Опять-таки, если не указать номер переменной, то очистится весь список отображаемых пе-ре-мен-ных.

Изменение значения переменной

И последнее. Изменение значения переменной на другое можно, например, произвести с по-мощью команд set или print .

(gdb) set <оператор присваивания> (gdb) print <оператор присваивания>

Например,

(gdb) whatis x
TYPE = WORD
(gdb) p x
$1 = 1
(gdb) set x:=2
(gdb)

При использовании set присваивание происходит "тихо". То же самое можно сделать, но с по-мощью команды print .

Например,

(gdb) p x
$2 = 2
(gdb) p x:=x-2
$3 = 0
(gdb)

При этом, как видно, выводится новое значение переменной.

Вот и все.

Удачной отладки!

Сегодня ты сделаешь еще один шаг в деле
изучения Linux систем. Я расскажу об основных
приемах при работе с gdb. Овладев ими ты сможешь понять, как работает любая программа, писать свои эксплоиты.

Вы, наверное, все слышали про такую вещь как отладчик, gdb – это и есть отладчик. GDB – GNU
Debugger. Это некое подобие SoftICE для Windows (для тех кто не знает – самый популярный и, на мой взгляд, вообще лучший отладчик), только под
Linux системы. Дело в том, что в сети не так уж много документов, которые демонстрируют работу этой вещи и в свое время я его осваивал сам. Итак,
в документе будут описаны базовые команды gdb. Все это будет показано на примере. А в качестве примера я решил взять ненужную прогу yes. Для тех, кто не знает – это программа просто выводит символ ‘y’ до бесконечности, для начала я решил научить ее выводить не этот символ, а строку ‘XAKEP’, хоть веселее будет.

Ну а теперь все по порядку. Сам отладчик запускается так:

Но можно вводить различные параметры, у нас это будет путь к исследуемой программе:

# gdb /usr/bin/yes

Можно исследовать core файлы, для этого нужно ввести следует ввести следующее:

# gdb /usr/bin/yes core

Еще может понадобится команда для просмотра содержимого регистров:

(gdb) info registers

либо так (сокращенный вариант)

Теперь рассмотрим как делать перехваты. Существуют
точки останова, точки перехвата и точки наблюдения. Более конкретно я бы хотел остановиться на точках останова. Их можно устанавливать на:

(gdb) break function - Остановить перед входом в функцию
(gdb) break *adress - Остановить перед выполнением инструкции по адресу.

После установок можно просмотреть все точки для этого воспользуйтесь командой:

(gdb) info break

А потом можно удалить эти точки:

(gdb) clear breakpoint - где break это название точки останова
(например, функция или адрес)

Очень необходимой вещью является возможность автоматического отображения различных значений при выполнении программы. Для этого существует команда display:

(gdb) display/format value , где format – это формат отображения, а value – само выражение которое нужно отобразить.

Для работы с отображением отведены следующие команды:

(gdb) info display - выдает инфу об отображениях
(gdb) delete num - где num – удалить элементы с индексом
num

Это был небольшой справочник по командам, чтобы понять основную идею.
Далее на примере хотелось бы продемонстрировать это и еще немного. И помните – здесь я дал лишь очень маленькую часть всех возможностей gdb, на самом деле у него их в сотни раз больше, поэтому читайте и учите.
Как я и обещал, берем ненужную прогу yes. Путь на вашей машине может не совпадать с моим, все зависит от операционки которой вы пользуетесь, если что воспользуйтесь поиском (команда
find).

# gdb /usr/bin/yes

После запуска он говорит приветственное сообщение.

GNU gdb 19991004




There is absolutely no warranty for GDB. Type "show warranty" for details.
This GDB was configured as "i386-redhat-linux"...
(no debugging symbols found)...

Так как yes выводит бесконечное число символов, то лучше бы их нам не видеть в отладчике, а вывод
программы можно направить на другую консоль. Откройте новый терминал, наберите who is i и вы получите имя консоли. Должно вылезти
что-то вроде этого:

Вот теперь просто привязываем к ней.

(gdb) tty /dev/pts/1

А теперь ставим точку останова на функцию puts(), а чтобы было понятней вот вам man-справка об функции(команда man
puts)

#include
int puts(const char *s);
puts() writes the string s and a trailing newline to std­
out.

Как видно, функция посылаем строку s на поток вывода. Вот она то нам и нужна. На ней то мы пока и остановимся.

(gdb) break puts
Breakpoint 1 at 0x8048698

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

(gdb) r
Starting program: /usr/bin/yes
Breakpoint 1 at 0x4006d585: file ioputs.c, line 32.

Breakpoint 1, 0x4006d585 in _IO_puts (str=0x8048e59 "y") at ioputs.c:32
32 ioputs.c: No such file or directory.
1: x/i $eip 0x4006d585 <_IO_puts+21>: mov 0x8(%ebp),%esi

О, вот и произошло чудо, сработал breakpoint. Что мы видим – а видим мы ни что иное, как параметр функции, точнее адрес, по которому он лежит. Что теперь нужно
сделать? Правильно, подправить данные по этому адресу. При этом мы затрем еще пару символов своими.

(gdb) set {char}0x8048e59="X"
(gdb) set {char}0x8048e5a="A"
(gdb) set {char}0x8048e5b="K"
(gdb) set {char}0x8048e5c="E"
(gdb) set {char}0x8048e5d="P"

Ну а теперь посмотрим на наше творение. Что там лежит в памяти:

(gdb) x/3sw 0x8048e59
0x8048e59 <_IO_stdin_used+437>: "XAKEP\004\b"
0x8048e61 <_IO_stdin_used+445>: ""
0x8048e62 <_IO_stdin_used+446>: ""

Теперь удалим наш брякпоинт:

(gdb) info break
Num Type Disp Enb Address What
1 breakpoint keep y 0x4006d585 in _IO_puts at ioputs.c:32
breakpoint already hit 1 time
(gdb) clear puts
Deleted breakpoint 1

И продолжим выполнение чтобы насладится результатом:

Вот и все. Выходим.

(gdb) q
The program is running. Exit anyway? (y or n) y

На этом практика заканчивается, остальное изучайте сами и помните что главное в этой жизни – это УЧЕНЬЕ.
Вот еще некоторые примеры работы:

Присоединение к работающему процессу:

// launch gdb
hack@exploit:~ > gdb
GNU gdb 4.18
Copyright 1998 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or distribute copies of it under certain conditions.
Type "show copying" to see the conditions.
There is absolutely no warranty for GDB. Type "show warranty" for
details.
This GDB was configured as "i386-suse-linux".
(gdb) attach "pid"
(gdb) attach 1127 // example

Поиск в памяти:

(gdb) x/d or x "address" show decimal
(gdb) x/100s "address" show next 100 decimals
(gdb) x 0x0804846c show decimal at 0x0804846c
(gdb) x/s "address" show strings at address
(gdb) x/105 0x0804846c show 105 strings at 0x0804846c
(gdb) x/x "address" show hexadecimal address
(gdb) x/10x 0x0804846c show 10 addresses at 0x0804846c
(gdb) x/b 0x0804846c show byte at 0x0804846c
(gdb) x/10b 0x0804846c-10 show byte at 0x0804846c-10
(gdb) x/10b 0x0804846c+20 show byte at 0x0804846c+20
(gdb) x/20i 0x0804846c show 20 assembler instructions at address

Список всех секций в исполняемом файле:

(gdb) maintenance info sections // or
(gdb) mai i s

Executable file:
`/home/hack/homepage/challenge/buf/basic", file type
elf32-i386.
0x080480f4->0x08048107 at 0x000000f4: .interp ALLOC

0x08048108->0x08048128 at 0x00000108: .note.ABI-tag
ALLOC LOAD READONLY DATA HAS_CONTENTS
0x08048128->0x08048158 at 0x00000128: .hash ALLOC
LOAD READONLY DATA HAS_CONTENTS
0x08048158->0x080481c8 at 0x00000158: .dynsym ALLOC
LOAD READONLY DATA HAS_CONTENTS
0x080481c8->0x08048242 at 0x000001c8: .dynstr ALLOC
LOAD READONLY DATA HAS_CONTENTS
0x08048242->0x08048250 at 0x00000242: .gnu.version
ALLOC LOAD READONLY DATA
HAS_CONTENTS

Бряк на адрес:

(gdb) disassemble main
Dump of assembler code for function main:
0x8048400

: push %ebp
0x8048401 : mov %esp,%ebp
0x8048403 : sub $0x408,%esp
0x8048409 : add $0xfffffff8,%esp
0x804840c : mov 0xc(%ebp),%eax
0x804840f : add $0x4,%eax
0x8048412 : mov (%eax),%edx
0x8048414 : push %edx
0x8048415 : lea 0xfffffc00(%ebp),%eax
...

(gdb) break *0x8048414 // example
Breakpoint 1 at 0x8048414
(gdb) break main // example
Breakpoint 2 at 0x8048409
(gdb)

GNU Debugger – переносимый отладчик проекта GNU, который работает на многих UNIX-подобных системах и умеет производить отладку многих языков программирования, включая Си, C++, Ada и Фортран. GNU Debugger – свободное программное обеспечение, распространяемое по лицензии GNU General Public License.

Первоначально GNU Debugger написан Ричардом Столлманом в 1988 году. За основу был взят отладчик DBX, поставлявшийся с дистрибутивом BSD. С 1990 до 1993 гг. проект поддерживался Джоном Джилмором, во время его работы в компании Cygnus Solutions. В настоящее время разработка координируется Управляющим комитетом GDB (GDB Steering Committee), назначенным Free Software Foundation.

Технические детали GNU Debugger

  • Особенности

GNU Debugger предлагает обширные средства для слежения и контроля за выполнением компьютерных программ. Пользователь может изменять внутренние переменные программ и даже вызывать функции независимо от обычного поведения программы. GNU Debugger может отлаживать исполняемые файлы в формате a.out, COFF (в том числе исполняемые файлы Windows), ECOFF, XCOFF, ELF, SOM, использовать отладочную информацию в форматах stabs, COFF, ECOFF, DWARF, DWARF2. Наибольшие возможности отладки предоставляет формат DWARF2.

GNU Debugger активно развивается. Например, в версии 7.0 добавлена поддержка «обратимой отладки», позволяющей отмотать назад процесс выполнения, чтобы посмотреть, что произошло. Также в версии 7.0 была добавлена поддержка скриптинга на .

Для работы с GNU Debugger были созданы и другие инструменты отладки например, датчики утечки памяти.

  • Мультиплатформенность и поддержка встроенных систем

GNU Debugger может быть скомпилирован для поддержки приложений для нескольких целевых платформ и переключаться между ними во время отладочной сессии. Процессоры, поддерживаемые GNU Debugger (2003): Alpha, ARM, H8/300, System/370, System/390, x86 и x86-64, IA-64 (Itanium), Motorola 68000, MIPS, PA-RISC, PowerPC, SuperH, SPARC, VAX, A29K, ARC, AVR, CRIS, D10V, D30V, FR-30, FR-V, Intel i960, M32R, 68HC11, Motorola 88000, MCORE, MN10200, MN10300, NS32K, Stormy16, V850 и Z8000. (Более новые выпуски не будут, вероятно, поддерживать некоторых из них.) Целевые платформы, на которых GNU Debugger не может быть запущен, в частности, встроенные системы, могут поддерживаться с помощью встроенного симулятора (процессоры ARM, AVR), либо приложения для них могут быть скомпилированы со специальными подпрограммами, обеспечивающими удалённую отладку под управлением GNU Debugger, запущенном на компьютере разработчика. Входным файлом для отладки, как правило, используется не прошиваемый двоичный файл, а файл в одном из поддерживающих отладочную информацию форматов, в первую очередь ELF, из которого впоследствии с помощью специальных утилит извлекается двоичный код для прошивки.

  • Удалённая отладка

При удалённой отладке GNU Debugger запускается на одной машине, а отлаживаемая программа запускается на другой. Связь осуществляется по специальному протоколу через последовательный порт или TCP/IP. Протокол взаимодействия с отладчиком специфичен для GNU Debugger, но исходные коды необходимых подпрограмм включены в архив отладчика. Как альтернатива, на целевой платформе может быть запущена использующая тот же протокол программа gdbserver из состава пакета GNU Debugger, исполняющая низкоуровневые функции вроде установки точек останова и доступа к регистрам и памяти.

Этот же режим используется для взаимодействия со встроенным отладчиком ядра Linux KGDB. С его помощью разработчик может отлаживать ядро как обычную программу: устанавливать точки останова, делать пошаговое исполнение кода, просматривать переменные. Встроенный отладчик требует наличия двух машин, соединенных через Ethernet или последовательный кабель, на одном из которых запущен GNU Debugger, на другом – отлаживаемое ядро.

  • Пользовательский интерфейс

В соответствии с идеологией ведущих разработчиков Free Software Foundation, GNU Debugger вместо собственного графического пользовательского интерфейса предоставляет возможность подключения к внешним IDE, управляющим графическим оболочкам либо использовать стандартный консольный текстовый интерфейс. Для сопряжения с внешними программами можно использовать язык текстовой строки (как это было сделано в первых версиях оболочки DDD), текстовый язык управления gdb/mi, либо интерфейс для языка .

Были созданы такие интерфейсы как DDD, cgdb, GDBtk/Insight и «GUD mode» в . С GNU Debugger могут взаимодействовать такие IDE, как

Linux: Полное руководство Колисниченко Денис Николаевич

22.2. Отладчик gdb

22.2. Отладчик gdb

Формат вызова отладчика gdb следующий:

gdb [-help] [-nx] [-q] [-batch] [-cd=dir] [-f] [-b bps] [-tty=dev] [-s symfile] [-e prog] [-sе prog] [-c core] [-x cmds] [-d dir] ]

Ключи отладчика описаны в таблице 22.1.

Ключи командной строки gdb Таблица 22.1

Ключ Назначение
-help или -h Вывод краткого описания всех параметров
-nx или -n Не обрабатывать команды файла инициализации.gdbinit
-q Не выводить приветствие и информацию об авторских правах
-batch Командный режим. Отладчик возвращает 0, если были выполнены все команды, указанные в файле, заданном параметром -x (и файле.gdbinit, если его использование разрешено). Если же хотя бы одна из команд не выполнена, возвращается ненулевое значение
-cd=каталог Установить рабочий каталог (по умолчанию используется текущий каталог)
-f или -fullname Данная опция нужна, если вы планируете использовать интерфейс текстового процессора Emacs для отладки ваших программ с помощью gdb . Для более подробного описаний обратитесь к справочной системе
-b bps (bits per second) Установить скорость обмена информацией по последовательному интерфейсу, если вы отлаживаете вашу программу удаленно
-tty=терминал Установить терминал в качестве стандартного ввода и вывода для отлаживаемой программы.
-s файл или -symbols=файл Читает таблицу символов из указанного файла
-write Разрешить запись в исполняемые и core-файлы
-e программа Использовать указанную программу в качестве фильтра дампа
-se=файл Читать таблицу символов из указанного файла и использовать указанный файл в качестве исполнимого
-core=файл или -с файл Указать файл дампа
-command=файл или -x файл Выполнить указанные в файле команды (используется в командном режиме)
-d каталог Добавить каталог к списку поиска исходных текстов
Последний параметр задает объект, который нужно отлаживать. Вы можете задать программу (prog), или дамп-файл (core), который будет создан в случае ошибки программы (Segmentation fault), или же подсоединиться к уже запущенному процессу (procID)
-p PID Подключиться к уже запущенному процессу (данная опция стала доступной в версии gdb 5.2)

Чтобы использовать gdb для отладки вашей программы, нужно добавить в исполняемый файл отладочную информацию. Для этого откомпилируете вашу программу с опцией -g:

$ gcc -g -o prog prog.c

Данная опция включает отладочную информацию в родном для операционной системы формате, с которым может работать gdb .

Затем нужно вызвать gdb так:

Если после запуска вашей программы произошла ошибка и был создан дамп-файл (core), можно передать отладчику и этот файл:

Можно также подключиться к уже запущенному процессу, для этого нужно передать его PID:

Только убедитесь сначала в том, что у вас нет файла 1111, поскольку gdb сначала ищет исполняемый файл, затем core-файл, а уже затем PID.

После запуска отладчика в интерактивном режиме вы можете использовать команды, самые важные из которых перечислены в таблице 22.2. Об остальных можно узнать в справочной системе: man gdb.

Команды gdb Таблица 22.2

Команда Назначение
break [файл:]функция Установить точку останова
run [аргументы] Запустить программу и передать ей указанные аргументы
bt Обратная трассировка: отобразить стек программы
print выражение Вывести значение выражении, операндами могут быть переменные, объявленные в вашей программа
С Продолжить выполнение программы (после останова)
Next Выполнить следующую строку. Это так называемый шаг «над» (step over). Если следующая строка - вызов функции, то мы выполним ее за один шаг - «перешагнем» ее
Step Выполнить следующую строку, Это так называемый шаг «в» (step into). Если следующая строка - вызов функции, то мы будем последовательно выполнять все операторы тела функции
help [имя] Вывести справку о команде отладчика или вывести общую информацию о нем
Quit Выход

В данной таблице приведены далеко не все команды. Если вас интересует более полная информация, обратитесь к руководству по gdb .

Из книги Язык программирования С# 2005 и платформа.NET 2.0. автора Троелсен Эндрю

Отладчик командной строки (cordbg.exe) Прежде чем перейти к рассмотрению возможностей компоновки C#-приложе-ний с помощью TextPad, следует отметить, что.NET Framework 2.0 SDK предлагает отладчик командной строки cordbg.ехe. Этот инструмент имеет множество опций, которые позволяют выполнить

Из книги Разработка приложений в среде Linux. Второе издание автора Джонсон Майкл К.

4.3. Отладчик GNU gdb - это отладчик, рекомендуемый Free Software Foundation, gdb представляет собой хороший отладчик командной строки, на котором строятся некоторые инструменты, включая режим gdb в Emacs, графический отладчик Data Display Debugger (http://www.gnu.org/software/ddd/) и встроенные отладчики в некоторых

Из книги Linux: Полное руководство автора Колисниченко Денис Николаевич

22.2. Отладчик gdb Формат вызова отладчика gdb следующий:gdb [-help] [-nx] [-q] [-batch] [-cd=dir] [-f] [-b bps] [-tty=dev] [-s symfile] [-e prog] [-sе prog] [-c core] [-x cmds] [-d dir] ]Ключи отладчика описаны в таблице 22.1.Ключи командной строки gdb Таблица 22.1 Ключ Назначение -help или -h Вывод краткого описания всех

Из книги Программирование для Linux. Профессиональный подход автора Митчелл Марк

1.4. GNU-отладчик gdb Отладчик - это программа, с помощью которой можно узнать, почему написанная вами программа ведет себя не так, как было задумано. Работать с отладчиком приходится очень часто. Большинство Linux-программистов имеет дело с GNU-отладчиком (GNU Debugger, GDB), который

Из книги Разработка ядра Linux автора Лав Роберт

Отладчик kgdb Отладчик kgdb - это заплата ядра, которая позволяет с помощью отладчика gdb отлаживать ядро по линии последовательной передачи. Для этого требуется два компьютера. На первом выполняется ядро с заплатой kgdb. Второй компьютер используется для отладки ядра по линии

Цель отладки программы - устранение ошибок в её коде. Для этого вам, скорее всего, придётся исследовать состояние переменных во время выполнения , равно как и сам процесс выполнения (например, отслеживать условные переходы). Тут отладчик - наш первый помощник. Конечно же, в Си достаточно много возможностей отладки без непосредственной остановки программы: от простогоprintf(3) до специальных систем ведения логов по сети и syslog . В ассемблере такие методы тоже применимы, но вам может понадобиться наблюдение за состоянием регистров, образ ( dump ) оперативной памяти и другие вещи, которые гораздо удобнее сделать в интерактивном отладчике. В общем, если вы пишете на ассемблере, то без отладчика вы вряд ли обойдётесь.

Начать отладку можно с определения точки останова ( breakpoint ), если вы уже приблизительно знаете, какой участок кода нужно исследовать. Этот способ используется чаще всего: ставим точку останова, запускам программу и проходим её выполнение по шагам, попутно наблюдая за необходимыми переменными и регистрами. Вы также можете просто запустить программу под отладчиком и поймать момент, когда она аварийно завершается из-за segmentation fault, - так можно узнать, какая инструкция пытается получить доступ к памяти, подробнее рассмотреть приводящую к ошибке переменную и так далее. Теперь можно исследовать этот код ещё раз, пройти его по шагам, поставив точку останова чуть раньше момента сбоя.

Начнём с простого. Возьмём программу Hello world и скомпилируем её с отладочной информацией при помощи ключа компилятора -g :

$ gcc -g hello.s -o hello $

Запускаем gdb:

$ gdb ./hello GNU gdb 6.4.90-debian Copyright (C) 2006 Free Software Foundation, Inc. GDB is free software, covered by the GNU General Public License, and you are welcome to change it and/or distribute copies of it under certain conditions. Type "show copying" to see the conditions. There is absolutely no warranty for GDB. Type "show warranty" for details. This GDB was configured as "i486-linux-gnu"...Using host libthread_db library "/lib/tls/libthread_db.so.1". (gdb)

GDB запустился, загрузил исследуемую программу, вывел на экран приглашение (gdb) и ждёт команд. Мы хотим пройти программу "по шагам" ( single-step mode ). Для этого нужно указать команду, на которой программа должна остановиться. Можно указать подпрограмму - тогда остановка будет осуществлена перед началом исполнения инструкций этой подпрограммы. Ещё можно указать имя файла и номер строки.

(gdb) b main Breakpoint 1 at 0x8048324: file hello.s, line 17. (gdb)

b - сокращение от break . Все команды в GDB можно сокращать, если это не создаёт двусмысленных расшифровок. Запускаем программу командой run . Эта же команда используется для перезапуска ранее запущенной программы.

(gdb) r Starting program: /tmp/hello Breakpoint 1, main () at hello.s:17 17 movl $4, %eax /* поместить номер системного вызова write = 4 Current language: auto; currently asm (gdb)

GDB остановил программу и ждёт команд. Вы видите команду вашей программы, которая будет выполнена следующей, имя функции , которая сейчас исполняется, имя файла и номер строки. Для пошагового исполнения у нас есть две команды: step (сокращённо s ) и next (сокращённо n ). Команда step производит выполнение программы с заходом в тела подпрограмм. Команда next выполняет пошагово только инструкции текущей подпрограммы.

(gdb) n 20 movl $1, %ebx /* первый параметр - в регистр %ebx */ (gdb)

Итак, инструкция на строке 17 выполнена, и мы ожидаем, что в регистре %eax находится число 4. Для вывода на экран различных выражений используется команда print (сокращённо p ). В отличие от команд ассемблера, GDB в записи регистров использует знак $ вместо % . Посмотрим, что в регистре %eax :

(gdb) p $eax $1 = 4 (gdb)

Действительно 4! GDB нумерует все выведенные выражения. Сейчас мы видим первое выражение ($1 ), которое равно 4. Теперь к этому выражению можно обращаться по имени. Также можно производить простые вычисления:

(gdb) p $1 $2 = 4 (gdb) p $1 + 10 $3 = 14 (gdb) p 0x10 + 0x1f $4 = 47 (gdb)

Пока мы играли с командой print , мы уже забыли, какая инструкция исполняется следующей. Команда info line выводит информацию об указанной строке кода. Без аргументов выводит информацию о текущей строке.

(gdb) info line Line 20 of "hello.s" starts at address 0x8048329 and ends at 0x804832e . (gdb)

Команда list (сокращённо l ) выводит на экран исходный код вашей программы. В качестве аргументов ей можно передать:

  • номер_строки - номер строки в текущем файле;
  • файл:номер_строки - номер строки в указанном файле;
  • имя_функции - имя функции, если нет неоднозначности;
  • файл:имя_функции - имя функции в указанном файле;
  • *адрес - адрес в памяти, по которому расположена необходимая инструкция.

Если передавать один аргумент , команда list выведет 10 строк исходного кода вокруг этого места. Передавая два аргумента, вы указываете строку начала и строку конца листинга.

(gdb) l main 12 за пределами этого файла */ 13 .type main, @function /* main - функция (а не данные) */ 14 15 16 main: 17 movl $4, %eax /* поместить номер системного вызова 18 write = 4 в регистр %eax */ 19 20 movl $1, %ebx /* первый параметр поместить в регистр 21 %ebx; номер файлового дескриптора 22 stdout = 1 */ (gdb) l *$eip 0x8048329 is at hello.s:20. 15 16 main: 17 movl $4, %eax /* поместить номер системного вызова 18 write = 4 в регистр %eax */ 19 20 movl $1, %ebx /* первый параметр поместить в регистр 21 %ebx; номер файлового дескриптора 22 stdout = 1 */ 23 movl $hello_str, %ecx /* второй параметр поместить в 24 регистр %ecx; указатель на строку */ (gdb) l 20, 25 20 movl $1, %ebx /* первый параметр поместить в регистр 21 %ebx; номер файлового дескриптора 22 stdout = 1 */ 23 movl $hello_str, %ecx /* второй параметр поместить в 24 регистр %ecx; указатель на строку */ 25 (gdb)

Запомните эту команду: list *$eip . С её помощью вы всегда можете просмотреть исходный код вокруг инструкции, выполняющейся в текущий момент. Выполняем нашу программу дальше:

(gdb) n 23 movl $hello_str, %ecx /* второй параметр поместить в регистр %ecx (gdb) n 26 movl $hello_str_length, %edx /* третий параметр поместить в регистр %edx (gdb)

Не правда ли, утомительно каждый раз нажимать n ? Если просто нажать Enter , GDB повторит последнюю команду:

(gdb) 29 int $0x80 /* вызвать прерывание 0x80 */ (gdb) Hello, world! 31 movl $1, %eax /* номер системного вызова exit = 1 */ (gdb)

Ещё одна удобная команда , о которой стоит знать - info registers . Конечно же, её можно сократить до i r . Ей можно передать параметр - список регистров, которые необходимо напечатать. Например, когда выполнение происходит в защищённом режиме, нам вряд ли будут интересны значения сегментных регистров.

(gdb) info registers eax 0xe 14 ecx 0x804955c 134518108 edx 0xe 14 ebx 0x1 1 esp 0xbfabb55c 0xbfabb55c ebp 0xbfabb5a8 0xbfabb5a8 esi 0x0 0 edi 0xb7f6bcc0 -1208566592 eip 0x804833a 0x804833a eflags 0x246 [ PF ZF IF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51 (gdb) info registers eax ecx edx ebx esp ebp esi edi eip eflags eax 0xe 14 ecx 0x804955c 134518108 edx 0xe 14 ebx 0x1 1 esp 0xbfabb55c 0xbfabb55c ebp 0xbfabb5a8 0xbfabb5a8 esi 0x0 0 edi 0xb7f6bcc0 -1208566592 eip 0x804833a 0x804833a eflags 0x246 [ PF ZF IF ] (gdb)

Так, а кроме регистров у нас ведь есть ещё и