当进程出现分段错误时,如何在Linux中生成核心转储?

时间:2020-03-05 18:41:06  来源:igfitidea点击:

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

解决方案

回答

这取决于我们使用的外壳。如果使用的是bash,则ulimit命令控制与程序执行有关的一些设置,例如是否应该转储core。如果我们输入

ulimit -c unlimited

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

在tcsh中,我们可以输入

limit coredumpsize unlimited

回答

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

回答

最后我要做的就是在崩溃之前将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来转储核心,如本博客此处所示。