FreeBSD Debug

Материал из OpenWiki
Перейти к: навигация, поиск

Отладка проблем во FreeBSD


Введение

Эта статья была написана уже довольно давно, так что частично она уже может устареть.

Говорят, что программ без ошибок не существует. Когда же речь идёт о крупных проектах, у которых сотни разработчиков и продолжительная история развития, в этом утверждении имеется значимая доля правды. Одним из таких крупных проектов является FreeBSD. Хотя модель разработки FreeBSD и позволяет проводить аудит кода тысячами разработчиков во всём мире, некоторые ошибки остаются незамеченными и проявляются только при определённых обстоятельствах. Так же, что наиболее актуально для данной статьи, когда в проект вводится значительное количество нового кода, требуется его тщательная отладка в реальных условиях и на реальных задачах. В этой статье я попытаюсь раскрыть основы методов отладки и нахождения ошибок в программах и ядре операционной системы FreeBSD на уровне, достаточном для написания содержательного отчёта об обнаруженной проблеме. Такие отчёты являются хорошим подспорьем разработчикам для локализации и устранения проблемы.

На кого ориентирована эта статья? Сложно сказать. Не каждый пользователь или системный администратор решится взять в руки отладчик, чтобы попытаться разобраться в сути проблемы. Но бывают случаи, когда сбои случаются регулярно и серьёзно мешают работе, либо в погоне за новыми возможностями вы стали использовать версию системы для разработчиков. Возможно, вы просто хотите помочь проекту и принимаете участие в тестировании предварительных выпусков системы или каких-нибудь экспериментальных патчей, программ или драйверов. Чтобы ваша помощь была наиболее полезной, либо вы хотите как можно скорее решить свою проблему, вы должны попытаться воспользоваться рассказанными в этой статье методиками по созданию наиболее информативного отчёта о проблеме (PR – Problem Report). Некоторые методики могут оказаться полезными для людей поддерживающих порты FreeBSD или желающих создать свой порт для какого-нибудь приложения.

Большинство приводимых в этой статье методик, утилит, имён переменных и других специфических данных ориентировано на использование в последних версиях FreeBSD, к моменту написания статьи это FreeBSD 6.2-RELEASE и 7.0-CURRENT. Но практически всё это будет работать и на более старых версиях системы. Если у вас по каким-то причинам не получается воспроизвести примеры или аналогичные статье действия, проверьте правильность параметров и имён в соответствующих руководствах пользователя.

Косвенные методы отладки

Бывает так, что программы работают некорректно или завершаются с ошибкой по причине неверной конфигурации. В этом случае конечно можно обвинить разработчиков в том, что не предусмотрели такой ситуации, но с другой стороны это ошибка администратора. Да и к тому же, программа может и не иметь прямого отношения к проекту FreeBSD. Из широко распространённых ошибок такого типа можно отметить: отсутствие файлов конфигурации, отсутствие каких-либо файлов специальных устройств (/dev/null, /dev/random и т.п.), неверные права доступа, отсутствие разделяемых библиотек, либо несоответствие их версий. Такие ошибки можно обнаружить и исправить без помощи отладчика и разработчиков. Но даже если не получается это сделать, информация, полученная при этом, будет очень полезна разработчикам.

Проверка оборудования

Файлы журналов

Не буду оригинальным, первый метод это, конечно же, чтение документации и файлов журналов. Если программа ничего не выводит и просто «молча» завершается, стоит проверить, нет ли среди её параметров или в файле конфигурации специальных опций для отладки, для повышения уровня отладочных сообщений, для запуска не в фоновом режиме и т.п. Возможно, что сервис syslogd не настроен на сохранение сообщений с тем уровнем или типом, который использует приложение. Если в документации нет информации о типе и уровне сообщений, с которыми программа взаимодействует с сервисом syslogd, всегда можно обратиться к исходному тексту. Простой пример того, как можно узнать эту информацию:

# cd /path/to/program/src
# grep –rnE "openlog|syslog" *
main.c:44:#include <syslog.h>
main.c:203:             syslog(LOG_CRIT, "cannot allocate buffer");
main.c:235:             syslog(LOG_ERR, "cannot encode message");
main.c:1425:    openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER);
main.c:1480:            syslog(LOG_ERR, "atexit failed: %m");
main.c:1484:            syslog(LOG_WARNING, "cannot start UDP transport");
main.c:1486:            syslog(LOG_WARNING, "cannot start LSOCK transport");
main.c:1493:            syslog(LOG_ERR, "evCreate: %m");
main.c:1501:            syslog(LOG_ERR, "error in config file"); 

Из этого вывода видно, что программа взаимодействует с демоном syslogd с помощью сообщений, тип которых определяется как LOG_USER, а уровни – LOG_CRIT, LOG_ERR, LOG_WARNING. Эти сообщения могут сохраняться сервисом syslogd в файлы, для которых в /etc/syslog.conf определена маска, например user.*, *.crit, *.warning или user.err.

Более простой метод – включить в syslog.conf сохранение всех сообщений в один файл, либо настроить выборочное сохранение сообщений для конкретной программы. Подробнее об этом можно почитать в руководствах syslog(3) и syslog.conf(5).

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

# cd /path/to/program/src
# grep –rnE "DEBUG|DBG" *
snmp_mibII/mibII_route.c:138:#ifdef DEBUG_ROUTE
snmp_mibII/mibII_route.c:152:#ifdef DEBUG_ROUTE 
...
snmpd/config.c:359:#ifdef DEBUGGING
snmpd/config.c:365:#ifdef DEBUGGING
...
snmpd/main.c:76:      LOG_DEBUG,      /* log_pri */
snmpd/main.c:1123:    syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid());

Здесь среди прочего вывода есть конструкции условной компиляции препроцессора языка Си #ifdef DEBUGGING и #ifdef DEBUG_ROUTE. Если посмотреть в код, то там будет нечто похожее:

#ifdef DEBUGGING
  fprintf(stderr, "EOF");
#endif

/* ... */

#ifdef DEBUG_ROUTE
  syslog(LOG_WARNING, "%s: DELETE: %u.%u.%u.%u "
        "%u.%u.%u.%u %u %u.%u.%u.%u not found", __func__,
        key.index[0], key.index[1], key.index[2],
        key.index[3], key.index[4], key.index[5],
        key.index[6], key.index[7], key.index[8],
        key.index[9], key.index[10], key.index[11],
        key.index[12]);
#endif

То есть, если на этапе обработки программы препроцессором языка Си определить константы DEBUGGING и DEBUG_ROUTE, то код, выводящий дополнительные сообщения будет включён в компилируемую программу, иначе он будет пропущен. Имена констант по негласному соглашению разработчиков обычно содержат в себе слова DEBUG или DBG. Так как эти соглашения являются негласными, то поиск перечисленных сочетаний может не дать результатов. Тогда можно попытаться использовать подобную команду:

# grep -rn -B2 -A2 -E "#\s*(ifdef|ifndef|if)" * | less

Задать значения констант препроцессора, чтобы нужный код был включён в программу, можно разными способами. Наиболее простой и надёжный способ – определить их в самом исходном тексте с помощью директив:

#ifndef DEBUGGING
#define DEBUGGING 1
#endif
#ifndef DEBUG_ROUTE
#define DEBUG_ROUTE 1
#endif

Только делать это нужно именно в тех файлах, где встречаются соответствующие директивы и желательно в самом начале файлов.

Более правильный, но в тоже время более сложный способ – перекомпилирование программы с заданием нужных констант в командной строке компилятора. Сложность здесь заключается в том, что программы могут конфигурироваться и компилироваться с помощью множества различных методов, для которых определение этих констант может оказаться различным. В случае если это системная программа или поставленное из портов ПО, можно переустановить его поместив строку CFLAGS+= –DDEBUGGING –DDEBUG_ROUTE в /etc/make.conf. Параметр –D<имя константы> в строке CFLAGS указывает компилятору (подразумевается gcc) на необходимость определить в заданное значение (если значение не указано, то подразумевается единица) соответствующую константу препроцессора. Сама же переменная CFLAGS содержит параметры, с которыми make(1) будет вызывать компилятор языка Си. В большинстве случаев этого должно быть достаточно. Что бы не изменять make.conf, можно попытаться указать утилите make дополнительные параметры через коммандную строку:

# make DEBUG_FLAGS="-DDEBUGGING –DDEBUG_ROUTE" install

Переменная DEBUG_FLAGS будет добавлена к CFLAGS, и, соответсвенно, компилятор будет вызван с нужными параметрами.

Для большинства программ, устанавливаемых из исходных текстов с использованием configure и gmake, аналогичных результатов можно добиться путём установки переменных окружения CFLAGS или CPPFLAGS (CXXFLAGS). Стоит так же проверить наличие дополнительных параметров с подобным функционалом у скрипта configure (при помощи ./configure --help), если конечно configure существует. Удостовериться в том, что константы установились, и программа будет верно скомпилирована, можно по выводу утилиты make. В параметрах компилятора обязательно должны присутствовать заданные константы, например:

...
==> lib
/bin/sh ..//libtool --mode=compile cc -c -O2 -fno-strict-aliasing -pipe  -DDEBUGGING -DDEBUG_ROUTE -o asn1.lo asn1.c
...

Когда программа выполняется в изолированном окружении, нужно помнить, что для работы с сервисом syslogd у неё должен быть доступ к нему. Сервис syslogd(8) может принимать сообщения от программ через UNIX сокеты и через сеть. Обычно это /var/run/log, /var/run/logpriv и 514 UDP порт. Но syslogd может быть сконфигурирован для прослушивания дополнительных сокетов (подробнее об этом можно прочитать в руководстве).

Поиск в Интернете

После получения хоть какой-то отладочной информации из вывода программы или из системных журналов нужно проанализировать её. Если причина ошибки остаётся непонятной, то надо воспользоваться поиском в Интернете, в архивах специализированных списков рассылок и форумов. Поиск в Интернете, это вообще искусство, которым овладевают со временем, но чтобы им овладеть, нужно хотя бы пытаться найти ответ по возникшей проблеме, прежде чем просить помощи у разработчиков. Простейшее «copy/paste» сообщения об ошибке в поисковик очень часто помогает найти советы по решению проблемы и сокращает время на ожидание, когда какой-нибудь «гуру» в форуме найдёт свободную минутку для ответа на ваши вопросы. Из поисковиков, по личному опыту, всем рекомендую http://google.com, и как частные случаи – http://groups.google.com и http://google.com/bsd. Так же, неплохой сервис поиска по спискам рассылок проекта FreeBSD есть у Рамблера – http://freebsd.rambler.ru, и на официальном сайте проекта есть поисковая система, как по всему сайту в целом, так и по конференциям.

ldd(1) и nm(1)

Может случиться так, что программа не запускается из-за проблем с разделяемыми библиотеками. При проблемах с некорректными версиями библиотек, их отсутствием и другими ошибками, выдаваемыми компоновщиком (смотрите руководство ld(1)) при запуске программы, могут помочь утилиты ldd(1) и nm(1). Простой пример:

/libexec/ld-elf.so.1: Shared object "libglib-2.0.so.0" not found, required by "mc"

Увидев такое сообщение при запуске программы, можно сделать вывод что не найдена библиотека "libglib-2.0.so.0". В сообщении об ошибке явно говорится, какой библиотеки не хватает для запуска программы, узнать полный список необходимых библиотек можно при помощи команды ldd:

# ldd /usr/local/bin/mc
/usr/local/bin/mc:
        libintl.so.6 => /usr/local/lib/libintl.so.6 (0x2810d000)
        libglib-2.0.so.0 => not found (0x0)
        libiconv.so.3 => /usr/local/lib/libiconv.so.3 (0x28116000)
        libncurses.so.6 => /lib/libncurses.so.6 (0x28203000)
        libc.so.6 => /lib/libc.so.6 (0x28242000)

Это удобно, например, при создании изолированных окружений chroot(8) или jail(8). Решением проблемы с отсутствующими библиотеками естественно является установка соответствующего пакета или порта, либо копирование недостающих файлов. Чтобы узнать в каком порте или пакете находится нужная библиотека, можно посмотреть список зависимостей программы и переустановить зависимости:

# pkg_info -rx mc-4.6.1
Information for mc-4.6.1_2:

Depends on:
Dependency: pkgconfig-0.15.0_1
Dependency: perl-5.8.7_2
Dependency: libiconv-1.9.2_1
Dependency: expat-1.95.8
Dependency: gettext-0.13.1_1
Dependency: glib-2.6.6

Либо найти нужный порт в базе установленных пакетов, и определить к какому из них относится утерянная библиотека. Для этого можно воспользоваться командой pkg_info с ключом "–W" или grep:

# cd /var/db/pkg
# grep -r libglib-2.0 *
glib-2.6.6/+CONTENTS:lib/libglib-2.0.a
glib-2.6.6/+CONTENTS:lib/libglib-2.0.so
glib-2.6.6/+CONTENTS:lib/libglib-2.0.so.6

Пример другой проблемы – компоновщик не может обнаружить требуемых программе объектов по имеющейся символьной информации в какой-либо из библиотек. Такие ошибки сопровождаются сообщениями "Undefined symbol xxx", где ххх – имя какого-то объекта, например, функции. Чаще всего это связано с неверной версией имеющейся библиотеки и может быть результатом некорректного обновления пакетов/портов или ручным вмешательством (замена библиотек или исполняемых файлов). Когда программа самостоятельно загружает динамические библиотеки при помощи dlopen(3), то она в большинстве случаев знает, в какой библиотеке не хватает нужных ей объектов. Вот реальный пример подобной проблемы:

snmpd[69703]: lm_load: open /usr/local/lib/snmp_mibII.so: Undefined symbol "op_begemot_mibII"

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

# nm /usr/local/lib/snmp_mibII.so | grep -A2 -B2 op_begemot_mibII  
00020ea0 b oidnum
00020f20 b oidnum
         U op_begemot_mibII
00005b07 T op_icmpstat
00006045 T op_ifentry

Флаг "U" перед именем op_begemot_mibII говорит о том, что этот объект неопределён (undefined) в этой библиотеке, хотя программа пытается его найти именно в ней. При беглом просмотре исходного кода (опять же при помощи grep) среди прочего вывода можно обнаружить:

# grep –r op_begemot_mibII *
snmp_mibII/mibII_begemot.c:op_begemot_mibII(struct snmp_context *ctx __unused, struct snmp_value *value,

# grep –A2 –B2 ^op_begemot_mibII snmp_mibII/mibII_begemot.c
*/
int
op_begemot_mibII(struct snmp_context *ctx __unused, struct snmp_value *value,
    u_int sub, u_int idx __unused, enum snmp_op op)
{

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

Реализация функции op_begemot_mibII в исходном тексте присутствует. Если реализация есть, почему её нет в собранной библиотеке? Разделяемые библиотеки, как и исполняемые модули, создаются из объектных файлов, которые являются результатом компиляции исходного кода в объектный. Просмотрев на список объектных файлов в каталоге после сборки, можно заметить, что для каждого файла с исходным текстом есть объектный файл:

# ls *.c *.o
mibII.c			mibII_ip.c		mibII_route.o
mibII.o			mibII_ip.o		mibII_tcp.c
mibII_begemot.c		mibII_ipaddr.c		mibII_tcp.o
mibII_ifmib.c		mibII_ipaddr.o		mibII_tree.c
mibII_ifmib.o		mibII_nettomedia.c	mibII_tree.o
mibII_ifstack.c		mibII_nettomedia.o	mibII_udp.c
mibII_ifstack.o		mibII_rcvaddr.c		mibII_udp.o
mibII_interfaces.c	mibII_rcvaddr.o
mibII_interfaces.o	mibII_route.c

Но у файла mibII_begemot.c, в котором находится реализация необходимой функции, его нет. Это значит, что файл не был скомпилирован. Для этого конкретного случая проблема решилась добавлением отсутствующего имени файла в Makefile и пересборкой библиотеки:

SRCS=	${MOD}_tree.c mibII.c mibII_ifmib.c mibII_ip.c			\
	mibII_interfaces.c mibII_ipaddr.c mibII_ifstack.c		\
	mibII_rcvaddr.c mibII_nettomedia.c mibII_tcp.c mibII_udp.c	\
	mibII_route.c mibII_begemot.c

При других подобных проблемах, решение может оказаться менее тривиальным. И в общем случае, узнать более точно, в какой библиотеке не хватает объектов – задача непростая. Можно попытаться поискать имя объекта в руководствах, которые обычно в большом количестве устанавливаются вместе с библиотеками, или в поисковике. Если результат будет удачным – переустановить необходимую библиотеку.

Трассировка

Другим чрезвычайно полезным методом является трассировка процессов. Трассирование системных вызовов во FreeBSD можно выполнять как минимум с помощью трёх различных утилит: ktrace, truss и strace. Последняя не входит в состав системы, но присутствует в дереве портов - devel/strace. С помощью трассировки можно определить последовательность действий программы и, возможно, обнаружить причину неправильной работы или сбоя. Особенно легко определить, какие файлы пытается открыть программа и увидеть результат этих попыток.

Простой пример, определим, в каком каталоге интерпретатор языка php пытается найти свой конфигурационный файл php.ini. Конечно, задача достаточно тривиально решается при помощи команд интерпретатора:

# echo "<? phpinfo(); ?>" | php | grep .ini
<tr><td class="e">Configuration File (php.ini) Path </td><td class="v">/usr/local/lib </td></tr>

Но, всё же, посмотрим, как эта задача решается при помощи трассировки:

# ktrace -t n /usr/local/bin/php
^C
# kdump | grep ini
 44172 php      NAMI  "./php-cgi.ini"
 44172 php      NAMI  "/usr/local/bin//php-cgi.ini"
 44172 php      NAMI  "/usr/local/lib/php-cgi.ini"
 44172 php      NAMI  "./php.ini"
 44172 php      NAMI  "/usr/local/bin//php.ini"
 44172 php      NAMI  "/usr/local/lib/php.ini"

Утилита ktrace(1) используется для управления специальной подсистемой ядра, отвечающей за трассирование системных вызовов. По-умолчанию, если не задан параметр командной строки "-f", ktrace создаёт в текущем рабочем каталоге файл ktrace.out с результатами своей работы. Вывод утилиты имеет нетекстовый формат, для расшифровки которого используется утилита kdump(1). В этом примере ktrace запускается с параметром "-t". Этот параметр указывает ядру точки трассирования находящиеся в коде ядра, при прохождении через которые генерируются события, отображаемые в журнале трассировки.

Как видите, трассировка дала несколько более широкое представление о действиях интерпретатора php. В этом примере показано только трассирование операций разрешения имён (точка трассирования "n"). Добавив к набору точек трассирования ещё и системные вызовы (точка "c") можно получить более интересную картину:

# ktrace -t nc /usr/local/bin/php
^C
# kdump | grep -A1 -B1 .ini
 47924 php      CALL  open(0xbfbff0a0,0,0x1b6)
 47924 php      NAMI  "./php-cgi.ini"
 47924 php      RET   open -1 errno 2 No such file or directory
 47924 php      CALL  open(0xbfbff0a0,0,0x1b6)
 47924 php      NAMI  "/usr/local/bin//php-cgi.ini"
 47924 php      RET   open -1 errno 2 No such file or directory
 47924 php      CALL  open(0xbfbff0a0,0,0x1b6)
 47924 php      NAMI  "/usr/local/lib/php-cgi.ini"
 47924 php      RET   open -1 errno 2 No such file or directory
 47924 php      CALL  open(0xbfbff0a0,0,0x1b6)
 47924 php      NAMI  "./php.ini"
 47924 php      RET   open -1 errno 2 No such file or directory
 47924 php      CALL  open(0xbfbff0a0,0,0x1b6)
 47924 php      NAMI  "/usr/local/bin//php.ini"
 47924 php      RET   open -1 errno 2 No such file or directory
 47924 php      CALL  open(0xbfbff0a0,0,0x1b6)
 47924 php      NAMI  "/usr/local/lib/php.ini"
 47924 php      RET   open 3

В этом выводе отображена последовательность попыток php открыть файлы конфигурации в различных каталогах. Так же видны коды возврата системного вызова open(2), по которым можно сделать вывод, что файл был найден только в каталоге /usr/local/lib/.

Выполнять трассировку при помощи ktrace(1) можно не только на этапе запуска процесса, при помощи опции "-p" есть возможность включить трассирование системных вызовов в уже исполняющемся процессе. Если вы не планируете завершать трассируемый процесс, то не забывайте отключить трассирование при помощи вызова ktrace с опцией "-С" или "-c". Программы, изменяющие свои реальный или эффективный идентификаторы пользователя или группы, могут трассироваться только суперпользователем. Для трассирования процессов потомков можно воспользоваться опцией "-d".

Ещё одна утилита для трассирования, входящая в базовую систему - это truss(1). Возможно, кому-то она покажется более дружественной, чем ktrace(1), к тому же её вывод не требует декодирования. Но для работы truss необходима смонтированная файловая система procfs(5), что не всегда приемлемо и возможно. Вот пример той же трассировки php при помощи truss:

# mount -t procfs procfs /proc
# truss -o truss.out php
^C
# grep .ini truss.out
open("./php-cgi.ini",0x0,0666)              ERR#2 'No such file or directory'
open("php/php-cgi.ini",0x0,0666)            ERR#2 'No such file or directory'
open("/usr/local/lib/php-cgi.ini",0x0,0666) ERR#2 'No such file or directory'
open("./php.ini",0x0,0666)                  ERR#2 'No such file or directory'
open("php/php.ini",0x0,0666)                ERR#2 'No such file or directory'
open("/usr/local/lib/php.ini",0x0,0666)     = 4 (0x4)
lstat("php.ini",0xbfbfe6f0)                 = 0 (0x0)

Как видите, в выводе truss параметры у системных вызовов представлены в более понятной форме. Это может оказаться полезным в ряде случаев. Например, при трассировании работающих с сетью программ в выводе truss легко читаются IP адреса. В общем, если вам недостаточно информации, выдаваемой одной из предложенных утилит, попробуйте выполнить трассировку другой. А так же, не забывайте, что в коллекции портов есть утилита strace [1].

Все три перечисленные утилиты предназначены для трассирования системных вызовов. В коллекции портов есть ещё одна утилита трассировки – sysutils/ltrace. Она предназначена для трассирования вызовов функций разделяемых библиотек, например, различные функции работы со строками (копирование, сравнение и т.п.). Подобная информация может оказаться полезной для более полного понимания того, как работает программа.

Другие утилиты

Отладка программ

И так, методы "косвенной отладки" не дали положительных результатов. Остаётся надеяться на помощь разработчиков, либо попытаться заняться отладкой самим.

Файлы .core

Какую же информацию могут получить пользователи с помощью отладчика, чтобы предоставить её разработчикам? Наибольший интерес для программиста представляет последовательность вызовов функций и состояние переменных перед тем как произошёл сбой. Эту информацию после краха программы можно получить из файла дампа памяти процесса, которые обычно называются по имени процесса с расширением core (смотрите руководство core(5)). Система создаёт файлы дампа при некорректных действиях программы, например, при обращении к некорректному адресу памяти, при вызове несуществующего системного вызова. На самом деле, создание дампа является действием по-умолчанию по обработке некоторых сигналов, таких как SIGSEGV, SIGSYS, SIGBUS и некоторых других. Подробное описание по сигналам и действиям по-умолчанию для них можно прочитать в руководстве signal(3).

Файлы дампа обычно сохраняются в рабочем каталоге процесса, но есть ряд случаев, когда дамп не будет сохранён. Во-первых, сохранение дампов можно отключить полностью через специальную переменную sysctl kern.coredump (1 – сохранять дампы, 0 – не сохранять). Во-вторых, если у пользователя, от имени которого работал процесс, нет прав для записи в рабочий каталог процесса, то файл дампа не будет создан. Например, многие сетевые серверы после запуска изменяют свой (или своих потомков) идентификатор пользователя на менее привилегированный, который может не иметь прав для записи в рабочий каталог процесса. Это ограничение можно обойти путём задания пути в переменной sysctl kern.corefile для сохранения дампов в каталог, доступный для записи всем пользователям. Через неё так же можно изменить и имя файла дампа, для того чтобы дампы не перезаписывались друг другом. Имя задаётся шаблоном при помощи специальных последовательностей: %N – имя файла работающего процесса; %P – идентификатор процесса; %U – идентификатор пользователя, от имени которого работал процесс. Например, создав каталог /var/coredumps c правами доступа 0777 можно определить значение sysctl kern.corefile="/var/coredumps/%U.%N.%P.core". В-третьих, на максимальный размер файла дампа может быть введено ограничение через переменную coredumpsize в login.conf(5). И, в-четвёртых, дамп не создаётся для процессов, которые изменяют свои реальный или эффективный идентификаторы пользователя или группы. Это поведение так же может быть изменено с помощью переменной sysctl kern.sugid_coredump.

Подытожив всё вышесказанное, настройм создание дампов памяти процессов в системе:

# cat >> /etc/sysctl.conf
kern.coredump=1
kern.corefile=/var/coredumps/%U.%N.%P.core
#Раскомментируйте следующую строку, если вы уверены в её необходимости
#kern.sugid_coredump=1
^D
# mkdir /var/coredumps
# chmod a=rwx /var/coredumps
# /etc/rc.d/sysctl restart

Для случаев, когда программа работает некорректно и не завершается с созданием дампа памяти, можно сделать дамп самостоятельно. Для этого используется утилита gcore(1). Чтобы gcore смогла создать файл дампа, ей необходима смонтированная файловая система procfs(5). В качестве параметров утилита принимает идентификатор исполняющегося процесса, так же можно указать путь к исполняемому файлу программы, чей дамп памяти вы хотите получить.

Подготовка к отладке

Введение в gdb

Основные термины и команды, необходиме для минимальных действий (сделать бэктрейс, например) :)

Отладка системных утилит

core-файлы

Для чего, как управляются, какие особенности (suid, права доступа, sysctl и т.п.)

Что нужно для облегчения отладки

Как собрать с отладочными символами и т.п. Просмотр спец опций отладки в исходниках, /etc/malloc.conf, трассировка..

Пару слов о программах из портов

Как собирать и устанавливать, куда обращаться с вопросами

Отладка ядра

Отладочные опции

Назначение отдельных опций, как собирать, что подкрутить для сохранения дампа

элементарное введение в DDB

какие команды, call doadump, panic, tr..

загрузка и отладка через serial консоль

как и что

исследование корки ядра

Что ещё можно попробовать

на цифровик сфоткать :)

Отладка модулей ядра

asf, особенности

Как правильно делать send-pr

Что писать, куда, кому. Как отвечать на feedback'и и т.п.

Литература и благодарности