我在Linux中有一个进程出现分段错误的进程.如何在失败时告诉它生成核心转储?
这取决于您使用的是什么shell.如果使用bash,则ulimit命令控制与程序执行相关的几个设置,例如是否应转储核心.如果你输入
ulimit -c unlimited
那么这将告诉bash它的程序可以转储任何大小的核心.如果需要,您可以指定52M而不是无限制的大小,但实际上这不是必需的,因为核心文件的大小可能永远不会成为您的问题.
在tcsh中,你要输入
limit coredumpsize unlimited
如上所述,这里要问的真正问题是如何在未启用核心转储的系统上启用核心转储.这个问题在这里得到解答.
如果您来到这里希望学习如何为挂起的进程生成核心转储,答案是
gcore
如果你的系统上没有gcore那么
kill -ABRT
不要使用kill -SEGV,因为它通常会调用信号处理程序,使得更难诊断卡住的进程
要检查核心转储的生成位置,请运行:
sysctl kernel.core_pattern
要么:
cat /proc/sys/kernel/core_pattern
%e
进程名称和%t
系统时间在哪里.你可以改变它/etc/sysctl.conf
并重新加载sysctl -p
.
如果未生成核心文件(通过:sleep 10 &
和测试killall -SIGSEGV sleep
),请通过以下方式检查限制:ulimit -a
.
如果您的核心文件大小有限,请运行:
ulimit -c unlimited
让它无限.
然后再次测试,如果核心转储成功,您将在分段故障指示后看到"(core dumped)",如下所示:
分段故障:11(核心转储)
另请参阅:core dumped - 但核心文件不在当前目录中?
在Ubuntu中,核心转储由Apport处理,可以位于/var/crash/
.但是,在稳定版本中默认禁用它.
有关更多详细信息,请检查:我在哪里可以找到Ubuntu中的核心转储?.
对于macOS,请参阅:如何在Mac OS X中生成核心转储?
我最后做的是在崩溃之前将gdb附加到进程,然后当它获得segfault时我执行了generate-core-file
命令.这迫使生成核心转储.
也许你可以这样做,这个程序演示了如何捕获分段错误并弹出到调试器(这是下面使用的原始代码AIX
),并将堆栈跟踪打印到分段故障点.您需要更改sprintf
要gdb
在Linux中使用的变量.
#include#include #include #include 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
.
要激活核心转储,请执行以下操作:
在 /etc/profile
评论行:
# ulimit -S -c 0 > /dev/null 2>&1
在/etc/security/limits.conf
评论中排队:
* soft core 0
执行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 #
要检查核心文件是否已写入,您可以使用cmd终止相关进程kill -s SEGV
(不应该需要,以防万一没有核心文件被写入,这可以用作检查):
# kill -s SEGV
一旦编写了corefile,请确保在相关文件(1./2./3.)中再次停用coredump设置!
对于Ubuntu 14.04
检查核心转储已启用:
ulimit -a
其中一行应该是:
core file size (blocks, -c) unlimited
如果不 :
gedit ~/.bashrc
并添加ulimit -c unlimited
到文件末尾并保存,重新运行终端.
使用调试信息构建应用程序:
在Makefile中 -O0 -g
运行创建核心转储的应用程序(应在application_name文件附近创建名为'core'的核心转储文件):
./application_name
在gdb下运行:
gdb application_name core