Как создать дамп ядра в Linux при ошибке сегментации?

196

У меня есть процесс в Linux, который вызывает ошибку сегментации. Как я могу сказать, что он генерирует дамп ядра, когда он терпит неудачу?

Теги:
coredump
tcsh

12 ответов

211
Лучший ответ

Это зависит от того, какую оболочку вы используете. Если вы используете bash, то команда ulimit управляет несколькими настройками, относящимися к выполнению программы, например, нужно ли вы сбросить ядро. Если вы наберете

ulimit -c unlimited

то это сообщит bash, что его программы могут выгружать ядра любого размера. Вы можете указать такой размер, как 52M, а не неограниченно, если вы хотите, но на практике это не обязательно, поскольку размер основных файлов, вероятно, никогда не будет проблемой для вас.

В tcsh введите

limit coredumpsize unlimited
  • 0
    Извините, но это действительно ответ на ваш вопрос? Вы спросили, как генерировать, но он говорит, как установить ограничения
  • 17
    @lzprgmr: чтобы уточнить: причина, по которой дампы ядра не генерируются по умолчанию, заключается в том, что ограничение не установлено и / или не установлено в 0, что предотвращает сброс ядра. Устанавливая неограниченный лимит, мы гарантируем, что дампы ядра всегда будут генерироваться.
Показать ещё 8 комментариев
53

Как объяснялось выше, реальный вопрос, задаваемый здесь, заключается в том, как включить дампы ядра в системе, где они не включены. На этот вопрос ответил.

Если вы пришли сюда, надеясь узнать, как создать основной дамп для зависания, ответ

gcore <pid>

если gcore недоступен в вашей системе, тогда

kill -ABRT <pid>

Не используйте kill -SEGV, поскольку это часто вызывает обработчик сигнала, что затрудняет диагностику застрявшего процесса

25

То, что я сделал в конце, было прикрепление gdb к процессу, прежде чем он разбился, а затем, когда он получил segfault, я выполнил команду generate-core-file. Это принудительное генерирование дампа ядра.

  • 0
    Как вы подключили GDB к процессу?
  • 6
    Чтобы ответить Ritwik G, чтобы прикрепить процесс к gdb, просто запустите gdb и введите 'attach <pid>', где <pid> - номер pid процесса, который вы хотите присоединить.
Показать ещё 2 комментария
19

Чтобы проверить, где генерируются дампы ядра, запустите:

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

сделать это неограниченным.

Затем проверьте снова, если дамп ядра успешен, вы увидите "(core dumped)" после индикации ошибки сегментации, как показано ниже:

Ошибка сегментации: 11 (ядро сброшено)

Смотрите также: ядро сброшено - но файл ядра не находится в текущем каталоге?


Ubuntu

В Ubuntu дампы ядра обрабатываются Apport и могут быть расположены в /var/crash/. Однако он по умолчанию отключен в стабильных выпусках.

Для более подробной информации, пожалуйста, проверьте: Где я могу найти дамп ядра в Ubuntu? ,

Macos

Для macOS см.: Как создать дамп ядра в Mac OS X?

  • 2
    В Ubuntu, чтобы быстро вернуться к нормальному поведению (сбросить файл ядра в текущем каталоге), просто остановите службу apport с помощью «остановки приложения sudo service». Также обратите внимание, что если вы работаете в Docker, этот параметр контролируется в хост-системе, а не в контейнере.
19

Может быть, вы могли бы сделать это таким образом, эта программа демонстрирует, как перехватить ошибку сегментации и выдает ее отладчику (это оригинальный код, используемый в 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 сбросить ядро, как показано здесь, в этом блоге здесь.

15

Есть больше вещей, которые могут повлиять на генерацию дампа ядра. Я столкнулся с ними:

  • каталог для дампа должен быть доступен для записи. По умолчанию это текущий каталог процесса, но его можно изменить, установив /proc/sys/kernel/core_pattern.
  • в некоторых условиях значение ядра в /proc/sys/fs/suid_dumpable может помешать генерации ядра.

Есть больше ситуаций, которые могут помешать генерации, которые описаны на странице руководства - попробуйте man core.

8

Для Ubuntu 14.04

  • Включить защитный дамп ядра:

    ulimit -a
    
  • Одна из строк должна быть:

    core file size          (blocks, -c) unlimited
    
  • Если нет:

    gedit ~/.bashrc и добавьте ulimit -c unlimited в конец файла и сохраните, запустите терминал.

  • Создайте приложение с отладочной информацией:

    В Makefile -O0 -g

  • Запустить приложение, создающее ядро ​​дампа (основной файл дампа с именем), должно быть создано около файла имени приложения):

    ./application_name
    
  • Запуск под gdb:

    gdb application_name core
    
  • 0
    На шаге 3, как «перезапустить» терминал? Вы имеете в виду перезагрузку?
  • 0
    @ Навин нет, просто закройте терминал и откройте новый, также кажется, что вы можете просто положить ulimit -c unlimited в терминал для временного решения, потому что только редактирование ~/.bashrc требует перезапуска терминала, чтобы изменения вступили в силу.
8

Чтобы активировать дамп ядра, выполните следующие действия:

  • В /etc/profile прокомментируйте строку:

    # ulimit -S -c 0 > /dev/null 2>&1
    
  • В /etc/security/limits.conf закомментируйте строку:

    *               soft    core            0
    
  • выполните cmd limit coredumpsize unlimited и проверьте его с помощью cmd limit:

    # 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
    #
    
  • чтобы проверить, записывается ли файл corefile, вы можете убить связанный процесс с помощью cmd kill -s SEGV <PID> (не нужно, на всякий случай, если файл ядра не будет записан, это может использоваться как проверка):

    # kill -s SEGV <PID>
    

После того, как файл core был записан, обязательно отключите параметры coredump снова в связанных файлах (1./2./3.)!

4

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

  • 4
    Под «текущим каталогом процесса» вы подразумеваете $ cwd во время запуска процесса? ~ / abc> / usr / bin / cat def в случае сбоя cat, является ли текущий каталог вопросом ~ / abc или / usr / bin?
  • 5
    ~ / А. Хм, комментарии должны быть длиной 15 символов!
Показать ещё 1 комментарий
1

Лучше включить программный дамп ядра, используя системный вызов 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));
}
  • 0
    почему так лучше?
  • 0
    Основной файл, сгенерированный после сбоя, не нужно ulimit -c unlimited в среде командной строки, а затем перезапустить приложение.
Показать ещё 4 комментария
0

Стоит отметить, что если у вас настроен systemd, то все немного по-другому. Обычно в настройках файлы ядра core_pattern посредством core_pattern sysctl core_pattern через 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
0

Подождите. Это автоматически делает. Не нужно это делать

  • 0
    Видимо, нет, иначе я бы не почувствовал необходимости задавать вопрос :-)

Ещё вопросы

Сообщество Overcoder
Наверх
Меню