gdb调试

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

今天碰到了一个bug,服务器在运行时会core dump在一个很灵异的地方,排除这个错误的过程,以及最后发现的错误结果很具有典型性,所牵涉到的技术也很多,拿来作为Linux调试的课程挺好的。:-P

整个里面假设读者已经知道怎么用gdb,如果不知道,请参见GDB Manual

首先,很幸运的是,这个问题是可以很容易重现的,而且更重要的,有core dump。

拿到core dump之后,惯例是查看一下调用栈:(为了避免泄漏商业秘密,所有函数名,文件名什么的都用foo啊,bar啊,foobar啊,blabla啊等等代替)。

(gdb) bt

#0 0x000000eb in ?? ()

#1 0x3aa1d941 in ?? ()

#2 0x000001f8 in ?? ()

#3 0x080cf888 in foo (range=10000) at foo/foo.c:18

#4 0x080c1f29 in bar () at bar/bar.c:423

[....]

(gdb) info f 0

Stack frame at 0xbfc42548:

eip = 0xeb; saved eip 0x3aa1d941

called by frame at 0xbfc4254c

Arglist at 0xbfc42540, args:

Locals at 0xbfc42540, Previous frame's sp is 0xbfc42548

Saved registers:

eip at 0xbfc42544

(gdb) f 3

#3 0x080cf888 in foo (range=10000) at foo/foo.c:18

18 return ((u32)random()) % range;

相当的灵异,栈上的0,1,2都是,一个返回地址怎么可能是0×1f8,而且,core dump的原因是因为eip 跑飞到了0xeb。到frame 3的时候看起来正常了,但是出错的地方在random这种简单的库函数上。不

过既然frame 3往下的部分都是好的,我们有理由认为栈并没有被搞坏。因为GDB在显示调用栈的时候可能会把一些不正确的调用栈也显示出来,我们干脆直接看内存:

(gdb) x/10w $esp

0xbfc42544: 0x3aa1d941 0x000001f8 0x080cf888 0x09582930

0xbfc42554: 0x0833f038 0xbfc42678 0x080c1f29 0x00002710

0xbfc42564: 0x0823747f 0xb7ca168c

看加粗的部分:这里就是frame 3返回地址,而上面的东西,就是bt显示出来的frame 1和frame 2了,而frame 0就是当前的eip了:它跑飞到了0xeb。

GDB果然在显示栈的时候做了手脚。

OK,我们反汇编看看这个返回地址,到底干了什么:

(gdb) disassemble 0x080cf888

Dump of assembler code for function _Z6foom:

0x080cf85c <_Z6foom+0>: push %ebp

0x080cf85d <_Z6foom+1>: mov %esp,%ebp

0x080cf85f <_Z6foom+3>: push %ebx

0x080cf860 <_Z6foom+4>: sub $0x4,%esp

[…]

0x080cf87a <_Z6foom+30>: movl $0x0,0xfffffff8(%ebp)

0x080cf881 <_Z6foom+37>: jmp 0x80cf893 <_Z6foom+55>

0x080cf883 <_Z6foom+39>: call 0x8051f90

0x080cf888 <_Z6foom+44>: mov $0x0,%edx

[…]

0x080cf899 <_Z6foom+61>: pop %ebx

0x080cf89a <_Z6foom+62>: pop %ebp

0x080cf89b <_Z6foom+63>: ret

End of assembler dump.

看起来也没干啥,继续看调用的地址是啥吧:

(gdb) disassemble 0x8051f90

Dump of assembler code for function random@plt:

0x08051f90 : jmp *0x833f140

0x08051f96 : push $0x1f8

0x08051f9b : jmp 0x8051b90 <_init+24>

有点意思啊,random@plt,PLT是什么?PLT是Linux ELF格式可执行文件当中的一个部分,称为Procedure Linkage Table。PLT是程序为了实现Linux共享库的动态迟绑定(Lazy Binding)而引入的一种机制。关于ELF格式、PLT,和下面要提到的GOT(Global Offset Table)的资料,可以参见下面这些链接:

The ELF Object File Format: Introduction

/article/1060

UNIX ELF File Format (PPT)

好了,言归正传,就算你不知道PLT,你也可以继续往下看。最土的办法,既然jump到一个地方,就看看这个地方是什么吧。

(gdb) p/x *0x833f140

$6 = 0x8051f96

显然这个重新跳回到了PLT当中,看下面:

(gdb) disassemble 0x8051f96

Dump of assembler code for function random@plt:

0x08051f90 : jmp *0x833f140

0x08051f96 : push $0x1f8 // 这是栈上的 0x1f8

0x08051f9b : jmp 0x8051b90 <_init+24>

又一个jmp,这次jmp到了什么地方呢?

(gdb) disassemble 0x8051b90

No function contains specified address.

相关文档
最新文档