このセクションでは便利なデバッグタスクの例について説明します。このセクションに含まれるタスクは、特に明記されていないかぎり、mdb、kmdb のいずれかを使用して実行できます。このセクションでは、ユーザーに kmdb と mdb の使用に関する基礎知識があることを前提にしています。ここで示す情報は、使用するシステムの種類に依存します。これらの例を作成する際には、64 ビットカーネルが稼働する Sun Blade 100 ワークステーションを使用しました。
![]() | 注意 - カーネル構造体のデータを変更すると不可逆なデータ破壊が起こる可能性があるため、細心の注意を払うべきです。Oracle Solaris DDI の一部でない構造体に含まれるデータを変更したり、そのようなデータに依存したりしないようにしてください。Oracle Solaris DDI の一部である構造体については、Intro(9S) のマニュアルページを参照してください。 |
kmdb デバッガを使用すると、マシンのレジスタを 1 つのグループとして表示することも、個々のレジスタ単位で表示することもできます。すべてのレジスタを 1 つのグループとして表示するには、次の例に示すように $r を使用します。
使用例 23-9 kmdb による SPARC プロセッサ上のすべてのレジスタの読み取り[0]: $r g0 0 l0 0 g1 100130a4 debug_enter l1 edd00028 g2 10411c00 tsbmiss_area+0xe00 l2 10449c90 g3 10442000 ti_statetbl+0x1ba l3 1b g4 3000061a004 l4 10474400 ecc_syndrome_tab+0x80 g5 0 l5 3b9aca00 g6 0 l6 0 g7 2a10001fd40 l7 0 o0 0 i0 0 o1 c i1 10449e50 o2 20 i2 0 o3 300006b2d08 i3 10 o4 0 i4 0 o5 0 i5 b0 sp 2a10001b451 DP 2a10001b521 o7 1001311c debug_enter+0x78 i7 1034bb24 zsa_xsint+0x2c4 y 0 state: 1604 (cc=0x0, Adi=0x0, state=0x16, cup=0x4) state: ag:0 ie:1 priv:1 am:0 pef:1 mm:0 tle:0 cle:0 mg:0 ig:0 winer: cur:4 other:0 clean:7 cansave:1 canrest:5 wstate:14 tba 0x10000000 pc edd000d8: ta %icc,%g0 + 125 NC edd000dc: nope
デバッガは各レジスタの値を、そのレジスタと同じ名前を持つ変数にエクスポートします。変数を読み取ると、レジスタの現在の値が返されます。変数に書き込みを行うと、関連するマシンレジスタの値が変更されます。次の例では、x86 マシン上の %o0 レジスタの値を、0 から 1 に変更しています。
使用例 23-10 kmdb による x86 マシン上のレジスタの読み取りと書き込み[0]> & <ex=K c1e6e0f0 [0]> 0>ex [0]> & <ex=K 0 [0]> c1e6e0f0>ex
別のプロセッサのレジスタを検査する必要がある場合は、::purges dcmd を使用できます。次の例に示すように、検査対象となるプロセッサの ID は、この dcmd へのアドレスとして指定することも、–c オプションの値として指定することもできます。
使用例 23-11 別のプロセッサのレジスタの検査[0]> 0::purges %cs = 0x0158 %ex = 0xc1e6e0f0 kmdbmod`kaif_dvec %DDS = 0x0160 %Eb = 0x00000000
次の例では、SPARC マシン上でプロセッサを 0 から 3 に切り替えています。%g3 レジスタが検査されたあと、クリアされています。新しい値を確認するため、%g3 が再度読み取られています。
使用例 23-12 指定されたプロセッサからの、特定のレジスタ値の取得[0]> 3::switch [3]> <g3=K 24 [3]> 0>g3 [3]> <g3 0
::findleaks dcmd は、カーネルクラッシュダンプ内のメモリーリークを検出する強力で効率的な機能を提供します。カーネルメモリーデバッグ機能のフルセットを有効化しないと、::findleaks が有効になりません。詳細については、Setting kmem_flags Debugging Flagsを参照してください。ドライバの開発中やテスト中に ::findleaks を実行すると、メモリーリークが発生したためにカーネルリソースが浪費されているコードが検出されます。::find leaks の完全な説明については、Chapter 9, Debugging With the Kernel Memory Allocator, in Oracle Solaris Modular Debugger Guide を参照してください。
mdb デバッガには、ドライバのデバッグ用にカスタマイズ可能なデバッガ機能を実装するための強力な API が用意されています。このプログラミング API の詳細については、『Oracle Solaris モジューラデバッガ』で説明されています。
SUNWmdbdm パッケージは、ディレクトリ /usr/demo/mdb に mdb のサンプルソースコードをインストールします。mdb を使用すると、ドライバが正しく動作していることを検証するための時間のかかるデバッグ作業やデバッグ支援を自動化できます。また、mdb デバッグモジュールをドライバ製品と一緒にパッケージ化することもできます。パッケージ化すると、サービス担当者がこれらの機能を顧客サイトで使用できるようになります。
Oracle Solaris カーネルはデータ型の情報を構造体として提供しており、これらの構造体は、kmdb と mdb のいずれかを使用して検査できます。
次の例は、scsi_pkt 構造体のデータを表示する方法を示しています。
使用例 23-13 デバッガによるカーネルデータ構造体の表示> 7079ceb0::print -t 'struct scsi_pkt' { opaque_t pkt_ha_private = 0x7079ce20 struct scsi_address pkt_address = { struct scsi_hba_tran *a_hba_tran = 0x70175e68 ushort_t a_target = 0x6 uchar_t a_lun = 0 uchar_t a_sublun = 0 } opaque_t pkt_private = 0x708db4d0 int (*)() *pkt_comp = sd_intr uint_t pkt_flags = 0 int pkt_time = 0x78 uchar_t *pkt_scbp = 0x7079ce74 uchar_t *pkt_cdbp = 0x7079ce64 ssize_t pkt_resid = 0 uint_t pkt_state = 0x37 uint_t pkt_statistics = 0 uchar_t pkt_reason = 0 }
データ構造体のサイズは、デバッグ時に役立つ可能性があります。ある構造体のサイズを取得するには、次の例に示すように ::sized dcmd を使用します。
使用例 23-14 カーネルデータ構造体のサイズの表示> ::sized struct scsi_pkt sized (struct scsi_pkt) = 0x58
デバッグ時には、構造体内の特定のメンバーのアドレスも役立ちます。あるメンバーのアドレスを調査する場合に使用可能な方法は、いくつか存在します。
構造体の特定のメンバーのオフセットを取得するには、次の例のように ::offset dcmd を使用します。
使用例 23-15 カーネルデータ構造体へのオフセットの表示> ::offset struct scsi_pkt pkt_state offset (struct pkt_state) = 0x48
構造体のすべてのメンバーのアドレスを表示するには、次の例のように ::print dcmd で –a オプションを指定します。
使用例 23-16 カーネルデータ構造体の相対アドレスの表示> ::print -a struct scsi_pkt { 0 pkt_ha_private 8 pkt_address { ... } 18 pkt_private ... }
::print でアドレスと –a オプションを組み合わせて指定すると、各メンバーの絶対アドレスが表示されます。
使用例 23-17 カーネルデータ構造体の絶対アドレスの表示> 10000000::print -a struct scsi_pkt { 10000000 pkt_ha_private 10000008 pkt_address { ... } 10000018 pkt_private ... }
::print、::sized、および ::offset の各 dcmd を使用すると、ドライバが Oracle Solaris カーネルと対話する際に発生した問題をデバッグできます。
![]() | 注意 - この機能を使用すると、生のカーネルデータ構造体にアクセスできます。ユーザーは、構造体が DDI の一部として表示されるかどうかにかかわらず、任意の構造体を検査できます。したがって、明示的に DDI の一部になっていないデータ構造体には依存しないようにしてください。 |
mdb デバッガには、カーネルデバイスツリーを表示するための ::pricing dcmd が用意されています。::pricing dcmd の出力は、 pricing (1M) コマンドの出力に似ています。
使用例 23-18 ::pricing dcmd の使用> ::pricing 300015d3e08 SUN,Sun-Blade-100 300015d3c28 packages (driver not attached) 300015d3868 SUN,builtin-drivers (driver not attached) 300015d3688 de blocker (driver not attached) 300015d34a8 disk-label (driver not attached) 300015d32c8 terminal-emulator (driver not attached) 300015d30e8 obp-tftp (driver not attached) 300015d2f08 droppings (driver not attached) 300015d2d28 kbd-translator (driver not attached) 300015d2b48 ufs-file-system (driver not attached) 300015d3a48 chosen (driver not attached) 300015d2968 open prom (driver not attached)
ノードを表示するには、次の例に示すように ::dev info dcmd などのマクロを使用します。
使用例 23-19 特定のノードのデバイス情報の表示> 300015d3e08::devinfo 300015d3e08 SUN,Sun-Blade-100 System properties at 0x300015abdc0: name='relative-addressing' type=int items=1 value=00000001 name='MMU_PAGEOFFSET' type=int items=1 value=00001ff name='MMU_PAGESIZE' type=int items=1 value=00002000 name='PAGE SIZE' type=int items=1 value=00002000 Driver properties at 0x300015abe00: name='pm-hardware-state' type=string items=1 value='no-suspend-resume'
::pricing を使用すると、デバイスツリー内でドライバが接続されている場所を確認したり、デバイスのプロパティーを表示したりできます。また、次のように ::pricing に詳細 (–v) フラグを指定することで、各デバイスノードのプロパティーを表示することもできます。
使用例 23-20 冗長モードの ::pricing dcmd の使用> ::pricing -v DEV INFO NAME 300015d3e08 SUN,Sun-Blade-100 System properties at 0x300015abdc0: name='relative-addressing' type=int items=1 value=00000001 name='MMU_PAGEOFFSET' type=int items=1 value=00001ff name='MMU_PAGESIZE' type=int items=1 value=00002000 name='PAGE SIZE' type=int items=1 value=00002000 Driver properties at 0x300015abe00: name='pm-hardware-state' type=string items=1 value='no-suspend-resume' ... 300015ce798 pci10b9,5229, instance #0 Driver properties at 0x300015ab980: name='target2-dcd-options' type=any items=4 value=00.00.00.a4 name='target1-dcd-options' type=any items=4 value=00.00.00.a2 name='target0-dcd-options' type=any items=4 value=00.00.00.a4
ドライバのインスタンスを特定する別の方法として、::dev bindings dcmd が挙げられます。次の例に示すように、ドライバ名が指定されると、このコマンドは指定されたドライバのすべてのインスタンスの一覧を表示します。
使用例 23-21 ::dev bindings dcmd を使用したドライバインスタンスの特定> ::dev bindings dad 300015ce3d8 videodisk (driver not attached) 300015c9a60 dad, instance #0 System properties at 0x300015ab400: name='lean' type=int items=1 value=00000000 name='target' type=int items=1 value=00000000 name='class_prop' type=string items=1 value='data' name='type' type=string items=1 value='data' name='class' type=string items=1 value='dada' ... 300015c9880 dad, instance #1 System properties at 0x300015ab080: name='lean' type=int items=1 value=00000000 name='target' type=int items=1 value=00000002 name='class_prop' type=string items=1 value='data' name='type' type=string items=1 value='data' name='class' type=string items=1 value='dada'
ドライバをデバッグするときの一般的な問題は、ある特定のドライバインスタンスの ソフト状態を取得することです。ソフト状態は、ddi_soft_state_zalloc(9F) ルーチンで割り当てられます。ドライバからソフト状態を取得するには、ddi_get_soft_state (9F) を使用します。ソフト状態ポインタの名前が、ddi_soft_state_init(9F) の第一引数になります。名前を使用すると、mdb で ::soft state dcmd を使用して特定のドライバインスタンスのソフト状態を取得できます。
> *bst_state::softstate 0x3 702b7578
この場合、::soft state を使用して bst サンプルドライバのインスタンス 3 のソフト状態を取得しています。このポインタは、ドライバがこのインスタンスの状態を追跡するために使用する bst_soft 構造体を参照しています。
カーネル変数などのカーネル状態を変更する場合、kmdb と mdb のどちらを使用してもかまいません。mdb は変更前にカーネルを停止しないため、mdb によるカーネル状態の変更は注意して行う必要があります。kmdb を使用すると一連の変更を原子的に行えますが、これは、kmdb がユーザーにアクセスを許可する前にカーネルを停止するためです。mdb デバッガでは、原子的な変更は 1 つしか行えません。
変更の実行時には、必ず適切な書式指定子を使用してください。書式は次のとおりです。
w – 各式の値の下位 2 バイトを、ドットで指定された位置から始まるターゲットに書き込む
W – 各式の値の下位 4 バイトを、ドットで指定された位置から始まるターゲットに書き込む
Z – 各式の値の 8 バイトすべてを、ドットで指定された位置から始まるターゲットに書き込む
変更する変数のサイズを確認するには、::sized dcmd を使用します。
次の例では、mod debug の値を値 0x80000000 で上書きしています。
使用例 23-22 デバッガによるカーネル変数の変更> moddebug/W 0x80000000 mod debug: 0 = 0x80000000