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

StackOverflow https://stackoverflow.com/questions/17965

Вопрос

У меня есть процесс в 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.

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

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

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

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

    # kill -s SEGV <PID>
    

Как только корефайл будет записан, обязательно снова отключите настройки coredump в соответствующих файлах (1./2./3.) !

Для Ubuntu 14.04

  1. Проверьте, включен ли дамп ядра:

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

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

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

  4. Создайте свое приложение с помощью отладочной информации :

    В Makefile -O0 -g

  5. Запустите приложение, создающее дамп ядра (файл дампа ядра с именем ‘core’ должен быть создан рядом с файлом application_name):

    ./application_name
    
  6. Запуск под управлением 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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top