如何以编程方式在C / C ++中引起核心转储


93

我想在我的C ++应用程序中的特定位置强制进行核心转储。

我知道我可以通过执行以下操作来做到这一点:

int * crash = NULL;
*crash = 1;

但是我想知道是否有更清洁的方法?

我正在使用Linux。


18
一种“更清洁”的核心转储方式?....好一个;)
OJ。

5
这好可爱。最好使用布尔值(c中的枚举?)... if(crash = TRUE){/ OH SHI ... * /}
Ape-in​​ago 2009年

3
顺便说一句,该方法不适用于所有UNIX。HPUX就是其中之一,它使您可以不受限制地读取和写入NULL(很幸运,这是可配置的)。
paxdiablo

1
我刚刚学到了3到4个很棒的新事物。谢谢。
Trevor Boyd Smith,

@pax多数民众赞成在找到通用方式的更多原因;)谢谢
hhafez

Answers:


76

提高信号号6(SIGABRT在Linux中)是一种方法(尽管请记住,并非所有POSIX实现中SIGABRT都必须为6,因此,SIGABRT如果不是quick'n,则可能需要使用值本身'脏调试代码)。

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

调用abort()也会导致核心转储,你甚至可以做到这一点,而不通过调用终止你的过程fork(),然后abort()在孩子-见这个答案的详细信息。


7
SIGABRT不必是信号号6(尽管通常是-,尤其是在Linux上)。
乔纳森·勒夫勒

4
不,您是对的,不是,但是我倾向于不必过多担心调试代码的正确性。如果那
真是荒唐可笑

2
在某些使用某些编译器和某些C库的体系结构上调用abort()可能是无用的(例如ARM上的gcc和glibc或uClibc),因为abort()函数是用noreturn属性声明的,并且编译器完全优化了所有返回信息,这使得核心文件无法使用。您无法在调用raise()或abort()本身之后跟踪它。因此,最好直接调用raise(SIGABRT)或kill(getpid(),SIGABRT),实际上是一样的。
亚历山大·阿梅尔金

3
抱歉,在ARM上,即使使用抬高(SIGABRT),也会发生相同的情况。因此,生成可跟踪核心文件的唯一方法是kill(getpid(),SIGABRT)
Alexander Amelkin 2014年

ulimit -c unlimited来自Suvesh Pratapa答案的提示对这个答案很有帮助。
鲍里斯·达彭(BorisDäppen),

74

几年前,谷歌发布了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帮助下启用核心转储的评论。

您如何在代码中设置ulimit?@ ks1322
卡兰·

@KaranJoisher这可能是值得的本身就是一个问题,但在短期可以使用setrlimit(RLIMIT_CORE, &core_limits);通过可用#include <sys/resource.h>。您创建类型的结构,rlimit然后设置rlim_currlim_max成员。
布伦特编写代码



6

生成核心转储的另一种方法:

$ bash
$ kill -s SIGSEGV $$

只需创建bash的新实例并使用指定的信号杀死它即可。的$$是外壳的PID。否则,您将杀死当前的bash,并且将被注销,终端关闭或断开连接。

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

非常简单实用!
firo 2014年

1
我也喜欢那个 甚至可以简化为bash -c 'kill -SIGSEGV $$'
Christian Krause 2014年

4

您可以使用kill(2)发送信号。

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

所以,

kill(getpid(), 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混为一谈,以便即使没有其他断言时,此特定断言也是活动的。
Rhys Ulerich 2011年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.