Как сгенерировать дамп ядра в Linux при ошибке сегментации?
Вопрос
У меня есть процесс в Linux, который получает ошибку сегментации.Как я могу сказать ему, чтобы он генерировал дамп ядра при сбое?
Решение
Это зависит от того, какую оболочку вы используете.Если вы используете bash, то команда ulimit управляет несколькими параметрами, относящимися к выполнению программы, например, следует ли вам сбрасывать ядро.Если вы наберете
ulimit -c unlimited
тогда это сообщит bash, что его программы могут выгружать ядра любого размера.Вы можете указать размер, например 52M, вместо unlimited, если хотите, но на практике в этом не должно быть необходимости, поскольку размер основных файлов, вероятно, никогда не будет для вас проблемой.
В tcsh вы бы набрали
limit coredumpsize unlimited
Другие советы
Как объяснялось выше, реальный вопрос, который здесь задается, заключается в том, как включить дампы ядра в системе, где они не включены.Здесь дан ответ на этот вопрос.
Если вы пришли сюда в надежде узнать, как сгенерировать дамп ядра для зависшего процесса, то ответ таков
gcore <pid>
если gcore недоступен в вашей системе, то
kill -ABRT <pid>
Не используйте kill -SEGV, так как это часто вызывает обработчик сигнала, затрудняя диагностику застрявшего процесса
Что я сделал в конце, так это присоединил gdb к процессу до его сбоя, а затем, когда он получил ошибку segfault, я выполнил generate-core-file
команда.Это принудительное создание дампа ядра.
Чтобы проверить, где генерируются дампы ядра, запустите:
sysctl kernel.core_pattern
или:
cat /proc/sys/kernel/core_pattern
где %e
является именем процесса и %t
системное время.Вы можете изменить это в /etc/sysctl.conf
и перезарядка с помощью sysctl -p
.
Если основные файлы не сгенерированы (проверьте это с помощью: sleep 10 &
и killall -SIGSEGV sleep
), проверьте пределы с помощью: ulimit -a
.
Если размер вашего основного файла ограничен, запустите:
ulimit -c unlimited
чтобы сделать его неограниченным.
Затем проверьте еще раз, если сброс ядра прошел успешно, вы увидите “(сброс ядра)” после индикации ошибки сегментации, как показано ниже:
Ошибка сегментации:11 (сброшенное ядро)
Смотрите также: ядро сброшено - но файла ядра нет в текущем каталоге?
Убунту
В Ubuntu дампы ядра обрабатываются Распределять и может быть расположен в /var/crash/
.Однако в стабильных версиях он по умолчанию отключен.
Для получения более подробной информации, пожалуйста, проверьте: Где я могу найти дамп ядра в Ubuntu?.
macOS
Для macOS см.: Как сгенерировать дампы ядра в Mac OS X?
Возможно, вы могли бы сделать это таким образом, эта программа является демонстрацией того, как перехватить ошибку сегментации и передать ее отладчику (это исходный код, используемый в AIX
) и выводит трассировку стека вплоть до точки ошибки сегментации.Вам нужно будет изменить sprintf
переменная для использования gdb
в случае с Linux.
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <stdarg.h>
static void signal_handler(int);
static void dumpstack(void);
static void cleanup(void);
void init_signals(void);
void panic(const char *, ...);
struct sigaction sigact;
char *progname;
int main(int argc, char **argv) {
char *s;
progname = *(argv);
atexit(cleanup);
init_signals();
printf("About to seg fault by assigning zero to *s\n");
*s = 0;
sigemptyset(&sigact.sa_mask);
return 0;
}
void init_signals(void) {
sigact.sa_handler = signal_handler;
sigemptyset(&sigact.sa_mask);
sigact.sa_flags = 0;
sigaction(SIGINT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGSEGV);
sigaction(SIGSEGV, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGBUS);
sigaction(SIGBUS, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGQUIT);
sigaction(SIGQUIT, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGHUP);
sigaction(SIGHUP, &sigact, (struct sigaction *)NULL);
sigaddset(&sigact.sa_mask, SIGKILL);
sigaction(SIGKILL, &sigact, (struct sigaction *)NULL);
}
static void signal_handler(int sig) {
if (sig == SIGHUP) panic("FATAL: Program hanged up\n");
if (sig == SIGSEGV || sig == SIGBUS){
dumpstack();
panic("FATAL: %s Fault. Logged StackTrace\n", (sig == SIGSEGV) ? "Segmentation" : ((sig == SIGBUS) ? "Bus" : "Unknown"));
}
if (sig == SIGQUIT) panic("QUIT signal ended program\n");
if (sig == SIGKILL) panic("KILL signal ended program\n");
if (sig == SIGINT) ;
}
void panic(const char *fmt, ...) {
char buf[50];
va_list argptr;
va_start(argptr, fmt);
vsprintf(buf, fmt, argptr);
va_end(argptr);
fprintf(stderr, buf);
exit(-1);
}
static void dumpstack(void) {
/* Got this routine from http://www.whitefang.com/unix/faq_toc.html
** Section 6.5. Modified to redirect to file to prevent clutter
*/
/* This needs to be changed... */
char dbx[160];
sprintf(dbx, "echo 'where\ndetach' | dbx -a %d > %s.dump", getpid(), progname);
/* Change the dbx to gdb */
system(dbx);
return;
}
void cleanup(void) {
sigemptyset(&sigact.sa_mask);
/* Do any cleaning up chores here */
}
Возможно, вам придется дополнительно добавить параметр, чтобы заставить gdb выгружать ядро, как показано здесь, в этом блоге здесь.
Есть и другие факторы, которые могут повлиять на создание дампа ядра.Я столкнулся с такими:
- каталог для дампа должен быть доступен для записи.По умолчанию это текущий каталог процесса, но его можно изменить, установив
/proc/sys/kernel/core_pattern
. - в некоторых условиях значение ядра в
/proc/sys/fs/suid_dumpable
может помешать созданию ядра.
Есть и другие ситуации, которые могут помешать генерации, описанные на странице руководства - попробуйте man core
.
Чтобы активировать дамп ядра, выполните следующие действия:
В
/etc/profile
прокомментируйте строку:# ulimit -S -c 0 > /dev/null 2>&1
В
/etc/security/limits.conf
закомментируйте строку:* soft core 0
выполните команду cmd
limit coredumpsize unlimited
и проверьте это с помощью cmdlimit
:# limit coredumpsize unlimited # limit cputime unlimited filesize unlimited datasize unlimited stacksize 10240 kbytes coredumpsize unlimited memoryuse unlimited vmemoryuse unlimited descriptors 1024 memorylocked 32 kbytes maxproc 528383 #
чтобы проверить, будет ли записан корефайл, вы можете завершить соответствующий процесс с помощью cmd
kill -s SEGV <PID>
(не должно быть необходимости, на всякий случай, если файл ядра не будет записан, это можно использовать в качестве проверки):# kill -s SEGV <PID>
Как только корефайл будет записан, обязательно снова отключите настройки coredump в соответствующих файлах (1./2./3.) !
Для Ubuntu 14.04
Проверьте, включен ли дамп ядра:
ulimit -a
Одна из строк должна быть :
core file size (blocks, -c) unlimited
Если нет :
gedit ~/.bashrc
и добавитьulimit -c unlimited
чтобы завершить файл и сохранить, повторно запустите терминал.Создайте свое приложение с помощью отладочной информации :
В Makefile
-O0 -g
Запустите приложение, создающее дамп ядра (файл дампа ядра с именем ‘core’ должен быть создан рядом с файлом application_name):
./application_name
Запуск под управлением gdb:
gdb application_name core
По умолчанию вы получите основной файл.Убедитесь, что текущий каталог процесса доступен для записи, иначе основной файл не будет создан.
Лучше включить дамп ядра программно, используя системный вызов setrlimit
.
пример:
#include <sys/resource.h>
bool enable_core_dump(){
struct rlimit corelim;
corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;
return (0 == setrlimit(RLIMIT_CORE, &corelim));
}
Подожди.Это происходит автоматически.Нет необходимости это делать
Стоит упомянуть, что если у вас есть systemd ( система ) настроившись, тогда все будет немного по-другому.При настройке обычно файлы ядра передаются по конвейеру с помощью core_pattern
значение sysctl, через systemd-coredump(8)
.Rlimit размера основного файла обычно уже настроен как "неограниченный".
Затем можно извлечь дампы ядра, используя coredumpctl(1)
.
Хранение дампов ядра и т.д.настраивается с помощью coredump.conf(5)
.Есть примеры того, как получить основные файлы на справочной странице coredumpctl, но вкратце это будет выглядеть так:
Найдите основной файл:
[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET 16163 1224 1224 11 present /home/vps/test_me
Получите основной файл:
[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163