前言
最近碰到了一个程序崩溃的问题,根据我的统计,这个问题出现的概率大概是400小时出现一次,出问题的概率比较小,而且由于未知原因,程序崩溃时的core dump文件没有生成。
后面我搭了一个测试环境反复去跑数据,连续测试了12个小时也并没有复现出来问题。这也是正常的,毕竟400小时/次的概率也是非常小的。目前可以利用的信息有 /var/log/kern.log
文件以及不含调试信息的可执行文件。
记录一下解决问题的方法。
kern.log
的崩溃信息
我在系统 /var/log/kern.log
文件中找到了崩溃信息,如下:
Nov 24 06:20:42 PC kernel: [ 2906.214694] A[9536]: segfault at 28 ip 00007f55572573a8 sp 00007f55367f9ec0 error 4 in B.so[7f5557249000+1d000]
Nov 24 06:20:42 PC kernel: [ 2906.214714] Code: c3 49 f7 f1 48 8b 47 18 4c 8b 14 d0 48 89 d5 4d 85 d2 74 4e 4d 8b 02 49 8b 48 08 eb 24 0f 1f 44 00 00 49 8b 00 48 85 c0 74 38 <48> 8b 48 08 4d 89 c2 31 d2 49 89 c0 48 89 c8 49 f7 f1 48 39 d5 75
总共就两行,发生了段错误,比较关键的是这一行信息 A[9536]: segfault at 28 ip 00007f55572573a8 sp 00007f55367f9ec0 error 4 in B.so[7f5557249000+1d000]
具体来说,
A[9536]
,代表名为A
、进程号(PID)为9536
的程序segfault at 28
,表示程序在试图访问28
这个地址的内存时产生了段错误ip 00007f55572573a8
,表示当时程序在执行地址为00007f55572573a8
的程序sp 00007f55367f9ec0
,表示当时程序的栈的地址error 4
,是错误码,4
表示用户态的错误in B.so[7f5557249000+1d000]
,表示是在B.so
文件产生的错误,这个.so
映射到内存(VMA)中的起始地址是7f5557249000
,其大小为1d000
计算 .so
文件的崩溃地址
我们知道 ip 00007f55572573a8
以及 B.so[7f5557249000+1d000]
,我们就可以计算执行的这一行指令在 .so
文件中的相对位置,即为 00007f55572573a8-7f5557249000=e3a8
。因此,我们需要在 .so
文件中找到 e3a8
地址对应的函数就可以找到是哪里出现的崩溃了。
找到崩溃的地方
我们可以使用 objdump
来查看二进制可能的附带信息,这个附带信息一般都会有函数名称。因为 objdump
里面包含的信息太多,通过 grep
会更方便一些,找到离 e3a8
最近的函数即可
objdump -tT B.so | grep e3
返回
000000000000e350 w F .text 00000000000000c2 _ZN1A1B1CI1DE1FERKS2_
000000000000e350 w DF .text 00000000000000c2 Base _ZN1A1B1CI1DE1FERKS2_
我们可以看到,离 e3a8
最近的函数是 _ZN1A1B1CI1DE1EERKS2_
,这个名字是经过 Name Mangling
的,通过命令 c++filt _ZN1A1B1CI1DE1EERKS2_
解析得到 A::B::C<D>::E(D const&)
,这个就是崩溃时候的函数了
One comment
问个问题,你是怎么关闭右上角的登录按钮的。