嵩馥 官方网页,benefly,人鱼帝妃
在现网环境下,程序奔溃后不一定会留下core文件,原因有很多,比如存储空间不足就是其中一个常见的原因。此时我们只能依据linux记录的错误日志来定位问题。
本文涉及以下几条命令
1)dmesg |grep -e 'segfault|general'
可以通过该命令过滤出发生崩溃的程序,以及对应的堆栈信息。之前看网上的其他文章仅过滤segfault,但我在实践中发现"general protection"的提示信息也在告诉我们进程崩了。目前我只遇到segfault和general这两种情况,如果还有其他的过滤条件可以给我留言。
举例: [root@vmware ~] dmesg |grep -e 'segfault|general' [ 374.549753] a.out[57228]: segfault at 0 ip 00000000004004fd sp 00007ffe7296f610 error 6 in a.out[400000+1000] [ 429.110096] b.out[96783]: segfault at 0 ip 00000000004004fd sp 00007ffcc3e697c0 error 6 in b.out[400000+1000] 字段说明: 1)ip:指令指针寄存器,字段后面的数字就是test程序出错时程序执行的位置 2)sp:堆栈指针寄存器 3)error:错误码,由三个字位组成的,从高到底分别为bit2 bit1和bit0 bit2: 值为1表示是用户态程序内存访问越界,值为0表示是内核态程序内存访问越界 bit1: 值为1表示是写操作导致内存访问越界,值为0表示是读操作导致内存访问越界 bit0: 值为1表示没有足够的权限访问非法地址的内容,值为0表示访问的非法地址根本没有对应的页面,也就是无效地址 4)b.out后面紧跟着的地址(这里是400000)这个在定位时也有用到,不知道该怎么描述,知道的给我留言
2)dmesg |grep 进(线)程名
通过进程或线程名来过滤。这里之所以强调线程,因为我在实践中发现dmesg里的信息可能只有线程名,所以推荐在给线程取名时使用统一前缀,比如你的主进程为test,那么线程可以取test_a,test_a,这样过滤时 grep test就能过滤出所有想要的信息
举例: [root@vmware ~] dmesg |grep a.out [ 374.549753] a.out[57228]: segfault at 0 ip 00000000004004fd sp 00007ffe7296f610 error 6 in a.out[400000+1000]
3)dmesg -c
dmesg命令查看到的信息在重启后将会被清空,若当前错误信息太多也可以通过该命令手动清空dmesg信息,以便下次问题的定位。-c(大写)参数为静默清空,如果清空前还想打印一次,可以通过-c(小写)参数。
注:
cat /var/log/messages |grep xxx
这里也保存进程奔溃信息,且重启后依然存在。
举例: [root@vmware ~] cat /var/log/messages|grep b.out may 8 09:24:04 vmware kernel: b.out[96783]: segfault at 0 ip 00000000004004fd sp 00007ffcc3e697c0 error 6 in b.out[400000+1000] may 8 09:24:04 vmware abrt-hook-ccpp: process 96783 (b.out) of user 0 killed by sigsegv - dumping core may 8 09:24:05 vmware abrt-server: executable '/root/b.out' doesn't belong to any package and processunpackaged is set to 'no'
date -d "1970-01-01 utc `echo "$(date +%s)-$(cat /proc/uptime|cut -f 1 -d' ')+时间戳"|bc `seconds"
举例: [ 672.091250] a.out[26520]: segfault at 0 ip 00000000004004fd sp 00007ffe51b27fe0 error 6 in a.out[400000+1000] [root@vmware ~] date -d "1970-01-01 utc `echo "$(date +%s)-$(cat /proc/uptime|cut -f 1 -d' ')+672.091250"|bc `seconds" 2019年 05月 08日 星期三 09:40:02 cst
奔溃发生的位置不同,该命令的使用方式也有所不同
1)在主进程中奔溃
addr2line -e 进程名 ip指令地址 -f
举例:
#include <stdio.h>
int main()
{
int *p = null;
*p = 0;
return 0;
}
[root@vmware ~] gcc a.c -g [root@vmware ~] ./a.out 段错误(吐核) [root@vmware ~] dmesg |grep a.out [ 1310.167335] a.out[122089]: segfault at 0 ip 00000000004004fd sp 00007ffcf08f3ab0 error 6 in a.out[400000+1000] [root@vmware ~] addr2line -e a.out 00000000004004fd -f func /root/a.c:5
通过该例子我们可以看到,程序发生段错误的函数以及具体位置。需要注意的是如果编译程序时没有加上-g参数,就只能显示出函数名,显示不出具体所在文件的位置.
2)动态库中奔溃
addr2line -e 进程名 “ip指令地址-动态库后紧跟着的地址” -f
举例:
#include<stdio.h> #include<string.h> void func() { int *p = null; memcpy(p, "test", 4); } int main() { func(); return 0; }
[root@vmware ~] dmesg |grep a.out [ 6807.501481] a.out[72684]: segfault at 0 ip 00007f6559bc7463 sp 00007fff80625b18 error 6 in libc-2.17.so[7f6559a7c000+1b6000] [root@vmware ~] ldd a.out linux-vdso.so.1 => (0x00007ffc643f6000) libc.so.6 => /lib64/libc.so.6 (0x00007f83ef206000) /lib64/ld-linux-x86-64.so.2 (0x00007f83ef5e2000)
[root@vmware ~] addr2line -e /lib64/libc.so.6 14b463 -f __memcpy_ssse3_back :? 这个这个例子我们可以看到,段错误发生的位置是在a.out进程调用的libc库里,因此addr2line指向的地址使用14b463 = 00007f6559bc7463 - 7f6559a7c000
如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复
如何在没有core文件的情况下用dmesg+addr2line定位段错误
用QT制作3D点云显示器——QtDataVisualization
网友评论