Генерация дампов упавших процессов
Описание
При падении процесса его память может быть сохранена в файл для дальнейшей диагностики. Расположение файла дампа зависит от настроек ядра, а его наличие и размер - от настройки исполняющегося процесса. По умолчанию во многих дистрибутивах Linux (например, Ubuntu и Debian) генерация дампов отключена.
Есть ряд причин, по которым дампы упавших процессов могут не сохраняться.
Наиболее частая причина - выставленный в 0 лимит на размер дампов RLIMIT_CORE
.
Другие причины описаны ниже:
-
У процесса нет доступа для записи файла дампа. (По умолчанию файл дампа называется
core
илиcore.pid
, гдеpid
- идентификатор упавшего процесса, и сохраняется в текущей папке исполнявшегося приложения. См. ниже об именовании файла дампа.) Запись дампа также не удастся если папка не доступна для записи или файл с таким же именем существует и не доступен для записи или не является обычным файлом (например, является папкой или ссылкой). -
Файл с таким же именем существует и доступен для записи, но слинкован жёсткой ссылкой.
-
На файловой системе недостаточно места или inode’ов или файловая система примонтирована в режиме только для чтения или квота пользователя превышена для этой файловой системы.
-
Текущая папка процесса отсутствует на файловой системе.
-
Лимит на размер дампа
RLIMIT_CORE
выставлен в 0 (наиболее частая причина). -
Лимит на максимальный размер файла который процесс может создать
RLIMIT_FSIZE
выставлен в 0. -
У исполняемого файла отсутствует право на чтение (Это мера безопасности чтобы пользователь не получил доступ к содержимому исполняемого файла через дамп).
-
Исполняемый файл имеет выставленный бит
setuid
и дампы таких файлов явно не разрешены настройкойfs.suid_dumpable
. -
Настройка
kernel.core_pattern
пуста и настройкаkernel.core_uses_pid
выставлена в 0. (Если же при пустой настройкеkernel.core_pattern
значениеkernel.core_uses_pid
не 0, то дамп будет записан в файл с именем.pid
) -
Ядро собрано без опции
CONFIG_COREDUMP
.
Настройка
Лимиты процесса
Чтобы включить генерацию дампов, необходимо выставить RLIMIT_CORE
в пользовательском процессе.
Целочисленные значения указывают максимальный размер файла дампа в 512-байтных блоках.
Ограничение размера применяется только для файлов, то есть в том случае, если настройка kernel.core_pattern
(см. ниже)
указывает на имя файла для дампа, в отличие от процесса.
Можно это сделать изнутри процесса при старте:
#include <sys/resource.h> void main(int argc, char** argv) { struct rlimit rlim; int res; rlim.rlim_cur = RLIM_INFINITY; rlim.rlim_max = RLIM_INFINITY; res = setrlimit(RLIMIT_CORE, &rlim); }
А также это можно сделать снаружи процесса перед его стартом (т.к. лимиты наследуются при создании дочерних процессов).
Например, через встроенную команду пользовательской оболочки ulimit
(в csh - limit
).
> ulimit -c 0
При нулевом значении файл дампа не создаётся.
Чтобы включить создание дампов без ограничений по размеру:
> ulimit -c unlimited
Проверяем снова:
> ulimit -c unlimited
После этого все дочерние процессы запущенные из этой оболочки будут генерировать дампы если нет других причин (см. Описание). Куда дампы будут сохраняться - зависит от переменных ядра sysctl.
Еще одна возможность - прописать лимиты в настройках системы /etc/security/limits.conf
и перезагрузиться.
После перезагрузки нужно проверить ulimit -c
, его значение должно стать unlimited
. Если же это не так, возможно в стартовых файлах оболочки (например
/etc/profile
также происходит выставление лимитов, тогда нужно их исправить ещё и там).
Переменные ядра sysctl
Настройка дампов производится следующими переменными:
-
kernel.core_pattern
-
kernel.core_pipe_limit
-
kernel.core_uses_pid
Для начала можно посмотреть на существующие настройки. В разных дистрибутивах настройки по умолчанию отличаются:
> sysctl kernel 2>/dev/null | grep core kernel.core_pattern = |/lib/systemd/systemd-coredump %P %u %g %s %t 9223372036854775808 %h kernel.core_pipe_limit = 0 kernel.core_uses_pid = 0
> sysctl kernel 2>/dev/null | grep core kernel.core_pattern = |/usr/share/apport/apport %p %s %c %d %P %E kernel.core_pipe_limit = 0 kernel.core_uses_pid = 0
> sysctl kernel 2>/dev/null | grep core kernel.core_pattern = |/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e kernel.core_pipe_limit = 0 kernel.core_uses_pid = 0
> sysctl kernel 2>/dev/null | grep core kernel.core_pattern = core kernel.core_pipe_limit = 0 kernel.core_uses_pid = 1
kernel.core_pattern
указывает имя файла для сохранения дампа либо исполняемую программу-обработчик дампов (если первым символом является |
).
kernel.core_pipe_limit
применяется только в случае использования программы-обработчика дампов.
kernel.core_uses_pid
влияет на имя файла для сохранения дампа если не используется программа-обработчик
(хотя некоторые обработчики применяют это значение для эмуляции поведения по-умолчанию, например apport
).
Если в kernel.core_pattern
сконфигурирован обработчик, то можно попробовать использовать его для получения дампов. Например, systemd-coredump
вполне
юзабелен и может отобразить список упавших процессов, а также выдать дамп для сохранения (см. описание systemd-coredump
ниже).
Если же обработчик не юзабелен или не настраивается (например, apport
- эмулирует поведение по умолчанию и сохраняет файл в текущую папку процесса с именем
core
и это не настраивается), то можно настроить сохранение файлов самостоятельно, например:
# sysctl 'kernel.core_pattern=/tmp/core_%e_%p_%t_%s.dump'
Чтобы настройка сохранялясь после перезагрузки, нужно прописать это в файл /etc/sysctl.d/50-core-dumps.conf
:
echo 'kernel.core_pattern = /tmp/core_%e_%p_%t_%s.dump' > /etc/sysctl.d/50-core-dumps.conf
Обработчики дампов
Systemd-coredump
Список упавших процессов можно просмотреть:
> coredumpctl TIME PID UID GID SIG COREFILE EXE Wed 2021-05-26 17:25:07 MSK 482770 0 0 6 missing /usr/local/bin/node Wed 2021-05-26 17:25:41 MSK 482958 0 0 6 missing /usr/local/bin/node Tue 2021-06-08 13:49:40 MSK 2590838 0 0 7 missing /home/mmak/devel/r/rostell_mg/priv/unix/rtx_mg3 Wed 2021-07-07 09:25:49 MSK 2242 1000 1000 6 missing /usr/share/discord/Discord Thu 2021-07-08 18:53:48 MSK 1514283 1000 1000 6 missing /usr/bin/bt-adapter Fri 2021-07-16 11:29:00 MSK 2805 1000 1000 11 missing /usr/bin/simple-scan Tue 2021-08-10 13:27:22 MSK 14050 0 0 11 missing /home/mmak/devel/r/rostell_mg/priv/unix/rtx_mg3 Tue 2021-08-10 13:27:22 MSK 13607 0 0 11 missing /home/mmak/devel/r/rostell_mg/priv/unix/rtx_mg3 Tue 2021-08-17 19:36:30 MSK 536042 0 0 11 missing /home/mmak/apps/erl23.2.7/bin/run_erl Sat 2021-08-21 06:18:37 MSK 280983 0 0 11 missing /home/mmak/apps/erl23.2.7/bin/run_erl Mon 2021-08-23 15:58:04 MSK 3574353 1000 1000 6 missing /usr/share/discord/Discord Wed 2021-09-08 09:31:35 MSK 3817 1000 1000 5 missing /usr/libexec/csd-keyboard Mon 2021-09-13 13:01:08 MSK 368526 1000 1000 11 present /home/mmak/devel/core.dumps/a.out
Сохранить дамп можно так:
coredumpctl dump {pid} > program.core
Где {pid} - идентификатор упавшего процесса. Его можно найти в таблице (см. выше).
Docker
При использовании контейнеров docker следует понимать, что процессы внутри контейнера исполняются ядром хостовой системы,
следовательно внутри контейнера не может существовать других настроек ядра, отличающихся от настроек хоста.
Здесь начинается различие в обработке настройки kernel.core_pattern
.
Если она указывает на файл, то интерпретация пути и текущей папки происходит в контексте точек монтирования контейнера (т.е. внутри).
Если же настройка указывает на процесс, то обработка происходит в хостовом окружении и точки монтирования контейнера не применяются.
Таким образом, если, например, в системе установлен пакет systemctl-coredump
, то дампы нужно снимать в хосте, где они и генерятся.
По умолчанию настройка ulimit -c
в контейнере уже выставлена в unlimited
, но если это не так, то при запуске контейнера нужно указать --ulimit core=-1
.