一、maps文件
maps文件可以查看某个进程的代码段、栈区、堆区、动态库、内核区对应的虚拟地址。
7f9c24b000-7f9c25f000 r-xp 00000000 00:02 3295 /lib64/libgcc_s.so.1
7f9c25f000-7f9c26e000 ---p 00014000 00:02 3295 /lib64/libgcc_s.so.1
7f9c26e000-7f9c26f000 r--p 00013000 00:02 3295 /lib64/libgcc_s.so.1
7f9c26f000-7f9c270000 rw-p 00014000 00:02 3295 /lib64/libgcc_s.so.1
7f9c270000-7f9c3cf000 r-xp 00000000 00:02 3306 /lib64/libc-2.29.so
7f9c3cf000-7f9c3de000 ---p 0015f000 00:02 3306 /lib64/libc-2.29.so
7f9c3de000-7f9c3e2000 r--p 0015e000 00:02 3306 /lib64/libc-2.29.so
7f9c3e2000-7f9c3e4000 rw-p 00162000 00:02 3306 /lib64/libc-2.29.so
第一列:虚拟地址空间的开始和结束地址vm_start - vm_end
第二列:虚拟地址空间的属性vm_flags
每种属性用一个字段:
r表示可读,w表示可写,x表示可执行,p和s共用一个字段,互斥关系,p表示私有段,s表示共享段,如果没有相应权限,则用-代替。
第三列:映射偏移。vm_pgoff 对有名映射,表示此段虚拟内存起始地址在文件中以页为单位的偏移。对匿名映射,它等于0或者vm_start/page_size。
第四列:映射文件所属设备号。对匿名映射来说,因为没有文件在磁盘上,所以没有设备号,始终为00:00。对有名映射来说,是映射的文件所在设备的设备号。
第五列:映射文件所属节点号。对匿名映射来说,因为没有文件在磁盘上,所以没有节点号,始终为0。对有名映射来说,是映射的文件的节点号。
第六列:映射文件名或堆、栈。对有名来说,是映射的文件名。对匿名映射来说,是此段虚拟内存在进程中的角色。[stack]表示在进程中作为栈使用,[heap]表示堆。其余情况则无显示。
查找pc和lr地址
程序发生异常时会生成中断发生时的地址pc和lr,此地址虚拟地址,可以使用maps定位对应的代码段
potentially unexpected fatal signal 7.
pc : 0000007f9c2ee138
lr : 0000000001034e68
sp : 0000007f27e20cc0
pc指针的值是0x7f9c2ee138,在maps中找到这个指针落在动态库libc-2.29.so所在的虚拟地址空间,该库的起始地址是0x7f9c270000,计算pc指针相对于起始地址的偏移地址为0x7e138。
反汇编
使用反汇编命令objdump,将libc-2.29.so动态库反汇编,并根据偏移地址定位代码段
objdump -d libc-2.29.so > libc.asm
打开libc.asm文件,查找0x7e138对应的代码段
000000000007e050 :
...
7e124: a93e08a1 stp x1, x2, [x5, #-32]
7e128: a93f0ca4 stp x4, x3, [x5, #-16]
7e12c: d65f03c0 ret
7e130: 92400c0e and x14, x0, #0xf
7e134: 927cec03 and x3, x0, #0xfffffffffffffff0
7e138: a940342c ldp x12, x13, [x1]
7e13c: cb0e0021 sub x1, x1, x14
7e140: 8b0e0042 add x2, x2, x14
...
由此可以看出,偏移地址0x7e138在memcpy中。但是代码中调用memcpy的地方太多了,所以还需要进一步定位lr指向的代码段。lr地址可使用相同方法定位,最终确定崩溃发生的代码段。