Публикую не проверяя по просьбе © imen


Это плазма падает, а юнити аккуратно ложится.
Аккуратно ложится, медленно снимает с себя core и призывно постанывает в сислог.

© LOR

Запись и анализ core

Объект (core dump) появляется, когда программа пытается сотворить несуразность с точки зрения ОС (ядра) и получает соответствующий событию сигнал.

man 5 core:

Для определённых сигналов действием по умолчанию является завершение процесса и создание дампа памяти процесса — дискового файла, содержащего образ памяти процесса на момент завершения. Этот образ может быть использован в отладчике (например, gdb(1)) для исследования состояния программы на момент её завершения. Список сигналов, которые приводят к созданию дампа памяти процесса, можно найти в signal(7).

man 7 signal:

…
       SIGQUIT       3        Core     Выход с клавиатуры
       SIGILL        4        Core     Несуществующая инструкция
       SIGABRT       6        Core     Сигнал аварии (abort), посланный
                                       abort(3)
       SIGFPE        8        Core     Ошибка операций с плавающей запятой
…
       SIGSEGV      11        Core     Некорректная ссылка в память
…

Дальнейшие действия зависят от конфигурации ОС: в любом случае выводится (правда гуём обычно не отображается) информация о событии, + в зависимости от настройки подсистемы журналирования — сообщение в журнал. И, если включена запись дампов, слепок памяти процесса (на момент получения сигнала) записывается на жёсткий диск.

Слепок памяти, занимаемой программой, может содержать конфиденциальную информацию, его запись в файл — потенциальная уязвимость. Сейчас я описываю простейший случай (использование базового профиля), на hardened-профиле разрешение записи core должно потребовать дополнительного разрешения (и вообще, кроме как в тестовых целях на рабочей станции разработчика, временно (!), этого делать не стоит).

Лирическое отступление про СПО:
// Системный/прикладной уровни и работоспособность vs правильность решения.
Ввязываясь в квест с отладкой, полезно помнить о некоторых особенностях предметной области.
Если в разработке Проприетарного ПО царит требование работоспособности (согласно некоторому набору тестов, с отягчающим обстоятельством ресурсоёмкости надлежащей проверки), то в экосистеме Свободного ПО, по крайней мере на системном уровне наблюдается примат правильности решения над принципиальной работоспособностью.
Откуда очевидным образом следует принципиальное различие в отношении к разделяемым библиотекам: тогда, когда на платформе самой распространённой ОС стандартом де-факто является статическая линковка, в GNU/Linux и прочих *BSD использование интегрированных зависимостей или статическая линковка интерпретируются как несуразность (редактор: заменить слово?).
Очевидным образом, различаются и ошибки, порождённые различием в подходах: если в СПО собираются свои ошибки и [в лучшем случае] недоработки в зависимостях, то в ППО можно налететь на следствие ошибки, давным-давно исправленной в upstream'е зависимости.
Правда на прикладном уровне часто царит «базар» (кратчайший путь — известный) с достаточно высокой интенсивностью процесса отбора.

// Отягчающее обстоятельство в случае кросс-платформенных приложений (культура использования разделяемых библиотек).

В силу вышеизложенного, сам по себе файл core, особенно отдельно от породившего его исполняемого файла, не интересен никому, кроме потенциального атакующего (злоумышленника). Хотя, строго говоря, в бинарных дистибутивах это и не совсем так.
Разработчику интересна расшифровка core.
Но простого разрешения записи core dump для получения информативной трассы недостаточно. Необходимо также включить в дамп (и как следствие — в порождающий его исполняемый файл, вместе с использовавшимися в проблемной ситуации библиотеками) отладочные символы.
Что делается на этапе сборки. В предположении использования GNU Compiller Collection — добавлением в список параметров компилятора, передаваемых переменной CFLAGS, опции -ggdb. Историческая альтернатива — опция -g.

man gcc:

…
   Options for Debugging Your Program or GCC
       GCC has various special options that are used for debugging either your program or GCC:
       -g  Produce debugging information in the operating system's native format (stabs, COFF, XCOFF, or DWARF 2).  GDB can work
           with this debugging information.

           On most systems that use stabs format, -g enables use of extra debugging information that only GDB can use; this
           extra information makes debugging work better in GDB but probably makes other debuggers crash or refuse to read the
           program.  If you want to control for certain whether to generate the extra information, use -gstabs+, -gstabs,
           -gxcoff+, -gxcoff, or -gvms (see below).

           GCC allows you to use -g with -O.  The shortcuts taken by optimized code may occasionally produce surprising results:
           some variables you declared may not exist at all; flow of control may briefly move where you did not expect it; some
           statements may not be executed because they compute constant results or their values are already at hand; some
           statements may execute in different places because they have been moved out of loops.

           Nevertheless it proves possible to debug optimized output.  This makes it reasonable to use the optimizer for
           programs that might have bugs.

           The following options are useful when GCC is generated with the capability for more than one debugging format.
…
       -ggdb
           Produce debugging information for use by GDB.  This means to use the most expressive format available (DWARF 2,
           stabs, or the native format if neither of those are supported), including GDB extensions if at all possible.

…

Для пакетов, предусматривающих дополнительные отладочные функции на уровне системы сборки также следует включить USE-флаг debug.
Добавление опции компилятора, строго говоря, меняет создаваемый файл, что, в некоторых случаях, может сказаться на воспроизводимости ошибки.
Но простого добавления опции включения отладочных символов недостаточно. При установке программы (формировании пакета) обычно производится зачистка лишних (и неиспользуемых) символов. Поэтому пакеты, используемые для отладки, требуют и специальной установки.
Например посредством включения для них:

FEATURES="splitdebug"

man make.conf:

…
       FEATURES = "sandbox"
              Defines  actions portage takes by default. This is an incremental variable.  Most of these settings are for devel‐
              oper use, but some are available to non-developers as well. The sandbox feature is very important and  should  not
              be disabled by default.
…
              splitdebug
                     Prior to stripping ELF etdyn and etexec files, the debugging info is stored for later use by various debug‐
                     gers.   This  feature  is disabled by nostrip.  You should also consider setting compressdebug so the files
                     don't suck up a lot of space.  For installation of source code, see installsources.
…

Очевидным образом, в нормальном режиме работы оба необходимых условия информативной отладки в лучшем случае не нужны.

Установка пакета (подсказка от megabaks http://megabaks.blogspot.ru/2012/10/portage.html):

CFLAGS="-march=native -O2 -pipe -ggdb"
CXXFLAGS="${CFLAGS}"
FEATURES="splitdebug"

# file /usr/bin/gxneur
/usr/bin/gxneur: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, stripped

# file /usr/lib/debug/usr/bin/gxneur.debug
/usr/lib/debug/usr/bin/gxneur.debug: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter *empty*, for GNU/Linux 2.6.32, not stripped

Но это лирическое отступление с информацией о содержимом файлов.
Практика показывает, что по крайней мере в исследуемом примере включать отладку для собственно проблемного приложения не требуется.

Для анализа core необходима специальная утилита — отладчик. Практическим инвариантом для СПО является gdb (GNU debugger). Пример начального приближения сессии отладки:

$ gdb -q $(which gxneur) --core /tmp/cores/core_gxneur-6.13902
Reading symbols from /usr/bin/gxneur...(no debugging symbols found)...done.
[New LWP 13902]
[New LWP 13905]
[New LWP 13906]

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `gxneur'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00007fb38afb9217 in raise () from /lib64/libc.so.6
[Current thread is 1 (Thread 0x7fb38f22a8c0 (LWP 13902))]

В данном конкретном случае программа пишет два разных дампа по разным сигналам. Второй:

$ gdb -q $(which gxneur) --core /tmp/cores/core_gxneur-11.13988
Reading symbols from /usr/bin/gxneur...(no debugging symbols found)...done.
[New LWP 13988]

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `gxneur'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00007ff793fd45e6 in ?? () from /lib64/libc.so.6

(помним, что достаточно часто для запуска программы используется обёртка shell-скрипта и потому финт с which не работает)
В первом приближении расшифровки интересен разве что список используемых библиотек, по которому можно определить список зависимых пакетов для режима отладки, например:

# equery b /lib64/libc.so.6
* Searching for /lib64/libc.so.6 ...
sys-libs/glibc-2.22-r4 (/lib64/libc.so.6 -> libc-2.22.so)
sys-libs/glibc-2.22-r4 (/lib64/libc-2.22.so)

По умолчанию запись core выключена в Linux и включена в FreeBSD (OpenBSD, NetBSD, OpenSolaris и проприетарные Unix'ы — ?, Windows — ???).
Linux (начиная с Linux 3.7 CONFIG_COREDUMP):

$ zgrep COREDUMP /proc/config.gz
CONFIG_COREDUMP=y
CONFIG_ALLOW_DEV_COREDUMP=y

Имя файла core можно посмотреть с помощью утилиты sysctl, явно прописать или переопределить в сеансе — ею же, зафиксировать изменения — в файле /etc/sysctl.conf).

man 5 core:


Именование файлов дампов памяти
По умолчанию файлу с дампом памяти присваивается имя 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 процесса, с которого делается дамп

# sysctl -a | grep kernel.core
kernel.core_pattern = /tmp/cores/core_%e-%s.%p
kernel.core_pipe_limit = 0
kernel.core_uses_pid = 0

$ grep kernel.core /etc/sysctl.conf
kernel.core_pattern = /tmp/cores/core_%e-%s.%p

По умолчанию имя файла дампа — core. Очевидное следствие — файл пишется в корень домашнего каталога пользователя, от имени которого работал процесс. Или не пишется, если нет прав записи, что достаточно часто встречается для пользователей демонов.
Очевидным решением проблемы является запись core в отдельный выделенный каталог (с учётом вышеприведённого замечания об информативности — можно даже во временный).
Необходимое условие — права на запись для всех.
В моём случае каталог временный (что следует из FHS), создаётся сервисом local при загрузке:

/etc/local.d/mk_core_dir.start:

#!/bin/sh
#
mkdir -m 0777 /tmp/cores

Пример полной (и полезной или, с учётом тенденций эволюции квалификации разработчиков, претендующей на полезность) расшифровки core выглядит следующим образом:

$ gdb -q $(which gxneur) --core /tmp/cores/core_gxneur-6.12629
Reading symbols from /usr/bin/gxneur...Reading symbols from /usr/lib64/debug//usr/bin/gxneur.debug...done.
done.
[New LWP 12629]
[New LWP 12634]
[New LWP 12635]

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `gxneur'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00007f28a6b7b217 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:55
55 ../sysdeps/unix/sysv/linux/raise.c: Нет такого файла или каталога.
[Current thread is 1 (Thread 0x7f28aadec8c0 (LWP 12629))]

Для второго сигнала (11) и случая отсутствия отладочных символов в проблемном исполняемом файле (показывающий, что они нужны не всегда):

$ gdb -q $(which gxneur) --core /tmp/cores/core_gxneur-11.25118
Reading symbols from /usr/bin/gxneur...(no debugging symbols found)...done.
[New LWP 25118]

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `gxneur'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 __strcmp_sse2_unaligned () at ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S:202
202 ../sysdeps/x86_64/multiarch/strcmp-sse2-unaligned.S: Нет такого файла или каталога.

Те же требования (флаги компиляции и особенности компоновки пакета) действительны и для случая ординарной отладки. Только уже для полного списка используемых библиотек, посмотреть который можно с помощью утилиты ldd.

С учётом послезнания (и вопросом о целесообразности включения интерактивной отладочной сессии):
x11-misc/gxneur
sys-libs/glibc
dev-libs/glib
x11-libs/libX11
x11-libs/libxcb

При отслеживании проблем в современных монстрах (например FireFox) размер дампа может составлять гигабайты. Что при записи core во временных раздел (/tmp/), монтируемый в tmpfs с разумным размером (обычно двух гигабайт хватает за глаза может привести к проблемам.



imen
2017.03.16 16:26:54
#cid91772

Ответить

Благодарю!
Необходимый минимум есть — и то хлеб.

Хотя согласно изначальной задумке предполагалось, что ты дополнишь материал хотя бы опытом по работе с самой распространённой ОС.

imen
2017.03.16 16:30:39
#cid91773

Ответить

Обнаруженные недочёты (отдельным комментарием, чтобы по исправлении можно было быстро и просто зачистить):

1. Во второй цитате (man 7 signal) на широком мониторе едет выравнивание.
2. Первая пропущенная опечатка:
s/во временных раздел/во временный раздел/
3. Вторая пропущенная опечатка (потеряна закрывающая скобка):
s/ (обычно двух гигабайт хватает за глаза может привести к проблемам/ (обычно двух гигабайт хватает за глаза) может привести к проблемам/

imen
2017.03.18 20:18:35
#cid91775

Ответить

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

sys-apps/opentmpfiles https://github.com/openrc/opentmpfiles
Описание: A standalone utility to process systemd-style tmpfiles.d files

imen
2017.03.18 20:38:56
#cid91776

Ответить

Ещё одна строчка потерялась.. ☺

Установить пакет в отладочном режиме можно несколькими различными способами.
Например задав необходимые параметры через переменные окружения. Зафиксировать которые можно посредством per-package bashrc file.

Т.е. в файл(ы), для рассматриваемого примера — /etc/portage/env/x11-misc/gxneur (и далее по списку) заносятся три строки (базовая часть переменной CFLAGS копируется из make.conf):

CFLAGS="-march=native -O2 -pipe -ggdb"
CXXFLAGS="${CFLAGS}"
FEATURES="splitdebug"