Быстрый старт с отладчиком GDB

GDB — стандартный отладчик для C, C++ и нескольких других языков. Компилируйте с флагом -g, запускайте gdb <программа>, ставьте точки останова (break), смотрите значения (print), выполняйте пошагово (step) или продолжайте (continue). В статье разберём пример с «делением на ноль», покажем рабочий порядок, типичные приёмы, альтернативы и чеклист для отладки.
Зачем нужен GDB — одно предложение
GDB позволяет «заглянуть внутрь» программы во время её выполнения: просмотреть стек, значения переменных и управлять исполнением, чтобы локализовать и исправить ошибку.
Краткие определения
- Точка останова (breakpoint): команда, приостанавливающая выполнение на заданной строке или функции.
- step (s): выполнить текущую строку и войти в функцию, если она вызывается.
- next (n): выполнить текущую строку, не заходя внутрь функций.
- SIGFPE: сигнал арифметической ошибки (например, деление на ноль).
Основы GDB
Перед тем как отлаживать, нужно скомпилировать программу так, чтобы компилятор сохранил отладочную информацию. Для gcc/clang это флаг -g. Например:
gcc -g -Wall gdb-test.c -o gdb-testУстановка GDB на Debian/Ubuntu:
sudo apt install gdbЗапуск отладчика для конкретного исполняемого файла:
gdb ./gdb-testПосле запуска gdb само исполняемое приложение ещё не запускается — вы находитесь в интерактивном интерфейсе отладчика и можете настроить брейкпоинты и параметры запуска. Для старта исполнения используйте команду run, при необходимости указывая аргументы:
run [аргументы]Основные команды, которые пригодятся сразу:
- break <номер_строки> — поставить точку останова на строке;
- break <функция> — точка останова на входе в функцию;
- run — запустить программу;
- continue (c) — продолжить выполнение после брейкпоинта;
- step (s) — выполнить одну строку и зайти внутрь функции;
- next (n) — выполнить одну строку, не заходя в функции;
- print <переменная> — показать значение переменной;
- backtrace (bt) — вывести стек вызовов;
- info locals — показать локальные переменные текущего фрейма;
- quit — выйти из gdb.
Важно: отладочная информация и оптимизации компилятора взаимодействуют. Оптимизированный код (-O2, -O3) может менять порядок инструкций и исчезновение переменных, что усложняет чтение состояния в gdb. Для комфортной интерактивной отладки собирайте с -g и без оптимизаций.
Пример: разбор кода и поиск ошибки
Исходный пример (сохраните как gdb-test.c):
#include
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. Проблема проявляется как “Floating point exception (core dumped)” — это не всегда связано с числами с плавающей точкой: в Unix-системах SIGFPE сигнализирует об арифметической ошибке, чаще всего при целочисленном делении на ноль.
Шаги отладки в GDB (переведённый и расширенный поток действий):
- Компиляция с отладочной информацией:
gcc -g -Wall gdb-test.c -o gdb-test- Запуск GDB на исполняемом файле:
gdb ./gdb-test- Установка точки останова в строке с делением (в примере строка 11):
(gdb) break 11- Запуск программы внутри gdb:
(gdb) runКогда брейкпоинт будет достигнут, gdb покажет текущую строку и вернёт управление:
Breakpoint 1, main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb)- Посмотреть значение переменной out:
(gdb) print out
$1 = 5- Продолжить выполнение до следующего попадания в брейкпоинт:
(gdb) continueПовторяя print и continue, вы обнаружите, что однажды out оказывается равным 0:
(gdb) print out
$3 = 0- Выполнить следующую инструкцию пошагово, чтобы увидеть момент исключения:
(gdb) step
Program received signal SIGFPE, Arithmetic exception.
0x080484aa in main () at gdb-test.c:11
11 tot = tot + 0xffffffff/out;
(gdb) step
Program terminated with signal SIGFPE, Arithmetic exception.
The program no longer exists.Вывод: деление на ноль вызывает SIGFPE — причина найдена. Исправление может быть простым: проверять out на ноль перед делением.
Пример исправления (псевдо-код):
if (out != 0) {
tot = tot + 0xffffffff / out;
} else {
// обработка нулевого значения, например, пропуск или лог
}Частые приёмы и советы
- Всегда компилируйте с -g при подготовке к отладке.
- Включайте -Wall, чтобы компилятор подсвечивал потенциальные проблемы.
- Для сложных багов используйте сочетание bt, info locals и print для понимания состояния стека.
- Если переменная «пропала» в оптимизированном билде, пересоберите без оптимизаций.
- Используйте watch
для отслеживания изменения выражения/переменной. - Для многопоточных программ применяйте thread apply all bt и переключайтесь между потоками с thread
.
Important: если вы получаете SIGFPE, SIGSEGV или похожие сигналы, gdb сразу покажет адрес и строку — это основная подсказка.
Когда GDB может не помочь (ограничения и подводные камни)
- Оптимизация компилятора: номера строк и значения переменных могут «не соответствовать» реальности.
- Инлайнинг и удаление переменных: некоторые локальные переменные могут быть недоступны в отладчике.
- Утечки памяти и гонки данных: для этих проблем полезнее valgrind, sanitizers (ASan/TSan) или статический анализ.
- Краш в нативном коде, вызванный внешними библиотеками: может потребоваться собрать эти библиотеки с -g.
Альтернативы и дополнительные инструменты
- lldb — отладчик от проекта LLVM, похож по функционалу и интегрируется с clang/LLDB.
- IDE-отладчики: Visual Studio, CLion, VS Code + расширения (могут дать графический интерфейс поверх gdb/lldb).
- printf/puts — простой, но эффективный прием при быстрых проверках или где сложно подключить отладчик.
- AddressSanitizer/ThreadSanitizer/UBSan — для поиска ошибок памяти и неопределённого поведения.
- valgrind — для поиска утечек памяти и ошибок доступа.
Ментальные модели и эвристики при отладке
- «Подход сверху-вниз»: сначала воспроизведите проблему, затем локализуйте модуль/функцию и уже внутри исследуйте переменные.
- «Разделяй и властвуй»: если поведение зависит от набора входных данных, минимизируйте вход до минимального воспроизводимого значения.
- «Смените инструмент»: если интерактивная отладка не даёт ответа, используйте санитайзеры или трассировку.
Чеклист для сессии отладки (роль — разработчик)
- Собрать с -g и без оптимизаций.
- Запустить в gdb: поставить брейкпоинт в предполагаемом месте.
- Проверить значения локальных переменных и аргументов функции (print, info locals).
- Посмотреть стек вызовов (bt).
- Использовать step/next, чтобы понять точный момент ошибки.
- Протестировать гипотезы, исправить и прогнать регрессию.
Роль — тимлид: убедиться в наличии воспроизводимого примера и минимальных тестов.
Роль — QA: подготовить набор входных данных, покрывающий баг, и проверочный чеклист после исправления.
Небольшая методология поиска ошибки (микропроцесс)
- Воспроизведите баг в контролируемых условиях.
- Минимизируйте входные данные до простейшего примера.
- Поставьте брейкпоинт до места, где проявляется симптом.
- Смотрите значения, стек и шагайте до места сбоя.
- Сформулируйте гипотезу, подтвердите/опровергните шагами в отладчике.
- Исправьте и добавьте тест, чтобы баг не вернулся.
Примеры команд-подсказок
- break main — установить брейкпоинт на входе в main
- break file.c:42 — брейкпоинт в файле file.c на строке 42
- watch x — остановить при изменении x
- info breakpoints — список брейкпоинтов
- delete
— удалить брейкпоинт
Критерии приёмки
- Были воспроизведены шаги для воспроизведения бага.
- Причина корня (root cause) определена и задокументирована.
- Исправление проверено unit/integration тестами.
- Производительность и поведение на краевых значениях протестированы.
1‑строчный глоссарий
- GDB: отладчик GNU для низкоуровневого анализа исполнения программ и значений переменных в них.
Частые вопросы и сценарии (edge-case gallery)
- Что если программа немедленно падает до того, как я успел поставить брейкпоинт? — Запускайте gdb и ставьте точку останова в main или используйте run и после короткого времени break; можно также запускать gdb с опцией –args и передавать параметры.
- Как отлаживать программу, запущенную извне (systemd, служба)? — Можно прикрепиться к PID с помощью attach
. - Как анализировать core dump? — gdb ./program corefile.
Краткая сводка (Summary)
GDB — мощный интерактивный инструмент, который помогает шаг за шагом локализовать ошибки: ставить точки останова, смотреть переменные, просматривать стек и выполнять код пошагово. Совмещайте gdb с современными средствами (sanitizers, valgrind) и не забывайте собирать с -g и без оптимизаций для удобства отладки.
Notes: если вы только начинаете, потратьте время на изучение bt, print, watch и основ управления потоками — это даст высокий бонус эффективности.
Образец исправления для gdb-test.c и пример теста, который стоит добавить в набор регрессии:
// тест: минимальный набор, проверяющий отсутствие SIGFPE
// вход — массив без нулей или с защитой при деленииСпасибо, что дочитали — практика и ёмкие воспроизводимые примеры ускорят процесс обучения GDB.
Похожие материалы
Несколько аккаунтов Skype: Multi Skype Launcher
Журнал для работы: повысить продуктивность
Персональные звуки уведомлений на Android
Скачивание шоу Hulu для офлайн‑просмотра
Microsoft Start: персонализированная новостная лента