如何生成一个核心转储在Linux上的分段错误?

我有一个进程在Linux得到一个分割错误。当它失败时,我如何告诉它生成一个核心转储?

437521 次浏览

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

ulimit -c unlimited

然后这将告诉bash,它的程序可以转储任何大小的内核。如果你愿意,你可以指定一个大小,比如52M,而不是无限,但在实践中,这不应该是必要的,因为核心文件的大小可能永远不会成为你的问题。

在tcsh中,您需要输入

limit coredumpsize unlimited

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

我在最后所做的是在进程崩溃之前将gdb附加到进程,然后当它得到段错误时,我执行generate-core-file命令。强制生成核心转储。

也许你可以这样做,这个程序演示了如何捕获分段错误,并将shell发送给调试器(这是AIX下使用的原始代码),并打印到分段错误点的堆栈跟踪。在Linux中,你需要改变sprintf变量来使用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

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

  1. /etc/profile注释行中:

    # ulimit -S -c 0 > /dev/null 2>&1
    
  2. In /etc/security/limits.conf comment out the line:

    *               soft    core            0
    
  3. execute the cmd limit coredumpsize unlimited and check it with 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. to check if the corefile gets written you can kill the relating process with cmd kill -s SEGV <PID> (should not be needed, just in case no core file gets written this can be used as a check):

    # kill -s SEGV <PID>
    

Once the corefile has been written make sure to deactivate the coredump settings again in the relating files (1./2./3.) !

如上所述,这里提出的真正问题是如何在未启用核心转储的系统上启用它们。这个问题在这里得到了解答。

如果您希望了解如何为挂起进程生成核心转储,那么答案是

gcore <pid>

如果gcore在您的系统上不可用,那么

kill -ABRT <pid>

不要使用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

让它无限。

然后再次测试,如果核心转储成功,你会看到“(核心转储)”分割故障指示如下:

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

参见:核心转储-但核心文件不在当前目录?


Ubuntu

在Ubuntu中,核心转储由< em >幻想< / em >处理,可以位于/var/crash/中。但是,在稳定版本中默认禁用它。

更多详细信息,请查看:我在哪里可以找到Ubuntu的核心转储?

macOS

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

Ubuntu 14.04

  1. Check core dump enabled:

    ulimit -a
    
  2. One of the lines should be :

    core file size          (blocks, -c) unlimited
    
  3. If not :

    gedit ~/.bashrc and add ulimit -c unlimited to end of file and save, re-run terminal.

  4. Build your application with debug information :

    In Makefile -O0 -g

  5. Run application that create core dump (core dump file with name ‘core’ should be created near application_name file):

    ./application_name
    
  6. Run under gdb:

    gdb application_name core
    

最好使用系统调用setrlimit以编程方式打开核心转储。

例子:

#include <sys/resource.h>


bool enable_core_dump(){
struct rlimit corelim;


corelim.rlim_cur = RLIM_INFINITY;
corelim.rlim_max = RLIM_INFINITY;


return (0 == setrlimit(RLIMIT_CORE, &corelim));
}

值得一提的是,如果你设置了systemd,那么事情就会有点不同。这种设置通常会通过core_pattern sysctl值将核心文件通过管道传输到systemd-coredump(8)。核心文件大小rlimit通常已经配置为“unlimited”。

然后可以使用coredumpctl(1)检索核心转储。

核心转储的存储等是由coredump.conf(5)配置的。在coredumpctl手册页中有一些如何获取核心文件的示例,但简而言之,它看起来像这样:

找到核心文件:

[vps@phoenix]~$ coredumpctl list test_me | tail -1
Sun 2019-01-20 11:17:33 CET   16163  1224  1224  11 present /home/vps/test_me

获取核心文件:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163

Ubuntu 19.04

其他的答案都帮不了我。但下面的总结起到了作用

用以下内容创建~/.config/apport/settings:

[main]
unpackaged=true

(这告诉apport也为自定义应用程序编写核心转储)

检查:ulimit -c。如果输出0,用

ulimit -c unlimited

只是为了以防万一重启apport:

sudo systemctl restart apport

崩溃文件现在用/var/crash/编写。但是你不能在gdb中使用它们。要在gdb中使用它们,请使用

apport-unpack <location_of_report> <target_directory>

进一步的信息:

  • 一些答案建议更改core_pattern。请注意,重新启动时该文件可能会被apport服务覆盖。
  • 仅仅停止出口并不能起到作用
  • ulimit -c值可能会在您尝试web的其他答案时自动更改。确保在设置核心转储创建过程中定期检查它。

引用:

  • https://stackoverflow.com/a/47481884/6702598 < a href = " https://stackoverflow.com/a/47481884/6702598 " > < / >

这通常是足够的:

ulimit -c unlimited

注意这将SSH段之间不持久!要添加持久性:

echo '* soft core unlimited' >> /etc/security/limits.conf

现在,如果你用的是Ubuntu,“apport"可能是在跑步。下面是检查方法:

sudo systemctl status apport.service

如果是,你可能会在以下位置之一找到核心转储:

/var/lib/apport/coredump
/var/crash

如果您想更改核心转储的位置

确保你有权限来创建文件,在你发送核心转储的目录中有目录不存在 !

举个例子。注意这将在重新启动时不持久:

sysctl -w kernel.core_pattern=/coredumps/core-%e-%s-%u-%g-%p-%t
mkdir /coredumps

确保正在崩溃的进程有权写入该文件。最简单的方法是这样的例子:

chmod 777 /coredumps

测试内核转储是否工作

> crash.c
gcc -Wl,--defsym=main=0 crash.c
./a.out
==output== Segmentation fault (core dumped)

如果它没有说“核心转储”;上面,有些东西不工作。