0%

利用Linux的coredump机制快速定位程序BUG

什么是coredump?

Coredump是继承于UNIX系统的机制,它用于保存程序出错而崩溃时的栈,内存,PID,UID,GID,时间等等信息的快照,通常用于程序诊断和调试,Coredump的信息在计算机中一般保存三天左右(依系统设定而定),如果出错的程序BUG不及时查找,超过三天系统会吧这些Coredump删除。

需要些什么工具?

一般来说,只需要objdump和gdb即可,诊断时源代码以原始为佳(core dumped时的未修改的代码)。

案例分析

下面是我展示的一个出错事例,供参考观摩。

程序崩溃了

这个程序运行时,一点问题也没有,就是退出时有小概率的情况出现崩溃,这种最让人头疼,像这种隐蔽BUG,很多情形不会触发它,却在某个特殊条件下,它突然就发生了。总结为两难:

  • 难确定(是否发生)
  • 难定位

见下图:

pic1

尝试用coredumpctl工具直接调试

coredumpctl是systemd的工具之一,只要用的是这个系统服务的,应该都有,此工具使用非常简单,可以命令输入以获帮助:

1
coredumpctl --help

或者,也可以查看它的man文档。

好了,言归正传,尝试输入命令以调试:

1
coredumpctl debug xxxx

上面的xxxx是程序文件名,关于该程序名,可以用coredumpctl list查看到

出现如下图的结果:

pic2

这种情况就比较复杂了,可以看见0x00007f77be94cf25 in ?? ()这句,Coredump也不能在源代码确定具体出错的位置了,作为比较,我展示另一个例子:

pic3

上图这个例子出错代码立马被Coredump断定出来,很显然执行这句代码时崩溃的:

1
*a = 0;

这句是我故意改错用于比较的,源代码是这样的:

1
2
3
4
5
6
bool input(string& filename, ...) {
cout << filename << endl;
int* a = 0;
*a = 0;
return true;
}

好了,我们继续前面的0x00007f77be94cf25 in ?? ()这句,我们不能像前面这个立马断定,那该怎么办呢?

coredumctl info查看栈信息

下面两张图展示了这个崩溃程序的栈信息。

图一:

pic4

图二: pic5

因为输出信息较宽,被我分成了两张图,注意图二中栈的调用列表,下面我们接着反汇编原始程序文件。

反汇编程序文件

反汇编原始崩溃程序文件时,不要忘记加--source参数,不然全是汇编代码查找效率就不是很高,即输入命令带反汇编:

1
objdump --source -d xxxx | less

图片展示:

pic6

同样,xxxx为程序文件名

这时,我们可以在less中依次查找各个栈地址(见图二所述),转到那个从libc刚出来,在程序文件最先出错位置,即:0x42ce8的文件位置,错误立马被锁定位置(可以依次查找栈上面的地址,顺藤摸瓜,可以断定那是在给list进行clear操作),原来是C++的类析构函数在析构一个list时出的错误,继而判定这个错误实际上是个多线程引起的错误,因为程序中还有一个子线程也在释放操作,是主线程和子线程同时释放引起,对于释放资源,主/子线程没有加同步,从而导致时而正常,时而出错,加上一个最简单的同步机制,问题解决。

欢迎关注我的其它发布渠道