この節では、カーネルメモリーアロケータのログ機能と、この機能を使用してシステムクラッシュのデバッギングを行う方法について説明します。
前述のように、各 buftag の後半には、対応するバッファに関する追加情報が含まれています。この情報の一部はデバッギング情報であり、また、アロケータの内部データも含まれています。この補助的データは種々の形式をとりますが、まとめて「バッファ制御」データあるいは bufctl データと呼ばれます。
しかし、誤ったコードによってこの bufctl ポインタも破壊される場合があるので、アロケータはバッファの bufctl ポインタが有効であるかどうかを知る必要があります。アロケータは、このポインタとその符号化されたバージョンを格納し、2 つのバージョンのクロスチェックを行うことにより、この補助ポインタの完全性を確認します。
図 6-5 に示すように、ポインタの 2 つのバージョンは、bcp (buffer control pointer) と bxstat (buffer control XOR status) です。アロケータは、式 bcp XOR bxstat がわかりやすい既知の値に等しくなるように bcp と bxstat を調整します。
これらのポインタの一方または両方が壊れている場合には、アロケータは容易に破壊を検出し、システムにパニックを発生させます。バッファが割り当て済みの場合には、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 4fffed 70ae3200 d1befaed
上記の手法を使用すると、0x70ae3200 が bufctl_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 です。「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) の実行の一部として呼び出された割り当てです。