菜鸟笔记
提升您的技术认知

linux64位系统 addr2line使用

简介

64位系统运行的可执行文件的符号表地址和实际运行时地址差异甚大。
譬如使用nm查看函数的地址为0x69207,但是运行时打印函数的地址为0x7FA3333F8207

那么我们通过backtrace,手动打印,gdb,pstack获取到函数调用栈信息时,如果可执行程序是经过strip过的,打印出来将是一堆0X7F开头的大地址(0x7FA3333F8207),使用addr2line直接进行定位,显示是??:00

原因是因为0x7FA3333F8207是动态映射的虚拟地址,该虚拟地址是通过而符号表地址(0x69207)+该代码段映射区间的地址(0x7fa33338f000)得来的。

那么我们如果要得到真正的代码位置,需要知道代码段映射地址区间,以及包含符号表信息的原始可执行程序

代码段映射地址区间

代码段映射地址区间是动态生成的,所以如果要获得真是的区间信息,必须再程序运行时通过命令
cat /proc/{pid}/smaps获取完整的映射信息。如果崩溃前没有完整的信息,那肯定就没法通过addr2line定位程序崩溃位置了。

程序运行以后,我们可以通过一下命令,获取的所有代码段映射地址区间:

cat /proc/{
  pid}/smaps | grep "[0-9a-z]\+\-[0-9a-z]\+ ..x."

拿flutter运行demo举例子,打印部分内容如下

00400000-00403000 r-xp 00000000 08:01 1061542                            /home/suchp/suchp_familly/github/project/myapp/build/linux/x64/debug/bundle/myapp
7fa2b0280000-7fa2b0300000 rwxp 00000000 00:00 0 
7fa2b0e00000-7fa2b0e80000 rwxp 00000000 00:00 0 
7fa2b1500000-7fa2b1580000 rwxp 00000000 00:00 0 
7fa2b1900000-7fa2b1980000 rwxp 00000000 00:00 0 
7fa2b1d00000-7fa2b1d80000 rwxp 00000000 00:00 0 
7fa2b2380000-7fa2b2400000 rwxp 00000000 00:00 0 
7fa2b2800000-7fa2b2880000 rwxp 00000000 00:00 0 
7fa2b3000000-7fa2b3080000 rwxp 00000000 00:00 0 
7fa2b3600000-7fa2b4000000 rwxp 00000000 00:00 0 
7fa2e0080000-7fa2e0100000 rwxp 00000000 00:00 0 
7fa2e0680000-7fa2e0700000 rwxp 00000000 00:00 0 
7fa2e107a000-7fa2e107f000 r-xp 00000000 08:01 1573497                    /usr/lib/x86_64-linux-gnu/gdk-pixbuf-2.0/2.10.0/loaders/libpixbufloader-png.so
7fa2e2275000-7fa2e2281000 r-xp 00000000 08:01 1447203                    /usr/lib/x86_64-linux-gnu/gio/modules/libdconfsettings.so
7fa2e2482000-7fa2e2493000 r-xp 00000000 08:01 1321733                    /usr/lib/x86_64-linux-gnu/libwayland-server.so.0.1.0
7fa2e2695000-7fa2e269c000 r-xp 00000000 08:01 1321798                    /usr/lib/x86_64-linux-gnu/libxcb-xfixes.so.0.0.0
7fa2e289d000-7fa2e28aa000 r-xp 00000000 08:01 1321015                    /usr/lib/x86_64-linux-gnu/libgbm.so.1.0.0
7fa2e2aac000-7fa2e2ae8000 r-xp 00000000 08:01 1320572                    /usr/lib/x86_64-linux-gnu/libEGL_mesa.so.0.0.0
7fa2e2cec000-7fa2e2cfe000 r-xp 00000000 08:01 1320570                    /usr/lib/x86_64-linux-gnu/libEGL.so.1.0.0

我们就可以知道代码地址在哪个区间中,从而知道该地址在哪个动态库中。
然后用虚拟地址0x7FA3333F8207减去左区间地址0x7fa33338f000即可得到真正的符号表地址

addr2line

使用addr2line

addr2line -f -e /usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.5600.4(未strip过的动态库或者可执行文件) 0x69207(符号表偏移地址)
g_shell_parse_argv
??:?