GDB与core_file配合调试
GDB与core_file配合调试
引子
在上一篇文章中,我们创建了一个会崩溃的main
可执行文件:
# 创建main.cpp
cat > main.cpp <<EOF
#include <iostream>
void test(){
std::cout << "test func" << std::endl;
throw "some error";
}
int main(){
std::cout<<"main started!"<<std::endl;
test();
return 0;
}
EOF
# 编译成可执行文件
g++ -g -o main main.cpp
直接执行./main
时的输出是这样的:
./main
main started!
test func
terminate called after throwing an instance of 'char const*'
Aborted (core dumped)
最后一行输出是Aborted(core dumped)
,中文系统也可能会输出核心已转储
,老写。bug
的朋友们应该看过不少
如果我们找到这个core dump
文件再丢给gdb
就可以复现了,现在先找找这个文件。
core_file文件位置
文件位置由/proc/sys/kernal/core_pattern
文件中的内容来定义,cat
一下瞧瞧:
cat /proc/sys/kernel/core_pattern
|/usr/share/apport/apport -p%p -s%s -c%c -d%d -P%P -u%u -g%g -- %E
这里默认是使用ubuntu
的崩溃报告来处理的,对于调试没什么用处,修改一下,如果当前是root
用户则可以直接:
echo './core.%e-%t-%p-%s-%u' > /proc/sys/kernel/core_pattern
其中的占位符简单了解:
%e
:可执行文件名称,executable
;%t
:时间戳,从1970.1.1 00:00:00
开始的秒数;%p
:执行进程的PID
,Process ID
;%s
:崩溃的信号,signal
;%u
:执行时的用户id
,user ID
;
我这里使用的docker
容器,虽然也是root
用户,但输出失败了:
echo './core.%e-%t-%p-%s-%u' > /proc/sys/kernel/core_pattern
bash: /proc/sys/kernel/core_pattern: Read-only file system
这里的问题在于,docker
容器没有自己的内核,是使用的宿主机的内核,它将宿主机内核以可读方式加载进容器中了,而宿主机内核只有root
用户才能修改,所以可以在宿主机上执行语句:
sudo bash -c "echo './core.%e-%t-%p-%s-%u' > /proc/sys/kernel/core_pattern"
或者在docker run
时添加--privileged
参数,这样容器拥有root
权限可以直接修改。
注意:这里不能替换成 sudo echo ... > ...
,因为在重定向(>
)时,sudo
就会失效,具体原因可以参考why-is-editing-core-pattern-restricted。
重新运行
这回再跑一下./main
,此时在当前目录下产生了一个core.main-1718874841-11192-6-0
文件,就可以使用gdb
调试了:
gdb ./main core.main-1718874841-11192-6-0
GNU gdb (Ubuntu 9.2-0ubuntu1~20.04.1) 9.2
Copyright (C) 2020 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 "x86_64-linux-gnu".
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 ./main...
(No debugging symbols found in ./main)
[New LWP 11192]
Core was generated by `./main'.
Program terminated with signal SIGABRT, Aborted.
--Type <RET> for more, q to quit, c to continue without paging--
可以发现直接暂停到了崩溃的地方,bt
指令看一下,成功复现了刚才的崩溃:
(gdb) bt
#0 __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:50
#1 0x00007fd893596859 in __GI_abort () at abort.c:79
#2 0x00007fd8938048d1 in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#3 0x00007fd89381037c in ?? () from /lib/x86_64-linux-gnu/libstdc++.so.6
#4 0x00007fd8938103e7 in std::terminate() () from /lib/x86_64-linux-gnu/libstdc++.so.6
#5 0x00007fd893810699 in __cxa_throw () from /lib/x86_64-linux-gnu/libstdc++.so.6
#6 0x000055af0ca44241 in test () at main.cpp:5
#7 0x000055af0ca44276 in main () at main.cpp:10
如果并没有产生core_file
可能在部分系统上,运行./main
时输出是这样的,注意最后一行并没有core dumped
:
./main
main started!
test func
terminate called after throwing an instance of 'char const*'
Aborted
这样就算设置了core_pattern
,当前目录下也没有core_file
产生。
首先引入一个指令ulimit -c
,查看允许产生core_file
的大小,在ubuntu
系统上默认ulimit -c
指令输出unlimited
,默认不限制core_file
的大小:
ulimit -c
unlimited
如果设置改成ulimit -c 0
,就不会输出core_file
了,输出就如前面一般,最后一行没有core dumped
。
但这里又有一个小坑,使用ulimit -c unlimited
后,重启或者注销后就会失效,可以使用docker
自行简单测试,解决办法:
echo '* soft core unlimited' >> /etc/security/limits.conf
总结
- 程序崩溃时可以产生
core_file
(此时输出有core dumped
字样),如果ulimit -c
输出不为0
则可以产生,否则需要使用ulimit -c unlimited
设置允许core_file
生成;其中的
unlimited
可以换为具体数值,如1024
; - 如果系统默认不产生
core_file
,需要这个指令使之重启后仍然产生:echo '* soft core unlimited' >> /etc/security/limits.conf
- 可以通过这个指令设置
core_file
产生在当前目录:sudo bash -c "echo './core.%e-%t-%p-%s-%u' > /proc/sys/kernel/core_pattern"
如果在
docker
容器中一般不可直接修改,可以修改宿主机的core_pattern
,或者在docker run
时提供--privileged
参数; - 成功产生
core_file
后,可以使用gdb ./main core_file
来复现崩溃。