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