ОПИСАНИЕ
Для определённых сигналов действием по умолчанию является завершение
процесса и создание дампа памяти процесса --- дискового файла,
содержащего образ памяти процесса на момент завершения. Этот образ может
быть использован в отладчике (например, gdb(1)) для исследования
состояния программы на момент её завершения. Список сигналов, которые
приводят к созданию дампа памяти процесса, можно найти в signal(7).
Процесс может установить свой программный предел ресурса RLIMIT_CORE в максимальное значение по размеру файла дампа, который будет создан, если процесс получит сигнал "дампа памяти"; подробней смотрите в getrlimit(2).
Есть несколько обстоятельств, при которых файл дампа памяти не создаётся:
Также, дамп память может не содержать часть адресного пространства процесса, если в madvise(2) указан флаг MADV_DONTDUMP.
Именование файлов дампов памяти
По умолчанию, файлу с дампом памяти присваивается имя core, но с помощью файла /proc/sys/kernel/core_pattern (начиная с Linux 2.6 и 2.4.21) можно задать шаблон, который будет использован для именования файлов дампов памяти. Шаблон может содержать описатели %, которые заменяются на следующие значения при создании файла дампа:
%% одиночный символ %
%c программный предел размера файла дампа рухнувшего процесса (начиная с Linux 2.6.24)
%d режим дампа — тоже, как значение возвращаемое prctl(2) с PR_GET_DUMPABLE (начиная с Linux 3.7)
%e имя исполняемого файла (без пути)
%E путь к исполняемому файлу, в котором символы косой черты ('/') заменена на восклицательные знаки ('!') (начиная с Linux 3.0).
%g (число) реальный GID процесса, с которого делается дамп
%h имя узла (как nodename, возвращаемое uname(2))
%i TID нити, из-за которой возник дамп, по отношению к пространству имён PID, в котором располагается нить (начиная с Linux 3.18)
%I TID нити, из-за которой возник дамп, по отношению к начальному пространству имён PID (начиная с Linux 3.18)
%p PID процесса, с которого делается дамп, так как он видится в пространстве имён PID, котором расположен процесс
%P initial PID процесса, с которого делается дамп, так как он видится в первоначальном пространстве имён PID, котором расположен процесс (начиная с Linux 3.12)
%s номер сигнала, вызвавшего создание дампа
%t время дампа, выражается в секундах с начала эпохи, 1970-01-01 00:00:00 +0000 (UTC)
%u (число) реальный UID процесса, с которого делается дамп
Одиночный % в конце шаблона отбрасывается от имени файла дампа вместе с символом после %, отличным от перечисленных ранее. Все остальные символы в шаблоне вставляются в имя файла дампа как есть. Шаблон может содержать символы '/', которые интерпретируются как разделители для имён каталогов. Максимальный размер получаемого имени файла дампа равен 128 байтам (64 байта для ядер до версии 2.6.19). Значение по умолчанию в этом файле равно "core". Для обратной совместимости, если /proc/sys/kernel/core_pattern не содержит "%p" и значение в /proc/sys/kernel/core_uses_pid (см. далее) не равно нулю, то к имени файла дампа будет добавлен .PID.
Начиная с версии 2.4, Linux также предоставляет более примитивный метод управления именем файла дампа памяти. Если файл /proc/sys/kernel/core_uses_pid содержит значение 0, то файл дампа памяти просто называется core. Если в этом файле содержится ненулевое значение, то к имени файла дампа добавится ID процесса (в виде core.PID).
Начиная с Linux 3.6, если значение в /proc/sys/fs/suid_dumpable равно 2 («suidsafe»), то шаблон должен быть или абсолютным путём (начинаться с символа '/'), или каналом, как описано далее.
Передача дампов памяти в программу через канал
Начиная с версии 2.6.19, Linux поддерживает альтернативный синтаксис файла /proc/sys/kernel/core_pattern. Если первым символом в этом файле будет символ канала (|), то оставшаяся строка воспринимается как программа которую нужно запустить. Вместо записи файла на диск дамп памяти передаётся в стандартный ввод программы. Отметим следующие моменты:Управление отображениями, записываемыми в дамп памяти
Начиная с версии 2.6.23, в Linux появился файл /proc/PID/coredump_filter, который определяет какие сегменты памяти записываются в файл дампа памяти при отклике на событие создания дампа памяти процесса с соответствующим ID процесса.Значение в файле является битовой маской типов отображений памяти (см. mmap(2)). Если бит в маске установлен, то выполняется дамп отображения памяти соответствующего типа; иначе дамп не выполняется. Биты в этом файле имеют следующее значение:
бит 0 Выполнять дамп анонимных частных отображений.
бит 1 Выполнять дамп анонимных общих отображений.
бит 2 Выполнять дамп частных отображений из виртуальной памяти (file-backed).
бит 3 Выполнять дамп общих отображений из виртуальной памяти (file-backed).
бит 4 (начиная с Linux 2.6.24) Выполнять дамп заголовков ELF.
бит 5 (начиная с Linux 2.6.28) Выполнять дамп частных огромных страниц.
бит 6 (начиная с Linux 2.6.28) Выполнять дамп общих огромных страниц.
бит 7 (начиная с Linux 4.4) Выполнять дамп частных страниц DAX.
бит 8 (начиная с Linux 4.4) Выполнять дамп общих страниц DAX.
По умолчанию, установлены следующие биты: 0, 1, 4 (если включён параметр настройки ядра CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS) и 5. Данное значение может быть изменено при запуске системы через параметр загрузки coredump_filter.
Значения этого файла отображается в шестнадцатеричной системе счисления (то есть значение по умолчанию выглядит как 33).
Для страниц ввода-вывода, отображённых в память, таких как фрейм-буфер, дамп никогда не выполняется, а виртуальные страницы DSO попадают в дамп всегда, независимо от значения coredump_filter.
Дочерний процесс, созданный fork(2), наследует значение coredump_filter родителя; значение coredump_filter сохраняется и при execve(2).
Полезно указывать значение coredump_filter в родительской оболочке до запуска программы, например:
$ echo 0x7 > /proc/self/coredump_filter $ ./какая-то_программа
Этот файл есть в системе только, если ядро было собрано с параметром настройки CONFIG_ELF_CORE.
ЗАМЕЧАНИЯ
Команду gdb(1) gcore можно использовать для получения дампа памяти
работающего процесса.
В версии Linux до 26.27 включительно, если для многонитевого процесса (или, точнее, процесса, который делит свою памяти с другим процессом, созданным с флагом CLONE_VM через clone(2)) выполняется дамп памяти, то ID процесса всегда добавляется к имени файла дампа, если ID процесса уже не включён в это имя с помощью %p в /proc/sys/kernel/core_pattern (это, главным образом, полезно когда применяется устаревшая реализация LinuxThreads, где каждая нить процесса имеет свой PID).
ПРИМЕР
Эта программа может использоваться для демонстрации синтаксиса канала в
файле /proc/sys/kernel/core_pattern. Следующий сеанс оболочки
демонстрирует использование данной программы (при компиляции был создан
исполняемый файл с именем core_pattern_pipe_test):
$ cc -o core_pattern_pipe_test core_pattern_pipe_test.c $ su Password: # echo "|$PWD/core_pattern_pipe_test %p UID=%u GID=%g sig=%s" > \ /proc/sys/kernel/core_pattern # exit $ sleep 100 ^\ # type control-backslash Quit (core dumped) $ cat core.info argc=5 argc[0]=</home/mtk/core_pattern_pipe_test> argc[1]=<20575> argc[2]=<UID=1000> argc[3]=<GID=100> argc[4]=<sig=3> Total bytes in core dump: 282624
Исходный код программы
/* core_pattern_pipe_test.c */ #define _GNU_SOURCE #include <sys/stat.h> #include <fcntl.h> #include <limits.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #define BUF_SIZE 1024 int main(int argc, char *argv[]) { int tot, j; ssize_t nread; char buf[BUF_SIZE]; FILE *fp; char cwd[PATH_MAX]; /* Изменяем наш текущий рабочий каталог на тот, что у упавшего процесса */ snprintf(cwd, PATH_MAX, "/proc/%s/cwd", argv[1]); chdir(cwd); /* Записываем вывод в файл "core.info" в этом каталоге */ fp = fopen("core.info", "w+"); if (fp == NULL) exit(EXIT_FAILURE); /* Показываем аргументы командной строки, переданные программе core_pattern */ fprintf(fp, "argc=%d\n", argc); for (j = 0; j < argc; j++) fprintf(fp, "argc[%d]=<%s>\n", j, argv[j]); /* Подсчитываем байты стандартного ввода (дампа памяти) */ tot = 0; while ((nread = read(STDIN_FILENO, buf, BUF_SIZE)) > 0) tot += nread; fprintf(fp, "Total bytes in core dump: %d\n", tot); fclose(fp); exit(EXIT_SUCCESS); }