生成coredump
核心转储基本上是程序崩溃时内存的快照。
它基本上是使用中的进程地址空间(来自包含所有虚拟内存区域的mm_struct结构),以及崩溃时的任何其他支持信息。
当操作系统由于程序中的故障而终止进程时,进程会转储核心。发生这种情况的最典型原因是程序访问了无效的指针值。例如,当我们试图取消引用NULL指针时,在退出之前,我们会收到一个SEGV信号。作为这个过程的一部分,操作系统试图将我们的信息写入一个文件,以便稍后进行事后分析。
我们可以使用核心转储来诊断和调试我们的计算机程序,方法是将核心文件与可执行文件一起加载到调试器中(用于符号和其他调试信息)。由于核心转储可以占用大量的磁盘空间,因此它们的大小有一个可配置的限制
让我们来看一下:
[root@localhost ~]# ulimit -c
0
修改成无限制:
[root@localhost ~]# ulimit -a -H
core file size (blocks, -c) unlimited
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited
pending signals (-i) 7183
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 4096
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) unlimited
cpu time (seconds, -t) unlimited
max user processes (-u) 7183
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
[root@localhost ~]# ulimit -c
unlimited
以下是示例代码:
/* t.c */
#include <stdio.h>
void foo()
{
int *ptr = 0;
*ptr = 7;
}
int main()
{
foo();
return 0;
}
如果我们运行代码,我们会得到以下运行时错误:
Segmentation fault (core dumped)
但它不在当前目录中。它在哪里?
让我们转到/proc/sys/kernel目录。
$ ls -la core*
-rw-r--r--. 1 root root 0 Aug 28 23:53 core_pattern
-rw-r--r--. 1 root root 0 Aug 28 16:12 core_pipe_limit
-rw-r--r--. 1 root root 0 Aug 28 23:53 core_uses_pid
core_pattern中有什么?
$ cat core_pattern
|/usr/libexec/abrt-hook-ccpp %s %c %p %u %g %t e
请注意,模式的第一个字符是“|”,内核将把模式的其余部分视为要运行的命令。核心转储将被写入该程序的标准输入,而不是文件。
因此,我的Fedora被配置为将其发送到自动错误报告工具(ABRT)。我们需要将core_pattern的行更改为“core”。
$ sudo bash -c 'echo core.%e.%p > /proc/sys/kernel/core_pattern'
$ cat /proc/sys/kernel/core_pattern
core.%e.%p
在设置中,%e表示可执行文件名,%p表示pid。
在设置了核心文件的大小(以512字节块为单位)后,我们再次运行代码:
$ ulimit -c unlimited
$ ./t
Segmentation fault (core dumped)
$ ls
core.t.3209 t t.c
核心转储文件格式
然而,核心文件过去只是一个二进制文件,因为在现代操作系统中,进程的地址空间可能不是顺序的,并且进程可能与其他进程共享页面,所以核心文件应该能够表示更多信息以及转储时程序的状态。在linux系统上,正在使用ELF(可执行和可链接格式)文件格式
分析核心文件:
我们可以将核心文件与gdb一起使用:
gdb executable core-file
在我们的案例中:
$ gdb ./t core.t.3529
GNU gdb (GDB) Fedora (7.5.0.20120926-25.fc18)
...
Reading symbols from /home/khong/TEST/DMP/t...done.
[New LWP 3529]
Core was generated by `./t'.
Program terminated with signal 11, Segmentation fault.
#0 0x00000000004004fc in foo () at t.c:6
6 *ptr = 7;
这表示第6行有问题。我们知道我们正在延迟这一行的NULL指针。
我们可以使用回溯来列出程序崩溃时进行的调用堆栈:
(gdb) backtrace
#0 0x00000000004004fc in foo () at t.c:6
#1 0x0000000000400512 in main () at t.c:11
要上下移动调用堆栈:
(gdb) up
#1 0x0000000000400512 in main () at t.c:11
11 foo();
(gdb) down
#0 0x00000000004004fc in foo () at t.c:6
6 *ptr = 7;