问题
下列是一个c++的崩溃,使用addr2line可以根据地址反解获取到具体的崩溃代码,原理是什么?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24pid: 13195, tid: 32264, name: utonavi.minimap >>> com.autonavi.minimap <<<
signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0
x0 0000000000000000 x1 00000073a1384e80 x2 0000000000000037 x3 0000000000000002
x4 0000007346c91677 x5 00000073a1384eb7 x6 676f6c616964227b x7 5f49554e227b3a22
x8 0000000000000041 x9 00000073a1384e80 x10 000000729a8fb741 x11 4e4556455f49554e
x12 5f49554e223a2254 x13 0a7d7d2254494e49 x14 000000000001c020 x15 0000000034155555
x16 0000007367374138 x17 000000751e920160 x18 000000729a8fa210 x19 00000073673b9f88
x20 0000000000000000 x21 0000000000000000 x22 000000729a8fb740 x23 00000073673b9f58
x24 000000729a8fc000 x25 000000729a8fb759 x26 0000000000000000 x27 000000000000000c
x28 000000729a8fb740 x29 000000729a8fb7f0
sp 000000729a8fb740 lr 00000073668f4cbc pc 0000000000000000
backtrace:
#00 pc 0000000000000000 <unknown>
#01 pc 000000000024fcb8 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#02 pc 000000000028aa34 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#03 pc 000000000020a220 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#04 pc 0000000000293c44 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#05 pc 0000000000293ab4 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#06 pc 00000000002237c8 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#07 pc 0000000000213414 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#08 pc 0000000000213794 /data/app/~~wdXHTUGs3NOnlBosse3xOg==/com.autonavi.minimap-BalUzJbyL60S0Dsc4ib0eg==/lib/arm64/libamapvcs.so
#09 pc 00000000000f55c8 /apex/com.android.runtime/lib64/bionic/libc.so (_ZL15__pthread_startPv+208)
#10 pc 000000000008efbc /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68)经常听到c++的同学说带符号的so,带符号的so和不带符号的so有什么区别?
文件格式
ELF文件有三种类型,可以通过ELF Header中的e_type成员进行区分:
可重定位文件(Relocatable File):ETL_REL。一般为.o文件,可以与其他目标文件链接来创建可执行文件或共享目标文件的代码和数据。
可执行文件(Executable File):ET_EXEC。它是一个可以执行的程序,例如linux中的bash,gcc等。
共享目标文件(Shared Object File):ET_DYN。一般为.so文件。目前常见于Android中
如图所示,为ELF文件的基本结构,主要由四部分组成:
- ELF Header 描述了整个ELF文件的基础信息,以及Program Header和Section Header的信息。
- ELF Program Header Table 这部分内容主要是程序运行时需要,且每一个entry可能包含多个section表
- ELF Section Header Table 这部分内容主要是用于程序链接,且每一个entry只包含一个section表
- ELF Sections (symtab表和dynsym表都属于section)
ELF Header
1 | private final char[] magic = new char[4]; |
ELF Program Header
1 | public PHType pType; //类型 |
PHDR:此类型header元素描述了program header table自身的信息。
LOAD:代码段,数据段等信息
DYNAMIC:描述了动态链接的相关信息,比如依赖了哪些库。
NOTE:附加信息
GNU_RELRO:链接相关
GNU_EH_FRAME: 异常处理相关
ELF Section Header
1 | public int nameOffset; // 相对于.shstrtab表中虚拟地址的偏移,主要是要获取字符串的名字 |
Symbal Table
1 | public int symNameOff;//4 相对于字符表中的index位置 |