Как читать и анализировать core dump в Linux с помощью gdb

11 минут чтения
Средний рейтинг статьи — 4.9

Иногда приложения в Linux падают с критической ошибкой, создавая core dump — снимок памяти процесса в момент аварии. Core dump содержит состояние регистров, стек вызовов, значения переменных и другую информацию, которая позволяет понять, почему приложение упало.

В этой статье разберём, как включить создание core dump, как открыть его в gdb и как анализировать ошибки на практике.

Включение core dump в Linux

По умолчанию многие системы ограничивают создание core dump. Чтобы разрешить их, нужно:

  1. Убедиться, что лимиты ядра позволяют создавать файлы:
ulimit -c unlimited
  1. Настроить директорию для хранения core dump (опционально):
sudo mkdir -p /var/dumps
sudo chmod 1777 /var/dumps
echo '/var/dumps/core.%e.%p.%t' | sudo tee /proc/sys/kernel/core_pattern

Здесь:

  • %e — имя исполняемого файла,
  • %p — PID процесса,
  • %t — время создания.

Теперь все аварийные процессы будут сохранять core dump в /var/dumps.

Проверка наличия core dump

После падения приложения можно убедиться, что core dump создан:

ls -lh /var/dumps

Файл будет содержать имя процесса, PID и timestamp. Этот файл и станет основным источником для анализа.

Анализ core dump с помощью gdb

Основная команда для открытия core dump:

gdb /path/to/executable /var/dumps/core.processname.pid

После запуска gdb можно выполнять несколько ключевых команд:

  • bt (backtrace) — вывод стеков вызова всех потоков, показывает последовательность функций до аварии.
  • frame N — переключение на конкретный фрейм в стеке, позволяет смотреть локальные переменные.
  • info locals — показывает локальные переменные текущего фрейма.
  • info threads — список всех потоков процесса, их состояние и ID.

Пример использования:

(gdb) bt
#0  0x00007f8c8a1d6c30 in divide_by_zero () at main.c:42
#1  0x00007f8c8a1d6c70 in main () at main.c:50
(gdb) frame 0
(gdb) info locals
denominator = 0
numerator = 100

Из этого примера видно, что ошибка произошла из-за деления на ноль в функции divide_by_zero().

Полезные команды для глубокого анализа

  • list — показывает исходный код вокруг текущей точки падения.
  • print variable — вывод значения конкретной переменной.
  • x /N format address — просмотр содержимого памяти.
  • thread apply all bt — вывод стеков вызова для всех потоков.

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

Советы по эффективному анализу

  1. Собирайте символьные таблицы
    Скомпилируйте приложение с -g, чтобы gdb показывал имена функций и переменных.
  2. Используйте core pattern для отладки production
    Настройка /proc/sys/kernel/core_pattern позволяет автоматически сохранять core dump в определённую директорию, чтобы их можно было анализировать после падений.
  3. Объединяйте с логами приложения
    Часто причина падения видна через сочетание core dump и логов.
  4. Скрипты и инструменты
    Для массового анализа можно использовать gdb -batch -ex 'bt' /path/to/executable /path/to/core, чтобы получить backtrace без интерактивной сессии.

Частые сценарии

  • Segmentation fault — gdb покажет точную строку, где произошло обращение к запрещённой памяти.
  • Divide by zero / arithmetic exception — локальные переменные подскажут значения, вызвавшие ошибку.
  • Use after free / heap corruption — можно использовать вместе с valgrind или AddressSanitizer для уточнения причин.

Core dump и gdb вместе позволяют полностью реконструировать состояние процесса в момент аварии, что делает их незаменимыми для отладки критических приложений.

Практический пример: анализ Segmentation Fault

Создадим маленькую программу crash_example.c:

#include <stdio.h>
#include <stdlib.h>
 
int main() {
    int *ptr = NULL;
    printf("Перед обращением к NULL\n");
    *ptr = 42;  // здесь будет segmentation fault
    printf("Эта строка не выполнится\n");
    return 0;
}

Скомпилируем с отладочными символами:

gcc -g crash_example.c -o crash_example

Запускаем программу:

./crash_example
Segmentation fault (core dumped)

Теперь в текущей директории появится файл core (или core.crash_example.pid в зависимости от core_pattern).

Анализ с помощью gdb

Открываем core dump:

gdb ./crash_example core

Внутри gdb:

(gdb) bt
#0  0x00005555555551b6 in main () at crash_example.c:7
(gdb) frame 0
(gdb) info locals
ptr = 0x0

Вывод показывает:

  • Ошибка произошла в строке *ptr = 42; (строка 7).
  • Переменная ptr равна NULL (0x0), что и вызвало segmentation fault.

Можно также вывести содержимое памяти (для наглядности):

(gdb) x/1x ptr
0x0: 0x0

Советы для более сложных приложений

  • Для многопоточных программ используйте:
thread apply all bt

чтобы увидеть стеки всех потоков.

  • Для программ с динамической памятью можно подключать valgrind или AddressSanitizer, чтобы отлавливать use-after-free и heap corruption вместе с core dump.
  • В продакшене удобно настроить core dump в отдельной папке, чтобы при падении сохранялся файл с PID и timestamp: /var/dumps/core.%e.%p.%t.

Итог

Core dump в Linux — это мощный инструмент для анализа аварийных завершений. Правильная настройка системы и использование gdb позволяют:

  • находить причины падений без догадок,
  • изучать поведение потоков и переменных,
  • восстанавливать полное состояние процесса для глубокого анализа.

Освоение работы с core dump — ключевой навык для системных разработчиков и инженеров по поддержке production-приложений.

11 минут чтения
Средний рейтинг статьи — 4.9

Настроить мониторинг за 30 секунд

Надежные оповещения о даунтаймах. Без ложных срабатываний