Как программно вызвать дамп ядра в 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()дочерний элемент - см. Этот ответ для подробностей.

Paxdiablo
источник
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.
Брент пишет код
31
#include <stdlib.h>   // C
//#include <cstdlib>  // C++

void core_dump(void)
{
    abort();
}
Джонатан Леффлер
источник
3
Почему бы просто не позвонить abort()напрямую?
DepressedDaniel
6

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

$ bash
$ kill -s SIGSEGV $$

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

$ bash 
$ kill -s SIGABRT $$
$ bash
$ kill -s SIGFPE $$
Зонк
источник
Очень просто и полезно!
firo
1
Мне это тоже нравится. Его даже можно упростить до bash -c 'kill -SIGSEGV $$'.
Кристиан Краузе
4

Вы можете использовать kill (2) для отправки сигнала.

#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);

Так,

kill(getpid(), SIGSEGV);
Юджин Йокота
источник
Ага. Добавил это к ответу.
Eugene Yokota
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

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

rka444
источник
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;
 }

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

karthik339
источник
0
#include <assert.h>
.
.
.
     assert(!"this should not happen");
sigjuice
источник
Вероятно, нужно прогадать с NDEBUG, чтобы это конкретное утверждение было активным, даже когда другие утверждения нет.
Рис Улерих