繁体   English   中英

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

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

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

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

ulimit -c unlimited

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

在 tcsh 中,你输入

limit coredumpsize unlimited

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

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

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

使其无限。

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

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

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


Ubuntu

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

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

苹果系统

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

我最后所做的是在进程崩溃之前将 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 */
}

您可能需要一个额外的参数添加到GET 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. /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.) 中的核心转储设置!

对于 Ubuntu 14.04

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

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

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

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

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

    在 Makefile -O0 -g

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

     ./application_name
  6. 在 gdb 下运行:

     gdb application_name core

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

值得一提的是,如果你有一个systemd设置,那么事情会有点不同。 该设置通常会通过systemd-coredump(8)通过core_pattern sysctl 值通过管道传输核心文件。 核心文件大小 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

获取核心文件:

[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

以防万一重启应用程序:

sudo systemctl restart apport

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

apport-unpack <location_of_report> <target_directory>

更多信息:

  • 一些答案建议更改core_pattern 请注意,该文件可能会在重新启动时被 apport 服务覆盖。
  • 简单地停止应用程序并没有完成工作
  • 当您尝试网络的其他答案时, ulimit -c值可能会自动更改。 请务必在设置核心转储创建期间定期检查它。

参考:

最好使用系统调用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));
}

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

完整步骤:

ulimit -c unlimited

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

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

选择放置文件的位置。 这是一个例子:

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)

如果上面没有说“核心转储”,则说明某些东西不起作用。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM