arm linux 开启 coredump file

1. 基本概念

之前一直在做 Android 相关的工作,在 Android 系统上无论是 java 进程还是 c++ 进程崩溃的时候都会有堆栈信息可以追溯是哪里挂了。java 进程挂的话,logcat 里面直接有错误堆栈信息。c++ 进程挂的话,/data/tomstone 目录里面会生成 coredump 信息。里面有错误堆栈,但错误堆栈只是一个地址调用而已,需要使用 addr2line 工具来将地址转换成文件行数。
现在纯 Linux 环境中开发 Camera 应用。当程序运行在过程中崩溃时,就只提示了一个进程 Abort 了。然后啥信息都没有。鬼才知道哪里出问题了。这个时候就得 coredump 出场了。Linux 系统默认是把 coredump 关闭的。打开 coredump 后,进程崩溃时,操作系统会将程序当时的内存状态记录下来,保存在一个文件中,这种行为就叫做 Core Dump(中文有的翻译成“核心转储”)。我们可以认为 core dump 是“内存快照”,但实际上,除了内存信息之外,还有些关键的程序运行状态也会同时 dump 下来,例如寄存器信息(包括程序指针、栈指针等)、内存管理信息、其他处理器和操作系统状态和信息。core dump 对于编程人员诊断和调试程序是非常有帮助的,因为对于有些程序错误是很难重现的,例如指针异常,而 core dump 文件可以再现程序出错时的情景。

2. 开启 core dump

我们先查询一下 coredump 是否打开了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/ # ulimit -a
-f: file size (blocks) unlimited
-t: cpu time (seconds) unlimited
-d: data seg size (kb) unlimited
-s: stack size (kb) 8192
-c: core file size (blocks) 0
-m: resident set size (kb) unlimited
-l: locked memory (kb) 64
-p: processes 1832
-n: file descriptors 1024
-v: address space (kb) unlimited
-w: locks unlimited
-e: scheduling priority 0
-r: real-time priority 0
/ #

ulimit -a 命令为查询当前的系统限制规则。 其中 core file size (blocks, -c) 0 表示 coredump 文件的大小为限制为 0,即关闭 coredump 功能。
通过以下命令来打开 coredump 功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/ # ulimit -c unlimited
/ # ulimit -a
-f: file size (blocks) unlimited
-t: cpu time (seconds) unlimited
-d: data seg size (kb) unlimited
-s: stack size (kb) 8192
-c: core file size (blocks) unlimited
-m: resident set size (kb) unlimited
-l: locked memory (kb) 64
-p: processes 1832
-n: file descriptors 1024
-v: address space (kb) unlimited
-w: locks unlimited
-e: scheduling priority 0
-r: real-time priority 0
/ #

我们可以看到 core file size 的限制变为 unlimited 为。也就是没有限制。这样就可以打开 coredump 功能了。
默认情况下 coredump 文件的存放路径为当前目录。我们可以通过以下命令来修改 coredump 的存放路径:

1
2
echo 0 > /proc/sys/kernel/core_uses_pid
echo "/data/core_%e_%p" > /proc/sys/kernel/core_pattern

以下命令把 coredump 文件存放到了 /data 目录

其中 %e, %p 的解析如下

1
2
3
4
5
6
7
%p - insert pid into filename 添加pid
%u - insert current uid into filename 添加当前uid
%g - insert current gid into filename 添加当前gid
%s - insert signal that caused the coredump into the filename 添加导致产生core的信号
%t - insert UNIX time that the coredump occurred into filename 添加core文件生成时的unix时间
%h - insert hostname where the coredump happened into filename 添加主机名
%e - insert coredumping executable name into filename 添加命令名

在测试过程中,我们需要一直打开 coredump 功能的,因此我们把以下命令加入到 /etc/profile 中。以便每次开机都生效

1
2
3
4
5
# enable coredump for debug
echo "enable coredump file"
ulimit -c unlimited
echo 0 > /proc/sys/kernel/core_uses_pid
echo "/data/core_%e_%p" > /proc/sys/kernel/core_pattern

3. gdb 调试 core dump

我们来写一个会崩溃的程序试试看会不会产生 coredump 文件。

1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

void get_value(int *value) {
*value = 31;
}

int main(int argc, char *argv[]) {
int *value = nullptr;
get_value(value);
printf("value = %d\n", *value);
return 0;
}

交叉编译这个程序,然后上传到板子上运行:

1
2
3
4
5
6
7
/data # ls
test
/data # ./test
Segmentation fault (core dumped)
/data # ls
core_test_252 test
/data #

我们看到产生了一个 coredump 文件 core_test_252。接下来我们需要使用 gdb 来查看 coredump 文件里面的错误堆栈。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/data # ls
core_test_252 test
/data # gdb test core_test_252
GNU gdb (GDB) 7.9.1
Copyright (C) 2015 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "arm-himix200-linux".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from test...done.
[New LWP 252]

warning: Could not load shared library symbols for linux-vdso.so.1.
Do you need "set solib-search-path" or "set sysroot"?
Core was generated by `./test'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 0x00010530 in get_value (value=0x0) at main.cpp:4
4 main.cpp: No such file or directory.
(gdb) bt
#0 0x00010530 in get_value (value=0x0) at main.cpp:4
#1 0x00010568 in main (argc=1, argv=0xbeedfe34) at main.cpp:9
(gdb)

使用 gdb test core_test_252 命令来加载 coredump 文件。 gdb execute_file_path coredump_file_path
加载完之后,使用 bt 指令来打印错误堆栈。bt 即 backtrace 的简写。
从上面的分析结果我们知道发生错误的地方在 main.cpp 第 4 行代码。