
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 コマンドを使用できます: