Возникла необходимость получить дамп РНР-процесса на Debian 9.
Рассмотрим механизм ядра, позволящий создать дамп, и настройку создания дампов в Linux.
Ниже будем говорить о создании дампа памяти процесса в Linux, а не дампа ядра при kernel panic — там он иной, см. Kdump на Arch Wiki.
Содержание
Linux Core Dump
Ядро создаёт дамп памяти процесса, если он выполнил недопустимую операцию, и должен быть остановлен.
Для этого при выполнении такой операции ядро отправляет один из аварийных сигналов процессу, после чего процесс обрабатывает сигнал сам, или с помощью сторонних обработчиков, что запускает механизм ядра, который создаёт дамп.
Список таких сигналов задаётся в макросе SIG_KERNEL_COREDUMP_MASK
:
... #define SIG_KERNEL_COREDUMP_MASK (\ rt_sigmask(SIGQUIT) | rt_sigmask(SIGILL) | \ rt_sigmask(SIGTRAP) | rt_sigmask(SIGABRT) | \ rt_sigmask(SIGFPE) | rt_sigmask(SIGSEGV) | \ rt_sigmask(SIGBUS) | rt_sigmask(SIGSYS) | \ rt_sigmask(SIGXCPU) | rt_sigmask(SIGXFSZ) | \ SIGEMT_MASK ...
Который используется в другом макросе — sig_kernel_coredump
:
... #define sig_kernel_coredump(sig) siginmask(sig, SIG_KERNEL_COREDUMP_MASK) ...
Который срабывает в случае Fatal-ошибок, и вызывает do_coredump()
:
... fatal: ... if (sig_kernel_coredump(signr)) { if (print_fatal_signals) print_fatal_signal(ksig->info.si_signo); proc_coredump_connector(current); ... do_coredump(&ksig->info); } ...
Ну а сама do_coredump()
создаёт дамп.
Сигналы и создание дампа
Проверим работу дампа.
Берём простой код на Си:
#include <stdio.h> #include <unistd.h> int main() { while(1) { pid_t pid = getpid(); printf ("Working with PID %lu\n", pid); sleep(5); } }
Собираем, и запускаем:
Во второй консоли — отправляем один из сигналов, например SIGSEGV
(Segmentation violation), код 11:
В окне с приложением проверяем:
Проверяем файл дампа:
Аналогично можно создать дамп практически любого процесса, например — запустим sleep
:
GDB — создать core dump
Кроме отправки сигнала — с помощью gdb
, а именно gcore
, можно создать дамп работающего процесса:
GDB — прочитать core dump
Что бы просмотреть содержимое — можем использовать gdb
, которому передаём путь к исполняемому файлу, процесс которого сгенерировал дамп, и путь к самому файлу дампа:
kernel.core_pattern
Во время создания дампа — ядро проверяет параметр kernel.core_pattern
, который определяет то, как будет обработан дамп.
Тут можно задать путь и имя файла, в который будет записан дамп, либо передать создание дампа внешнему обработчику, например systemd-coredump
(рассмотрим ниже).
См. документацию Naming of core dump files тут>>>.
Из наиболее используемых опций тут:
%e
executable filename (without path prefix)%p
PID of dumped process, as seen in the PID namespace in which the process resides%t
time of dump, expressed as seconds since the Epoch, 1970-01-01 00:00:00 +0000 (UTC)
Собственно файл /tmp/coredump-make_dump.2714790, который мы открыли в GDB, и состоит из kernel.core_pattern = /tmp/coredump-%e.%p
:
/tmp
каталог%e
— имя файла начинается с coredump + имя исполняемого файла make_dump%p
— и PID убитого процесса — 2714790
Помимо указания на путь к файлу и созданию его имени — в core_pattern
можно указать пайп |
, и передать данные через него, например в /dev/null
или в хендлер типа systemd-coredump
.
limits.conf
Кроме имени файла — ядро проверит значение soft и hard лимитов для core
в /etc/security/limits.conf
:
Либо проверяем в рабочем окружении:
Лимиты конкретного процесса можно получить через его дескриптор в /proc
:
И лимиты:
fs.suid_dumpable
Иногда дамп может не создаваться, если процесс в процессе выполнения выполнил запрос на смену UID, например через вызов setuid()
.
Определяется флагом fs.suid_dumpable
:
Может принимать значение 0, 1 или 2, см. man proc:
- 0: (default) This provides the traditional (pre-Linux 2.6.13) behaviour. A core dump will NOT be produced for a process which has changed credentials (by calling seteuid or similar) or whose binary does not have read permission enabled.
- 1: («debug«) All processes dump core when possible.
- 2: («suidsafe«) Any binary which normally would not be dumped (see «0» above) is dumped readable by root only.
systemd-coredump
В systemd
, разумеется, добавлен свой обработчик дампов — уже упомянутый systemd-coredump
.
На Arch Linux он используется по-умолчанию, на Debian 9 ставим из репозитория:
Файл параметров — /etc/systemd/coredump.conf
.
После установки настраиваем ядро — через пайп передаём создание дампа в systemd-coredump
:
Проверяем:
Создаём дамп какого-то процесса:
coredumpctl
Для работы с дампами через systemd-coredump
— используем coredumpctl
:
В колонке SIG сразу видим код сигнала, с которым был убит процесс, в данном случае 11 == SIGSEGV
.
Сами файлы дампов systemd-coredump
сохраняет в /var/lib/systemd/coredump
:
Просмотреть дамп — передаём условие для MATCH, например — PID:
Debian — core dump не создаётся
Всё вышеописанное отлично работает на двух нотбуках с Arch Linux — но на серверах проекта с Debian 9 дамп обычным способом, без systemd-coredump
, не создаётся.
Конфиг:
Запускаем процесс, убиваем — файл дампа в /tmp
не появляется.
Запускаем приложение ещё раз:
И проверяем лимиты процесса
Soft лимит размера файла дампа задан в ноль, т.е. создание дампа отключено вообще.
Задаём его в unlimited:
Запускаем программу, проверяем лимит теперь:
Создаём дамп:
И проверяем его:
Готово.
Ссылки по теме
- Understand and configure core dumps on Linux
- Hunting the Core
- Core dump (Arch Wiki)
- Generate PHP core dumps on segfaults in PHP-FPM
- Generating a gdb backtrace
- Проблема с eaccelerator и генерация coredump для php-fpm
- How to get a core dump for a segfault on Linux
- kill: Creating a core dump