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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/17965/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 16:21:54  来源:igfitidea点击:

How to generate a core dump in Linux on a segmentation fault?

linuxbashunixcoredumptcsh

提问by Nathan Fellman

I have a process in Linux that's getting a segmentation fault. How can I tell it to generate a core dump when it fails?

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

采纳答案by Eli Courtwright

This depends on what shell you are using. If you are using bash, then the ulimit command controls several settings relating to program execution, such as whether you should dump core. If you type

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

ulimit -c unlimited

then that will tell bash that its programs can dump cores of any size. You can specify a size such as 52M instead of unlimited if you want, but in practice this shouldn't be necessary since the size of core files will probably never be an issue for you.

那么这将告诉 bash 它的程序可以转储任何大小的内核。如果需要,您可以指定诸如 52M 之类的大小而不是无限制,但实际上这不是必需的,因为核心文件的大小可能永远不会成为您的问题。

In tcsh, you'd type

在 tcsh 中,你输入

limit coredumpsize unlimited

回答by Mark Harrison

By default you will get a core file. Check to see that the current directory of the process is writable, or no core file will be created.

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

回答by Nathan Fellman

What I did at the end was attach gdb to the process before it crashed, and then when it got the segfault I executed the generate-core-filecommand. That forced generation of a core dump.

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

回答by t0mm13b

Maybe you could do it this way, this program is a demonstration of how to trap a segmentation fault and shells out to a debugger (this is the original code used under AIX) and prints the stack trace up to the point of a segmentation fault. You will need to change the sprintfvariable to use gdbin the case of Linux.

也许您可以这样做,该程序演示了如何捕获分段错误并将其输出到调试器(这是在 下使用的原始代码AIX)并打印堆栈跟踪直至分段错误。您将需要更改sprintfgdb在 Linux 中使用的变量。

#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 */
}

You may have to additionally add a parameter to get gdb to dump the core as shown here in this blog here.

您可能需要一个额外的参数添加到GET GDB转储核心如下所示,在这个博客在这里

回答by mlutescu

There are more things that may influence the generation of a core dump. I encountered these:

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

  • the directory for the dump must be writable. By default this is the current directory of the process, but that may be changed by setting /proc/sys/kernel/core_pattern.
  • in some conditions, the kernel value in /proc/sys/fs/suid_dumpablemay prevent the core to be generated.
  • 转储的目录必须是可写的。默认情况下,这是进程的当前目录,但可以通过设置/proc/sys/kernel/core_pattern.
  • 在某些情况下,内核值 in/proc/sys/fs/suid_dumpable可能会阻止生成内核。

There are more situations which may prevent the generation that are described in the man page - try man core.

还有更多情况可能会阻止手册页中描述的生成 - 尝试man core

回答by Edgar Jordi

In order to activate the core dump do the following:

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

  1. In /etc/profilecomment the line:

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

    *               soft    core            0
    
  3. execute the cmd limit coredumpsize unlimitedand 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>
    
  1. /etc/profile评论行中:

    # ulimit -S -c 0 > /dev/null 2>&1
    
  2. /etc/security/limits.conf注释掉这一行:

    *               soft    core            0
    
  3. 执行 cmdlimit 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>
    

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

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

回答by George Co

As explained above the real question being asked here is how to enable core dumps on a system where they are not enabled. That question is answered here.

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

If you've come here hoping to learn how to generate a core dump for a hung process, the answer is

如果您来这里是希望学习如何为挂起的进程生成核心转储,那么答案是

gcore <pid>

if gcore is not available on your system then

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

kill -ABRT <pid>

Don't use kill -SEGV as that will often invoke a signal handler making it harder to diagnose the stuck process

不要使用 kill -SEGV,因为这通常会调用信号处理程序,从而更难诊断卡住的进程

回答by kenorb

To check where the core dumps are generated, run:

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

sysctl kernel.core_pattern

or:

或者:

cat /proc/sys/kernel/core_pattern

where %eis the process name and %tthe system time. You can change it in /etc/sysctl.confand reloading by sysctl -p.

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

If the core files are not generated (test it by: sleep 10 &and killall -SIGSEGV sleep), check the limits by: ulimit -a.

如果未生成核心文件(通过:sleep 10 &和 进行测试killall -SIGSEGV sleep),请通过以下方式检查限制:ulimit -a

If your core file size is limited, run:

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

ulimit -c unlimited

to make it unlimited.

使其无限。

Then test again, if the core dumping is successful, you will see “(core dumped)” after the segmentation fault indication as below:

然后再次测试,如果core dumping成功,你会在segmentation fault指示后看到“(core dumped)”,如下图:

Segmentation fault: 11 (core dumped)

分段错误:11(核心已转储)

See also: core dumped - but core file is not in current directory?

另请参阅:核心转储 - 但核心文件不在当前目录中?



Ubuntu

Ubuntu

In Ubuntu the core dumps are handled by Apportand can be located in /var/crash/. However, it is disabled by default in stable releases.

在 Ubuntu 中,核心转储由Apport处理并且可以位于/var/crash/. 但是,它在稳定版本中默认是禁用的。

For more details, please check: Where do I find the core dump in Ubuntu?.

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

macOS

苹果系统

For macOS, see: How to generate core dumps in Mac OS X?

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

回答by mrgloom

For Ubuntu 14.04

对于 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 ~/.bashrcand add ulimit -c unlimitedto 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
    
  1. 检查启用的核心转储:

    ulimit -a
    
  2. 其中一行应该是:

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

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

  4. 使用调试信息构建您的应用程序:

    在生成文件中 -O0 -g

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

    ./application_name
    
  6. 在 gdb 下运行:

    gdb application_name core
    

回答by kgbook

Better to turn on core dump programmatically using system call setrlimit.

最好使用 system call 以编程方式打开核心转储setrlimit

example:

例子:

#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));
}