
Heap analysis tooling for dlmalloc
libdlmalloc은 GDB와 함께 사용하도록 설계된 python 스크립트로, Doug Lea의 할당자(일명 dlmalloc)를 분석하는 데 사용할 수 있습니다. 현재 dlmalloc 2.8.x 버전을 지원합니다. 일부 부분은 GDB와 독립적으로 사용할 수도 있습니다. 예를 들어 스냅샷된 힙 메모리의 오프라인 분석을 수행하는 데 사용할 수 있습니다.
libdlmalloc은 libtalloc, unmask_jemalloc, libheap 같은 힙 분석용 gdb python 스크립트에서 영감을 받았습니다. 일부 기본 기능은 이러한 프로젝트와 거의 동일합니다.
libdlmalloc은 주로 dlmalloc 2.8.3을 사용하는 32비트 및 64비트 Cisco ASA 장치에서 테스트되었습니다. 다른 2.8.x 버전에서도 작동해야 하지만, 상당한 차이로 인해 <= 2.7.x 같은 이전 릴리스에서는 작동하지 않습니다.
특정 2.8.x 릴리스나 특정 장치에서 libdlmalloc을 성공적으로 테스트한 경우 저자들에게 알려주시면 문서를 업데이트하겠습니다.
이 스크립트는 python3를 지원하는 비교적 최신 버전의 GDB만 요구합니다. 우리는 주로 python3에서 테스트했으므로 현재 python2.7에서는 작동하지 않을 것으로 예상합니다.
gdb 명령을 사용하려면 다음을 사용할 수 있습니다:``` (gdb) source libdlmalloc_28x.py
핵심 로직의 상당 부분은 `dl_helper` 클래스로 분리되어 있으며, 이를 통해
GDB 세션 외부에서 libdlmalloc을 직접 가져오고 특정 중요한 구조체에
액세스할 수 있습니다. 이는 오프라인 청크/힙 스냅샷을 분석하려는 경우
유용합니다.
# 사용법
대부분의 기능은 별도의 GDB 명령이 제공되는 unmask_jemalloc 및
libtalloc의 접근 방식을 모델로 합니다. 다만 상당수의 스위치도
사용합니다.
현재 지원되는 명령의 전체 목록을 보려면 `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를 사용하여 청크의 hex 내용을 덤프할 수 있으며, -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
청크 내부에서도 검색할 수 있습니다. 다음 값을 찾기 위해 두 개의 청크를 검색해 보겠습니다.
`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
`dlmstate` 명령은 개별 dlmalloc 힙 (`MSPACES`로 컴파일된 경우 일명 mspace)을 관리하는 데 사용되는
`mstate` 구조를 분석하는 데 사용할 수 있습니다. `-h` 스위치로 명령의
사용법을 확인할 수 있습니다.```
(gdb) dlmstate -h
[libdlmalloc] usage: dlmstate [-v] [-f] [-x] [-c <count>] <addr>
[libdlmalloc] <addr> a mstate struct addr. Optional if mstate cached
[libdlmalloc] -v use verbose output (multiples for more verbosity)
[libdlmalloc] -c print bin counts
[libdlmalloc] --depth how deep to count each bin (default 10)
[libdlmalloc] NOTE: Last defined mstate will be cached for future use
mstate를 보유한 주소를 알고 있다면(이는 보통 첫 번째 malloc asegment 안의 첫 번째 chunk입니다), 해당 주소를 dlmstate에 전달할 수 있습니다:``` (gdb) dlmstate 0xa8400008 struct dl_mstate @ 0xa8400008 { smallmap = 0b000000000000010000011111111100 treemap = 0b000000000000000000000000000111 dvsize = 0x0 topsize = 0x2ebdf040 least_addr = 0xa8400000 dv = 0x0 top = 0xad020f90 trim_check = 0x200000 magic = 0x2900d4d8 smallbin[00] (sz 0x0) = 0xa840002c, 0xa840002c [EMPTY] smallbin[01] (sz 0x8) = 0xa8400034, 0xa8400034 [EMPTY] smallbin[02] (sz 0x10) = 0xacbf7ad0, 0xa88647f0 smallbin[03] (sz 0x18) = 0xa95059b8, 0xa9689a20 smallbin[04] (sz 0x20) = 0xac79a028, 0xa87206f8 smallbin[05] (sz 0x28) = 0xacff0120, 0xa948a0f8 smallbin[06] (sz 0x30) = 0xac4e4af8, 0xacb56878 smallbin[07] (sz 0x38) = 0xacfe3880, 0xacfe0df0 smallbin[08] (sz 0x40) = 0xa9509b28, 0xa9509b28 smallbin[09] (sz 0x48) = 0xa8a1dc80, 0xa8a1dc80 smallbin[10] (sz 0x50) = 0xac782cb0, 0xac782cb0 smallbin[11] (sz 0x58) = 0xacbf7a88, 0xacbf7a88 [EMPTY] smallbin[12] (sz 0x60) = 0xac782c00, 0xac782c00 [EMPTY] smallbin[13] (sz 0x68) = 0xacbf7a78, 0xacbf7a78 [EMPTY] smallbin[14] (sz 0x70) = 0xa89b9650, 0xa89b9650 [EMPTY] smallbin[15] (sz 0x78) = 0xac789828, 0xac789828 [EMPTY] smallbin[16] (sz 0x80) = 0xa89b9738, 0xa94af740 smallbin[17] (sz 0x88) = 0xac4e5700, 0xac4e5700 [EMPTY] smallbin[18] (sz 0x90) = 0xac788030, 0xac788030 [EMPTY] smallbin[19] (sz 0x98) = 0xac782bc8, 0xac782bc8 [EMPTY] smallbin[20] (sz 0xa0) = 0xa89b9718, 0xa89b9718 [EMPTY] smallbin[21] (sz 0xa8) = 0xa8a1dc20, 0xa8a1dc20 [EMPTY] smallbin[22] (sz 0xb0) = 0xac782af8, 0xac782af8 [EMPTY] smallbin[23] (sz 0xb8) = 0xac789ed0, 0xac789ed0 [EMPTY] smallbin[24] (sz 0xc0) = 0xacbf7a20, 0xacbf7a20 [EMPTY] smallbin[25] (sz 0xc8) = 0xac789940, 0xac789940 [EMPTY] smallbin[26] (sz 0xd0) = 0xac789eb8, 0xac789eb8 [EMPTY] smallbin[27] (sz 0xd8) = 0xa94af6e8, 0xa94af6e8 [EMPTY] smallbin[28] (sz 0xe0) = 0xacbf78e8, 0xacbf78e8 [EMPTY] smallbin[29] (sz 0xe8) = 0xac4e4e68, 0xac4e4e68 [EMPTY] smallbin[30] (sz 0xf0) = 0xac4e5780, 0xac4e5780 [EMPTY] smallbin[31] (sz 0xf8) = 0xac7880b0, 0xac7880b0 [EMPTY] treebin[00] (sz 0x180) = 0xac783cb0 treebin[01] (sz 0x200) = 0xac789dc0 treebin[02] (sz 0x300) = 0xa883db48 treebin[03] (sz 0x400) = 0x0 [EMPTY] treebin[04] (sz 0x600) = 0x0 [EMPTY] treebin[05] (sz 0x800) = 0x0 [EMPTY] treebin[06] (sz 0xc00) = 0x0 [EMPTY] treebin[07] (sz 0x1000) = 0x0 [EMPTY] treebin[08] (sz 0x1800) = 0x0 [EMPTY] treebin[09] (sz 0x2000) = 0x0 [EMPTY] treebin[10] (sz 0x3000) = 0x0 [EMPTY] treebin[11] (sz 0x4000) = 0x0 [EMPTY] treebin[12] (sz 0x6000) = 0x0 [EMPTY] treebin[13] (sz 0x8000) = 0x0 [EMPTY] treebin[14] (sz 0xc000) = 0x0 [EMPTY] treebin[15] (sz 0x10000) = 0x0 [EMPTY] treebin[16] (sz 0x18000) = 0x0 [EMPTY] treebin[17] (sz 0x20000) = 0x0 [EMPTY] treebin[18] (sz 0x30000) = 0x0 [EMPTY] treebin[19] (sz 0x40000) = 0x0 [EMPTY] treebin[20] (sz 0x60000) = 0x0 [EMPTY] treebin[21] (sz 0x80000) = 0x0 [EMPTY] treebin[22] (sz 0xc0000) = 0x0 [EMPTY] treebin[23] (sz 0x100000) = 0x0 [EMPTY] treebin[24] (sz 0x180000) = 0x0 [EMPTY] treebin[25] (sz 0x200000) = 0x0 [EMPTY] treebin[26] (sz 0x300000) = 0x0 [EMPTY] treebin[27] (sz 0x400000) = 0x0 [EMPTY] treebin[28] (sz 0x600000) = 0x0 [EMPTY] treebin[29] (sz 0x800000) = 0x0 [EMPTY] treebin[30] (sz 0xc00000) = 0x0 [EMPTY] treebin[31] (sz 0xffffffff) = 0x0 [EMPTY] footprint = 0x33800000 max_footprint = 0x33800000 mflags = 0x7 mutex = 0x0,0x0,0x0,0x0,0xa8400000, seg = struct malloc_segment @ 0xa84001d4 { base = 0xa8400000 size = 0x33800000 next = 0x0 sflags = 0x8
출력 속도를 높이기 위해 느린 장치에서는 마지막으로 읽은 mstate 데이터를 캐시합니다. 따라서 dlmstate를 다시 실행하면 이전에 덤프된 출력(물론 오래된 것일 수 있음)이 표시됩니다.```
(gdb) dlmstate
[libdlmalloc] Using cached mstate
struct dl_mstate @ 0xa8400008 {
smallmap = 0b000000000000010000011111111100
treemap = 0b000000000000000000000000000111
dvsize = 0x0
topsize = 0x2ebdf040
least_addr = 0xa8400000
dv = 0x0
top = 0xad020f90
trim_check = 0x200000
magic = 0x2900d4d8
smallbin[00] (sz 0x0) = 0xa840002c, 0xa840002c [EMPTY]
smallbin[01] (sz 0x8) = 0xa8400034, 0xa8400034 [EMPTY]
smallbin[02] (sz 0x10) = 0xacbf7ad0, 0xa88647f0
smallbin[03] (sz 0x18) = 0xa95059b8, 0xa9689a20
[...]
-c 스위치는 지정된 bin의 청크 수를 계산하는 데 사용할 수 있습니다. 참고로
시리얼 라인을 통해 디버깅하는 경우 이 작업이 상당히 느릴 수 있으므로, 계산할
bin 항목 수를 제한하는 --depth 옵션도 제공합니다. 기본적으로 깊이는
10으로 설정됩니다:```
(gdb) dlmstate -c
[libdlmalloc] Using cached mstate
smallbin[00] (sz 0x0) = 0xa840002c, 0xa840002c [EMPTY] smallbin[01] (sz 0x8) = 0xa8400034, 0xa8400034 [EMPTY] smallbin[02] (sz 0x10) = 0xacbf7ad0, 0xa88647f0 [10+] smallbin[03] (sz 0x18) = 0xa95059b8, 0xa9689a20 [10+] smallbin[04] (sz 0x20) = 0xac79a028, 0xa87206f8 [10+] smallbin[05] (sz 0x28) = 0xacff0120, 0xa948a0f8 [10+] smallbin[06] (sz 0x30) = 0xac4e4af8, 0xacb56878 [10+] smallbin[07] (sz 0x38) = 0xacfe3880, 0xacfe0df0 [10] smallbin[08] (sz 0x40) = 0xa9509b28, 0xa9509b28 [2] smallbin[09] (sz 0x48) = 0xa8a1dc80, 0xa8a1dc80 [2] smallbin[10] (sz 0x50) = 0xac782cb0, 0xac782cb0 [2] [...]
표시된 바와 같이 개수는 bin 내용물의 오른쪽 대괄호 안에 표시됩니다.
우리는 mstate 비트맵을 사용하여 bin이 비어 있는지 먼저 테스트하므로, 가끔 힙을 가리키는 유효한 포인터를 가지지만 `[EMPTY]`로 표시된 bin 항목을 볼 수 있습니다. 이 포인터들은 그 시점에서는 단지 오래된 것입니다.
## dlcallback
우리는 플러그인 간 콜백(inter-plugin callback) 개념을 지원합니다. 지정된 모듈에 콜백 함수를 등록할 수 있으며, 해당 함수는 조사 대상의 상태에 대한 여러 정보를 담은 dict와 함께 호출됩니다.
콜백은 dlchunk와 dlmstate가 인수를 가지고 수행하는 작업을 모두 마쳤을 때 호출됩니다.
사용법은 `-h` 스위치로 확인할 수 있습니다:```
(gdb) dlcallback -h
[libdlmalloc] usage: dlcallback <option>
[libdlmalloc] disable temporarily disable the registered callback
[libdlmalloc] enable enable the registered callback
[libdlmalloc] status check if a callback is registered
[libdlmalloc] clear forget the registered callback
[libdlmalloc] register <name> <module> use a global function <name> as callback from <module>
[libdlmalloc] ex: register mpcallback libmempool/libmempool
이 기능을 시연하기 위해, 별도의 GDB 플러그인인 libmempool용으로 개발한 콜백을 사용할 것입니다,``` (gdb) dlcallback register mpcallback libmempool/libmempool [libmempool] loaded [libdlmalloc] mpcallback registered as callback (gdb) dlcallback status [libdlmalloc] a callback is registered and enabled
이제 dlchunk와 같은 명령을 사용하면 몇 가지 추가 주석을 볼 수 있습니다:```
(gdb) dlchunk 0xacff59d0
0xacff59d0 M sz:0x000f8 fl:CP alloc_pc:0x08262b45,-
(gdb) dlchunk -v 0xacff59d0
struct malloc_chunk @ 0xacff59d0 {
prev_foot = 0x8140d4d0
size = 0xf8 (CINUSE|PINUSE)
struct mp_header @ 0xacff59d8 {
mh_magic = 0xa11c0123
mh_len = 0xcc
mh_refcount = 0x0
mh_unused = 0x0
mh_fd_link = 0xa9515ed0 (OK)
mh_bk_link = 0xa84005c4 (-)
alloc_pc = 0x8262b45 (-)
free_pc = 0x0 (-)
마찬가지로, dlmstate에 표시된 기본 dlmalloc mstate에 훨씬 더 많은 데이터가 추가된 것을 볼 수 있습니다:``` (gdb) dlmstate [libdlmalloc] Using cached mstate struct dl_mstate @ 0xa8400008 { smallmap = 0b000000000000010000011111111100 treemap = 0b000000000000000000000000000111 dvsize = 0x0 topsize = 0x2ebdf040 least_addr = 0xa8400000 dv = 0x0 top = 0xad020f90 trim_check = 0x200000 magic = 0x2900d4d8 smallbin[00] (sz 0x0) = 0xa840002c, 0xa840002c [EMPTY] smallbin[01] (sz 0x8) = 0xa8400034, 0xa8400034 [EMPTY] smallbin[02] (sz 0x10) = 0xacbf7ad0, 0xa88647f0 smallbin[03] (sz 0x18) = 0xa95059b8, 0xa9689a20 smallbin[04] (sz 0x20) = 0xac79a028, 0xa87206f8 smallbin[05] (sz 0x28) = 0xacff0120, 0xa948a0f8 smallbin[06] (sz 0x30) = 0xac4e4af8, 0xacb56878 smallbin[07] (sz 0x38) = 0xacfe3880, 0xacfe0df0 smallbin[08] (sz 0x40) = 0xa9509b28, 0xa9509b28 smallbin[09] (sz 0x48) = 0xa8a1dc80, 0xa8a1dc80 smallbin[10] (sz 0x50) = 0xac782cb0, 0xac782cb0 smallbin[11] (sz 0x58) = 0xacbf7a88, 0xacbf7a88 [EMPTY] smallbin[12] (sz 0x60) = 0xac782c00, 0xac782c00 [EMPTY] smallbin[13] (sz 0x68) = 0xacbf7a78, 0xacbf7a78 [EMPTY] smallbin[14] (sz 0x70) = 0xa89b9650, 0xa89b9650 [EMPTY] smallbin[15] (sz 0x78) = 0xac789828, 0xac789828 [EMPTY] smallbin[16] (sz 0x80) = 0xa89b9738, 0xa94af740 smallbin[17] (sz 0x88) = 0xac4e5700, 0xac4e5700 [EMPTY] smallbin[18] (sz 0x90) = 0xac788030, 0xac788030 [EMPTY] smallbin[19] (sz 0x98) = 0xac782bc8, 0xac782bc8 [EMPTY] smallbin[20] (sz 0xa0) = 0xa89b9718, 0xa89b9718 [EMPTY] smallbin[21] (sz 0xa8) = 0xa8a1dc20, 0xa8a1dc20 [EMPTY] smallbin[22] (sz 0xb0) = 0xac782af8, 0xac782af8 [EMPTY] smallbin[23] (sz 0xb8) = 0xac789ed0, 0xac789ed0 [EMPTY] smallbin[24] (sz 0xc0) = 0xacbf7a20, 0xacbf7a20 [EMPTY] smallbin[25] (sz 0xc8) = 0xac789940, 0xac789940 [EMPTY] smallbin[26] (sz 0xd0) = 0xac789eb8, 0xac789eb8 [EMPTY] smallbin[27] (sz 0xd8) = 0xa94af6e8, 0xa94af6e8 [EMPTY] smallbin[28] (sz 0xe0) = 0xacbf78e8, 0xacbf78e8 [EMPTY] smallbin[29] (sz 0xe8) = 0xac4e4e68, 0xac4e4e68 [EMPTY] smallbin[30] (sz 0xf0) = 0xac4e5780, 0xac4e5780 [EMPTY] smallbin[31] (sz 0xf8) = 0xac7880b0, 0xac7880b0 [EMPTY] treebin[00] (sz 0x180) = 0xac783cb0 treebin[01] (sz 0x200) = 0xac789dc0 treebin[02] (sz 0x300) = 0xa883db48 treebin[03] (sz 0x400) = 0x0 [EMPTY] treebin[04] (sz 0x600) = 0x0 [EMPTY] treebin[05] (sz 0x800) = 0x0 [EMPTY] treebin[06] (sz 0xc00) = 0x0 [EMPTY] treebin[07] (sz 0x1000) = 0x0 [EMPTY] treebin[08] (sz 0x1800) = 0x0 [EMPTY] treebin[09] (sz 0x2000) = 0x0 [EMPTY] treebin[10] (sz 0x3000) = 0x0 [EMPTY] treebin[11] (sz 0x4000) = 0x0 [EMPTY] treebin[12] (sz 0x6000) = 0x0 [EMPTY] treebin[13] (sz 0x8000) = 0x0 [EMPTY] treebin[14] (sz 0xc000) = 0x0 [EMPTY] treebin[15] (sz 0x10000) = 0x0 [EMPTY] treebin[16] (sz 0x18000) = 0x0 [EMPTY] treebin[17] (sz 0x20000) = 0x0 [EMPTY] treebin[18] (sz 0x30000) = 0x0 [EMPTY] treebin[19] (sz 0x40000) = 0x0 [EMPTY] treebin[20] (sz 0x60000) = 0x0 [EMPTY] treebin[21] (sz 0x80000) = 0x0 [EMPTY] treebin[22] (sz 0xc0000) = 0x0 [EMPTY] treebin[23] (sz 0x100000) = 0x0 [EMPTY] treebin[24] (sz 0x180000) = 0x0 [EMPTY] treebin[25] (sz 0x200000) = 0x0 [EMPTY] treebin[26] (sz 0x300000) = 0x0 [EMPTY] treebin[27] (sz 0x400000) = 0x0 [EMPTY] treebin[28] (sz 0x600000) = 0x0 [EMPTY] treebin[29] (sz 0x800000) = 0x0 [EMPTY] treebin[30] (sz 0xc00000) = 0x0 [EMPTY] treebin[31] (sz 0xffffffff) = 0x0 [EMPTY] footprint = 0x33800000 max_footprint = 0x33800000 mflags = 0x7 mutex = 0x0,0x0,0x0,0x0,0xa8400000, seg = struct malloc_segment @ 0xa84001d4 { base = 0xa8400000 size = 0x33800000 next = 0x0 sflags = 0x8 struct mp_mstate @ 0xa84001e4 { mp_smallbin[00] - sz: 0x00000000 cnt: 0x0000, mh_fd_link: 0x0 mp_smallbin[01] - sz: 0x00000008 cnt: 0x0000, mh_fd_link: 0x0 mp_smallbin[02] - sz: 0x00000010 cnt: 0x0000, mh_fd_link: 0x0 mp_smallbin[03] - sz: 0x00000018 cnt: 0x0000, mh_fd_link: 0x0 mp_smallbin[04] - sz: 0x00000020 cnt: 0x0000, mh_fd_link: 0x0 mp_smallbin[05] - sz: 0x00000028 cnt: 0x0000, mh_fd_link: 0x0 mp_smallbin[06] - sz: 0x00000030 cnt: 0x0213, mh_fd_link: 0xacfdf800 mp_smallbin[07] - sz: 0x00000038 cnt: 0x0cb3, mh_fd_link: 0xaae0ff70 mp_smallbin[08] - sz: 0x00000040 cnt: 0x1c99, mh_fd_link: 0xac4e4b30 mp_smallbin[09] - sz: 0x00000048 cnt: 0x027b, mh_fd_link: 0xaae0fe30 mp_smallbin[10] - sz: 0x00000050 cnt: 0x0415, mh_fd_link: 0xac782c68 mp_smallbin[11] - sz: 0x00000058 cnt: 0x012d, mh_fd_link: 0xac799fd8 mp_smallbin[12] - sz: 0x00000060 cnt: 0x0125, mh_fd_link: 0xacbf7a78 mp_smallbin[13] - sz: 0x00000068 cnt: 0x0a06, mh_fd_link: 0xac789b78 mp_smallbin[14] - sz: 0x00000070 cnt: 0x003e, mh_fd_link: 0xa9515fc8 mp_smallbin[15] - sz: 0x00000078 cnt: 0x0074, mh_fd_link: 0xac789830 mp_smallbin[16] - sz: 0x00000080 cnt: 0x0124, mh_fd_link: 0xac7827a0 mp_smallbin[17] - sz: 0x00000088 cnt: 0x0016, mh_fd_link: 0xac799f50 mp_smallbin[18] - sz: 0x00000090 cnt: 0x0025, mh_fd_link: 0xac784e58 mp_smallbin[19] - sz: 0x00000098 cnt: 0x004e, mh_fd_link: 0xac4e56f8 mp_smallbin[20] - sz: 0x000000a0 cnt: 0x01c8, mh_fd_link: 0xacfefbf0 mp_smallbin[21] - sz: 0x000000a8 cnt: 0x0189, mh_fd_link: 0xacff05e0 mp_smallbin[22] - sz: 0x000000b0 cnt: 0x00e9, mh_fd_link: 0xacbf79c8 mp_smallbin[23] - sz: 0x000000b8 cnt: 0x0165, mh_fd_link: 0xac96be20 mp_smallbin[24] - sz: 0x000000c0 cnt: 0x0017, mh_fd_link: 0xac789a50 mp_smallbin[25] - sz: 0x000000c8 cnt: 0x001a, mh_fd_link: 0xacb4d998 mp_smallbin[26] - sz: 0x000000d0 cnt: 0x004d, mh_fd_link: 0xa9519150 mp_smallbin[27] - sz: 0x000000d8 cnt: 0x0024, mh_fd_link: 0xacbf78f0 mp_smallbin[28] - sz: 0x000000e0 cnt: 0x002c, mh_fd_link: 0xacff49d8 mp_smallbin[29] - sz: 0x000000e8 cnt: 0x0014, mh_fd_link: 0xa89b9658 mp_smallbin[30] - sz: 0x000000f0 cnt: 0x0008, mh_fd_link: 0xacfde720 mp_smallbin[31] - sz: 0x000000f8 cnt: 0x0044, mh_fd_link: 0xacff59d8 mp_treebin[00] - sz: 0x00000180 cnt: 0x0190, mh_fd_link: 0xacb48318 mp_treebin[01] - sz: 0x00000200 cnt: 0x0134, mh_fd_link: 0xa95059d8 mp_treebin[02] - sz: 0x00000300 cnt: 0x01ac, mh_fd_link: 0xad01cd38 mp_treebin[03] - sz: 0x00000400 cnt: 0x004e, mh_fd_link: 0xacffbac8 mp_treebin[04] - sz: 0x00000600 cnt: 0x0073, mh_fd_link: 0xac4e4fa0 mp_treebin[05] - sz: 0x00000800 cnt: 0x0030, mh_fd_link: 0xacfebe20 mp_treebin[06] - sz: 0x00000c00 cnt: 0x0277, mh_fd_link: 0xac7887e8 mp_treebin[07] - sz: 0x00001000 cnt: 0x004f, mh_fd_link: 0xa9507570 mp_treebin[08] - sz: 0x00001800 cnt: 0x0041, mh_fd_link: 0xac784fa8 mp_treebin[09] - sz: 0x00002000 cnt: 0x0010, mh_fd_link: 0xac74f248 mp_treebin[10] - sz: 0x00003000 cnt: 0x0024, mh_fd_link: 0xac796020 mp_treebin[11] - sz: 0x00004000 cnt: 0x0028, mh_fd_link: 0xacf9a3e0 mp_treebin[12] - sz: 0x00006000 cnt: 0x009a, mh_fd_link: 0xad01cf68 mp_treebin[13] - sz: 0x00008000 cnt: 0x000b, mh_fd_link: 0xacae3978 mp_treebin[14] - sz: 0x0000c000 cnt: 0x0027, mh_fd_link: 0xad014678 mp_treebin[15] - sz: 0x00010000 cnt: 0x000b, mh_fd_link: 0xacab7098 mp_treebin[16] - sz: 0x00018000 cnt: 0x0062, mh_fd_link: 0xacafa7c8 mp_treebin[17] - sz: 0x00020000 cnt: 0x0007, mh_fd_link: 0xac2cda88 mp_treebin[18] - sz: 0x00030000 cnt: 0x0012, mh_fd_link: 0xac800720 mp_treebin[19] - sz: 0x00040000 cnt: 0x000a, mh_fd_link: 0xac6e21e0 mp_treebin[20] - sz: 0x00060000 cnt: 0x0006, mh_fd_link: 0xaa5b0f28 mp_treebin[21] - sz: 0x00080000 cnt: 0x0004, mh_fd_link: 0xacf152e8 mp_treebin[22] - sz: 0x000c0000 cnt: 0x000e, mh_fd_link: 0xaac896f0 mp_treebin[23] - sz: 0x00100000 cnt: 0x0000, mh_fd_link: 0x0 mp_treebin[24] - sz: 0x00180000 cnt: 0x0004, mh_fd_link: 0xa934b730 mp_treebin[25] - sz: 0x00200000 cnt: 0x0001, mh_fd_link: 0xaa6d6cc8 mp_treebin[26] - sz: 0x00300000 cnt: 0x0003, mh_fd_link: 0xacc1feb0 mp_treebin[27] - sz: 0x00400000 cnt: 0x0001, mh_fd_link: 0xa8f39370 mp_treebin[28] - sz: 0x00600000 cnt: 0x0000, mh_fd_link: 0x0 mp_treebin[29] - sz: 0x00800000 cnt: 0x0001, mh_fd_link: 0xa9689a40 mp_treebin[30] - sz: 0x00c00000 cnt: 0x0001, mh_fd_link: 0xaae41208 mp_treebin[31] - sz: 0xffffffff cnt: 0x0001, mh_fd_link: 0xab641738 [UNSORTED]
## 콜백 사전
현재 우리는 libdlmalloc에서 콜백 함수로 많은 정보를 그냥 내보내며, 콜백 함수는 그 정보를 가지고 원하는 대로 처리할 수 있습니다. 대부분의 콜백이 필요로 하는 것보다 더 많은 정보를 제공합니다. 또한 콜백은 표시할 추가 정보를 결정하기 위해 콜백을 발생시킨 플러그인을 인식하고 있어야 할 것으로 기대됩니다. 반대로, 콜백을 호출하는 플러그인(이 경우 libdlmalloc)은 이 외부 콜백 제공자가 수행하는 어떤 것에 대해서도 알 필요가 없고(또는 신경 쓸 필요도 없습니다).
콜백 함수에 제공하는 데이터의 예는 다음과 같습니다:
* `caller`: 호출하는 gdb 명령 또는 함수의 이름
* `allocator`: 청크 주소를 관리하는 백킹 할당자
* `addr`: 코어 할당자의 메타데이터 이후의 청크 내용 주소
* `hdr_sz`: 코어 할당자 메타데이터 헤더의 크기
* `chunksz`: 코어 할당자 메타데이터 헤더에 따른 청크 크기
* `min_hdr_sz`: 이 코어 할당자에 대해 가능한 최소 헤더 크기
* `data_size`: `addr`에 있는 데이터의 크기
* `inuse`: 코어 할당자에 따라 청크가 사용 중인지 여부
* `chunk_info`: 호출 라이브러리가 청크 정보를 출력하는지 여부
* `size_sz`: 디버깅 대상 플랫폼에서 계산된 `size_t` 데이터 타입의 크기
# 향후 개발
향후 Cisco ASA 연구를 하면서 필요에 따라 libdlmalloc에 기능을 추가할 가능성이 높습니다. 현재 계획된 추가 사항은 다음과 같습니다:
- libheap이나 shadow의 최신 설계와 비슷하게 디버그 엔진 로직을 추상화
- 모든 msegment를 탐색하여 특정 값을 검색하는 `dlsearch` 작성
- 해제된(free) 청크를 위한 dlchunk 옵션으로, 링키지를 따라가며 빈(bin)을 찾아 연결된 `mstate` 베이스 주소를 추론
# dlmalloc 참고 사항
## dlmalloc vs ptmalloc
glibc의 일부인 ptmalloc 할당자는 dlmalloc에서 정기적으로 포크되었습니다. 다음 표는 버전 간의 관계를 보여줍니다:
| dlmalloc | ptmalloc | 빈(bin) 유형 |
| -------------- | --------- | ---------------------------- |
| dlmalloc 2.5.x | N/A | bins |
| dlmalloc 2.6.x | ptmalloc | smallbins/bins |
| dlmalloc 2.7.x | ptmalloc2 | fastbins/smallbins/largebins |
| dlmalloc 2.8.x | ptmalloc3 | smallbins/treebins |
## 참고 자료
dlmalloc 2.8.x는 대형 할당에 트리 구조를 사용한다는 점 등 여러 면에서 이전 dlmalloc 버전과 다릅니다. 가장 좋은 문서는 [소스 코드](http://g.oswego.edu/pub/misc/)입니다. ptmalloc2와 ptmalloc3의 차이점(dlmalloc 2.7.x와 2.8.x의 차이에 해당)에 대한 좋은 배경 지식을 원한다면 blackngel의 Phrack 67 논문 [The House Of Lore: Reloaded](http://phrack.org/issues/67/8.html)를 참조하세요.
# 문의
이 도구에 대한 피드백을 환영하며, 풀 리퀘스트도 기꺼이 받습니다.
* Aaron Adams
* Email: `aaron<dot>adams<at>nccgroup<dot>trust`
* Twitter: @fidgetingbits
* Cedric Halbronn
* Email: `cedric<dot>halbronn<at>nccgroup<dot>trust`
* Twitter: @saidelike