Как отлаживать программы на C в Linux с помощью gdb
На этой странице
- Основные сведения об отладчике GDB
- Пример использования GDB
- Заключение
Независимо от того, насколько вы опытный программист, любое разрабатываемое вами программное обеспечение не может быть полностью свободным от ошибок. Таким образом, выявление ошибок и их исправление — одна из важнейших задач в цикле разработки программного обеспечения. Хотя существует множество способов выявления ошибок (тестирование, самопроверка кода и т. д.), существует специальное программное обеспечение, называемое отладчиками, которое поможет вам понять, в чем именно заключается проблема, чтобы вы могли легко ее исправить.
Если вы программист C/C++ или разрабатываете программное обеспечение с использованием языков программирования Fortran и Modula-2, вам будет приятно узнать, что существует отличный отладчик — GDB — который позволяет легко отлаживать код на наличие ошибок и других проблем. В этой статье мы обсудим основы GDB, включая некоторые полезные функции/опции, которые он предоставляет.
Но прежде чем мы двинемся дальше, стоит упомянуть, что все инструкции и примеры, представленные в этой статье, были протестированы на Ubuntu 14.04LTS. Пример кода, используемый в руководстве, написан на языке C; используемая нами оболочка командной строки — bash (версия 4.3.11); мы использовали версию GDB 7.7.1.
Основы отладчика GDB
С точки зрения непрофессионала, GDB позволяет вам заглянуть внутрь программы во время ее выполнения, что позволяет вам определить, в чем именно заключается проблема. Хорошо обсудите использование отладчика GDB на рабочем примере в следующем разделе, но перед этим обсудите несколько основных моментов, которые помогут вам в дальнейшем.
Во-первых, чтобы успешно использовать отладчики, такие как GDB, вы должны скомпилировать свою программу таким образом, чтобы компилятор также выдавал отладочную информацию, необходимую отладчикам. Например, в случае компилятора gcc, который будет использоваться для компиляции примера программы C далее в этом руководстве, вам нужно использовать параметр командной строки -g при компиляции кода.
Чтобы узнать, что говорится на странице руководства компилятора gcc об этой опции командной строки, перейдите сюда.
Следующий шаг — убедиться, что в вашей системе установлен GDB. Если это не так, и вы работаете в системе на основе Debian, такой как Ubuntu, вы можете легко установить инструмент, используя следующую команду:
sudo apt-get install gdb
Для установки на любой другой дистрибутив перейдите сюда.
Теперь, когда вы скомпилировали свою программу таким образом, что она готова к отладке, и GDB находится в вашей системе, вы можете выполнить свою программу в режиме отладки, используя следующую команду:
gdb [prog-executable-name]
Хотя это запустит отладчик GDB, исполняемый файл вашей программы не будет запущен в этот момент. Это время, когда вы можете определить параметры, связанные с отладкой. Например, вы можете определить точку останова, которая сообщает GDB приостановить выполнение программы на определенном номере строки или функции.
Двигаясь дальше, чтобы фактически запустить вашу программу, вам нужно выполнить следующую команду gdb:
run
Здесь стоит упомянуть, что если ваша программа требует передачи ей некоторых аргументов командной строки, вы можете указать их здесь. Например:
run [arguments]
GDB предоставляет множество полезных команд, которые пригодятся при отладке. Хорошо обсудим некоторые из них в примере в следующем разделе.
Пример использования ГБД
Теперь у нас есть общее представление о GDB, а также о его использовании. Итак, давайте возьмем пример и применим знания там. Вот пример кода:
#include <stdio.h>
int main()
{
int out = 0, tot = 0, cnt = 0;
int val[] = {5, 54, 76, 91, 35, 27, 45, 15, 99, 0};
while(cnt < 10)
{
out = val[cnt];
tot = tot + 0xffffffff/out;
cnt++;
}
printf("\n Total = [%d]\n", tot);
return 0;
}
По сути, этот код делает следующее: он выбирает каждое значение, содержащееся в массиве val, присваивает его выходному целому числу, а затем вычисляет tot, суммируя предыдущее значение переменных и результат 0xffffffff/out.
Проблема здесь в том, что когда код запускается, он выдает следующую ошибку:
$ ./gdb-test
Floating point exception (core dumped)
Таким образом, для отладки кода первым шагом будет компиляция программы с параметром -g. Вот команда:
gcc -g -Wall gdb-test.c -o gdb-test
Далее давайте запустим GDB и сообщим ему, какой исполняемый файл мы хотим отлаживать. Вот команда для этого:
gdb ./gdb-test
Теперь ошибка, которую я получаю, является исключением с плавающей запятой, и, как многие из вас, возможно, уже знают, она вызвана n % x, когда x равно 0. Итак, имея это в виду, я поставил точку останова в строке номер 11, где происходит разделение. Это было сделано следующим образом:
(gdb) break 11
Обратите внимание, что (gdb) — это приглашение отладчика, я только что написал команду break.
Теперь я попросил GDB начать выполнение программы:
run
Итак, когда точка останова сработала в первый раз, вот что показал GDB в выводе:
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb)
Как видно из приведенного выше вывода, отладчик показал строку, в которой была поставлена точка останова. Теперь давайте распечатаем текущее значение out. Это можно сделать следующим образом:
(gdb) print out
$1 = 5
(gdb)
Как видите, было напечатано значение 5. Итак, на данный момент все в порядке. Я попросил отладчик продолжить выполнение программы до следующей точки останова, что можно сделать с помощью команды c.
c
Я продолжал делать эту работу, пока не увидел, что значение out равно нулю.
...
...
...
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$2 = 99
(gdb) c
Continuing.
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) print out
$3 = 0
(gdb)
Теперь, чтобы подтвердить, что это именно проблема, я использовал команду GDBs s (или step) вместо c на этот раз. Причина в том, что я просто хотел выполнить строку 11, где выполнение программы в настоящее время приостановлено, и посмотреть, произойдет ли сбой в этот момент.
Вот что произошло:
(gdb) s
Program received signal SIGFPE, Arithmetic exception.
0x080484aa in main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
Да, как подтверждается выделенным выводом выше, именно здесь было выдано исключение. Окончательное подтверждение пришло, когда я снова попытался запустить команду s:
(gdb) s
Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.
Таким образом, вы можете отлаживать свои программы с помощью GDB.
Заключение
Здесь мы только коснулись поверхности, так как GDB предлагает множество возможностей для изучения и использования пользователями. Просмотрите справочную страницу GDB, чтобы узнать больше об этом инструменте, и попробуйте использовать его всякий раз, когда вы отлаживаете что-то в своем коде. С отладчиком связано некоторое время обучения, но оно того стоит.