libdlmalloc 是一个设计用于与 GDB 配合使用的 python 脚本,可用于分析 Doug Lea 分配器(又名 dlmalloc)。它目前支持 dlmalloc 2.8.x 版本。请注意,某些部分也可以独立于 GDB 使用,例如对某些快照的堆内存进行离线分析。
libdlmalloc 的灵感来源于其他用于分析堆的 gdb python 脚本,例如 libtalloc、unmask_jemalloc 和 libheap。某些基本功能与这些项目几乎完全相同。
libdlmalloc 主要在 32 位和 64 位 Cisco ASA 设备上进行了测试,这些设备使用 dlmalloc 2.8.3。它应该可以与其他 2.8.x 版本一起使用,但由于存在显著差异,它无法在更早的版本(例如 <= 2.7.x)上运行。
如果你在某个特定的 2.8.x 版本或特定设备上成功测试了 libdlmalloc,请告知作者,我们将更新文档。
该脚本只需要一个相对较新的、支持 python3 的 GDB 版本。我们主要是在 python3 上测试的,因此预计它在 python2.7 上目前会出问题。
如果你想使用 gdb 命令,可以使用:``` (gdb) source libdlmalloc_28x.py
大部分核心逻辑被拆分到了 `dl_helper` 类中,使你可以直接导入 libdlmalloc 并在 GDB 会话之外访问某些重要的结构体。如果你想离线分析 chunk/堆快照,这会非常有用。
# 用法
大部分功能都模仿了 unmask_jemalloc 和 libtalloc 中的做法,即提供一个独立的 GDB 命令。不过我们也使用了相当多的开关选项。
要查看当前支持的命令的完整列表,可以使用 `dlhelp` 命令:
## dlhelp
这是用于查看可用命令的主函数。每个命令都支持 `-h` 选项,通过该选项你可以获得更详细的使用说明。```
(gdb) dlhelp
[libdlmalloc] dlmalloc commands for gdb
[libdlmalloc] dlchunk : show one or more chunks metadata and contents
[libdlmalloc] dlmstate : print mstate structure information. caches address after first use
[libdlmalloc] dlcallback : register a callback or query/modify callback status
[libdlmalloc] dlhelp : this help message
[libdlmalloc] NOTE: Pass -h to any of these commands for more extensive usage. Eg: dlchunk -h
dlchunk 可以为你提供某个块的摘要,或更详细的
每个字段的信息。你还可以使用它列出关于
多个块的信息、搜索块等。dlchunk 的用法如下所示:```
(gdb) dlchunk -h
[libdlmalloc] usage: dlchunk [-v] [-f] [-x] [-c ]
[libdlmalloc] a dlmalloc chunk header
[libdlmalloc] -v use verbose output (multiples for more verbosity)
[libdlmalloc] -f use explicitly, rather than be smart
[libdlmalloc] -x hexdump the chunk contents
[libdlmalloc] -m max bytes to dump with -x
[libdlmalloc] -c number of chunks to print
[libdlmalloc] -s search pattern when print chunks
[libdlmalloc] --depth depth to search inside chunk
[libdlmalloc] -d debug and force printing stuff
[libdlmalloc] Flag legend: C=CINUSE, P=PINUSE
基本输出如下:```
(gdb) dlchunk 0xacff59d0
0xacff59d0 M sz:0x000f8 fl:CP
如你所见,你需要给它实际 dlmalloc 元数据本身的地址。要获得更详细的输出,可以使用 -v。```
(gdb) dlchunk -v 0xacff59d0
struct malloc_chunk @ 0xacff59d0 {
prev_foot = 0x8140d4d0
size = 0xf8 (CINUSE|PINUSE)
您还可以使用 `-c <count>` 选项列出多个相邻的块。```
(gdb) dlchunk -c 2 0xacff59d0
0xacff59d0 M sz:0x000f8 fl:CP
0xacff5ac8 M sz:0x00270 fl:CP
(gdb) dlchunk -v -c 2 0xacff59d0
struct malloc_chunk @ 0xacff59d0 {
prev_foot = 0x8140d4d0
size = 0xf8 (CINUSE|PINUSE)
--
struct malloc_chunk @ 0xacff5ac8 {
prev_foot = 0x8140d4d0
size = 0x270 (CINUSE|PINUSE)
-x 转储数据块的十六进制内容,
并使用 -m 控制要转储的字节数。```
(gdb) dlchunk -v -x -m 16 -c 2 0xacff59d0
struct malloc_chunk @ 0xacff59d0 {
prev_foot = 0x8140d4d0
size = 0xf8 (CINUSE|PINUSE)
0x10 bytes of chunk data:
0xacff59d8: 0xa11c0123 0x000000cc 0x00000000 0x00000000struct malloc_chunk @ 0xacff5ac8 { prev_foot = 0x8140d4d0 size = 0x270 (CINUSE|PINUSE) 0x10 bytes of chunk data: 0xacff5ad0: 0xa11c0123 0x00000244 0x00000000 0x00000000
您还可以在块内进行搜索。让我们在 2 个块中搜索该值
`0x00000244`,如上所述,该值仅出现在第二个块中。```
(gdb) dlchunk -s 0x00000244 -c 2 0xacff59d0
0xacff59d0 M sz:0x000f8 fl:CP [NO MATCH]
0xacff5ac8 M sz:0x00270 fl:CP [MATCH]
所搜索块数内的所有匹配项都将显示。让我们搜索 0xa11c01123,我们上面看到它同时存在于两个块中:```
(gdb) dlchunk -s 0xa11c0123 -c 2 0xacff59d0
0xacff59d0 M sz:0x000f8 fl:CP [MATCH]
0xacff5ac8 M sz:0x00270 fl:CP [MATCH]
## dlmstate