Отладчик GNU GDB |
19.04.2005 Илья Аввакумов |
Откровенно говоря, программа GNU GDB довольно многофункциональная. Пошаговая отладка — лишь одна из ее возможностей. В этой статье я попытался описать те лишь команды GDB, которые позволяют проводить удобную пошаговую отладку программ, написанных на Free Pascal.
Чтобы программу можно было отлаживать, она должна быть откомпилирована с ключом -g
.
Поскольку GDB ориентирован не на Pascal, а на C и C++, то использование GDB для отладки Pascal-программ иногда сопряжено с неудобствами.
Приведу список подводных камней, обнаруженных мною и разработчиками Free Pascal (перечисленных в user's manual).
...
type
{$IFDEF DEBUG}
dbl = double;
{$ELSE}
dbl = extended;
{$ENDIF}
...
var x : dbl;
...
(gdb) print A[1,1]выдаст первую строку массива A. Для просмотра требуемого элемента следует писать
(gdb) print A[1][1]
Все примеры отлаживались с использованием GNU GDB 5.0.
gdb [опции] [имя_файла | ID процесса]
После запуска видим "nice GDB logo" (если это почему-то раздражает, то опция -q
позволяет не выводить это введение с информацией об авторских правах и прочая). В следующей строке приглашение
(gdb)
ждет ввода команды.
Ниже приводится краткий перечень команд GDB.
Краткую справку о любой команде можно получить, введя
(gdb) help [имя_команды, можно краткое]
Если при запуске GDB имя исполняемого файла не было указано (что следовало бы делать), то указать его можно командой file
.
file
(gdb) file <имя исполняемого файла, который подлежит отладке>
Для того, чтобы пролистать содержимое исходника, используйте команду list
(сокращенно l
; большая часть наиболее полезных команд имеют сокращения). При этом подразумевается, что исходник расположен в том же каталоге, что и исполняемый файл. Как правило, так оно и есть.
list
(сокращенно l
)Пролистывает 10 строк вниз, начиная с текущей. Для пролистывания вверх следует набрать
(gdb) list -
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
[avva@localhost home]$
Информацию о командах этого раздела можно получить, введя
(gdb) help breakpoints
Точки останова — такие, когда GDB приостанавливает выполнение программы. Как уже упоминалось, имеется 3 типа точек останова:
Команда break
(gdb) break [аргумент]
или, сокращенно
(gdb) b [аргумент]
определяет точку останова. В качестве аргумента может выступать
(gdb) b 394 Breakpoint 1 at 0x805a650: file maeq.pas, line 394.
(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.
Допускается использование нескольких точек останова на одной строке (функции, адресе).
Существуют различные виды точек просмотра, и задаются они различными командами:
watch
(сокращенно wa
)
(gdb) wa <переменная>Выполнение программы приостанавливается всякий раз, когда значение указанной переменной изменяется.
rwatch
(сокращенно rw
)
(gdb) rw <переменная>Выполнение приостанавливается всякий раз, когда программа считывает значение указанной переменной.
awatch
(сокращенно aw
)
(gdb) aw <переменная>Выполнение приостанавливается всякий раз, когда программа обращается к указанной переменной, как для считывания, так и для записи.
Замечу от себя, что команды rwatch
и awatch
у меня почему-то капризничают — часто не устанавливают точки просмотра на переменную. Зато команда watch
работала всегда.
Информацию о всех установленных точках останова можно вывести командой info
.
Команда info
имеет много возможностей, но в данном случае воспользуемся лишь следующим ее форматом:
(gdb) info breakpoints
или, кратко
(gdb) i b
Выводится подробная информация о всех точках останова (как breakpoints, так и watchpoints), включающая - номер - 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)
При этом, как видно, выводится новое значение переменной.
Вот и все.
Удачной отладки!