看一个coredump例子:
看一个coredump例子: Core was generated by `./xuzhina_dump_c07_s2_ex'. Program terminated with signal 11, Segmentation fault. #0 0x0285b9b7 in std::_List_node_base::hook(std::_List_node_base*) () from /usr/lib/libstdc++.so.6 Missing separate debuginfos, use: debuginfo-install glibc-2.12-1.149.el6_6.4.i686 libgcc-4.4.7-11.el6.i686 libstdc++-4.4.7-11.el6.i686 (gdb) bt #0 0x0285b9b7 in std::_List_node_base::hook(std::_List_node_base*) () from /usr/lib/libstdc++.so.6 #1 0x080488fd in std::list<int, std::allocator<int> >::_M_insert(std::_List_iterator<int>, int const&) () #2 0x08048784 in std::list<int, std::allocator<int> >::push_back(int const&) () #3 0x08048676 in main ()
查看一下崩溃函数的汇编:
0 0x0285b9b7 in std::_List_node_base::hook(std::_List_node_base*) () from /usr/lib/libstdc++.so.6 (gdb) disassemble Dump of assembler code for function _ZNSt15_List_node_base4hookEPS_: 0x0285b9a0 <+0>: push %ebp 0x0285b9a1 <+1>: mov %esp,%ebp 0x0285b9a3 <+3>: mov 0xc(%ebp),%eax 0x0285b9a6 <+6>: mov 0x8(%ebp),%edx 0x0285b9a9 <+9>: mov 0x4(%eax),%ecx 0x0285b9ac <+12>: mov %eax,(%edx) 0x0285b9ae <+14>: mov %ecx,0x4(%edx) 0x0285b9b1 <+17>: mov 0x4(%eax),%ecx 0x0285b9b4 <+20>: mov %edx,0x4(%eax) => 0x0285b9b7 <+23>: mov %edx,(%ecx) 0x0285b9b9 <+25>: pop %ebp 0x0285b9ba <+26>: ret End of assembler dump.
看一下寄存器的值:
(gdb) i r eax 0xbfedc248 -1074937272 ecx 0x0 0 edx 0x9309028 154177576 ebx 0x9faff4 10465268 esp 0xbfedc1c8 0xbfedc1c8 ebp 0xbfedc1c8 0xbfedc1c8 esi 0x0 0 edi 0x0 0 eip 0x285b9b7 0x285b9b7 <std::_List_node_base::hook(std::_List_node_base*)+23> eflags 0x10282 [ SF IF RF ] cs 0x73 115 ss 0x7b 123 ds 0x7b 123 es 0x7b 123 fs 0x0 0 gs 0x33 51
可见,是由于ecx的值为0所导致的。而ecx的值是由eax得来的,而eax的值则是从ebp+0xc上得来的。由于this指针放在ebp+0x8上,所以,ebp+0xc放置第一个参数。
由bits/stl_list.h:
void hook(_List_node_base * const __position);
可知,是__position的_Prev的值为0.那么__position是从哪里来的?
根据堆栈和stl_list.h里的函数:
void _M_insert(iterator __position, const value_type& __x) { _Node* __tmp = _M_create_node(__x); __tmp->hook(__position._M_node); } void push_back(const value_type& __x) { this->_M_insert(end(), __x); }
可知,这个__position是end()的返回值,结合list的定义,可知,__position实际上是链表的尾部。
那么尾部的元素怎么可能是0呢?
看一下main函数:
(gdb) disassemble Dump of assembler code for function main: 0x080485e4 <+0>: push %ebp 0x080485e5 <+1>: mov %esp,%ebp 0x080485e7 <+3>: and $0xfffffff0,%esp 0x080485ea <+6>: push %esi 0x080485eb <+7>: push %ebx 0x080485ec <+8>: sub $0x38,%esp 0x080485ef <+11>: lea 0x18(%esp),%eax 0x080485f3 <+15>: mov %eax,(%esp) 0x080485f6 <+18>: call 0x80486e6 <_ZNSt4listIiSaIiEEC2Ev> 0x080485fb <+23>: movl $0x5,0x20(%esp) 0x08048603 <+31>: lea 0x20(%esp),%eax 0x08048607 <+35>: mov %eax,0x4(%esp) 0x0804860b <+39>: lea 0x18(%esp),%eax 0x0804860f <+43>: mov %eax,(%esp) 0x08048612 <+46>: call 0x8048750 <_ZNSt4listIiSaIiEE9push_backERKi> 0x08048617 <+51>: movl $0x3,0x24(%esp) 0x0804861f <+59>: lea 0x24(%esp),%eax 0x08048623 <+63>: mov %eax,0x4(%esp) 0x08048627 <+67>: lea 0x18(%esp),%eax 0x0804862b <+71>: mov %eax,(%esp) 0x0804862e <+74>: call 0x8048786 <_ZNSt4listIiSaIiEE10push_frontERKi> 0x08048633 <+79>: lea 0x18(%esp),%eax ---Type <return> to continue, or q <return> to quit--- 0x08048637 <+83>: mov %eax,(%esp) 0x0804863a <+86>: call 0x80487bc <_ZNKSt4listIiSaIiEE4sizeEv> 0x0804863f <+91>: shl $0x2,%eax 0x08048642 <+94>: mov %eax,0x8(%esp) 0x08048646 <+98>: movl $0x0,0x4(%esp) 0x0804864e <+106>: lea 0x18(%esp),%eax 0x08048652 <+110>: mov %eax,(%esp) 0x08048655 <+113>: call 0x80484b8 <memset@plt> 0x0804865a <+118>: movl $0x8,0x28(%esp) 0x08048662 <+126>: lea 0x28(%esp),%eax 0x08048666 <+130>: mov %eax,0x4(%esp) 0x0804866a <+134>: lea 0x18(%esp),%eax 0x0804866e <+138>: mov %eax,(%esp) 0x08048671 <+141>: call 0x8048750 <_ZNSt4listIiSaIiEE9push_backERKi> => 0x08048676 <+146>: movl $0xc,0x2c(%esp) 0x0804867e <+154>: lea 0x2c(%esp),%eax 0x08048682 <+158>: mov %eax,0x4(%esp) 0x08048686 <+162>: lea 0x18(%esp),%eax 0x0804868a <+166>: mov %eax,(%esp) 0x0804868d <+169>: call 0x8048750 <_ZNSt4listIiSaIiEE9push_backERKi> 0x08048692 <+174>: mov $0x0,%ebx 0x08048697 <+179>: lea 0x18(%esp),%eax 0x0804869b <+183>: mov %eax,(%esp) ---Type <return> to continue, or q <return> to quit--- 0x0804869e <+186>: call 0x80486d2 <_ZNSt4listIiSaIiEED2Ev> 0x080486a3 <+191>: mov %ebx,%eax 0x080486a5 <+193>: add $0x38,%esp 0x080486a8 <+196>: pop %ebx 0x080486a9 <+197>: pop %esi 0x080486aa <+198>: mov %ebp,%esp 0x080486ac <+200>: pop %ebp 0x080486ad <+201>: ret 0x080486ae <+202>: mov %edx,%ebx 0x080486b0 <+204>: mov %eax,%esi 0x080486b2 <+206>: lea 0x18(%esp),%eax 0x080486b6 <+210>: mov %eax,(%esp) 0x080486b9 <+213>: call 0x80486d2 <_ZNSt4listIiSaIiEED2Ev> 0x080486be <+218>: mov %esi,%eax 0x080486c0 <+220>: mov %ebx,%edx 0x080486c2 <+222>: mov %eax,(%esp) 0x080486c5 <+225>: call 0x8048518 <_Unwind_Resume@plt> End of assembler dump.
由
0x08048642 <+94>: mov %eax,0x8(%esp) 0x08048646 <+98>: movl $0x0,0x4(%esp) 0x0804864e <+106>: lea 0x18(%esp),%eax 0x08048652 <+110>: mov %eax,(%esp) 0x08048655 <+113>: call 0x80484b8 <memset@plt> 0x0804865a <+118>: movl $0x8,0x28(%esp) 0x08048662 <+126>: lea 0x28(%esp),%eax 0x08048666 <+130>: mov %eax,0x4(%esp) 0x0804866a <+134>: lea 0x18(%esp),%eax 0x0804866e <+138>: mov %eax,(%esp) 0x08048671 <+141>: call 0x8048750 <_ZNSt4listIiSaIiEE9push_backERKi> => 0x08048676 <+146>: movl $0xc,0x2c(%esp)
可知,链表是放在esp+0x18的位置,并且用memset把链表两个值初始化为0.
源代码:
1 #include <list> 2 #include <string.h> 3 4 int main() 5 { 6 std::list<int> list; 7 8 list.push_back( 5 ); 9 list.push_front( 3 ); 10 11 memset( &list, 0, list.size()*sizeof( int ) ); 12 13 list.push_back( 8 ); 14 list.push_back( 12 ); 15 16 return 0; 17 }
《coredump问题原理探究》Linux x86版7.4节List coredump例子
原文地址:http://blog.csdn.net/xuzhina/article/details/45277185