Як програмно викликати дамп ядра в C / C ++


93

Я хотів би примусити дамп ядра в певному місці в моєму додатку C ++.

Я знаю, що можу це зробити, виконавши щось на зразок:

int * crash = NULL;
*crash = 1;

Але я хотів би знати, чи існує чистіший спосіб?

Я, до речі, використовую Linux.


18
"Чистіший" спосіб звалища ядра? .... хороший;)
ОВ.

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

3
До речі, цей метод працює не у всіх UNIX. HPUX, наприклад, дозволяє безкарно читати та писати NULL (на щастя, це можна налаштувати).
paxdiablo

1
Я щойно дізнався, як 3 чи 4 чудові нові речі. Дякую.
Тревор Бойд Сміт,

@pax - це більше причин знайти загальний спосіб;) Спасибі
hhafez

Відповіді:


76

Підвищення сигналу № 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, а компілятор повністю оптимізує всю інформацію про повернення, що робить основний файл непридатним для використання. Ви не можете простежити його за покликом підняти () або перервати (). Тому набагато краще викликати рейз (SIGABRT) безпосередньо або вбивати (getpid (), SIGABRT), що практично те саме.
Олександр Амелкін

3
На жаль, на ARM те ж саме відбувається навіть з рейзом (SIGABRT). Тож єдиний спосіб створити відстежуваний основний файл - це kill (getpid (), SIGABRT)
Олександр Амелкін

Натяк на ulimit -c unlimitedвідповідь Сувеша Пратапи мені дуже допоміг для цієї відповіді.
Борис Даппен,

74

Кілька років тому Google випустив бібліотеку coredumper .

Огляд

Бібліотеку coredumper можна компілювати в програми для створення основних дампів запущеної програми - без завершення. Він підтримує однопотокові та багатопотокові дампи ядра, навіть якщо ядро ​​не підтримує багатопотокові файли ядра.

Coredumper поширюється на умовах ліцензії BSD.

Приклад

Це далеко не повний приклад; це просто дає вам відчути, як виглядає coredumper API.

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

Це не те, про що ви просили, але, можливо, це навіть краще :)


3
Я спочатку був дуже схвильований, коли натрапив на цю відповідь. Але основний самоскид сьогодні виглядає досить старим і ледачим. Там навіть ознака того, що він більше не працює на сучасних Linux ядра: stackoverflow.com/questions/38314020 / ...
jefe2000

37

Як зазначено в керівництві сигналу , будь-який сигнал із дією, перерахованою як «ядро», змусить дамп ядра. Деякі приклади:

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допомогло.

Як би ви встановили обмеження в коді? @ ks1322
Karan Joisher

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


11

Закликати

abort();

Пов’язане, іноді ви хочете отримати зворотну трасування без фактичного дампа ядра і дозволити програмі продовжувати працювати: перевірте функції glibc backtrace () та backtrace_symbols (): http://www.gnu.org/s/libc/ manual / html_node / Backtraces.html


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

Одна з проблем цього простого підходу полягає в тому, що тільки одна нитка буде coredumped.


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, тому це конкретне твердження є активним, навіть коли інші твердження ні.
Rhys Ulerich
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.