欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

Android系统开发之诊断原生代码崩溃问题分析

程序员文章站 2022-05-11 14:43:34
诊断原生代码崩溃问题 原生代码崩溃问题的类型 以下部分详细介绍了最常见的几类原生代码崩溃问题。每类崩溃问题都包含一段debuggerd输出示例,其中的关键证据可以帮助您区分特定类型的崩溃问题(以橙色...

诊断原生代码崩溃问题

原生代码崩溃问题的类型

以下部分详细介绍了最常见的几类原生代码崩溃问题。每类崩溃问题都包含一段debuggerd输出示例,其中的关键证据可以帮助您区分特定类型的崩溃问题(以橙色斜体突出显示)。

中止

中止操作很有趣,因为这是刻意而为。执行中止操作可通过多种不同的方法(包括调用abort(3)、使assert(3)失败、使用 android 特有的严重记录类型之一)来实现,但所有这些方法都涉及到调用abort。一般来说,abort调用会向调用线程发出 sigabrt 信号,因此为了识别这种情况,您需要在debuggerd输出中查找以下两项内容:libc.so中显示“abort”的帧,以及 sigabrt 信号。

如上文所述,您可能会看到明确的“中止消息”行。不过,您还应该查看logcat输出,了解此线程在刻意终止自身之前所记录的内容,因为与 assert(3) 或高级别的严重记录设备不同的是,abort(3) 不接受任何消息。

当前版本的 android 内嵌了tgkill(2)调用,因此它们的堆栈是最容易读取的,因为对 abort(3) 进行的调用位于最顶端:

pid: 4637, tid: 4637, name: crasher  >>> crasher <<<
signal 6 (sigabrt), code -6 (si_tkill), fault addr --------
abort message: 'some_file.c:123: some_function: assertion "false" failed'
 r0  00000000  r1  0000121d  r2  00000006  r3  00000008
 r4  0000121d  r5  0000121d  r6  ffb44a1c  r7  0000010c
 r8  00000000  r9  00000000  r10 00000000  r11 00000000
 ip  ffb44c20  sp  ffb44a08  lr  eace2b0b  pc  eace2b16
backtrace:
 #00 pc 0001cb16  /system/lib/libc.so (abort+57)
 #01 pc 0001cd8f  /system/lib/libc.so (__assert2+22)
 #02 pc 00001531  /system/bin/crasher (do_action+764)
 #03 pc 00002301  /system/bin/crasher (main+68)
 #04 pc 0008a809  /system/lib/libc.so (__libc_init+48)
 #05 pc 00001097  /system/bin/crasher (_start_main+38)
在原始中止调用(此处为帧 4)与实际发送信号(此处为帧 0)之间,较低版本的 android 需要遵循复杂的路径。特别是在 32 位 arm 上运行的 android,它在 __libc_android_abort(此处为帧 3)上添加了另外的平台序列 raise/pthread_kill/tgkill:

pid: 1656, tid: 1656, name: crasher  >>> crasher <<<
signal 6 (sigabrt), code -6 (si_tkill), fault addr --------
abort message: 'some_file.c:123: some_function: assertion "false" failed'
 r0 00000000  r1 00000678  r2 00000006  r3 f70b6dc8
 r4 f70b6dd0  r5 f70b6d80  r6 00000002  r7 0000010c
 r8 ffffffed  r9 00000000  sl 00000000  fp ff96ae1c
 ip 00000006  sp ff96ad18  lr f700ced5  pc f700dc98  cpsr 400b0010
backtrace:
 #00 pc 00042c98  /system/lib/libc.so (tgkill+12)
 #01 pc 00041ed1  /system/lib/libc.so (pthread_kill+32)
 #02 pc 0001bb87  /system/lib/libc.so (raise+10)
 #03 pc 00018cad  /system/lib/libc.so (__libc_android_abort+34)
 #04 pc 000168e8  /system/lib/libc.so (abort+4)
 #05 pc 0001a78f  /system/lib/libc.so (__libc_fatal+16)
 #06 pc 00018d35  /system/lib/libc.so (__assert2+20)
 #07 pc 00000f21  /system/xbin/crasher
 #08 pc 00016795  /system/lib/libc.so (__libc_init+44)
 #09 pc 00000abc  /system/xbin/crasher
您可以使用 crasher abort 重现此类崩溃问题的实例

纯 null 指针解引用
这是典型的原生代码崩溃问题,虽然它只是下一类崩溃问题的特殊情况,但值得单独说明,因为这类崩溃问题通常无需细细思量。

在以下示例中,尽管崩溃函数在 libc.so 中,但因为字符串函数仅在指定给它们的指针处进行操作,所以您可以推断出在调用 strlen(3) 时指定的是 null 指针;对于此类崩溃问题,应直接找调用代码的作者加以解决。在这种情况下,帧 #01 是不良调用程序。

pid: 25326, tid: 25326, name: crasher  >>> crasher <<<
signal 11 (sigsegv), code 1 (segv_maperr), fault addr 0x0
 r0 00000000  r1 00000000  r2 00004c00  r3 00000000
 r4 ab088071  r5 fff92b34  r6 00000002  r7 fff92b40
 r8 00000000  r9 00000000  sl 00000000  fp fff92b2c
 ip ab08cfc4  sp fff92a08  lr ab087a93  pc efb78988  cpsr 600d0030

backtrace:
 #00 pc 00019988  /system/lib/libc.so (strlen+71)
 #01 pc 00001a8f  /system/xbin/crasher (strlen_null+22)
 #02 pc 000017cd  /system/xbin/crasher (do_action+948)
 #03 pc 000020d5  /system/xbin/crasher (main+100)
 #04 pc 000177a1  /system/lib/libc.so (__libc_init+48)
 #05 pc 000010e4  /system/xbin/crasher (_start+96)
您可以使用 crasher strlen-null 重现此类崩溃问题的实例

低地址 null 指针解引用
在许多情况下,故障地址不会为 0,而是其他一些小数字。两位或三位地址尤其常见,而六位地址几乎肯定不是 null 指针解引用 - 这需要 1 mib 的偏移量。通常,当您有代码将 null 指针解引用为看似有效的结构时,就会发生这种情况。常见的函数是 fprintf(3)(或任何其他使用 file* 的函数)和 readdir(3),因为代码通常无法检查到底是 fopen(3) 先成功还是 opendir(3) 调用先成功。

以下是 readdir 的示例:

pid: 25405, tid: 25405, name: crasher  >>> crasher <<<
signal 11 (sigsegv), code 1 (segv_maperr), fault addr 0xc
 r0 0000000c  r1 00000000  r2 00000000  r3 3d5f0000
 r4 00000000  r5 0000000c  r6 00000002  r7 ff8618f0
 r8 00000000  r9 00000000  sl 00000000  fp ff8618dc
 ip edaa6834  sp ff8617a8  lr eda34a1f  pc eda618f6  cpsr 600d0030

backtrace:
 #00 pc 000478f6  /system/lib/libc.so (pthread_mutex_lock+1)
 #01 pc 0001aa1b  /system/lib/libc.so (readdir+10)
 #02 pc 00001b35  /system/xbin/crasher (readdir_null+20)
 #03 pc 00001815  /system/xbin/crasher (do_action+976)
 #04 pc 000021e5  /system/xbin/crasher (main+100)
 #05 pc 000177a1  /system/lib/libc.so (__libc_init+48)
 #06 pc 00001110  /system/xbin/crasher (_start+96)
在此示例中,崩溃问题的直接原因是 pthread_mutex_lock(3) 曾尝试访问地址 0xc(帧 0)。但是 pthread_mutex_lock 执行的第一项操作是解引用指定给它的 pthread_mutex_t* 的 state 元素。如果您查看源代码,则会发现该元素在结构中的偏移量为零,这表示指定给 pthread_mutex_lock 的指针 0xc 无效。从帧 1 可以看出,readdir 将该指针指定给它,这会从指定的 dir* 中提取 mutex_ 字段。通过查看该结构,您会发现 struct dir 中 mutex_ 的偏移量为 sizeof(int) + sizeof(size_t) + sizeof(dirent*),在 32 位设备上即 4 + 4 + 4 = 12 = 0xc,由此找到错误所在:调用程序向 readdir 传递了一个 null 指针。此时,您可以将该堆栈粘贴到堆栈工具中,以找出这个问题在 logcat 中的发生位置。

  struct dir {
 int fd_;
 size_t available_bytes_;
 dirent* next_;
 pthread_mutex_t mutex_;
 dirent buff_[15];
 long current_pos_;
  };
在大多数情况下,实际上您可以跳过此分析。一个充分的低位故障地址通常意味着您可以跳过堆栈中的任意 libc.so 帧,并直接归咎于调用的代码。但情况并非总是如此,这些例外将是您用作展示的绝佳机会。

您可以使用 crasher fprintf-null 或 crasher readdir-null 重现此类崩溃问题的实例

fortify 失败
fortify 失败是中止的一种特殊情况,当 c 库检测到可能导致安全漏洞的问题时,就会发生 fortify 失败。很多 c 库函数已得到加强;它们需要一个额外的参数来确定缓冲区的实际大小,并在运行时检查您尝试执行的操作是否真的适合。以下示例显示代码尝试 read(fd, buf, 32) 入实际上只有 10 字节长的缓冲区…

pid: 25579, tid: 25579, name: crasher  >>> crasher <<<
signal 6 (sigabrt), code -6 (si_tkill), fault addr --------
abort message: 'fortify: read: prevented 32-byte write into 10-byte buffer'
 r0 00000000  r1 000063eb  r2 00000006  r3 00000008
 r4 ff96f350  r5 000063eb  r6 000063eb  r7 0000010c
 r8 00000000  r9 00000000  sl 00000000  fp ff96f49c
 ip 00000000  sp ff96f340  lr ee83ece3  pc ee86ef0c  cpsr 000d0010

backtrace:
 #00 pc 00049f0c  /system/lib/libc.so (tgkill+12)
 #01 pc 00019cdf  /system/lib/libc.so (abort+50)
 #02 pc 0001e197  /system/lib/libc.so (__fortify_fatal+30)
 #03 pc 0001baf9  /system/lib/libc.so (__read_chk+48)
 #04 pc 0000165b  /system/xbin/crasher (do_action+534)
 #05 pc 000021e5  /system/xbin/crasher (main+100)
 #06 pc 000177a1  /system/lib/libc.so (__libc_init+48)
 #07 pc 00001110  /system/xbin/crasher (_start+96)
您可以使用 crasher fortify 重现此类型崩溃问题的实例

-fstack-protector 检测到的堆栈损坏
编译器的 -fstack-protector 选项会在具有栈上缓冲区的函数中插入检查机制,以防止缓冲区溢出。默认情况下,此选项会为平台代码而非应用启用。如果启用此选项,编译器会向函数序言添加指令,以在堆栈上写入刚刚超过上一局部值的随机值,并向函数结尾添加指令以进行回读并确认是否发生更改。如果该值已更改,则已被缓冲区溢出覆盖,因此该结尾会调用 __stack_chk_fail 来记录消息和中止。

pid: 26717, tid: 26717, name: crasher  >>> crasher <<<
signal 6 (sigabrt), code -6 (si_tkill), fault addr --------
abort message: 'stack corruption detected'
 r0 00000000  r1 0000685d  r2 00000006  r3 00000008
 r4 ffd516d8  r5 0000685d  r6 0000685d  r7 0000010c
 r8 00000000  r9 00000000  sl 00000000  fp ffd518bc
 ip 00000000  sp ffd516c8  lr ee63ece3  pc ee66ef0c  cpsr 000e0010

backtrace:
 #00 pc 00049f0c  /system/lib/libc.so (tgkill+12)
 #01 pc 00019cdf  /system/lib/libc.so (abort+50)
 #02 pc 0001e07d  /system/lib/libc.so (__libc_fatal+24)
 #03 pc 0004863f  /system/lib/libc.so (__stack_chk_fail+6)
 #04 pc 000013ed  /system/xbin/crasher (smash_stack+76)
 #05 pc 00001591  /system/xbin/crasher (do_action+280)
 #06 pc 00002219  /system/xbin/crasher (main+100)
 #07 pc 000177a1  /system/lib/libc.so (__libc_init+48)
 #08 pc 00001144  /system/xbin/crasher (_start+96)
您可以通过回溯中是否出现 __stack_chk_fail 以及特定中止消息将此中止与其他类型的中止区分开来。

您可以使用 crasher smash-stack 重现此类型崩溃问题的实例

崩溃转储
如果您现在没有正在调查的特定崩溃问题,则平台来源包括用于测试 debuggerd 的工具,名为 crasher。如果您在 system/core/debuggerd/ 中 mm,则您的路径中会出现 crasher 和 crasher64(您可以借助后者测试 64 位崩溃问题)。根据您提供的命令行参数,crasher 崩溃的方式多种多样。使用 crasher --help 可查看当前支持的选择。

为了介绍崩溃转储中的各个方面,我们来看看以下崩溃转储示例:

*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
build fingerprint: 'android/aosp_flounder/flounder:5.1.51/aosp/enh08201009:eng/test-keys'
revision: '0'
abi: 'arm'
pid: 1656, tid: 1656, name: crasher  >>> crasher <<<
signal 6 (sigabrt), code -6 (si_tkill), fault addr --------
abort message: 'some_file.c:123: some_function: assertion "false" failed'
 r0 00000000  r1 00000678  r2 00000006  r3 f70b6dc8
 r4 f70b6dd0  r5 f70b6d80  r6 00000002  r7 0000010c
 r8 ffffffed  r9 00000000  sl 00000000  fp ff96ae1c
 ip 00000006  sp ff96ad18  lr f700ced5  pc f700dc98  cpsr 400b0010
backtrace:
 #00 pc 00042c98  /system/lib/libc.so (tgkill+12)
 #01 pc 00041ed1  /system/lib/libc.so (pthread_kill+32)
 #02 pc 0001bb87  /system/lib/libc.so (raise+10)
 #03 pc 00018cad  /system/lib/libc.so (__libc_android_abort+34)
 #04 pc 000168e8  /system/lib/libc.so (abort+4)
 #05 pc 0001a78f  /system/lib/libc.so (__libc_fatal+16)
 #06 pc 00018d35  /system/lib/libc.so (__assert2+20)
 #07 pc 00000f21  /system/xbin/crasher
 #08 pc 00016795  /system/lib/libc.so (__libc_init+44)
 #09 pc 00000abc  /system/xbin/crasher
tombstone written to: /data/tombstones/tombstone_06
*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
如果您要搜索原生代码崩溃问题的日志,则带有空格的星号行很有帮助。字符串“*** ***”很少出现在日志中,除了在原生代码崩溃问题开始的时候。

build fingerprint:
'android/aosp_flounder/flounder:5.1.51/aosp/enh08201009:eng/test-keys'
您可以通过指纹准确识别崩溃问题发生的版本号。这与 ro.build.fingerprint 系统属性完全相同。

revision: '0'
revision 指的是硬件,而不是软件。通常情况下不使用 revision,但使用 revision 有助于您自动忽略由不良硬件导致的已知错误。这与 ro.revision 系统属性完全相同。

abi: 'arm'
abi 是 arm、arm64、mips、mips64、x86 或 x86-64 之一。这对上面提到的 stack 脚本最有用,这样它就知道要使用的工具链。

pid: 1656, tid: 1656, name: crasher >>> crasher <<<
此行可标识崩溃进程中的特定线程。在这种情况下,它是进程的主线程,因此进程 id 和线程 id 一致。第一个名称是线程名称,在 >>> 和 <<< 中间的名称是进程名称。对于应用,进程名称通常是完全限定的文件包名称(如 com.facebook.katana),这在提交错误或尝试在 google play 中查找相应应用时很有用。在查找崩溃问题之前的相关日志行方面,pid 和 tid 也很有用。

signal 6 (sigabrt), code -6 (si_tkill), fault addr --------
您可从该行得知接收的信号 (sigabrt) 以及有关如何接收该信号的更多信息 (si_tkill)。debuggerd 报告的信号是 sigabrt、sigbus、sigfpe、sigill、sigsegv 和 sigtrap。信号专用的代码因特定信号而异。

abort message: 'some_file.c:123: some_function: assertion "false" failed'
并非所有崩溃问题都会有中止消息行,但发生中止时,会出现该消息行。这是从此 pid/tid 的最后一行严重 logcat 输出中自动收集而来的,而在有意中止的情况下,这可以解释该程序自行终止的原因。

r0 00000000 r1 00000678 r2 00000006 r3 f70b6dc8
r4 f70b6dd0 r5 f70b6d80 r6 00000002 r7 0000010c
r8 ffffffed r9 00000000 sl 00000000 fp ff96ae1c
ip 00000006 sp ff96ad18 lr f700ced5 pc f700dc98 cpsr 400b0010
寄存器转储显示收到信号时 cpu 寄存器的内容。(本区段在各 abi 之间变化很大。)这些内容的有用程度取决于确切的崩溃问题。

backtrace:
 #00 pc 00042c98 /system/lib/libc.so (tgkill+12)
 #01 pc 00041ed1 /system/lib/libc.so (pthread_kill+32)
 #02 pc 0001bb87 /system/lib/libc.so (raise+10)
 #03 pc 00018cad /system/lib/libc.so (__libc_android_abort+34)
 #04 pc 000168e8 /system/lib/libc.so (abort+4)
 #05 pc 0001a78f /system/lib/libc.so (__libc_fatal+16)
 #06 pc 00018d35 /system/lib/libc.so (__assert2+20)
 #07 pc 00000f21 /system/xbin/crasher
 #08 pc 00016795 /system/lib/libc.so (__libc_init+44)
 #09 pc 00000abc /system/xbin/crasher
您可以通过回溯得知崩溃问题发生时我们所处的代码位置。第一列是帧号(与 gdb 的样式一致,其中最底下的帧是 0)。pc 值与共享库的位置(而非绝对地址)相关。下一列是映射区域的名称(通常是共享库或可执行文件,但可能不适用于经过 jit 编译的代码)。最后,如果有符号,则会显示与 pc 值对应的符号以及到该符号的偏移量(以字节为单位)。您可以结合使用此符号和 objdump(1) 来找到相应的编译器指令。

tombstone
tombstone written to: /data/tombstones/tombstone_06
您可由此得知 debuggerd 写入额外信息的位置。 debuggerd 会保留最多 10 个 tombstone,从编号 00 至 09 循环并根据需要覆盖现有 tombstone。

tombstone 包含与崩溃转储相同的信息,还包含一些其他信息。例如,它包含所有线程(不仅仅是崩溃线程)的回溯、浮点寄存器、原始堆栈转储,以及寄存器中地址周围的内存转储。最有用的是,它还包含完整的内存映射(类似于 /proc/pid/maps)。以下是 32 位 arm 进程崩溃的示例(带注释):

memory map: (fault address prefixed with --->)
--->ab15f000-ab162fff r-x 0 4000 /system/xbin/crasher (buildid:
b9527db01b5cf8f5402f899f64b9b121)
这里需要注意两点。第一点是该行带有前缀“--->”。当您的崩溃问题不仅仅是 null 指针解引用时,这些映射最有用。如果故障地址较小,则其很可能是 null 指针解引用的某个变体。否则,通过查看故障地址周围的映射,您通常可以了解发生的问题。通过查看映射可识别的一些可能存在的问题包括:

读/写延伸到内存块末尾之外。
在内存块开始之前读/写。
尝试执行非代码内容。
在堆栈末尾之外运行。
尝试写入代码(如上例所述)。
需要注意的第二点是,可执行文件和共享库文件将在 android m 和更高版本中显示 buildid(如果有),因此您可以确切地看到崩溃代码的版本。(从 android m 开始,平台二进制文件默认包含 buildid。ndk r12 和更高版本还会自动将 -wl,--build-id 传递到链接器。)

ab163000-ab163fff r--30001000  /system/xbin/crasher
ab164000-ab164fff rw-01000
f6c80000-f6d7ffff rw-0 100000  [anon:libc_malloc]
在 android 上,该堆不一定是单个区域。堆区域将被标记为 [anon:libc_malloc]。

f6d82000-f6da1fff r--0  20000  /dev/__properties__/u:object_r:logd_prop:s0
f6da2000-f6dc1fff r--0  20000  /dev/__properties__/u:object_r:default_prop:s0
f6dc2000-f6de1fff r--0  20000  /dev/__properties__/u:object_r:logd_prop:s0
f6de2000-f6de5fff r-x04000  /system/lib/libnetd_client.so (buildid: 08020aa06ed48cf9f6971861abf06c9d)
f6de6000-f6de6fff r--30001000  /system/lib/libnetd_client.so
f6de7000-f6de7fff rw-40001000  /system/lib/libnetd_client.so
f6dec000-f6e74fff r-x0  89000  /system/lib/libc++.so (buildid: 8f1f2be4b37d7067d366543fafececa2) (load base 0x2000)
f6e75000-f6e75fff ---01000
f6e76000-f6e79fff r--  890004000  /system/lib/libc++.so
f6e7a000-f6e7afff rw-  8d0001000  /system/lib/libc++.so
f6e7b000-f6e7bfff rw-01000  [anon:.bss]
f6e7c000-f6efdfff r-x0  82000  /system/lib/libc.so (buildid: d189b369d1aafe11feb7014d411bb9c3)
f6efe000-f6f01fff r--  810004000  /system/lib/libc.so
f6f02000-f6f03fff rw-  850002000  /system/lib/libc.so
f6f04000-f6f04fff rw-01000  [anon:.bss]
f6f05000-f6f05fff r--01000  [anon:.bss]
f6f06000-f6f0bfff rw-06000  [anon:.bss]
f6f0c000-f6f21fff r-x0  16000  /system/lib/libcutils.so (buildid: d6d68a419dadd645ca852cd339f89741)
f6f22000-f6f22fff r--  150001000  /system/lib/libcutils.so
f6f23000-f6f23fff rw-  160001000  /system/lib/libcutils.so
f6f24000-f6f31fff r-x0e000  /system/lib/liblog.so (buildid: e4d30918d1b1028a1ba23d2ab72536fc)
f6f32000-f6f32fff r--d0001000  /system/lib/liblog.so
f6f33000-f6f33fff rw-e0001000  /system/lib/liblog.so
通常,共享库会有 3 个相邻条目。一个是可读且可执行条目(代码),一个是只读条目(只读数据),还有一个是读写条目(可变数据)。第一列显示映射的地址范围,第二列显示权限(采用常规 unix ls(1) 样式),第三列显示到文件的偏移量(十六进制),第四列显示区域大小(十六进制),第五列显示文件(或其他区域名称)。

f6f34000-f6f53fff r-x0  20000  /system/lib/libm.so (buildid: 76ba45dcd9247e60227200976a02c69b)
f6f54000-f6f54fff ---01000
f6f55000-f6f55fff r--  200001000  /system/lib/libm.so
f6f56000-f6f56fff rw-  210001000  /system/lib/libm.so
f6f58000-f6f58fff rw-01000
f6f59000-f6f78fff r--0  20000  /dev/__properties__/u:object_r:default_prop:s0
f6f79000-f6f98fff r--0  20000  /dev/__properties__/properties_serial
f6f99000-f6f99fff rw-01000  [anon:linker_alloc_vector]
f6f9a000-f6f9afff r--01000  [anon:atexit handlers]
f6f9b000-f6fbafff r--0  20000  /dev/__properties__/properties_serial
f6fbb000-f6fbbfff rw-01000  [anon:linker_alloc_vector]
f6fbc000-f6fbcfff rw-01000  [anon:linker_alloc_small_objects]
f6fbd000-f6fbdfff rw-01000  [anon:linker_alloc_vector]
f6fbe000-f6fbffff rw-02000  [anon:linker_alloc]
f6fc0000-f6fc0fff r--01000  [anon:linker_alloc]
f6fc1000-f6fc1fff rw-01000  [anon:linker_alloc_lob]
f6fc2000-f6fc2fff r--01000  [anon:linker_alloc]
f6fc3000-f6fc3fff rw-01000  [anon:linker_alloc_vector]
f6fc4000-f6fc4fff rw-01000  [anon:linker_alloc_small_objects]
f6fc5000-f6fc5fff rw-01000  [anon:linker_alloc_vector]
f6fc6000-f6fc6fff rw-01000  [anon:linker_alloc_small_objects]
f6fc7000-f6fc7fff rw-01000  [anon:arc4random _rsx structure]
f6fc8000-f6fc8fff rw-01000  [anon:arc4random _rs structure]
f6fc9000-f6fc9fff r--01000  [anon:atexit handlers]
f6fca000-f6fcafff ---01000  [anon:thread signal stack guard page]
请注意,从 android 5.0 (lollipop) 开始,c 库会对其大部分匿名的映射区域进行命名,因此无名区域将会有所减少。

f6fcb000-f6fccfff rw- 0 2000 [stack:5081]
名为 [stack:tid] 的区域是指定线程的堆栈。

f6fcd000-f702afff r-x0  5e000  /system/bin/linker (buildid: 84f1316198deee0591c8ac7f158f28b7)
f702b000-f702cfff r--  5d0002000  /system/bin/linker
f702d000-f702dfff rw-  5f0001000  /system/bin/linker
f702e000-f702ffff rw-02000
f7030000-f7030fff r--01000
f7031000-f7032fff rw-02000
ffcd7000-ffcf7fff rw-0  21000
ffff0000-ffff0fff r-x01000  [vectors]
您看到的是 [vector] 还是 [vdso] 取决于架构。arm 使用 [vector],而所有其他架构均使用 [vdso]。