Как программно вызвать дамп ядра в C / C ++


93

Я хотел бы принудительно создать дамп ядра в определенном месте в моем приложении C ++.

Я знаю, что могу сделать это, выполнив что-нибудь вроде:

int * crash = NULL;
*crash = 1;

Но хотелось бы знать, есть ли способ чище?

Кстати, я использую Linux.


18
"Более чистый" способ дампа ядра? .... хороший;)
OJ.

5
Это мило. А еще лучше использовать логическое значение (перечисление в c?) ... if ( crash = TRUE) {/ OH SHI ... * /}
Ape-inago

3
Кстати, этот метод работает не во всех UNIX. HPUX, например, позволяет безнаказанно читать и записывать NULL (к счастью, это можно настроить).
paxdiablo

1
Я только что выучил 3 или 4 отличных новых вещи. Спасибо.
Trevor Boyd Smith

@pax - это еще одна причина найти общий способ;) Спасибо
hhafez

Ответы:


78

Повышение сигнала номер 6 ( SIGABRTв Linux) - один из способов сделать это (хотя имейте в виду, что SIGABRT не обязательно должен быть 6 во всех реализациях POSIX, поэтому вы можете использовать само SIGABRTзначение, если это что-то другое, кроме quick'n 'грязный код отладки).

#include <signal.h>
: : :
raise (SIGABRT);

Вызов abort()также вызовет дамп ядра, и вы даже можете сделать это, не завершая свой процесс, путем вызова, fork()за которым следует только abort()дочерний элемент - см. Этот ответ для подробностей.


7
SIGABRT не обязательно должен быть сигналом номер 6 (хотя часто так и есть, особенно в Linux).
Джонатан Леффлер,

4
Нет, вы правы, это не так, но я стараюсь не слишком беспокоиться о правильности кода отладки. Если это ускользнет от нас, чистота моего кода будет наименьшей из моих забот :-)
paxdiablo

2
Вызов abort () может быть бесполезным на некоторых архитектурах с некоторыми компиляторами и некоторыми библиотеками C (например, gcc и glibc или uClibc на ARM), потому что функция abort () объявлена ​​с атрибутом noreturn, а компилятор полностью оптимизирует всю возвращаемую информацию, что делает основной файл непригодным для использования. Вы не можете отследить его после самого вызова raise () или abort (). Так что гораздо лучше вызвать повышение (SIGABRT) напрямую или kill (getpid (), SIGABRT), что практически одно и то же.
Александр Амелькин

3
Извините, на ARM то же самое происходит даже с повышением (SIGABRT). Таким образом, единственный способ создать отслеживаемый файл ядра - это kill (getpid (), SIGABRT)
Александр Амелькин

Намек на ulimit -c unlimitedответ Сувеша Пратапы очень помог мне в этом ответе.
Борис Дэппен

75

Несколько лет назад Google выпустила библиотеку coredumper .

Обзор

Библиотеку coredumper можно скомпилировать в приложения для создания дампов ядра запущенной программы - без завершения работы. Он поддерживает как однопоточные, так и многопоточные дампы ядра, даже если ядро ​​изначально не поддерживает многопоточные файлы ядра.

Coredumper распространяется на условиях лицензии BSD.

пример

Это далеко не полный пример; он просто дает вам представление о том, как выглядит API coredumper.

#include <google/coredumper.h>
...
WriteCoreDump('core.myprogram');
/* Keep going, we generated a core file,
 * but we didn't crash.
 */

Это не то, о чем вы просили, но, может быть, даже лучше :)


3
Сначала я был очень взволнован, когда наткнулся на этот ответ. Но core dumper в наши дни выглядит довольно старым и дряхлым. Есть даже указание на то, что он больше не работает на современных ядрах Linux: stackoverflow.com/questions/38314020/…
jefe2000 07

37

Как указано на странице руководства по сигналам , любой сигнал с действием, указанным как 'core', вызовет дамп ядра. Вот несколько примеров:

SIGQUIT       3       Core    Quit from keyboard
SIGILL        4       Core    Illegal Instruction
SIGABRT       6       Core    Abort signal from abort(3)
SIGFPE        8       Core    Floating point exception
SIGSEGV      11       Core    Invalid memory reference

Убедитесь, что вы включили дампы ядра:

ulimit -c unlimited

Спасибо, ваше замечание о включении дампов ядра ulimit -c unlimitedпомогло.

Как бы вы установили ulimit из кода? @ ks1322
Karan Joisher

@KaranJoisher Это, вероятно, стоит отдельного вопроса, но вкратце вы можете использовать setrlimit(RLIMIT_CORE, &core_limits);доступную через #include <sys/resource.h>. Вы создаете структуру типа, rlimitа затем устанавливаете члены rlim_curи rlim_max.
Брент пишет код



6

Другой способ создания дампа ядра:

$ bash
$ kill -s SIGSEGV $$

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

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$

Очень просто и полезно!
firo

1
Мне это тоже нравится. Его даже можно упростить до bash -c 'kill -SIGSEGV $$'.
Кристиан Краузе


2

Иногда бывает уместно сделать что-то вроде этого:

int st = 0;
pid_t p = fork();

if (!p) {
    signal(SIGABRT, SIG_DFL);
    abort(); // having the coredump of the exact copy of the calling thread
} else {
    waitpid(p, &st, 0); // rip the zombie
}

// here the original process continues to live

Одна проблема с этим простым подходом состоит в том, что только один поток будет объединен.


1
 #include <stdio.h>
 #include <stdlib.h>
 int main()
 {
   printf("\n");
   printf("Process is aborting\n");
   abort();
   printf("Control not reaching here\n");
   return 0;
 }

используйте этот подход везде, где хотите :)


0
#include <assert.h>
.
.
.
     assert(!"this should not happen");

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