Oracle® Solaris 11.2 デバイスドライバの記述

印刷ビューの終了

更新: 2014 年 9 月
 
 

kmdbmdb を使用した便利なデバッグタスク

このセクションでは便利なデバッグタスクの例について説明します。このセクションに含まれるタスクは、特に明記されていないかぎり、mdbkmdb のいずれかを使用して実行できます。このセクションでは、ユーザーに kmdbmdb の使用に関する基礎知識があることを前提にしています。ここで示す情報は、使用するシステムの種類に依存します。これらの例を作成する際には、64 ビットカーネルが稼働する Sun Blade 100 ワークステーションを使用しました。


Caution

注意  -  カーネル構造体のデータを変更すると不可逆なデータ破壊が起こる可能性があるため、細心の注意を払うべきです。Oracle Solaris DDI の一部でない構造体に含まれるデータを変更したり、そのようなデータに依存したりしないようにしてください。Oracle Solaris DDI の一部である構造体については、Intro(9S) のマニュアルページを参照してください。


kmdb によるシステムレジスタの調査

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 を使用したデバッガコマンドの記述

mdb デバッガには、ドライバのデバッグ用にカスタマイズ可能なデバッガ機能を実装するための強力な API が用意されています。このプログラミング API の詳細については、『Oracle Solaris モジューラデバッガ』で説明されています。

SUNWmdbdm パッケージは、ディレクトリ /usr/demo/mdbmdb のサンプルソースコードをインストールします。mdb を使用すると、ドライバが正しく動作していることを検証するための時間のかかるデバッグ作業やデバッグ支援を自動化できます。また、mdb デバッグモジュールをドライバ製品と一緒にパッケージ化することもできます。パッケージ化すると、サービス担当者がこれらの機能を顧客サイトで使用できるようになります。

カーネルデータ構造体情報の取得

Oracle Solaris カーネルはデータ型の情報を構造体として提供しており、これらの構造体は、kmdbmdb のいずれかを使用して検査できます。


注 - kmdbmdb の dcmd は、mdb 用として設計された圧縮シンボリックデバッギング情報を含むオブジェクトでしか使用できません。現在、この情報を利用できるのは、特定の Oracle Solaris カーネルモジュールのみです。このシンボリックデバッギング情報を処理するには、SUNWzlib パッケージをインストールする必要があります。

次の例は、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 カーネルと対話する際に発生した問題をデバッグできます。


Caution

注意  -  この機能を使用すると、のカーネルデータ構造体にアクセスできます。ユーザーは、構造体が DDI の一部として表示されるかどうかにかかわらず、任意の構造体を検査できます。したがって、明示的に DDI の一部になっていないデータ構造体には依存しないようにしてください。



注 - 前述の dcmd は、mdb 用として設計された圧縮シンボリックデバッギング情報を含むオブジェクトでしか使用しないようにしてください。現在、シンボリックデバッギング情報を使用できるのは、特定の Oracle Solaris カーネルモジュールのみです。シンボリックデバッギング情報を処理するには、SUNWzlib (32 ビット) または SUNWzlibx (64 ビット) 圧縮ソフトウェアをインストールする必要があります。kmdb デバッガは、SUNWzlib または SUNWzlibx パッケージの有無にかかわらず、シンボリックタイプのデータを処理できます。

デバイスツリー情報の取得

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 構造体を参照しています。

カーネル変数の変更

カーネル変数などのカーネル状態を変更する場合、kmdbmdb のどちらを使用してもかまいません。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