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

Nat*_*man 208 unix linux bash coredump tcsh

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

Eli*_*ght 237

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

ulimit -c unlimited
Run Code Online (Sandbox Code Playgroud)

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

在tcsh中,你要输入

limit coredumpsize unlimited
Run Code Online (Sandbox Code Playgroud)

  • @lzprgmr:澄清一下:默认情况下未生成核心转储的原因是未设置限制和/或设置为0,这会阻止核心被转储.通过设置无限制的限制,我们保证始终可以生成核心转储. (20认同)
  • 这个[链接](http://www.randombugs.com/linux/core-dumps-linux.html)更深入,并提供了更多选项,以便在Linux中生成核心转储.唯一的缺点是某些命令/设置无法解释. (6认同)
  • 在bash 4.1.2(1)中,不能指定诸如52M之类的释放限制,从而导致无效的数字错误消息.手册页告诉"值以1024字节为增量". (6认同)
  • 好吧,我有一个"小"OpenGL项目,曾经做过一些奇怪的事情,并导致X服务器崩溃.当我退回时,我看到一个可爱的小17 GB核心文件(在25 GB的分区上).保持核心文件的大小限制绝对是一个好主意:) (3认同)

Geo*_* Co 57

如上所述,这里要问的真正问题是如何在未启用核心转储的系统上启用核心转储.这个问题在这里得到解答.

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

gcore <pid>
Run Code Online (Sandbox Code Playgroud)

如果你的系统上没有gcore那么

kill -ABRT <pid>
Run Code Online (Sandbox Code Playgroud)

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

  • 我认为“-ABRT”比“-SEGV”更有可能调用信号处理程序,因为中止比段错误更有可能恢复。(如果您处理段错误,通常它会在处理程序退出时再次触发。)用于生成核心转储的信号的更好选择是“-QUIT”。 (2认同)

ken*_*orb 28

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

sysctl kernel.core_pattern
Run Code Online (Sandbox Code Playgroud)

要么:

cat /proc/sys/kernel/core_pattern
Run Code Online (Sandbox Code Playgroud)

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

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

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

ulimit -c unlimited
Run Code Online (Sandbox Code Playgroud)

让它无限.

然后再次测试,如果核心转储成功,您将在分段故障指示后看到"(core dumped)",如下所示:

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

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


Ubuntu的

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

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

苹果系统

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

  • 对于Ubuntu,要快速恢复正常行为(在当前目录中转储核心文件),只需使用"sudo service apport stop"停止apport服务.另请注意,如果您在docker中运行,则该设置在主机系统上受到控制,而不在容器内. (3认同)

Nat*_*man 24

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

  • 要回答Ritwik G,要将进程附加到gdb,只需启动gdb并输入'attach <pid>',其中<pid>是要附加的进程的pid编号. (6认同)

t0m*_*13b 19

也许你可以这样做,这个程序演示了如何捕获分段错误并弹出到调试器(这是下面使用的原始代码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 */
}
Run Code Online (Sandbox Code Playgroud)

您可能需要另外添加一个参数,以获得GDB转储如下图所示,在这个博客的核心位置.


小智 16

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

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

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


小智 9

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

  1. /etc/profile评论行:

    # ulimit -S -c 0 > /dev/null 2>&1
    
    Run Code Online (Sandbox Code Playgroud)
  2. /etc/security/limits.conf评论中排队:

    *               soft    core            0
    
    Run Code Online (Sandbox Code Playgroud)
  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
    #
    
    Run Code Online (Sandbox Code Playgroud)
  4. 要检查核心文件是否已写入,您可以使用cmd终止相关进程kill -s SEGV <PID>(不应该需要,以防万一没有核心文件被写入,这可以用作检查):

    # kill -s SEGV <PID>
    
    Run Code Online (Sandbox Code Playgroud)

一旦编写了corefile,请确保在相关文件(1./2./3.)中再次停用coredump设置!


mrg*_*oom 8

对于Ubuntu 14.04

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

    ulimit -a
    
    Run Code Online (Sandbox Code Playgroud)
  2. 其中一行应该是:

    core file size          (blocks, -c) unlimited
    
    Run Code Online (Sandbox Code Playgroud)
  3. 如果不 :

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

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

    在Makefile中 -O0 -g

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

    ./application_name
    
    Run Code Online (Sandbox Code Playgroud)
  6. 在gdb下运行:

    gdb application_name core
    
    Run Code Online (Sandbox Code Playgroud)


kgb*_*ook 5

最好使用系统调用以编程方式打开核心转储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));
}
Run Code Online (Sandbox Code Playgroud)


Paw*_*lov 5

值得一提的是,如果您设置了systemd,那么情况会有所不同。设置通常会通过core_patternsysctl 值通过管道传输核心文件systemd-coredump(8)管道传输核心文件。核心文件大小 rlimit 通常已配置为“无限制”。

然后可以使用以下命令检索核心转储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
Run Code Online (Sandbox Code Playgroud)

获取核心文件:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163
Run Code Online (Sandbox Code Playgroud)


The*_*ser 5

乌班图19.04

所有其他答案本身对我没有帮助。但以下总结完成了这项工作

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

[main]
unpackaged=true
Run Code Online (Sandbox Code Playgroud)

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

查看:ulimit -c。如果输出 0,则修复它

ulimit -c unlimited
Run Code Online (Sandbox Code Playgroud)

只是为了以防万一重新启动应用程序:

sudo systemctl restart apport
Run Code Online (Sandbox Code Playgroud)

崩溃文件现在以/var/crash/. 但你不能将它们与 gdb 一起使用。要将它们与 gdb 一起使用,请使用

apport-unpack <location_of_report> <target_directory>
Run Code Online (Sandbox Code Playgroud)

更多信息:

  • 一些答案建议改变core_pattern。请注意,重新启动时该文件可能会被 apport 服务覆盖。
  • 仅仅停止 app 并不能解决问题
  • ulimit -c当您尝试网络上的其他答案时,该值可能会自动更改。请务必在设置核心转储创建过程中定期检查它。

参考:


the*_*ire 5

这通常就足够了:

ulimit -c unlimited
Run Code Online (Sandbox Code Playgroud)

请注意,这不会在 ssh 部分之间持续存在!添加持久性:

echo '* soft core unlimited' >> /etc/security/limits.conf
Run Code Online (Sandbox Code Playgroud)

现在,如果您使用的是 Ubuntu,“apport”可能正在运行。检查方法如下:

sudo systemctl status apport.service
Run Code Online (Sandbox Code Playgroud)

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

/var/lib/apport/coredump 
/var/crash
Run Code Online (Sandbox Code Playgroud)

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

确保您具有创建文件的权限,并且该目录存在于您要向其发送核心转储的目录中!

这是一个例子。请注意,这不会在重新启动后持续存在

sysctl -w kernel.core_pattern=/coredumps/core-%e-%s-%u-%g-%p-%t
mkdir /coredumps
Run Code Online (Sandbox Code Playgroud)

确保崩溃的进程有权对此进行写入。最简单的方法是这样的示例:

chmod 777 /coredumps
Run Code Online (Sandbox Code Playgroud)

测试核心转储是否有效

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

如果上面没有说“核心转储”,则说明某些功能无法正常工作。