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


当前回答

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

其他回答

也许您可以这样做,这个程序演示了如何捕获分段错误并将其外壳传递给调试器(这是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转储内核,如本文所示。

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

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

ulimit -c unlimited

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

在tcsh中,您需要输入

limit coredumpsize unlimited

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

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

gcore <pid>

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

kill -ABRT <pid>

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

Ubuntu 19.04

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

创建~ /。配置/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