Linux中如何在进程出现分段错误时生成核心转储?

我在Linux中有一个进程出现分段错误的进程。 如何告诉它在失败时生成核心转储?

这取决于你正在使用的shell。 如果使用bash,则ulimit命令控制与程序执行相关的几个设置,例如是否应该转储核心。 如果你input

ulimit -c unlimited 

那么这将告诉bash其程序可以转储任何大小的核心。 你可以指定一个大小,如52M,而不是无限的,但实际上这不应该是必要的,因为核心文件的大小可能永远不会是你的问题。

在tcsh中,你会input

 limit coredumpsize unlimited 

如上所述,这里提出的真正问题是如何在未启用系统的情况下启用核心转储。 这个问题在这里回答。

如果你来这里希望学习如何生成一个挂起的过程核心转储,答案是

 gcore <pid> 

如果你的系统上没有gcore的话

 kill -ABRT <pid> 

不要使用kill -SEGV,因为它经常会调用一个信号处理程序,从而难以诊断卡住的进程

我最后做的是在进程崩溃之前将gdb附加到进程中,然后在得到segfault时执行了generate-core-file命令。 这迫使核心转储的产生。

也许你可以这样做,这个程序演示了如何将一个分段错误和shell捕获到一个debugging器(这是在AIX下使用的原始代码),并将堆栈跟踪打印到分段故障点。 您将需要更改sprintfvariables以在Linux中使用gdb

 #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转储核心,如此处所示。

还有更多的事情可能会影响核心转储的产生。 我遇到这些:

  • 转储的目录必须是可写的。 默认情况下,这是进程的当前目录,但可以通过设置/proc/sys/kernel/core_pattern
  • 在某些情况下, /proc/sys/fs/suid_dumpable的内核值可能会阻止生成内核。

有更多的情况可能会阻止在手册页中描述的世代 – 尝试man core

要检查核心转储的生成位置,请运行:

 sysctl kernel.core_pattern 

其中%e是进程名称, %t是系统时间。 您可以在/etc/sysctl.conf更改它,并通过sysctl -p重新加载。

如果核心文件没有生成(testing: sleep 10 &killall -SIGSEGV sleep ),检查限制: ulimit -a

如果核心文件大小有限,请运行:

 ulimit -c unlimited 

使其无限制。

然后再次testing,如果核心转储成功,则会在分段故障指示后看到“(核心转储)”,如下所示:

分割故障:11(核心转储)


Ubuntu的

在Ubuntu中,转储通常由/var/crash/apport处理,但采用不同的格式,但在稳定版本中默认情况下不启用。 阅读更多在Ubuntu维基 。

它使用core_pattern将核心转储直接传送到apport:

 $ cat /proc/sys/kernel/core_pattern |/usr/share/apport/apport %p %s %c 

所以即使核心文件被ulimit禁用, apport仍然会捕获崩溃( 如何启用或禁用Apport? )。


OS X

对于OS X,请参阅: 如何在Mac OS X中生成核心转储?

为了激活核心转储,请执行以下操作:

  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. 检查核心文件是否被写入,可以用cmd kill -s SEGV <PID>相关进程(不应该需要,以防万一没有写入核心文件,这可以用作检查):

     # kill -s SEGV <PID> 

核心文件写入后,请确保在相关文件(1./2./3。)中再次取消核心转储设置!

默认情况下你会得到一个核心文件。 检查进程的当前目录是否可写,否则不会创build核心文件。

对于Ubuntu 14.04

  1. 检查核心转储已启用:

     ulimit –a 
  2. 其中一条线应该是:

     core file size (blocks, -c) unlimited 
  3. 如果不 :

    gedit ~/.bashrc并添加ulimit -c unlimited到文件结尾并保存,重新运行terminal。

  4. 用debugging信息构build您的应用程序:

    在Makefile -O0 -g

  5. 运行创build核心转储的应用程序(在application_name文件附近应该创build名称为“core”的核心转储文件):

     ./application_name 
  6. 在gdb下运行:

     gdb application_name core