
mempool用ヒープ分析ツール
予備的な注意:これは asatools の一部として使用することを推奨しますが、単体でも 使用できます。
libmempool は、Cisco ASA デバイスのさまざまなヒープ内に存在する mempool 関連のデータ構造の解析を支援する Python スクリプトおよび GDB 解析ツールです。
通常、この情報はヒープチャンクに埋め込まれているか、dlmalloc の
mstate 構造体などの一般的なヒープ構造に対するカスタム拡張として
存在します。
Cisco は、一般的なアロケーション、DMA などのさまざまな目的のためにマッピングされたメモリ領域を表す用語として mempool を使用しています。これらの領域には通常、dlmalloc などのヒープが含まれています。これらの mempool 上の割り当てルーチンは、通常、基盤となるヒープアロケータのラッパーを使用して実行され、これらのラッパーは結果の割り当てに mempool 固有のメタデータを注入します。このメタデータを mempool ヘッダー、略して mh と呼びます。同様に、mempool を mp と表記することがよくあります。mempool ヘッダー を表す mh の使用は、Cisco ASA lina バイナリに見られるさまざまな文字列とも一致しています。
libmempool は、mempool ヘッダーやデータ構造に関連するいくつかの事項を分析するためのスタンドアロンツールとして使用できますが、その最大の価値は、libdlmalloc や libptmalloc などの他のライブラリからコールバックとして使用されることにあります。
mempool の特定の側面、例えば使用中チャンクを追跡するために使用されるビンは、dlmalloc 2.8.x の mstate 構造体内に埋め込まれており、同じビンサイズに従うことに注意してください。これは、ほぼ必然的に、libdlmalloc を使用して mempool データを内包する mstate に少なくとも手を加える必要があることを意味します。
libmempool は、dlmalloc2.8 または glibc の ptmalloc2 ベースのアロケータを使用する 32 ビット / 64 ビットの Cisco ASA バージョン(ASA5500-X シリーズと GNS3 の両方)でテストされています。多数の ASA バージョン(多数の 8.x.y および 9.x.y ブランチを含む)でテストされています。ただし、特定のバージョンで動作しない可能性もあります。
libmempool をスタンドアロンで使用するには、libmempool.py ファイルをプロジェクトにインポートするだけです。これにより、mpcallback オブジェクトの登録など、限定された操作を行うことができます。これは、記録されたヒープ機能をオフラインで分析する場合に役立ちます。
GDB にインポートするには、スクリプトに必要なのは python サポート付きの GDB だけです。最近のほとんどの GDB バージョンは python 3 に移行していますが、2.7 を想定しているものもあります。このスクリプトは両方でテストされていますが、主な開発とテストは python 3 で行われています。
(gdb) source libmempool_gdb.py
gdb 関連のロジックのほとんどを libmempool.py から libmempool_gdb.py に分離しているのは、抽象化をテストするためと、GDB の外部で libmempool.py を簡単に使用できるようにするためです。これは将来変更される可能性があります。最終的には、libheap や shadow などの他のヒープ解析ツールで使用されているものと同様のデバッグエンジンの抽象化を実装したいと考えているためです。
libmempool の価値の多くは、公開されている mpcallback コールバック関数に由来しますが、確認できる組み込みの GDB コマンドも多数あります。
(gdb) mphelp
[libmempool] mempool commands for gdb
[libmempool] mpheader -v -x <addr> : show chunk contents (-v for verbose, -x for data dump)
[libmempool] mpbinwalk [-v] [-p <addr>] <sz> : walk an mpbin and operate on each chunk in a bin
[libmempool] mpbin <addr> : determine to which bin an mp_header is associated to
[libmempool] mpmstate <addr> : display and cache a mempool mstate address
[libmempool] mphelp
何らかの mempool ヘッダーのアドレスが分かっていれば、そのデータを解析できます。これは mempool ヘッダー自体のアドレスである必要があり、コアアロケータのチャンクメタデータのアドレスではないことに注意してください。それでは、次のように内容をダンプできます。
(gdb) mpheader 0x7fffbc1c1ca0
struct mp_header @ 0x7fffbc1c1ca0 {
mh_magic = 0xa11c0123
mh_len = 0x3
mh_refcount = 0x10000
mh_unused = 0x0
mh_fd_link = 0x7fffbc1c19e0 (OK)
mh_bk_link = 0x7ffff7ff7540 (-)
alloc_pc = 0x55555849e260 (-)
free_pc = 0x0 (-)
}
-x を使用してチャンクの16進数内容をダンプすることもできます。
(gdb) mpheader -x 0x7fffbc1c1ca0
struct mp_header @ 0x7fffbc1c1ca0 {
mh_magic = 0xa11c0123
mh_len = 0x3
mh_refcount = 0x10000
mh_unused = 0x0
mh_fd_link = 0x7fffbc1c19e0 (OK)
mh_bk_link = 0x7ffff7ff7540 (-)
alloc_pc = 0x55555849e260 (-)
free_pc = 0x0 (-)
0x3 bytes of chunk data:
0x7fffbc1c1cd0: 0x55 0x04 0x03
}
Mempool にはビンという概念があります。ビンは dlmalloc のビンと同じサイズの双方向リンクリストですが、フリーチャンクではなく使用中チャンクを追跡するために使用されます。これは Cisco デバイスでのメモリ使用量の記録のために行われます。mempool ヘッダーを含むチャンクを見つけても、ヒープ上の mstate 構造体がどこにあるのかまだ分からないことがよくあります。所在を把握するには、mpbin コマンドを使用できます。このコマンドは、使用中チャンクが現在存在する mempool ビンのアドレスを教えてくれます。例:
(gdb) mpbin 0x7fffbc1c1ca0
[libmempool] Found bin start at 0x7ffff7ff7540
[libmempool] Cached new mp_mstate @ 0x7ffff7ff73c0
[libmempool] mp_smallbin[08] - sz: 0x00000040 cnt: 0x00d3, mh_fd_link: 0x7fffbc1c1ca0
このコマンドは、mstate の mempool 部分の先頭を見つけただけでなく、それをキャッシュし、チャンクが存在する特定のビンも一覧表示します。オプションで mpbinwalk コマンドを使用して、このビンからすべての 0xd3 チャンクを一覧表示したり、特定の数までだけ一覧表示したりできます:
(gdb) mpbinwalk 0x40
[libmempool] mp_header @ 0x7ffff7ff7540 - mh_len: 0x00000000, alloc_pc: 0x00000000 [BIN HEAD]
[libmempool] mp_header @ 0x7fffbc1c1ca0 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1c19e0 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1c1750 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1bffa0 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[libmempool] mp_header @ 0x7fffbc1bff60 - mh_len: 0x00000003, alloc_pc: 0x5555584a1288
[libmempool] mp_header @ 0x7fffbc1c0050 - mh_len: 0x00000003, alloc_pc: 0x55555849e260
[...]
次に、mstate 構造体の mempool 部分全体(つまり、すべてのビンと関連統計)をダンプしたい場合は、mpmstate コマンドを使用できます:
(gdb) mpmstate 0x7ffff7ff73c0
struct mp_mstate @ 0x7ffff7ff73c0 {
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: 0x0000, mh_fd_link: 0x0
mp_smallbin[07] - sz: 0x00000038 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[08] - sz: 0x00000040 cnt: 0x00d3, mh_fd_link: 0x7fffbc1c1ca0
mp_smallbin[09] - sz: 0x00000048 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[10] - sz: 0x00000050 cnt: 0x0429, mh_fd_link: 0x7fffa4000d10
mp_smallbin[11] - sz: 0x00000058 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[12] - sz: 0x00000060 cnt: 0x335d, mh_fd_link: 0x7fffb80064b0
mp_smallbin[13] - sz: 0x00000068 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[14] - sz: 0x00000070 cnt: 0x073a, mh_fd_link: 0x7fffbc1c7260
mp_smallbin[15] - sz: 0x00000078 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[16] - sz: 0x00000080 cnt: 0x0301, mh_fd_link: 0x7fffbc1c72d0
mp_smallbin[17] - sz: 0x00000088 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[18] - sz: 0x00000090 cnt: 0x0c98, mh_fd_link: 0x7fffc9488920
mp_smallbin[19] - sz: 0x00000098 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[20] - sz: 0x000000a0 cnt: 0x0161, mh_fd_link: 0x7fffa40009a0
mp_smallbin[21] - sz: 0x000000a8 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[22] - sz: 0x000000b0 cnt: 0x0092, mh_fd_link: 0x7fffa4000a40
mp_smallbin[23] - sz: 0x000000b8 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[24] - sz: 0x000000c0 cnt: 0x0120, mh_fd_link: 0x7fffbc1c1270
mp_smallbin[25] - sz: 0x000000c8 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[26] - sz: 0x000000d0 cnt: 0x00ba, mh_fd_link: 0x7fffbc1b51a0
mp_smallbin[27] - sz: 0x000000d8 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[28] - sz: 0x000000e0 cnt: 0x005b, mh_fd_link: 0x7fffc9485020
mp_smallbin[29] - sz: 0x000000e8 cnt: 0x0000, mh_fd_link: 0x0
mp_smallbin[30] - sz: 0x000000f0 cnt: 0x016e, mh_fd_link: 0x7fffbc1c7040
mp_smallbin[31] - sz: 0x000000f8 cnt: 0x0000, mh_fd_link: 0x0
mp_treebin[00] - sz: 0x00000180 cnt: 0x050f, mh_fd_link: 0x7fffbc1c7130
mp_treebin[01] - sz: 0x00000200 cnt: 0x00ce, mh_fd_link: 0x7fffbc1c2610
mp_treebin[02] - sz: 0x00000300 cnt: 0x011a, mh_fd_link: 0x7fffa40053c0
mp_treebin[03] - sz: 0x00000400 cnt: 0x013e, mh_fd_link: 0x7fffa4000f80
mp_treebin[04] - sz: 0x00000600 cnt: 0x016f, mh_fd_link: 0x7fffbc1c2a80
mp_treebin[05] - sz: 0x00000800 cnt: 0x009a, mh_fd_link: 0x7fffbc1b4880
mp_treebin[06] - sz: 0x00000c00 cnt: 0x0081, mh_fd_link: 0x7fffbc1b38b0
mp_treebin[07] - sz: 0x00001000 cnt: 0x002b, mh_fd_link: 0x7fffbc1b2330
mp_treebin[08] - sz: 0x00001800 cnt: 0x0326, mh_fd_link: 0x7fffc9368e10
mp_treebin[09] - sz: 0x00002000 cnt: 0x0038, mh_fd_link: 0x7fffc92e9c60
mp_treebin[10] - sz: 0x00003000 cnt: 0x00b9, mh_fd_link: 0x7fffa4003380
mp_treebin[11] - sz: 0x00004000 cnt: 0x006d, mh_fd_link: 0x7fffc9457720
mp_treebin[12] - sz: 0x00006000 cnt: 0x023b, mh_fd_link: 0x7fffbc1ac000
mp_treebin[13] - sz: 0x00008000 cnt: 0x0018, mh_fd_link: 0x7fffc946f850
mp_treebin[14] - sz: 0x0000c000 cnt: 0x0030, mh_fd_link: 0x7fffc935fcc0
mp_treebin[15] - sz: 0x00010000 cnt: 0x0019, mh_fd_link: 0x7fffb44262b0
mp_treebin[16] - sz: 0x00018000 cnt: 0x0073, mh_fd_link: 0x7fffc93fe020
mp_treebin[17] - sz: 0x00020000 cnt: 0x0018, mh_fd_link: 0x7fffc94368f0
mp_treebin[18] - sz: 0x00030000 cnt: 0x000c, mh_fd_link: 0x7fffb0665010
mp_treebin[19] - sz: 0x00040000 cnt: 0x001c, mh_fd_link: 0x7fffa836d010
mp_treebin[20] - sz: 0x00060000 cnt: 0x000d, mh_fd_link: 0x7fffa8c55010
mp_treebin[21] - sz: 0x00080000 cnt: 0x001d, mh_fd_link: 0x7fffa9009010
mp_treebin[22] - sz: 0x000c0000 cnt: 0x0006, mh_fd_link: 0x7fffa9081010
mp_treebin[23] - sz: 0x00100000 cnt: 0x000a, mh_fd_link: 0x7fffb025f010
mp_treebin[24] - sz: 0x00180000 cnt: 0x000b, mh_fd_link: 0x7fffa8b38010
mp_treebin[25] - sz: 0x00200000 cnt: 0x000e, mh_fd_link: 0x7fffb008a010
mp_treebin[26] - sz: 0x00300000 cnt: 0x0007, mh_fd_link: 0x7fffb0323010
mp_treebin[27] - sz: 0x00400000 cnt: 0x0002, mh_fd_link: 0x7fffa87f5010
mp_treebin[28] - sz: 0x00600000 cnt: 0x0003, mh_fd_link: 0x7fffa83e9010
mp_treebin[29] - sz: 0x00800000 cnt: 0x0001, mh_fd_link: 0x7fffab328010
mp_treebin[30] - sz: 0x00c00000 cnt: 0x0001, mh_fd_link: 0x7fffd706d010
mp_treebin[31] - sz: 0xffffffff cnt: 0x0003, mh_fd_link: 0x7fffa9326010 [UNSORTED]
}
libmempool 内に、dlmalloc および ptmalloc を認識するコールバックを実装しています。これは、libdlmalloc または libptmalloc から呼び出され、それらのチャンク注釈を mempool 固有の追加データで補強することを目的としています。たとえば、libdlmalloc を使用して dlmalloc チャンクの詳細なリストを出力し、そのチャンクが内部に mempool ヘッダーを保持している場合、mempool コールバックがそれを出力します。
他のツールを介して使用した場合の外観については、libdlmalloc と libptmalloc の両方の README ファイルを参照してください。
今後の Cisco ASA リサーチや必要に応じて、libmempool に機能を追加する可能性が高いです。現在計画されている追加事項は以下のとおりです:
このツールに関するフィードバックをお待ちしています。プルリクエストも歓迎します。
Aaron Adams
aaron<dot>adams<at>nccgroup<dot>trustCedric Halbronn
cedric<dot>halbronn<at>nccgroup<dot>trust