简体   繁体   English

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

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

I have a process in Linux that's getting a segmentation fault.我在 Linux 中有一个进程出现分段错误。 How can I tell it to generate a core dump when it fails?我如何告诉它在失败时生成核心转储?

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.如果您使用 bash,则 ulimit 命令控制与程序执行相关的几个设置,例如您是否应该转储核心。 If you type如果你输入

ulimit -c unlimited

then that will tell bash that its programs can dump cores of any size.那么这将告诉 bash 它的程序可以转储任何大小的内核。 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.如果需要,您可以指定诸如 52M 之类的大小而不是无限制,但实际上这不是必需的,因为核心文件的大小可能永远不会成为您的问题。

In tcsh, you'd type在 tcsh 中,你输入

limit coredumpsize unlimited

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,因为这通常会调用信号处理程序,从而更难诊断卡住的进程

To check where the core dumps are generated, run:要检查生成核心转储的位置,请运行:

sysctl kernel.core_pattern

or:要么:

cat /proc/sys/kernel/core_pattern

where %e is the process name and %t the system time.其中%e是进程名称, %t是系统时间。 You can change it in /etc/sysctl.conf and reloading by sysctl -p .您可以在/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 Apport and can be located in /var/crash/ .在 Ubuntu 中,核心转储由Apport处理,可以位于/var/crash/ However, it is disabled by default in stable releases.但是,它在稳定版本中默认是禁用的。

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 中生成核心转储?

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-file command.我最后所做的是在进程崩溃之前将 gdb 附加到进程,然后当它出现段错误时,我执行了generate-core-file命令。 That forced generation of a core dump.强制生成核心转储。

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.也许您可以这样做,该程序演示了如何捕获分段错误并将 shell 输出到调试器(这是在AIX下使用的原始代码)并打印堆栈跟踪,直到出现分段错误。 You will need to change the sprintf variable to use gdb in the case of Linux.在 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 */
}

You may have to additionally add a parameter to get gdb to dump the core as shown here in this blog here .您可能需要一个额外的参数添加到GET GDB转储核心如下所示,在这个博客在这里

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 .默认情况下,这是进程的当前目录,但可以通过设置/proc/sys/kernel/core_pattern
  • in some conditions, the kernel value in /proc/sys/fs/suid_dumpable may prevent the core to be generated.在某些情况下, /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

In order to activate the core dump do the following:为了激活核心转储,请执行以下操作:

  1. In /etc/profile comment the line:/etc/profile注释该行:

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

     * soft core 0
  3. execute the cmd limit coredumpsize unlimited and check it with cmd limit :执行 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. 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):要检查核心文件是否被写入,您可以使用 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.) 中的核心转储设置!

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 ~/.bashrc and add ulimit -c unlimited to end of file and save, re-run terminal. gedit ~/.bashrc并将ulimit -c unlimited添加到文件末尾并保存,重新运行终端。

  4. Build your application with debug information :使用调试信息构建您的应用程序:

    In Makefile -O0 -g在 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 文件附近创建名为“core”的核心转储文件):

     ./application_name
  6. Run under gdb:在 gdb 下运行:

     gdb application_name core

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.检查进程当前目录是否可写,否则不会创建核心文件。

It's worth mentioning that if you have a systemd set up, then things are a little bit different.值得一提的是,如果你有一个systemd设置,那么事情会有点不同。 The set up typically would have the core files be piped, by means of core_pattern sysctl value, through systemd-coredump(8) .该设置通常会通过systemd-coredump(8)通过core_pattern sysctl 值通过管道传输核心文件。 The core file size rlimit would typically be configured as "unlimited" already.核心文件大小 rlimit 通常已配置为“无限制”。

It is then possible to retrieve the core dumps using coredumpctl(1) .然后可以使用coredumpctl(1)检索核心转储。

The storage of core dumps, etc. is configured by coredump.conf(5) .核心转储等的存储由coredump.conf(5)配置。 There are examples of how to get the core files in the coredumpctl man page, but in short, it would look like this:在 coredumpctl 手册页中有如何获取核心文件的示例,但简而言之,它看起来像这样:

Find the core file:找到核心文件:

[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

Get the core file:获取核心文件:

[vps@phoenix]~$ coredumpctl -o test_me.core dump 16163

Ubuntu 19.04 Ubuntu 19.04

All other answers themselves didn't help me.所有其他答案本身都没有帮助我。 But the following sum up did the job但以下总结完成了工作

Create ~/.config/apport/settings with the following content:使用以下内容创建~/.config/apport/settings

[main]
unpackaged=true

(This tells apport to also write core dumps for custom apps) (这告诉 apport 也为自定义应用程序编写核心转储)

check: ulimit -c .检查: ulimit -c If it outputs 0, fix it with如果它输出 0,请修复它

ulimit -c unlimited

Just for in case restart apport:以防万一重启应用程序:

sudo systemctl restart apport

Crash files are now written in /var/crash/ .崩溃文件现在写在/var/crash/ But you cannot use them with gdb.但是您不能将它们与 gdb 一起使用。 To use them with gdb, use要将它们与 gdb 一起使用,请使用

apport-unpack <location_of_report> <target_directory>

Further information:更多信息:

  • Some answers suggest changing core_pattern .一些答案建议更改core_pattern Be aware, that that file might get overwritten by the apport service on restarting.请注意,该文件可能会在重新启动时被 apport 服务覆盖。
  • Simply stopping apport did not do the job简单地停止应用程序并没有完成工作
  • The ulimit -c value might get changed automatically while you're trying other answers of the web.当您尝试网络的其他答案时, ulimit -c值可能会自动更改。 Be sure to check it regularly during setting up your core dump creation.请务必在设置核心转储创建期间定期检查它。

References:参考:

Better to turn on core dump programmatically using system call setrlimit .最好使用系统调用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));
}

Make sure that you have the permissions to create files and the directory exists in the directory you're sending a core dump to!确保您具有创建文件的权限,并且该目录存在于您要发送核心转储的目录中!

The full steps:完整步骤:

ulimit -c unlimited

Note this will not persist between ssh sections !请注意,这不会在 ssh 部分之间持续存在 To add persistence:添加持久性:

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

Choose where to put the files.选择放置文件的位置。 Here's an example:这是一个例子:

sysctl -w kernel.core_pattern=/coredumps/core-%e-%s-%u-%g-%p-%t
mkdir /coredumps

Make sure that the process that's crashing has access to write to this.确保崩溃的进程有权对此进行写入。 The easiest way would be an example like this:最简单的方法是这样的示例:

chmod 777 /coredumps

Test that it works:测试它是否有效:

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

If it doesn't say "core dumped" above, something isn't working.如果上面没有说“核心转储”,则说明某些东西不起作用。

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

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