参考:How to get a core dump for a segfault on Linux
◈ Ubuntu 使用一种叫做 apport 的系统来报告 apt 包有关的崩溃信息。
◈ 设定 kernel.core_pattern=|/usr/share/apport/apport %p %s %c %d %P 意味着核心转储将被通过管道送给 apport 程序。
◈ apport 的日志保存在文件 /var/log/apport.log 中。
◈ apport 默认会忽略来自不属于 Ubuntu 软件包一部分的二进制文件的崩溃信息
如果需要拿到自己的文件,需要跳过了 apport,并把 kernel.core_pattern 重新设置为:
sysctl -w kernel.core_pattern=/tmp/core-%e.%p.%h.%t
因为我在一台开发机上,我不在乎 apport 是否工作,我也不想尝试让 apport 把我的核心转储留在磁盘上。
现在你有了核心转储,接下来干什么?
好的,现在我们了解了 ulimit 和 kernel.core_pattern ,并且实际上在磁盘的 /tmp 目录中有了一个核心转储文件。太好了!接下来干什么?我们仍然不知道该程序为什么会出现段错误!
下一步将使用 gdb 打开核心转储文件并获取堆栈调用序列。
从 gdb 中得到堆栈调用序列
你可以像这样用 gdb 打开一个核心转储文件:
1. $ gdb -c my_core_file
接下来,我们想知道程序崩溃时的堆栈是什么样的。在 gdb 提示符下运行 bt 会给你一个调用序列(backtrace)。在我的例子里,gdb 没有为二进制文件加载符号信息,所以这些函数名就像 “??????”。幸运的是,(我们通过)加载符号修复了它。
下面是如何加载调试符号。
symbol-file /path/to/my/binary
sharedlibrary
这从二进制文件及其引用的任何共享库中加载符号。一旦我这样做了,当我执行 bt 时,gdb 给了我一个带有行号的漂亮的堆栈跟踪!
如果你想它能工作,二进制文件应该以带有调试符号信息的方式被编译。在试图找出程序崩溃的原因时,堆栈跟踪中的行号非常有帮助。:)
查看每个线程的堆栈
通过以下方式在 gdb 中获取每个线程的调用栈!
thread apply all bt full
gdb + 核心转储 = 惊喜
如果你有一个带调试符号的核心转储以及 gdb,那太棒了!您可以上下查看调用堆栈(LCTT 译注:指跳进调用序列不同的函数中以便于查看局部变量),打印变量,并查看内存来得知发生了什么。这是最好的。
如果您仍然正在基于 gdb 向导来工作上,只打印出栈跟踪与bt也可以。