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

Linux利用maps文件和反汇编定位崩溃地址

一、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 <memcpy@@GLIBC_2.17>:
   ...	
   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地址可使用相同方法定位,最终确定崩溃发生的代码段。