Основы программирования в Linux - Нейл Мэтью
Шрифт:
Интервал:
Закладка:
Отладочная информация может увеличить исполняемый файл во много (до десяти) раз. Несмотря на увеличение размера исполняемого файла (он займет больше места на диске), объем памяти, необходимый для выполнения программы, практически остается тем же самым. Перед вводом программы в эксплуатацию неплохо удалить из нее отладочную информацию, но только после того, как программа полностью отлажена.
ПримечаниеУдалить отладочную информацию из исполняемого файла без повторной компиляции можно, выполнив команду strip <файл>.
Отладка с помощью gdb
Для отладки программы вы можете применять отладчик проекта GNU, gdb. Это очень мощный отладчик, который распространяется бесплатно и может использоваться на многих платформах UNIX. Он также служит отладчиком по умолчанию в системах Linux. gdb перенесен на многие другие платформы и может применяться для отладки встроенных систем реального времени.
Запуск gdb
Перекомпилируйте программу примера для отладки и запустите gdb:
$ cc-g -o debug3 debug3.c
$ gdb debug3
GNU gdb 6.6
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 "i586-suse-linux"...
Using host libthread_db library "/lib/libthread_db.so.1".
(gdb)
У gdb есть довольно подробная интерактивная система помощи и полное справочное руководство, представляемое как набор файлов, которые можно просматривать с помощью программы info или из редактора Emacs.
(gdb) help
List of classes of commands:
aliases -- Aliases of other commands
breakpoints -- Making program stop at certain points
data -- Examining data
files -- Specifying and examining files
internals -- Maintenance commands
obscure -- Obscure features
running -- Running the program
stack -- Examining the stack
status -- Status inquiries
support -- Support facilities
tracepoints -- Tracing of program execution without stopping the program
user-defined -- User-defined commands
Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Command name abbreviations are allowed if unambiguous,
(gdb)
Сам по себе отладчик gdb — приложение, выполняющееся в текстовом режиме, но он предоставляет несколько сокращенных клавишных команд для выполнения повторяющихся задач. Во многих версиях есть редактирование в командной строке с хронологией команд, так что вы можете прокрутить список назад и выполнить ту же команду снова (попробуйте воспользоваться клавишами перемещения курсора). Все версии отладчика поддерживают "пустую команду"; нажатие клавиши <Enter> выполняет последнюю команду еще раз. Это особенно удобно при проверке выполнения программы в построчном режиме с помощью команд step или next.
Для завершения работы gdb применяйте команду quit.
Выполнение программы
Выполнить программу можно с помощью команды run. Любые аргументы, переданные вами команде run, пересылаются в программу как ее собственные аргументы. В данном случае вам не нужны никакие аргументы.
Предположим, что ваша система, как и системы обоих авторов, теперь генерирует сообщение о нарушении сегментации памяти. Если нет, читайте дальше. Вы узнаете, что делать, когда одна из ваших программ действительно сгенерирует сообщение о нарушении сегментации. Если вы не получили такого сообщения, но хотите поработать с этим примером во время чтения книги, когда первая из проблем, связанных с доступом к памяти, будет устранена, можно взять программу из файла debug4.c.
(gdb) run
Starting program: /home/neil/BLP4e/chapter10/debug3
Program received signal SIGSEGV, Segmentation fault.
0x0804846f in sort (a=0x804a040, n=5) at debug3.c:23
23 /* 23 */ if(a[j].key > a[j+1].key) {
(gdb)
Программа, как и прежде, выполняется неверно. Когда программа дает сбой, gdb указывает причину и местонахождение. Теперь вы можете выяснять первопричину проблемы.
В зависимости от ядра вашей системы, версий библиотеки С и компилятора сбой программы может произойти в другом месте, например в строке 25, когда элементы массива меняются местами, а не в строке 23, когда сравниваются поля key элементов массива. Если это так, вы увидите следующее сообщение:
Program received signal SIGSEGV, Segmentation fault.
0x8000613 in sort (a=0x8001764, n=5) at debug3.c:25
25 /* 25 */ a[j] = a[j+1];
Вы все равно можете продолжать следить за примером сеанса работы gdb, который описывается далее.
Трассировка стека
Программа была остановлена при выполнении функции sort в строке 23 исходного файла debug3.c. Если при компиляции вы не включили в программу дополнительную отладочную информацию (cc -g), то не сможете увидеть, где программа дала сбой, и использовать имена переменных для просмотра данных.
Увидеть, как вы добрались до этого места, можно с помощью команды backtrace:
(gdb) backtrace
#0 0x0804846f in sort (a=0x804a040, n=5) at debug3.c:23
#1 0x08048583 in main() at debug3.c:37
(gdb)
Это очень простая программа и трассировка у нее короткая, т.к. вы не вызывали много функций из других функций. Вы только видите, что sort была вызвана из main в строке 37 того же файла debug3.c. Обычно проблема гораздо сложнее, и команда backtrace применяется для определения маршрута, который привел к месту ошибки. Эта информация очень полезна при отладке функций, вызываемых из множества разных мест.
У команды backtrace есть сокращенная форма bt и для совместимости с другими отладчиками есть команда where, выполняющая ту же функцию.
Просмотр переменных
Отладчик вывел данные в момент остановки программы, и в трассировке стека показаны значения аргументов функции.
Функция sort была вызвана с параметром а, значение которого 0х804а040. Это адрес массива. Обычно он в различных системах разный и зависит от используемых компилятора и операционной системы.
Сбойная строка 23 — сравнение одного элемента массива с другим:
/* 23 */ if (a[j].key > a[j+1].key) {
Отладчик можно применять для просмотра содержимого параметров функции, локальных переменных и глобальных данных. Команда print отображает содержимое переменных и других выражений:
(gdb) print j
$1 = 4
Вы видите, что у локальной переменной j значение 4. Любые значения, выводимые командами gdb, подобными данной, сохраняются для будущего использования в псевдопеременных. В данном случае переменной $1 присвоено значение 4, на случай, если она вам позже понадобится. Последующие команды будут сохранять свои результаты в переменных $2, $3 и т.д.
Значение переменной j, равное 4, означает, что программа попыталась выполнить оператор
if (а[4].key > а[4+1].key)
У массива array, который вы передали функции sort, только пять элементов, которые пронумерованы от 0 до 4. Поэтому данный оператор считывает несуществующий элемент массива array[5]. Переменная цикла j приняла некорректное значение.
Если ваша программа завершилась в строке 25, система обнаружила чтение за пределами массива, только когда взялась за перестановку элементов массива, выполнив оператор
/* 25 */ а[j] = a[j+1];
который при j, равной 4, дает в результате
а[4] = а[4+1];
Просмотреть элементы передаваемого массива можно, применив выражение в команде print. В программе gdb вы можете использовать почти любое допустимое выражение языка С для вывода значения переменной, элемента массива или указателя.
(gdb) print а[3]
$2 = {data = "alex", ' ' <repeats 4091 times>, key = 1}
(gdb)
Отладчик gdb сохраняет результаты выполнения команд в псевдопеременных вида $<номер>. Результат последней команды всегда хранится в псевдопеременной $, а предыдущей — в $$. Это позволяет результат одной команды использовать в другой. Например:
(gdb) print j
$3 = 4
(gdb) print a[$-1].key
$4 = 1
Вывод листинга программы
Вы можете в программе gdb вывести на экран исходный текст программы с помощью команды list. Она выводит фрагмент кода, расположенного рядом с текущей позицией. Последующие вызовы list выведут остальной текст. Команде list можно задать в качестве аргумента имя функции, и команда отобразит фрагмент текста в этом месте программы, или можно указать пару номеров строк, и на экране появится текст программы, находящийся между этими строками.