Программирование для Linux. Профессиональный подход - страница 8
>
В первую очередь необходимо запустить программу под отладчиком. Для этого введите команду >run
и требуемые аргументы. Попробуем вызвать программу без аргументов:
>(gdb) run
>Starting program: reciprocal
>Program received signal SIGSEGV, Segmentation fault.
>__strtol_internal (nptr=0x0, endptr=0x0, base=10, group=0)
>at strtol.c:287
>287 strtol.c: No such file or directory.
>(gdb)
Проблема заключается в том, что в функции >main()
не предусмотрены средства контроля ошибок. Программа ожидает наличия аргумента, а в данном случае его нет. Получение сигнала >SIGSEGV
означает крах программы. Отладчик определяет, что причина краха находится в функции >__strtol_internal()
. Эта функция является частью стандартной библиотеки, но ее исходный файл отсутствует. Вот почему появляется сообщение "No such file or directory". С помощью команды >where
можно просмотреть содержимое стека:
>(gdb) where
>#0 __strtol_internal (nptr=0x0, endptr=0x0, base=10, group=0)
> at strtol.c:287
>#1 0x40096fb6 in atoi (nptr=0x0) at ../stdlib/stdlib.h:251
>#2 0x804863e in main (argc=1, argv=0xbffff5e4) at main.c:8
Как нетрудно заметить, функция >main()
вызвала функцию >atoi()
, передав ей нулевой указатель, что и стало причиной ошибки.
С помощью команды >up
можно подняться но стеку на два уровня, дойдя до функции >main()
:
>(gdb) up 2
>#2 0x804863е in main (argc=1, argv=0xbffff5e4) at main.c:8
>8 i = atoi(argv[1]);
Заметьте, что отладчик нашел исходный файл >main.c
и отобразил строку, где располагается ошибочный вызов функции. Узнать значение нужной локальной переменной позволяет команда >print
:
>(gdb) print argv[1]
>$2 = 0x0
Это подтверждает нашу догадку о том, что причина ошибки — передача функции >atoi()
указателя >NULL
.
Установка контрольной точки осуществляется посредством команды >break
:
>(gdb) break main
>Breakpoint 1 at 0x804862e: file main.c, line 8.
В данном случае контрольная точка размещена в первой строке функции >main()
. Давайте теперь заново запустим программу, передав ей один аргумент:
>(gdb) run 7
>Starting program: reciprocal 7
>Breakpoint 1, main (argc=2, argv=0xbffff5e4) at main.c:8
>8 i = atoi(argv[1]);
Как видите, отладчик остановился на контрольной точке- Перейти на следующую строку можно с помощью команды >next
:
>(gdb) next
>9 printf("The reciprocal of %d is %g\n", i,
>reciprocal(i));
Если требуется узнать, что происходит внутри функции >reciprocal()
, воспользуйтесь командой >step
:
>(gdb) step
>reciprocal (i=7) at reciprocal.cpp:6
>6 assert(i != 0);
Иногда удобнее запускать отладчик >gdb
непосредственно из редактора Emacs, а не из командной строки. Для этого следует ввести в редакторе команду >M-x gdb
. Когда отладчик останавливается в контрольной точке, редактор Emacs автоматически открывает соответствующий исходный файл. Не правда ли. проще разобраться в происходящем, глядя на весь файл, а не на одну его строку?
1.5. Поиск дополнительной информации
В каждый дистрибутив Linux входит масса полезной документации. В ней можно прочесть почти все из того, о чем говорится в этой книге (хотя это, очевидно, займет больше времени). Документация не всегда хорошо организована, поэтому поиск нужной информации требует определенной изобретательности. Иногда представленные факты оказываются устаревшими, так что не стоит всему слепо верить.
Ниже описаны наиболее полезные источники информации о программировании в Linux.
1.5.1. Интерактивная документация
В дистрибутивы Linux входят >man
-страницы с описанием большинства стандартных команд, системных вызовов и стандартных библиотечных функций. Интерактивная документация разбита на разделы, которым присвоены номера. Для программистов наиболее важными являются следующие разделы:
(1) пользовательские команды;
(2) системные вызовы:
(3) стандартные библиотечные функции:
(8) системные/административные команды.
Числа обозначают номера разделов. Для доступа к страницам интерактивной документации применяется команда >man
. Она имеет вид >man имя
, где имя — название команды или функции. Иногда одно и то же имя встречается в разных разделах. В этом случае номер раздела нужно указать явно, поставив его перед именем. К примеру, так вызывается страница с описанием команды