Как посмотреть core dump linux
Julia Evans
This week at work I spent all week trying to debug a segfault. I’d never done this before, and some of the basic things involved (get a core dump! find the line number that segfaulted!) took me a long time to figure out. So here’s a blog post explaining how to do those things!
At the end of this blog post, you should know how to go from “oh no my program is segfaulting and I have no idea what is happening” to “well I know what its stack / line number was when it segfaulted, at least!“.
what’s a segfault?
This “C++ vtable pointer” thing is what was happening to my segfaulting program. I might explain that in a future blog post because I didn’t know any C++ at the beginning of this week and this vtable lookup thing was a new way for a program to segfault that I didn’t know about.
But! This blog post isn’t about C++ bugs. Let’s talk about the basics, like, how do we even get a core dump?
step 1: run valgrind
I found the easiest way to figure out why my program is segfaulting was to use valgrind: I ran
and this gave me a stack trace of what happened. Neat!
But I also wanted to do a more in-depth investigation and find out more than just what valgrind was telling me! So I wanted to get a core dump and explore it.
How to get a core dump
A core dump is a copy of your program’s memory, and it’s useful when you’re trying to debug what went wrong with your problematic program.
When your program segfaults, the Linux kernel will sometimes write a core dump to disk. When I originally tried to get a core dump, I was pretty frustrated for a long time because – Linux wasn’t writing a core dump!! Where was my core dump.
Here’s what I ended up doing:
ulimit: set the max size of a core dump
For example these are the limits for a random Firefox process on my system:
kernel.core_pattern: where core dumps are written
kernel.core_pattern is a kernel parameter or a “sysctl setting” that controls where the Linux kernel writes core dumps to disk.
It’s important to know that kernel.core_pattern is a global settings – it’s good to be a little careful about changing it because it’s possible that other systems depend on it being set a certain way.
kernel.core_pattern & Ubuntu
By default on Ubuntu systems, this is what kernel.core_pattern is set to
This caused me a lot of confusion (what is this apport thing and what is it doing with my core dumps??) so here’s what I learned about this:
So you have a core dump. Now what?
The next step is to open the core file with gdb and get a backtrace.
Getting a backtrace from gdb
You can open a core file with gdb like this:
Here’s how to load debugging symbols.
If you want this to work, the binary should be compiled with debugging symbols. Having line numbers in your stack traces is extremely helpful when trying to figure out why a program crashed 🙂
look at the stack for every thread
Here’s how to get the stack for every thread in gdb!
gdb + core dumps = amazing
If you have a core dump & debugging symbols and gdb, you are in an amazing situation!! You can go up and down the call stack, print out variables, and poke around in memory to see what happened. It’s the best.
If you are still working on being a gdb wizard, you can also just print out the stack trace with bt and that’s okay 🙂
I might write about ASAN more in the future if I ever get it to work 🙂
getting a stack trace from a core dump is pretty approachable!
This blog post sounds like a lot and I was pretty confused when I was doing it but really there aren’t all that many steps to getting a stack trace out of a segfaulting program:
if that doesn’t work, or if you want to have a core dump to investigate:
I was able using gdb to figure out that there was a C++ vtable entry that is pointing to some corrupt memory, which was somewhat helpful and helped me feel like I understood C++ a bit better. Maybe we’ll talk more about how to use gdb to figure things out another day!
You might also like the Recurse Center, my very favorite programming community (my posts about it)
Использование дампов ядра для диагностики сбойных программ
Дампы ядра часто применяются для диагностики и поиска ошибок в Линуксовых и Юниксовых программах. Они помогут системному администратору выяснить, отчего рухнула та или иная программа, например, Lighttpd, Apache или PHP-CGI. Файл дампа ядра генерируется всякий раз, когда программа нештатно завершается из-за ошибки, нарушения политики безопасности операционной системы, попытки записывать данные вне отведенной ей области памяти и так далее. В этой статье рассказано, как подключить генерацию файлов дампов ядра и отслеживать с их помощью ошибки в программах.
Как подключить создание файлов дампа ядра
Как просмотреть текущие настройки файлов дампа ядра
Нулевой вывод команды означает, что файлы дампов не создаются.
Как изменить настройки
Как подключить генерацию файлов дампа ядра для рухнувших программ и ошибок сегментации
Найдите в /etc/profile строку
И измените ее, чтобы получилось:
Также следует внести изменения в файл /etc/sysctl.conf. В этот файл следует дописать три строки:
Не забудьте сохранить отредактированные файлы.
Что означают последние три записи?
Совершив все вышеописанные действия, запустите дампирование при помощи команды (Redhat и подобные дистрибутивы):
И запишите настройки в /etc/sysctl.conf при помощи следующей команды:
Как инициировать создание дампов ядра для конкретного демона
Например, для демона lighttped, в файл /etc/init.d/lighttped нужно добавить строку:
Сохраните файл. Затем перезапустите демон:
Правильный вывод последней команды:
Имейте в виду, что эта вышеприведенная строка является специфичной только для Redhat. Для всех остальных дистрибутивов конфигурацию прописывают строками:
Все, теперь можно отправлять дамп ядра разработчикам или распространителям программы.
Core dump
A core dump is a file containing a process’s address space (memory) when the process terminates unexpectedly. Core dumps may be produced on-demand (such as by a debugger), or automatically upon termination. Core dumps are triggered by the kernel in response to program crashes, and may be passed to a helper program (such as systemd-coredump) for further processing. A core dump is not typically used by an average user, but may be passed on to developers upon request where it can be invaluable as a post-mortem snapshot of the program’s state at the time of the crash, especially if the fault is hard to reliably reproduce.
Contents
Disabling automatic core dumps
Users may wish to disable automatic core dumps for a number of reasons:
Using sysctl
sysctl can be used to set the kernel.core_pattern to nothing to disable core dump handling. Create this file
To apply the setting immediately, use sysctl :
Using systemd
Then reload systemd’s configuration.
This method alone is usually sufficient to disable userspace core dumps, so long as no other programs enable automatic core dumps on the system, but the coredump is still generated in memory and systemd-coredump run.
Using PAM limits
The maximum core dump size for users logged in via PAM is enforced by limits.conf. Setting it to zero disables core dumps entirely. [3]
Using ulimit
Command-line shells such as bash or zsh provide a builtin ulimit command which can be used to report or set resource limits of the shell and the processes started by the shell. See bash(1) § SHELL BUILTIN COMMANDS or zshbuiltins(1) for details.
To disable core dumps in the current shell:
Making a core dump
To generate a core dump of an arbitrary process, first install the gdb package. Then find the PID of the running process, for example with pgrep:
Attach to the process:
Then at the (gdb) prompt:
Where do they go?
Examining a core dump
Use coredumpctl to find the corresponding dump:
Pay attention to «Signal» row, that helps to identify crash cause. For deeper analysis you can examine the backtrace using gdb:
When gdb is started, use the bt command to print the backtrace:
See Debugging/Getting traces if debugging symbols are requested, but not found.
Linux: создание coredump памяти процесса, systemd-coredump и Debian
Возникла необходимость получить дамп РНР-процесса на Debian 9.
Рассмотрим механизм ядра, позволящий создать дамп, и настройку создания дампов в Linux.
Ниже будем говорить о создании дампа памяти процесса в Linux, а не дампа ядра при kernel panic – там он иной, см. Kdump на Arch Wiki.
Linux Core Dump
Ядро создаёт дамп памяти процесса, если он выполнил недопустимую операцию, и должен быть остановлен.
Для этого при выполнении такой операции ядро отправляет один из аварийных сигналов процессу, после чего процесс обрабатывает сигнал сам, или с помощью сторонних обработчиков, что запускает механизм ядра, который создаёт дамп.
Список таких сигналов задаётся в макросе SIG_KERNEL_COREDUMP_MASK :
Который используется в другом макросе – sig_kernel_coredump :
Который срабывает в случае Fatal-ошибок, и вызывает do_coredump() :
Ну а сама do_coredump() создаёт дамп.
Сигналы и создание дампа
Проверим работу дампа.
Берём простой код на Си:
Собираем, и запускаем:
Во второй консоли – отправляем один из сигналов, например SIGSEGV (Segmentation violation), код 11:
В окне с приложением проверяем:
Проверяем файл дампа:
Аналогично можно создать дамп практически любого процесса, например – запустим sleep :
GDB – создать core dump
GDB – прочитать core dump
kernel.core_pattern
Тут можно задать путь и имя файла, в который будет записан дамп, либо передать создание дампа внешнему обработчику, например systemd-coredump (рассмотрим ниже).
См. документацию Naming of core dump files тут>>>.
Из наиболее используемых опций тут:
Собственно файл /tmp/coredump-make_dump.2714790, который мы открыли в GDB, и состоит из kernel.core_pattern = /tmp/coredump-%e.%p :
limits.conf
Кроме имени файла – ядро проверит значение soft и hard лимитов для core в /etc/security/limits.conf :
Либо проверяем в рабочем окружении:
Лимиты конкретного процесса можно получить через его дескриптор в /proc :
fs.suid_dumpable
Определяется флагом fs.suid_dumpable :
Может принимать значение 0, 1 или 2, см. man proc:
systemd-coredump
На Arch Linux он используется по-умолчанию, на Debian 9 ставим из репозитория:
После установки настраиваем ядро – через пайп передаём создание дампа в systemd-coredump :
Создаём дамп какого-то процесса:
coredumpctl
Для работы с дампами через systemd-coredump – используем coredumpctl :
Сами файлы дампов systemd-coredump сохраняет в /var/lib/systemd/coredump :
Просмотреть дамп – передаём условие для MATCH, например – PID:
Как посмотреть core dump linux
Процесс может установить свой программный предел ресурса RLIMIT_CORE в максимальное значение по размеру файла дампа, который будет создан, если процесс получит сигнал «дампа памяти»; подробней смотрите в getrlimit(2).
Есть несколько обстоятельств, при которых файл дампа памяти не создаётся:
* У процесса нет прав на запись файла дампа (по умолчанию файл дампа называется core или core.pid, где pid — ID процесса из которого делается дамп, и создаётся в текущем рабочем каталоге. Подробней об именовании смотрите далее). Запись файла дампа завершится неудачно, если каталог, в котором он создаётся, недоступен для записи, или если файл с таким же именем уже существует и недоступен для записи или это необычный файл (например, это каталог или символьная ссылка). * Существует файл (обычный, доступный на запись) с именем, которое будет использовано для дампа памяти, но есть более одной жёсткой ссылки на этот файл. * Файловая система, где должен быть создан файл дампа, переполнена, закончились иноды, она смонтирована только для чтения, достигнут предел пользовательской квоты. * Каталог, в котором должен быть создан файл дампа, не существует. * Пределы ресурсов RLIMIT_CORE (размер файла дампа) или RLIMIT_FSIZE (размер файла) для процесса установлены в ноль; смотрите getrlimit(2) и документацию на команду оболочки ulimit (limit в csh(1)). * Исполняемый процессом файл недоступен на чтение. * Процесс выполняет программу с установленными битом set-user-ID (set-group-ID), который принадлежит пользователю (группе) не совпадающей с ID реального пользователя (группы) процесса или процесс выполняется программу, имеющую файловые мандаты (смотрите capabilities(7)). Однако посмотрите описание операции prctl(2) PR_SET_DUMPABLE, и описание файла /proc/sys/fs/suid_dumpable в proc(5). * (начиная с Linux 3.7) Ядро настроено без параметра CONFIG_COREDUMP.
Также, дамп память может не содержать часть адресного пространства процесса, если в madvise(2) указан флаг MADV_DONTDUMP.
Именование файлов дампов памяти
%% одиночный символ % %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 процесса, с которого делается дамп
Начиная с версии 2.4, Linux также предоставляет более примитивный метод управления именем файла дампа памяти. Если файл /proc/sys/kernel/core_uses_pid содержит значение 0, то файл дампа памяти просто называется core. Если в этом файле содержится ненулевое значение, то к имени файла дампа добавится ID процесса (в виде core.PID).
Начиная с Linux 3.6, если значение в /proc/sys/fs/suid_dumpable равно 2 («suidsafe»), то шаблон должен быть или абсолютным путём (начинаться с символа ‘/’), или каналом, как описано далее.
Передача дампов памяти в программу через канал
Управление отображениями, записываемыми в дамп памяти
Значение в файле является битовой маской типов отображений памяти (см. 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 в родительской оболочке до запуска программы, например:
Этот файл есть в системе только, если ядро было собрано с параметром настройки CONFIG_ELF_CORE.
ЗАМЕЧАНИЯ
В версии Linux до 26.27 включительно, если для многонитевого процесса (или, точнее, процесса, который делит свою памяти с другим процессом, созданным с флагом CLONE_VM через clone(2)) выполняется дамп памяти, то ID процесса всегда добавляется к имени файла дампа, если ID процесса уже не включён в это имя с помощью %p в /proc/sys/kernel/core_pattern (это, главным образом, полезно когда применяется устаревшая реализация LinuxThreads, где каждая нить процесса имеет свой PID).