Solaris モジューラデバッガ

メモリー割り当てログ

この節では、カーネルメモリーアロケータのログ機能と、この機能を使用してシステムクラッシュのデバッギングを行う方法について説明します。

buftag データの完全性

前述のように、各 buftag の後半には、対応するバッファーに関する追加情報が含まれています。この情報の一部はデバッギング情報であり、また、アロケータの内部データも含まれています。この補助的データは種々の形式をとりますが、まとめて「バッファー制御」データあるいは bufctl データと呼ばれます。

しかし、誤ったコードによってこの bufctl ポインタも破壊される場合があるので、アロケータはバッファーの bufctl ポインタが有効であるかどうかを知る必要があります。アロケータは、このポインタとその符号化されたバージョンを格納し、2 つのバージョンのクロスチェックを行うことにより、この補助ポインタの完全性を確認します。

図 9–5 に示すように、ポインタの 2 つのバージョンは、bcp (buffer control pointer) と bxstat (buffer control XOR status) です。アロケータは、式 bcp XOR bxstat がわかりやすい既知の値に等しくなるように bcp と bxstat を調整します。

図 9–5 buftag の追加のデバッギングデータ

この図は walker の例を示しています。

これらのポインタの一方または両方が壊れている場合には、アロケータは容易に破壊を検出し、システムにパニックを発生させます。バッファーが割り当て済みの場合には、bcp XOR bxstat = 0xa110c8ed (「allocated」) になります。バッファーが未使用の場合には、bcp XOR bxstat = 0xf4eef4ee (「freefree」) になります。


注 –

「未使用バッファーの検査 (0xdeadbeef)」に示されている例をもう一度調べて、例に示されている buftag ポインタがこの説明どおりであることを確認してください。


アロケータは、buftag が壊れていることを発見した場合には、システムにパニックを発生させ、次のようなメッセージを出します。

kernel memory allocator: boundary tag corrupted
    bcp ^ bxstat = 0xffeef4ee, should be f4eef4ee

bcp が壊れていても、そのバッファーが割り当て済みか未使用かによって、それぞれ bxstat XOR 0xf4eef4ee または bxstat XOR 0xa110c8ed の値からその値を取り出すことが可能です。

bufctl ポインタ

buftag 領域に含まれているバッファー制御 (bufctl) ポインタは、そのキャッシュの kmem_flags に応じて種々の意味を持ちます。KMF_AUDIT フラグによって切り替えられる動作は、特に興味深いものです。KMF_AUDIT フラグが設定されていない場合には、カーネルメモリーアロケータは、各バッファーの kmem_bufctl_t 構造体を割り当てます。この構造体には、各バッファーに関する最小限のアカウンティング情報が含まれています。KMF_AUDIT フラグが設定されている場合には、アロケータはこの代わりに、kmem_bufctl_t の拡張バージョンである kmem_bufctl_audit_t を割り当てます。

この節では、KMF_AUDIT フラグが設定されていることを前提とします。このビットが設定されていないキャッシュは、使用可能なデバッギング情報の量が少なくなります。

kmem_bufctl_audit_t (略称は bufctl_audit) には、このバッファーに対して発生した最後のトランザクションに関する追加情報が含まれています。次の例で、bufctl_audit マクロを適用して監査レコードを調べる方法を示します。ここに示したバッファーは、「メモリー破壊の検出」で使用したサンプルバッファーです。

> 0x70a9ae00,5/KKn
0x70a9ae00:     5               4ef83
                0               0
                1               bbddcafe
                feedface        139d
                70ae3200        d1befaed

上記の手法を使用すると、0x70ae3200bufctl_audit レコードを指していることが容易にわかります。これはレッドゾーンの後の最初のポインタです。bufctl_audit レコードを調べるには、bufctl_audit マクロを適用します。

> 0x70ae3200$<bufctl_audit
0x70ae3200:     next            addr            slab
                70378000        70a9ae00        707c86a0
0x70ae320c:     cache           timestamp       thread
                70039928        e1bd0e26afe     70aac4e0
0x70ae321c:     lastlog         contents        stackdepth
                7011c7c0        7018a0b0        4
0x70ae3228:
                kmem_zalloc+0x30
                pid_assign+8
                getproc+0x68
                cfork+0x60

「addr」フィールドは、この bufctl_audit レコードに対応するバッファーのアドレスです。これはオリジナルアドレス 0x70a9ae00 です。0x70a9ae00. 「cache」フィールドは、このバッファーが割り当てられている kmem_cache を指します。::kmem_cache dcmd を使用して、次のようにしてこのキャッシュを調べることができます。

> 0x70039928::kmem_cache
ADDR     NAME                      FLAG  CFLAG  BUFSIZE  BUFTOTL
70039928 kmem_alloc_24             020f 000000       24      612

「timestamp」フィールドは、このトランザクションが発生した時刻を表します。この時刻は gethrtime(3C) と同じ形式で表されます。

「thread」は、このバッファーに対して最後のトランザクションを行なったスレッドへのポインタです。「lastlog」および「contents」ポインタは、アロケータのトランザクションログの中の位置を指します。これらのログについては、「アロケータのログ機能」で詳しく説明します。

一般的に、bufctl_audit が提供するもっとも有用な情報は、トランザクションが発生した時点で記録されるスタックトレースです。この場合、このトランザクションは fork(2) の実行の一部として呼び出された割り当てです。