Рейтинг@Mail.ru

Наши друзья и партнеры

UnixForum





Библиотека сайта rus-linux.net

Как отлаживать программы на языке C в Linux с помощью отладчика GDB

Оригинал: How to debug C programs in Linux using gdb
Автор: Himanshu Arora
Дата публикации: 16 января 2017 г.
Перевод: А.Панин
Дата перевода: 7 марта 2017 г.

Вне зависимости от вашего опыта программирования, все разработанное вами программное обеспечение просто не может не содержать ошибок. По этой причине поиск и устранение ошибок являются одними из наиболее важных задач, выполняемых в рамках цикла разработки программного обеспечения. Хотя и существует несколько способов выявления ошибок в коде (тестирование, самостоятельный аудит кода и другие), для этой цели создан отдельный тип программного обеспечения под названием "отладчики", позволяющего вам найти проблемный фрагмент кода и максимально быстро исправить его.

Если вы разрабатываете программное обеспечение на языках C/C++ или пользуетесь такими более редкими языками программирования, как Fortran и Modula-2, вам будет полезно знать о существовании отличного отладчика под названием GDB, который позволяет достаточно просто отлаживать ваш код, помогая устранять ошибки и различные проблемные конструкции. В рамках данной статьи мы постараемся обсудить основные приемы работы с GDB, включая некоторые полезные функции/параметры данного инструмента.

Но перед тем, как двинуться дальше, стоит упомянуть о том, что все инструкции и примеры, приведенные в данной статье, были протестированы в системе Ubuntu 14.04 LTS. В статье был использован пример кода на языке C; в качестве командной оболочки использовалась командная оболочка Bash (версии 4.3.11); также стоит сказать о том, что для отладки тестовой программы использовался отладчик GDB версии 7.7.1.

Основные аспекты использования GDB

По сути, GDB позволяет вам заглянуть внутрь программы в процессе ее исполнения, способствуя тем самым идентификации и локализации проблемы. Мы обсудим методику использования отладчика GDB на основе примера в следующем разделе, но перед этим стоит рассмотреть несколько основных аспектов использования отладчика, которые окажутся полезными в будущем.

Во-первых, для успешного использования таких отладчиков, как GDB, вам придется компилировать вашу программу таким образом, чтобы компилятор генерировал отладочную информацию, необходимую отладчикам. Например, в случае компилятора GCC, который будет впоследствии использоваться для компиляции примера программы на языке C, вам придется дополнительно передать параметр -g на этапе компиляции кода.

Вы можете получить дополнительную информацию о данном параметре компилятора на его странице руководства.

На следующем шаге следует убедиться в том, что отладчик GDB установлен в вашей системе. Если он не установлен и вы используете основанный на Debian дистрибутив, такой, как Ubuntu, вы можете установить данный инструмент с помощью следующей команды:

sudo apt-get install gdb

Инструкции по установке отладчика в других дистрибутивах приведены на данной странице.

Теперь, когда вы скомпилировали вашу программу со специальным параметром компилятора для ее подготовки к отладке и установили в систему отладчик GDB, вы можете выполнить программу в режиме отладки с помощью следующей команды:

gdb [имя-бинарного-файла]

Хотя данная команда и инициирует запуск отладчика GDB, ваша программа не начнет исполняться сразу же после его запуска. В этот момент у вас имеется возможность задать параметры отладки. Например, вы можете установить точку останова, сообщающую отладчику GDB о том, что следует приостановить исполнение программы на строке с определенным номером или функции.

Для того, чтобы инициировать исполнение вашей программы, вам придется выполнить следующую команду GDB:

run

Стоит упомянуть и о том, что в том случае, если вашей программе нужно передать некие аргументы командной строки, вы можете передать их вместе с данной командной. Например:

run [аргументы]

GDB поддерживает большое количество полезных команд, которые находят свое применение в процессе отладки программных продуктов. Мы обсудим некоторые из них в следующем разделе.

Пример использования 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, устанавливает это значение в качестве значения целочисленной переменной out, после чего рассчитывает значение переменной tot путем суммирования ее предыдущего значения и результата вычисления 0xffffffff/out.

Проблема заключается в том, что после запуска скомпилированного кода выводится следующее сообщение об ошибке:

$ ./gdb-test
Floating point exception (core dumped)

Итак, для отладки кода в первую очередь следует скомпилировать код программы с использованием параметра компилятора -g. Это команда компиляции:

gcc -g -Wall gdb-test.c -o gdb-test

Далее предлагаю запустить отладчик GDB и сообщить ему имя исполняемого файла, который мы хотим отлаживать. Для этого используется следующая команда:

gdb ./gdb-test

Теперь следует обратить внимание на то, что в процессе исполнения программы выводится сообщение об ошибке "floating point exception" и, как многие из вас наверняка знают, данная ошибка обычно связана с делением произвольного значения на ноль. Помня об этом, я помещаю точку останова в строку под номером 11, где осуществляется деление. Это делается следующим образом:

(gdb) break 11

Обратите внимание на приветствие отладчика (gdb), после которого я ввел команду break 11.

Теперь я прошу 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)

Теперь для подтверждения предположения о том, что имеется проблема, я использую команду GDB 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 для получения дополнительной информации о данном инструменте и попытайтесь самостоятельно использовать его для отладки своего кода. Рассматриваемый отладчик не является дружелюбным, но трата времени на его изучение вполне оправдана.


Поделиться: