Як генерувати основний дамп у Linux за помилкою сегментації?


217

У мене в Linux процес, який отримує помилку в сегментації. Як я можу сказати, що він генерує основний дамп, коли він не працює?


Відповіді:


249

Це залежить від того, яку оболонку ви використовуєте. Якщо ви використовуєте bash, то команда ulimit керує кількома налаштуваннями, що стосуються виконання програми, наприклад, чи слід скидати ядро. Якщо ви введете

ulimit -c unlimited

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

В tcsh ви введете

limit coredumpsize unlimited

21
@lzprgmr: Для уточнення: причиною того, що дамп ядра не генерується за замовчуванням, є те, що межа не встановлена ​​та / або встановлена ​​на 0, що запобігає скидженню ядра. Встановлюючи ліміт необмеженого рівня, ми гарантуємо, що основні відвали завжди можуть створюватися.
Eli Courtwright

6
Це посилання заглиблюється та дає ще кілька варіантів, щоб дозволити генерацію основних скидів у Linux. Єдиним недоліком є ​​те, що деякі команди / налаштування залишаються незрозумілими.
Сальса

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

4
Ну, у мене був "невеликий" проект OpenGL, який одного разу зробив якусь дивну річ і спричинив збій X-сервера. Коли я ввійшов назад, я побачив милий маленький базовий файл розміром 17 Гб (на розділі 25 ГБ). Це, безумовно, гарна ідея обмежити розмір основного файлу обмеженим :)
IceCool

1
@PolarisUser: Якщо ви хочете переконатися, що ваш розділ не буде з'їдений, я рекомендую встановити ліміт приблизно як 1 гіг. Це повинно бути достатньо великим, щоб обробляти будь-який розумний дамп основного ядра, не загрожуючи використати весь ваш залишок на жорсткому диску.
Eli Courtwright

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 (скидається ядро)

Дивитися також: core dumped - але основний файл відсутній у поточному каталозі?


Ubuntu

У Ubuntu основними дампами обробляються Apport і вони можуть бути розміщені в/var/crash/ . Однак він стабільно вимкнено за умовчанням.

Для отримання більш детальної інформації, будь ласка, перевірте: Де я можу знайти основний дамп в Ubuntu?.

macOS

Про macOS дивіться у розділі: Як генерувати основні скиди в Mac OS X?


3
Щоб Ubuntu швидко повернувся до нормальної поведінки (скидання основного файлу в поточну директорію), просто зупиніть службу apport із "зупинкою apport service sudo". Також зауважте, що якщо ви працюєте в docker, це налаштування контролюється в хост-системі, а не в контейнері.
Digicrat

26

Що я зробив наприкінці, це приєднати gdb до процесу перед тим, як він вийшов з ладу, а потім, коли він отримав сегмент за замовчуванням, я виконав generate-core-fileкоманду. Це вимушене покоління основного сміття.


Як ви долучили gdb до процесу?
Чані

6
Щоб відповісти на Ritwik G, щоб приєднати процес до gdb, просто запустіть gdb та введіть "attach <pid>", де <pid> - номер pid процесу, який ви хочете долучити.
Жан-Домінік Фраттіні

(скорочено ge)
користувач202729

Якщо у них є нове запитання, вони повинні задати нове питання, а не ставити коментар.
користувач202729

Дивна річ НЕ я вже встановлений 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 - спробуйте 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>(це не потрібно, на випадок, якщо жоден основний файл не буде записаний, це може бути використане як перевірка):

    # kill -s SEGV <PID>

Після того, як основний файл буде записаний, переконайтеся, що знову відключити настройки 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, як «запустити» термінал? Ви маєте на увазі перезавантаження?
Naveen

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

4

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


4
Під "поточним каталогом процесу" ви маєте на увазі $ cwd на момент запуску процесу? ~ / abc> / usr / bin / cat def, якщо кішка виходить з ладу, чи є поточний каталог у питанні ~ / 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в середовищі командного рядка, а потім повторно запускати програму.
кгкнига

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

У такому випадку краще використовувати ulimit -c unlimited. Крім того, ви можете компілювати з визначенням marco, додаток не буде містити enable_core_dumpсимвол, якщо не визначити цей макрос при випуску, і ви отримаєте основний дамп замінити на версію налагодження.
кгкнижка

навіть якщо він кваліфікований макросом, це все ще вимагає від мене перекомпіляції, якщо я хочу створити дамп ядра, а не просто виконувати команду в оболонці перед повторним запусканням.
Натан Фелман

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

(Це повідомляє про можливість також писати основні скиди для спеціальних додатків)

перевірити: ulimit -c. Якщо він виводить 0, зафіксуйте його

ulimit -c unlimited

Про всяк випадок, якщо перезапустити приклад:

sudo systemctl restart apport

Файли збоїв тепер записані в /var/crash/. Але ви не можете використовувати їх з gdb. Щоб використовувати їх з gdb, використовуйте

apport-unpack <location_of_report> <target_directory>

Додаткова інформація:

  • Деякі відповіді пропонують змінити core_pattern. Пам’ятайте, що цей файл може перезаписатися службою apport при перезапуску.
  • Просто зупиняючи приклад, це не справило справи
  • ulimit -cЗначення може переодягнутися автоматично в той час як ви намагаєтеся інші відповіді в Інтернеті. Не забудьте регулярно перевіряти це під час налаштування вашого основного дампського створення.

Список літератури:

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.