在 zxdb 中检查内存

Zxdb 支持使用以下命令检查内存:

aspace:显示映射的内存区域。

aspace 命令(缩写为 as)会输出该进程的地址空间信息。在紫红色中,虚拟内存由虚拟内存对象 (VMO) 层次结构组成。

如果不指定任何参数,aspace 命令会显示进程中的所有 VMO。

[zxdb] as

给定地址后,aspace 命令会显示仅包含该地址的 VMO 层次结构。 这对于确定地址在内存中的位置非常有用,因为 VMO 的名称通常指示具体的区域类型。

[zxdb] as 0x10b7f304d28

了解输出

在以下示例中,aspace 命令详细介绍了 0x10b7f304d28 地址的以下信息:

  • 包含地址的 VMO 的层次结构。
  • 每个 VMO 的地址和大小。
  • 每个 VMO 的名称,可以提供有关其用途的线索。
    • 从本例中的名称可以看出,该地址位于由 pthread 分配的堆栈中。
          Start              End   Size  Koid    Offset  Com.Pgs  Name
      0x1000000   0x7ffffffff000   127T                           proc:3109
      0x1000000   0x7ffffffff000   127T                             root
  0x10b7f104000    0x10b7f305000     2M                               useralloc
  0x10b7f105000    0x10b7f305000     2M  3824       0x0        2        pthread_t:0x10c4ea38b00

以下是可以在 aspace 命令输出中包含的相关 VMO 名称:

  • initial-thread:启动线程的堆栈。
  • pthread_t:0x...:pthread 创建的线程的堆栈。该地址指示该线程的“pthread_t 结构”的内存位置。
  • *uncompressed-bootfs:来自 bootfs(核心系统库)的内存映射库。libs 命令可以告知您该地址的库名称。
  • stack: msg of ...:启动堆栈。这个堆栈非常小,仅供动态链接器和加载器代码使用。
  • scudo:*:使用 Scudo 内存管理器分配的页面。如果进程使用的是 scudo,则这些区域是应用堆。
  • vdso/next:实现后续系统调用的内置库。
  • vdso/stable:用于实现稳定系统调用的内置库。
  • blob-*:来自 blobfs 的映射库。libs 命令可以告知您该地址的库名称。

如需详细了解 VMO,请使用命令 handle -k <koid>

“Cmt.Pgs”列显示了映射的 VMO 中该内存区域中已提交的页面(而非字节)的数量。对于 blob 和其他共享 VMO 等内存映射文件,这可能令人惊讶。

如果 VMO 为子级(如映射的 blob 一样),则原始数据将出现在父级 VMO 中,但实际映射的子级 VMO 会间接引用此数据。子项中只有那些因写入时复制而复制的页面才会被计为已提交。这就是为什么 Blob 和其他未修改文件的提交页数为 0 的原因。

mem-analyze:转储内存,尝试解释指针。

此命令会尝试将内存解释为指针,并对它们指向的内容进行解码。包含相应符号的地址会进行符号化处理,而其他地址则指示它们所属内存映射区域的名称(请参阅 aspace 命令)。这对于转储未知内存很有用。

[zxdb] ma 0x42ff9c2fdd30
       Address               Data
0x42ff9c2fdd30 0x00000000000015f0
0x42ff9c2fdd38 0x0000000000000008
0x42ff9c2fdd40 0x000042f401a8a730 ▷ ldso
0x42ff9c2fdd48 0x000042f401a8a9f8 ▷ $(dls3.app)
0x42ff9c2fdd50 0x0000000000000053
0x42ff9c2fdd58 0x0000000010469c6b
0x42ff9c2fdd60 0x000042f401a8a9f8 ▷ $(dls3.app)
0x42ff9c2fdd68 0x0000000000000000
0x42ff9c2fdd70 0x000042ff9c2fde70 ▷ inside map "stack: msg of 0x1000"
0x42ff9c2fdd78 0x000042f4015e5548 ▷ dls3 + 0x42b
0x42ff9c2fdd80 0x10469c6b10769c7b
0x42ff9c2fdd88 0x10569c3310469c23
0x42ff9c2fdd90 0x10469c2710469c37

另请参阅 stack,它是用于堆栈分析的 mem-analyze 命令的变体。

mem-read:转储进程内存

mem-read 命令(缩写为 x)可提供指定地址的十六进制转储。您可以提供地址,并视需要使用 -s 选项替换默认大小。

[zxdb] x -s 100 0x42ff9c2fdd30
0x42ff9c2fdd30:  f0 15 00 00 00 00 00 00-08 00 00 00 00 00 00 00  |
0x42ff9c2fdd40:  30 a7 a8 01 f4 42 00 00-f8 a9 a8 01 f4 42 00 00  |0    B       B
0x42ff9c2fdd50:  53 00 00 00 00 00 00 00-6b 9c 46 10 00 00 00 00  |S       k F
0x42ff9c2fdd60:  f8 a9 a8 01 f4 42 00 00-00 00 00 00 00 00 00 00  |     B
0x42ff9c2fdd70:  70 de 2f 9c ff 42 00 00-48 55 5e 01 f4 42 00 00  |p /  B  HU^  B
0x42ff9c2fdd80:  7b 9c 76 10 6b 9c 46 10-23 9c 46 10 33 9c 56 10  |{ v k F # F 3 V 
0x42ff9c2fdd90:  37 9c 46 10

您还可以提供计算结果为地址的表达式。如果指针的类型具有已知大小,则转储会自动显示相应数量的字节:

[zxdb] x &self->main_waker
0x1605a5d1ed0:  70 1a c8 36 47 04 00 00-68 fe 3d dd 25 01 00 00  |p  6G   h = %

stack-data:提供堆栈的低层级分析

stack-data 命令以与 mem-analyze 类似的方式分析堆栈。它默认为当前线程堆栈的顶部。stack-data 命令会尝试解码内存区域中存在的地址,但也会为线程的已知寄存器值和堆栈基址指针添加注解。

[zxdb] stack-data
      Address               Data
0x1605a5d1428 0x000042a352fca11f ◁ rsp. ▷ _zx_port_wait + 0x1f
0x1605a5d1430 0x000001605a5d1460 ◁ frame 1 rsp. ▷ inside map "initial-thread"
0x1605a5d1438 0x000001605a5d1540 ▷ inside map "initial-thread"
0x1605a5d1440 0x7fffffffffffffff
0x1605a5d1448 0x0000044ab6c81800 ▷ inside map "scudo:primary"
0x1605a5d1450 0x000001605a5d14d0 ◁ rbp, frame 1 base. ▷ inside map "initial-thread"
0x1605a5d1458 0x00000125dd3566f5 ▷ fuchsia_zircon_status::Status::ok
0x1605a5d1460 0x0000000000000000 ◁ frame 2 rsp
0x1605a5d1468 0x0000000000000000
0x1605a5d1470 0x0000000000000000
0x1605a5d1478 0x0000000000000000
0x1605a5d1480 0x0000000000000000 ◁ rdx, r14

在“备注”列中,向左箭头表示哪些寄存器指向该堆栈位置,而向右箭头表示堆栈入口点的值所指向的位置(如果应将其解译为地址)。

sym-near:将地址映射到符号

sym-near 命令(缩写为 sn)会尝试将地址映射到符号名称。运行此命令会输出位于相应地址中或该地址前面的符号的名称和行信息(如果有),最常用于指示指针指向什么。

[zxdb] sym-near 0x125dd3a845e
0x125dd3a845e, power_manager::main() • main.rs:37