作为工作几年的老程序猿,肯定会遇到coredump,log severity设置的比较高,导致可用的log无法分析问题所在。 更悲剧的是,这个问题不好复现!所以现在你手头唯一的线索就是这个程序的尸体:coredump。你不得不通过它,来寻找问题根源。
通过上几篇文章,我们知道了函数参数是如何传递的,和函数调用时栈是如何变化的;当然了还有AT&T的汇编基础,这些,已经可以使我们具备了一定的调试基础。其实,很多调试还是需要经验+感觉的。当然说这句话可能会被打。但是你不得不承认,随着调试的增多,你的很多推断在解决问题时显得很重要,因此,我们需要不断积累经验,来面对各种case。
导致coredump的原因很多,比如死锁,这些还不要操作系统相关的知识,这些问题的分析不在本文的讨论范围之内。大家敬请期待接下来的文章吧!本文从一个非常典型的coredump入手。
请下载本文用到的coredump: Linux Debugging: coredump 分析入门的材料
首先使用gdb a.out core.25992打开这个core
看一下backtrace是什么:
Program received signal SIGSEGV, Segmentation fault. 0x0000000000400703 in __do_global_dtors_aux () (gdb) bt Cannot access memory at address 0x303938373635343b出错的地方很奇怪,而且整个callstack都被破坏了,因此首先看一下寄存器和bp是否正常:
(gdb) i r rax 0x7fffffffe040 140737488347200 rbx 0x400820 4196384 rcx 0x3332312c21646c72 3689065110378409074 rdx 0x0 0 rsi 0x40091d 4196637 rdi 0x7fffffffe059 140737488347225 rbp 0x3039383736353433 0x3039383736353433 rsp 0x7fffffffe060 0x7fffffffe060 r8 0x30393837363534 13573712489362740 r9 0x7ffff7dc3680 140737351792256 r10 0xffffffffffffffff -1 r11 0x7ffff7389ae0 140737341070048 r12 0x400660 4195936 r13 0x7fffffffe180 140737488347520 r14 0x0 0 r15 0x0 0 rip 0x400703 0x400703 <__do_global_dtors_aux+83> eflags 0x10202 [ IF RF ] cs 0x33 51 ss 0x2b 43 ds 0x0 0 es 0x0 0 fs 0x0 0 gs 0x0 0 fctrl 0x37f 895 fstat 0x0 0 ftag 0xffff 65535 fiseg 0x0 0 fioff 0x0 0 foseg 0x0 0 fooff 0x0 0 fop 0x0 0 mxcsr 0x1f80 [ IM DM ZM OM UM PM ] (gdb) x/i $rip 0x400703 <__do_global_dtors_aux+83>: fidivl -0x1e(%rdx) (gdb) x/20i $rip-10 0x4006f9 <__do_global_dtors_aux+73>: add %cl,-0x75(%rax) 0x4006fc <__do_global_dtors_aux+76>: adc $0x200947,%eax 0x400701 <__do_global_dtors_aux+81>: cmp %rbx,%rdx 0x400704 <__do_global_dtors_aux+84>: jb 0x4006e8 <__do_global_dtors_aux+56> 0x400706 <__do_global_dtors_aux+86>: movb $0x1,0x200933(%rip) # 0x601040 <completed.6159> 0x40070d <__do_global_dtors_aux+93>: add $0x8,%rsp 0x400711 <__do_global_dtors_aux+97>: pop %rbx 0x400712 <__do_global_dtors_aux+98>: leaveq 0x400713 <__do_global_dtors_aux+99>: retq 0x400714 <__do_global_dtors_aux+100>: nopw %cs:0x0(%rax,%rax,1) 0x400720 <frame_dummy>: push %rbp 0x400721 <frame_dummy+1>: cmpq $0x0,0x2006df(%rip) # 0x600e08 <__JCR_LIST__> 0x400729 <frame_dummy+9>: mov %rsp,%rbp 0x40072c <frame_dummy+12>: je 0x400748 <frame_dummy+40> 0x40072e <frame_dummy+14>: mov $0x0,%eax 0x400733 <frame_dummy+19>: test %rax,%rax 0x400736 <frame_dummy+22>: je 0x400748 <frame_dummy+40> 0x400738 <frame_dummy+24>: mov $0x600e08,%edi 0x40073d <frame_dummy+29>: mov %rax,%r11 0x400740 <frame_dummy+32>: leaveq
rbp的值很奇怪,基本确定栈被破坏了(bt不正常,也应该看一下栈是否出问题了)。打印一下栈的内容,看是否栈被写坏了:
(gdb) x/30c $rsp-20 0x7fffffffe04c: 33 ‘!‘ 44 ‘,‘ 49 ‘1‘ 50 ‘2‘ 51 ‘3‘ 52 ‘4‘ 53 ‘5‘ 54 ‘6‘ 0x7fffffffe054: 55 ‘7‘ 56 ‘8‘ 57 ‘9‘ 48 ‘0‘ 0 ‘\000‘ 7 ‘\a‘ 64 ‘@‘ 0 ‘\000‘ 0x7fffffffe05c: 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0x7fffffffe064: 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ -21 ‘\353‘ 5 ‘\005‘我们看到了特殊的字符!,1234567890。当然实际的生产环境可能不会这么简单,比如笔者曾经遇到过这个字符串是/local/share/tracker_...这种目录的字符串,后来发现拼接路径的时候出现错误导致路径非常长,在路径拷贝的时候出现了写坏栈的情况。
多打印一下栈的内容:
(gdb) x/40c $rsp-40 0x7fffffffe038: -100 ‘\234‘ 7 ‘\a‘ 64 ‘@‘ 0 ‘\000‘ 1 ‘\001‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0x7fffffffe040: 72 ‘H‘ 101 ‘e‘ 108 ‘l‘ 108 ‘l‘ 111 ‘o‘ 44 ‘,‘ 32 ‘ ‘ 119 ‘w‘ 0x7fffffffe048: 111 ‘o‘ 114 ‘r‘ 108 ‘l‘ 100 ‘d‘ 33 ‘!‘ 44 ‘,‘ 49 ‘1‘ 50 ‘2‘ 0x7fffffffe050: 51 ‘3‘ 52 ‘4‘ 53 ‘5‘ 54 ‘6‘ 55 ‘7‘ 56 ‘8‘ 57 ‘9‘ 48 ‘0‘ 0x7fffffffe058: 0 ‘\000‘ 7 ‘\a‘ 64 ‘@‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘ 0 ‘\000‘可以看出,字符串"Hello, World!,1234567890"这个字符串溢出导致栈被破坏。
我们不应该用rbp打印吗?
还记得在函数返回时,rbp会恢复为上一层调用者的bp吗?因为字符串溢出/越界,导致已经恢复不了原来的bp了。
这个bug很简单。实际上,有的coredump就是这种无心的错误啊。
尊重原创,转载请注明出处: anzhsoft http://blog.csdn.net/anzhsoft/article/details/18762915