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


217

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


Ответы:


249

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

ulimit -c unlimited

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

В tcsh вы наберете

limit coredumpsize unlimited

21
@lzprgmr: чтобы уточнить: причина, по которой дампы ядра не генерируются по умолчанию, заключается в том, что ограничение не установлено и / или не установлено в 0, что предотвращает сброс ядра. Устанавливая неограниченный лимит, мы гарантируем, что дампы ядра всегда будут генерироваться.
Эли Кортрайт

6
Эта ссылка идет глубже и дает еще несколько опций для включения генерации дампов ядра в linux. Единственный недостаток - некоторые команды / настройки остаются необъясненными.
Сальса

6
На bash 4.1.2 (1) -релизы, такие как 52M, не могут быть указаны, что приводит к сообщению об ошибке неверного номера. Страница man говорит, что «Значения с шагом 1024 байта».
A1An

4
Ну, у меня был «маленький» проект OpenGL, который когда-то делал странные вещи и вызывал сбой X-сервера. Когда я снова вошел в систему, я увидел симпатичный маленький файл ядра объемом 17 ГБ (в разделе 25 ГБ). Это определенно хорошая идея - ограничить размер основного файла :)
IceCool

1
@PolarisUser: Если вы хотите убедиться, что ваш раздел не съеден, я рекомендую установить ограничение примерно в 1 гиг. Это должно быть достаточно большим, чтобы справиться с любым разумным дампом ядра, при этом не угрожая использовать все оставшееся место на жестком диске.
Эли Кортрайт

60

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

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

gcore <pid>

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

kill -ABRT <pid>

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


Я думаю, что гораздо более вероятно, что -ABRTвызовет обработчик сигнала, чем -SEGV, поскольку прерывание с большей вероятностью будет восстановимо, чем сегфоут. (Если вы обрабатываете segfault, обычно он просто срабатывает снова, как только ваш обработчик завершает работу.) Лучший выбор сигнала для генерации дампа ядра - это -QUIT.
celticminstrel

32

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

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

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

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

Macos

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


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

26

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


Как вы подключили GDB к процессу?
Чани

6
Чтобы ответить Ritwik G, чтобы прикрепить процесс к gdb, просто запустите gdb и введите 'attach <pid>', где <pid> - номер pid процесса, который вы хотите присоединить.
Жан-Доминик Фраттини

(сокращенно как ge)
user202729

Если у них есть новый вопрос, они должны задать новый вопрос вместо того, чтобы спрашивать в комментарии.
user202729

Странная вещь не я уже установлен ulimit -cна unlimited, но файл ядра успокоен не создан, generate-core-fileфайл в GdB сессии действительно создает файл ядра, спасибо.
CodyChan

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 сбросить ядро , как показано здесь , в этом блоге здесь .


16

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

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

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


9

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

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

    # kill -s SEGV <PID>

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


9

Для 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

На шаге 3, как «перезапустить» терминал? Вы имеете в виду перезагрузку?
Навин

@ Навин нет, просто закройте терминал и откройте новый, также, кажется, вы можете просто вставить ulimit -c unlimitedтерминал для временного решения, потому что только редактирование ~/.bashrcтребует перезапуска терминала, чтобы изменения вступили в силу.
mrgloom

4

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


4
Под "текущим каталогом процесса" вы подразумеваете $ cwd во время запуска процесса? ~ / abc> / usr / bin / cat def в случае сбоя cat, является ли текущий каталог вопросом ~ / abc или / usr / bin?
Натан Феллман

5
~ / а. Хм, комментарии должны быть длиной 15 символов!
Марк Харрисон

5
Это будет текущий каталог во время SEGV. Кроме того, процессы, работающие с другим эффективным пользователем и / или группой, чем реальный пользователь / группа, не будут записывать файлы ядра.
Даррон

2

Лучше включить программный дамп ядра с помощью системного вызова 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));
}

почему так лучше?
Натан Феллман

Основной файл, созданный после сбоя, не нужно ulimit -c unlimitedв командной строке среды, а затем перезапустите приложение.
kgbook

Я не хочу, чтобы дамп ядра каждый раз падал, только когда пользователь связывается со мной как разработчиком, чтобы посмотреть на него. Если он выходит из строя 100 раз, мне не нужно смотреть на 100 дампов ядра.
Натан Феллман

В этом случае лучше использовать ulimit -c unlimited. Также вы можете скомпилировать с определением marco, приложение не будет включать enable_core_dumpсимвол, если не определит этот макрос при выпуске, и вы получите дамп ядра, замененный отладочной версией.
kgbook

даже если он определен макросом, мне все равно придется перекомпилировать, если я хочу сгенерировать дамп ядра, а не просто выполнить команду в оболочке перед повторным запуском.
Натан Феллман

1

Стоит отметить, что если у вас настроен 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

0

Ubuntu 19.04

Все остальные ответы не помогли мне. Но следующая сумма сделала работу

Создайте ~/.config/apport/settingsсо следующим содержанием:

[main]
unpackaged=true

(Это говорит apport также писать дампы ядра для пользовательских приложений)

проверить: ulimit -c. Если он выдает 0, исправьте это с помощью

ulimit -c unlimited

На всякий случай перезапустите apport:

sudo systemctl restart apport

Файлы Crash теперь записаны в /var/crash/. Но вы не можете использовать их с GDB. Чтобы использовать их с GDB, используйте

apport-unpack <location_of_report> <target_directory>

Дальнейшая информация:

  • Некоторые ответы предлагают изменить core_pattern. Помните, что этот файл может быть перезаписан сервисом apport при перезапуске.
  • Просто остановка apport не сделала работу
  • ulimit -cЗначение может переодеться автоматически в то время как вы пытаетесь другие ответы в Интернете. Обязательно проверяйте его регулярно во время настройки создания дампа ядра.

Ссылки:

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.