Читает таблицу символов из указанного файла -write Разрешить запись в исполняемые и core-файлы -e программа Использовать указанную программу в качестве фильтра дампа -se=файл Читать таблицу символов из указанного файла и использовать указанный файл в качестве исполнимого -core=файл или -с файл Указать файл дампа -command=файл или -x файл Выполнить указанные в файле команды (используется в командном режиме) -d каталог Добавить каталог к списку поиска исходных текстов [prog|core|procID] Последний параметр задает объект, который нужно отлаживать. Вы можете задать программу (prog), или дамп-файл (core), который будет создан в случае ошибки программы (Segmentation fault), или же подсоединиться к уже запущенному процессу (procID) -p PID Подключиться к уже запущенному процессу (данная опция стала доступной в версии gdb 5.2) Чтобы использовать gdb для отладки вашей программы, нужно добавить в исполняемый файл отладочную информацию. Для этого откомпилируете вашу программу с опцией -g:
$ gcc -g -o prog prog.c
Данная опция включает отладочную информацию в родном для операционной системы формате, с которым может работать gdb.
Затем нужно вызвать gdb так:
$ gdb prog
Если после запуска вашей программы произошла ошибка и был создан дамп-файл (core), можно передать отладчику и этот файл:
$ gdb prog core
Можно также подключиться к уже запущенному процессу, для этого нужно передать его PID:
$ gdb 1111
Только убедитесь сначала в том, что у вас нет файла 1111, поскольку gdb сначала ищет исполняемый файл, затем core-файл, а уже затем PID.
После запуска отладчика в интерактивном режиме вы можете использовать команды, самые важные из которых перечислены в таблице 22.2. Об остальных можно узнать в справочной системе: man gdb.
Команды gdb Таблица 22.2
Команда Назначение break [файл:]функция Установить точку останова run [аргументы] Запустить программу и передать ей указанные аргументы bt Обратная трассировка: отобразить стек программы print выражение Вывести значение выражении, операндами могут быть переменные, объявленные в вашей программа С Продолжить выполнение программы (после останова) Next Выполнить следующую строку. Это так называемый шаг «над» (step over). Если следующая строка — вызов функции, то мы выполним ее за один шаг — «перешагнем» ее Step Выполнить следующую строку, Это так называемый шаг «в» (step into). Если следующая строка — вызов функции, то мы будем последовательно выполнять все операторы тела функции help [имя] Вывести справку о команде отладчика или вывести общую информацию о нем Quit Выход
В данной таблице приведены далеко не все команды. Если вас интересует более полная информация, обратитесь к руководству по gdb.
22.3. Пример отладки программы
Давайте напишем программу, которая обнуляет элементы массива
a[]
. Да, программа ничего полезного не делает, но на ее примере можно продемонстрировать работу с отладчиком gdb.Вот листинг программы:
Листинг 22.1. Демонстрационная программа, содержащая ошибку
#include
int main() {
char developer[]="Denis";
int a[10];
int i;
do {
a[i]=0;
i++;
} while (i<10);
return 0;
}
Назовем нашу программу test.c и откомпилируем ее:
$ gcc -g -o test test.с
Опция -g добавляет отладочную информацию для отладчика gdb, а опция -o указывает имя результирующего файла.
Просмотрите листинг программы. Программа не делает ничего подозрительного — она всего лишь в цикле do обнуляет все элементы массива — сначала нулевой элемент a[0] становится нулем, потом первый, второй и так далее.
Попробуйте запустить программу, и вы увидите сообщение: Segmentation fault. В чем же причина? Попробуем выяснить ее с помощью отладчика gdb. Запустите отладчик с параметром test (это имя нашего исполняемого файла):
$ gdb test
В отладчике gdb введем команду run для запуска программы. И что мы видим? Что программа получила сигнал SIGSEGV, то есть имеет место ошибка Segmentation fault. Эта ошибка произошла в строке 12: a[i]=0. Но что может быть опасного в этом операторе? Ошибка Segmentation fault может произойти по нескольким причинам, одной из которых является выход за пределы массива. Проверим это: введите команду print i.
Команда print выводит значение указанной переменной (или выражения). Ого! Оказывается, мы пытаемся обнулить не нулевой элемент массива, а 715910728-ой! Почему же так произошло? Может быть, это gdb нагло врет и вместо значения переменной i выводит непонятно что? Для проверки на лживость введите команду print developer, которая выведет на экран значение переменной developer. С переменной developer все нормально — ее значение «Denis» (рис. 22.1).
Рис. 22.1. Сессия gdb
Так что же произошло? Так как переменная i не является глобальной, ее значение не обнуляется при запуске программы. Чтобы избежать подобной ошибки, нужно инициализировать переменную при объявлении:
int i = 0;
Вот мы и нашли ошибку!
Что же еще можно сделать с помощью gdb? Можно установить breakpoint, то есть точку останова, прерывающую выполнение программы в указанном месте. Это нужно для того, чтобы проследить состояние некоторых переменных и/или стека программы перед запуском какой-нибудь функции или же для пошаговой трассировки программы. Для пошаговой трассировки программы установите точку останова для функции main:
break main
Для установки точки останова на другую функцию введите команду break и в качестве аргумента укажите имя функции. Теперь запустите программу на выполнение (команда run). Команде run можно передать также аргументы, с которыми должна запускаться программа, например, run /home/denis/report.txt.
Когда отладчик достигнет точки останова, он приостановит выполнение программы и будет ждать ваших инструкций. Затем введите команду next для выполнения следующей строки. Команда next — это команда трассировки «над» функцией, то есть оператор вызова функции будет выполнен за один шаг. Команда step используется для пошаговой трассировки функций. Если вы хотите продолжить нормальное выполнение программы после точки останова, введите команду с.
Для отображения стека программы предназначена команда bt (backtrace). Команда list используется для отображения исходного текста программы (рис. 22.2).
Рис. 22.2. Команда list
Естественно, весь текст программы не поместится на экране, поэтому отладчик отобразит только его часть. Чтобы еще раз не вводить команду list, просто нажмите Enter, и gdb выполнит предыдущую команду.
Команда help предназначена для отображения справки по командам отладчика, а программа quit — для выхода из него.
Возможности программы gdb этим не ограничиваются. Отладчик gdb — это очень мощная программа, и я советую вам почаще использовать команду help — узнаете много полезного для себя.
Если вам удобнее использовать графический интерфейс, чем символьный, вы можете воспользоваться одним из интерфейсов к программе gdb. Один из них — KDbg. Все, что мы только что проделали с помощью команд отладчика gdb, вы можете сделать, используя меню интерфейса KDbg (рис. 22.3).
Рис. 22.3. Программа KDbg
Программа KDbg понравилась мне еще тем, что позволяет удобно просматривать регистры, потоки, память, стек и прочее, имеющее непосредственное отношение к процессу отладки. Однако имейте в виду, что интерфейс KDbg сильно ограничивает возможности отладки, потому что позволяет выполнять лишь базовые функции.
Существуют и другие оболочки для отладчика gdb, например, DDD. Эта оболочка обладает чуть большими возможностями, чем KDbg, но все же она является лишь надстройкой над gdb. Оболочек много, a gdb — один. Вы можете выбрать оболочку на свой вкус, а я вообще предпочитаю gdb без всяких оболочек.
Рис. 22.4. Оболочка DDD
22.4. Трассировка системных вызовов
Вы когда-нибудь задумывались о том, какие системные вызовы использует наша программа во время своего выполнения? Если да, то этот пункт как раз для вас. Возможно, пока он только удовлетворит ваше любопытство, но через некоторое время эта информация станет вам по-настоящему необходима.