linux crash在动态库中,通过map查找crash位置
2016-04-23 08:57
627 查看
linux进程crash时,通常我们可以通过gdb+core或addr2line解析出进程crash在哪一个函数中,有时crash在动态链接库中,解析出的core可能只有一个地址,而不能知道是在哪一个函数,这时可以尝试通过/proc/进程ID/maps的方法找到crash的位置。
一个动态库的实现:
头文件sample_fun.h
使用g++将这个源文件编译出动态库
g++ -fPIC -shared sample_fun.cpp -o libsample_fun.so
调用动态库的实现sample_main.cpp
将这个文件编译可执行程序并连接动态库
g++ sample_main.cpp -L. libsample_fun.so -o sample_main
运行着个程序发生了crash,并且生成了core文件,
./sample_main
Segmentation fault (core dumped)
通过gdb+core看到了crash的地址
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/nap/sample_main...(no debugging symbols found)...done.
[New LWP 4170]
warning: Can't read pathname for load map: Input/output error.
Core was generated by `./sample_main'.
Program terminated with signal 11, Segmentation fault.
#0 0xb773a478 in ???
(gdb) bt
#0 0xb773a478 in ???
#1 0x08048770 in ???
#2 0x08048763 in ???
(gdb)
通过查看进程的map可以看出crash的位置在libsample_fun.so的代码段,
08048000-08049000 r-xp 00000000 08:05 1059318 /home/nap/sample_main
08049000-0804a000 r--p 00000000 08:05 1059318 /home/nap/sample_main
0804a000-0804b000 rw-p 00001000 08:05 1059318 /home/nap/sample_main
b7449000-b744b000 rw-p 00000000 00:00 0
b744b000-b7467000 r-xp 00000000 08:05 1311741 /lib/i386-linux-gnu/libgcc_s.so.1
b7467000-b7468000 r--p 0001b000 08:05 1311741 /lib/i386-linux-gnu/libgcc_s.so.1
b7468000-b7469000 rw-p 0001c000 08:05 1311741 /lib/i386-linux-gnu/libgcc_s.so.1
b7469000-b7493000 r-xp 00000000 08:05 1315013 /lib/i386-linux-gnu/libm-2.15.so
b7493000-b7494000 r--p 00029000 08:05 1315013 /lib/i386-linux-gnu/libm-2.15.so
b7494000-b7495000 rw-p 0002a000 08:05 1315013 /lib/i386-linux-gnu/libm-2.15.so
b7495000-b7638000 r-xp 00000000 08:05 1310845 /lib/i386-linux-gnu/libc-2.15.so
b7638000-b763a000 r--p 001a3000 08:05 1310845 /lib/i386-linux-gnu/libc-2.15.so
b763a000-b763b000 rw-p 001a5000 08:05 1310845 /lib/i386-linux-gnu/libc-2.15.so
b763b000-b763f000 rw-p 00000000 00:00 0
b763f000-b7717000 r-xp 00000000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7717000-b7718000 ---p 000d8000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7718000-b771c000 r--p 000d8000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b771c000-b771d000 rw-p 000dc000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b771d000-b7724000 rw-p 00000000 00:00 0
b773a000-b773b000 r-xp 00000000 08:05 1059319 /home/nap/libsample_fun.so
b773b000-b773c000 r--p 00000000 08:05 1059319 /home/nap/libsample_fun.so
b773c000-b773d000 rw-p 00001000 08:05 1059319 /home/nap/libsample_fun.so
b773d000-b773f000 rw-p 00000000 00:00 0
b773f000-b7740000 r-xp 00000000 00:00 0 [vdso]
b7740000-b7760000 r-xp 00000000 08:05 1311879 /lib/i386-linux-gnu/ld-2.15.so
b7760000-b7761000 r--p 0001f000 08:05 1311879 /lib/i386-linux-gnu/ld-2.15.so
b7761000-b7762000 rw-p 00020000 08:05 1311879 /lib/i386-linux-gnu/ld-2.15.so
bf97d000-bf99e000 rw-p 00000000 00:00 0 [stack]
接下来我们要求出crash的函数在libsample_fun.so中的地址,计算方式如下
发生crash的地址 - 动态库的起始地址 + 偏移地址
在我们的例子中为0xb773a478 - 0xb773a000 + 0x00000000 = 0x478
通过 nm -n libsample_fun.so将这个动态库中的符号表按地址顺序输出
nap@nap-HP-431-Notebook-PC:~$ nm -n libsample_fun.so
w _Jv_RegisterClasses
w __cxa_finalize@@GLIBC_2.1.3
w __gmon_start__
U printf@@GLIBC_2.0
00000330 T _init
000003a0 t __do_global_dtors_aux
00000420 t frame_dummy
00000457 t __i686.get_pc_thunk.bx
0000045c T _Z8testFun4v
000004a0 t __do_global_ctors_aux
000004d8 T _fini
00000574 r __FRAME_END__
00001f14 d __CTOR_LIST__
00001f18 d __CTOR_END__
00001f1c d __DTOR_LIST__
00001f20 d __DTOR_END__
00001f24 d __JCR_END__
00001f24 d __JCR_LIST__
00001f28 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_
0000200c d __dso_handle
00002010 A __bss_start
00002010 A _edata
00002010 b completed.6159
00002014 b dtor_idx.6161
00002018 A _end
找到最接近0x478且比0x478下的地址,这个地址的函数就是发生crash的函数
使用c++filt将这个函数名打印出来
nap@nap-HP-431-Notebook-PC:~$ c++filt _Z8testFun4v
testFun4()
这样我们就找到了crash的函数。
一个动态库的实现:
头文件sample_fun.h
#ifndef _SAMPLE_FUN_H_ #define _SAMPLE_FUN_H_ void testFun4(); #endif
源文件sample_fun.cpp #include <stdio.h> #include "sample_fun.h" void testFun4() { int* p = NULL; printf("%d", *p); //will crash }
使用g++将这个源文件编译出动态库
g++ -fPIC -shared sample_fun.cpp -o libsample_fun.so
调用动态库的实现sample_main.cpp
#include <iostream> #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include "sample_fun.h" using namespace std; #define BUFFLEN 256 void testFun1(); void testFun2(); void testFun3(); int main(int argc, char** argv) { int pid = getpid(); char cmdBuf[BUFFLEN] = {0x00}; sprintf(cmdBuf, "cat /proc/%d/maps > /home/nap/%d.maps", pid, pid); //save current process maps system(cmdBuf); testFun1(); } void testFun1() { testFun2(); } void testFun2() { testFun3(); } void testFun3() { testFun4(); //call this function will crash }
将这个文件编译可执行程序并连接动态库
g++ sample_main.cpp -L. libsample_fun.so -o sample_main
运行着个程序发生了crash,并且生成了core文件,
./sample_main
Segmentation fault (core dumped)
通过gdb+core看到了crash的地址
GNU gdb (Ubuntu/Linaro 7.4-2012.04-0ubuntu2.1) 7.4-2012.04
Copyright (C) 2012 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law. Type "show copying"
and "show warranty" for details.
This GDB was configured as "i686-linux-gnu".
For bug reporting instructions, please see:
<http://bugs.launchpad.net/gdb-linaro/>...
Reading symbols from /home/nap/sample_main...(no debugging symbols found)...done.
[New LWP 4170]
warning: Can't read pathname for load map: Input/output error.
Core was generated by `./sample_main'.
Program terminated with signal 11, Segmentation fault.
#0 0xb773a478 in ???
(gdb) bt
#0 0xb773a478 in ???
#1 0x08048770 in ???
#2 0x08048763 in ???
(gdb)
通过查看进程的map可以看出crash的位置在libsample_fun.so的代码段,
08048000-08049000 r-xp 00000000 08:05 1059318 /home/nap/sample_main
08049000-0804a000 r--p 00000000 08:05 1059318 /home/nap/sample_main
0804a000-0804b000 rw-p 00001000 08:05 1059318 /home/nap/sample_main
b7449000-b744b000 rw-p 00000000 00:00 0
b744b000-b7467000 r-xp 00000000 08:05 1311741 /lib/i386-linux-gnu/libgcc_s.so.1
b7467000-b7468000 r--p 0001b000 08:05 1311741 /lib/i386-linux-gnu/libgcc_s.so.1
b7468000-b7469000 rw-p 0001c000 08:05 1311741 /lib/i386-linux-gnu/libgcc_s.so.1
b7469000-b7493000 r-xp 00000000 08:05 1315013 /lib/i386-linux-gnu/libm-2.15.so
b7493000-b7494000 r--p 00029000 08:05 1315013 /lib/i386-linux-gnu/libm-2.15.so
b7494000-b7495000 rw-p 0002a000 08:05 1315013 /lib/i386-linux-gnu/libm-2.15.so
b7495000-b7638000 r-xp 00000000 08:05 1310845 /lib/i386-linux-gnu/libc-2.15.so
b7638000-b763a000 r--p 001a3000 08:05 1310845 /lib/i386-linux-gnu/libc-2.15.so
b763a000-b763b000 rw-p 001a5000 08:05 1310845 /lib/i386-linux-gnu/libc-2.15.so
b763b000-b763f000 rw-p 00000000 00:00 0
b763f000-b7717000 r-xp 00000000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7717000-b7718000 ---p 000d8000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b7718000-b771c000 r--p 000d8000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b771c000-b771d000 rw-p 000dc000 08:05 1575071 /usr/lib/i386-linux-gnu/libstdc++.so.6.0.16
b771d000-b7724000 rw-p 00000000 00:00 0
b773a000-b773b000 r-xp 00000000 08:05 1059319 /home/nap/libsample_fun.so
b773b000-b773c000 r--p 00000000 08:05 1059319 /home/nap/libsample_fun.so
b773c000-b773d000 rw-p 00001000 08:05 1059319 /home/nap/libsample_fun.so
b773d000-b773f000 rw-p 00000000 00:00 0
b773f000-b7740000 r-xp 00000000 00:00 0 [vdso]
b7740000-b7760000 r-xp 00000000 08:05 1311879 /lib/i386-linux-gnu/ld-2.15.so
b7760000-b7761000 r--p 0001f000 08:05 1311879 /lib/i386-linux-gnu/ld-2.15.so
b7761000-b7762000 rw-p 00020000 08:05 1311879 /lib/i386-linux-gnu/ld-2.15.so
bf97d000-bf99e000 rw-p 00000000 00:00 0 [stack]
接下来我们要求出crash的函数在libsample_fun.so中的地址,计算方式如下
发生crash的地址 - 动态库的起始地址 + 偏移地址
在我们的例子中为0xb773a478 - 0xb773a000 + 0x00000000 = 0x478
通过 nm -n libsample_fun.so将这个动态库中的符号表按地址顺序输出
nap@nap-HP-431-Notebook-PC:~$ nm -n libsample_fun.so
w _Jv_RegisterClasses
w __cxa_finalize@@GLIBC_2.1.3
w __gmon_start__
U printf@@GLIBC_2.0
00000330 T _init
000003a0 t __do_global_dtors_aux
00000420 t frame_dummy
00000457 t __i686.get_pc_thunk.bx
0000045c T _Z8testFun4v
000004a0 t __do_global_ctors_aux
000004d8 T _fini
00000574 r __FRAME_END__
00001f14 d __CTOR_LIST__
00001f18 d __CTOR_END__
00001f1c d __DTOR_LIST__
00001f20 d __DTOR_END__
00001f24 d __JCR_END__
00001f24 d __JCR_LIST__
00001f28 a _DYNAMIC
00001ff4 a _GLOBAL_OFFSET_TABLE_
0000200c d __dso_handle
00002010 A __bss_start
00002010 A _edata
00002010 b completed.6159
00002014 b dtor_idx.6161
00002018 A _end
找到最接近0x478且比0x478下的地址,这个地址的函数就是发生crash的函数
使用c++filt将这个函数名打印出来
nap@nap-HP-431-Notebook-PC:~$ c++filt _Z8testFun4v
testFun4()
这样我们就找到了crash的函数。
相关文章推荐
- 腾讯云CentOS7安装LNMP+wordpress
- centos7的initrd.img解压缩
- Linux编程(文件描述符)
- 加锁
- Linux配置java环境
- Linux查询子网掩码网关DNS
- Linux 存储速度测试脚本
- linux命令(16)---文件权限管理命令
- Linux 发邮件磁盘空间监控(python)
- Ubuntu系统备份和恢复
- CentOS 6.X 下使用git远程提交
- CentOS 6.X 安装git客户端
- 7.3Linux中的任务计划实现详解
- 8.1Linux文件系统基础概念
- CentOS 6.X 下使用git远程提交
- CentOS 6.X 安装git客户端
- Linux部署ThinkPHP 验证码不显示
- firewall-cmd命令使用
- 安装ntfs-3g挂载ntfs格式硬盘=centos7自学之三
- ubuntu sublime 支持拼音输入的方法