WinDbg の概要 (カーネルモード)

WinDbg は、Windows 用デバッグ ツールに含まれているカーネルモードおよびユーザーモードのデバッガーです。 この記事では、カーネルモード デバッガーとして WinDbg の使用を開始するのに役立つ演習について説明します。

Windows 用デバッグ ツールを入手する方法については、「WinDbg Windows デバッガーをダウンロードしてインストールする」を参照してください。 デバッグ ツールをインストールしたら、64 ビット (x64) および 32 ビット (x86) バージョンのツールのインストール ディレクトリを検索します。 次に例を示します。

  • C:\Program Files (x86)\Windows Kits\10\Debuggers\x64
  • C:\Program Files (x86)\Windows Kits\10\Debuggers\x86

カーネル ]モードのデバッグを設定する

カーネルモード デバッグ環境には、ホスト コンピューターターゲット コンピューターの 2 台のコンピューターが通常あります。 デバッガーはホスト コンピューター上で実行され、デバッグ対象のコードはターゲット コンピューター上で実行されます。 ホストとターゲットはデバッグ ケーブルで接続されます。

Windows デバッガーでは、次の種類のケーブルがサポートされています。

  • イーサネット
  • USB 3.0
  • シリアル ("null モデム" とも呼ばれます)

速度と信頼性を確保するには、イーサネット ケーブルとローカル ネットワーク ハブを使用する必要があります。 次の図は、イーサネット ケーブルを使用してデバッグするために接続されたホスト コンピューターとターゲット コンピューターを示しています。

デバッグのためにイーサネット経由で接続されているホスト コンピューターとターゲット コンピューターを示す図。

以前のバージョンの Windows のオプションは、シリアル ケーブルなどの直接ケーブルを使用することです。

デバッグ用のデバッグ ケーブルを使用して接続されたホスト コンピューターとターゲット コンピューターを示す図。

ホスト コンピューターとターゲット コンピューターの設定方法の詳細については、「カーネルモード デバッグの手動での設定」を参照してください。

仮想マシン - VM

Hyper-V 仮想マシンへのデバッガーの接続については、「仮想マシンのネットワーク デバッグの設定 - KDNET」を参照してください。

カーネルモード デバッグ セッションを確立する

ホストとターゲット コンピューターを設定し、デバッグ ケーブルで接続したら、カーネルモードデバッグ セッションを確立できます。 セットアップで使用したものと同じトピックの手順に従います。 たとえば、イーサネット経由でデバッグするためのホスト コンピューターとターゲット コンピューターを設定する場合は、次の記事でカーネル モード デバッグ セッションを確立する手順を確認できます。

WinDbg の使用を開始する

  1. ホスト コンピューターで WinDbg を開き、ターゲット コンピューターとのカーネルモード デバッグ セッションを確立します。

  2. デバッガーのドキュメント CHM ファイルを開くには、[ヘルプ] メニューに移動して [コンテンツ] を選択します。 デバッガーのドキュメントは、Windows 用デバッグ ツールでオンラインでも入手できます。

  3. カーネルモード デバッグ セッションを確立する際、WinDbg が自動的にターゲット コンピューターを中断する可能性があります。 WinDbg が中断されない場合は、[デバッグ] メニューに移動して [中断] を選択します。

  4. [WinDbg] ウィンドウの下部にあるコマンド ラインに、次のコマンドを入力します。

    .sympath srv*

    出力は次の例のようになります。

    Symbol search path is: srv*
    Expanded Symbol search path is: cache*;SRV*https://msdl.microsoft.com/download/symbols
    

    シンボルの検索パスにより、シンボル (PDB) ファイルを検索する場所が WinDbg に指示されます。 デバッガーには、関数名や変数名など、コード モジュールに関する情報を取得するためのシンボル ファイルが必要です。

    次のコマンドを入力して、シンボル ファイルの初期検索と読み込みを行うよう WinDbg に指示します。

    .reload

  5. 読み込まれたモジュールの一覧を取得するには、次のコマンドを入力します。

    lm

    出力は次の例のようになります。

    0:000>3: kd> lm
    start             end                 module name
    fffff800`00000000 fffff800`00088000   CI         (deferred)
    ...
    fffff800`01143000 fffff800`01151000   BasicRender   (deferred)
    fffff800`01151000 fffff800`01163000   BasicDisplay  (deferred)
    ...
    fffff800`02a0e000 fffff800`03191000   nt  (pdb symbols) C:\...\ntkrnlmp.pdb
    fffff800`03191000 fffff800`03200000   hal (deferred)
    ...
    
  6. ターゲット コンピューターの実行を開始するには、次のコマンドを入力します。

    g

  7. もう一度中断するには、[デバッグ] メニューに移動して [中断] を選択します。

  8. 次のコマンドを入力して、nt モジュール内の _FILE_OBJECT データ型を調べます。

    dt nt!_FILE_OBJECT

    出力は次の例のようになります。

    0:000>0: kd> dt nt!_FILE_OBJECT
       +0x000 Type             : Int2B
       +0x002 Size             : Int2B
       +0x008 DeviceObject     : Ptr64 _DEVICE_OBJECT
       +0x010 Vpb              : Ptr64 _VPB
       ...
       +0x0c0 IrpList          : _LIST_ENTRY
       +0x0d0 FileObjectExtension : Ptr64 Void
    
  9. 次のコマンドを入力して、nt モジュール内のシンボルのいくつかを調べます。

    x nt!*CreateProcess*

    出力は次の例のようになります。

    0:000>0: kd> x nt!*CreateProcess*
    fffff800`030821cc nt!ViCreateProcessCallbackInternal (<no parameter info>)
    ...
    fffff800`02e03904 nt!MmCreateProcessAddressSpace (<no parameter info>)
    fffff800`02cece00 nt!PspCreateProcessNotifyRoutine = <no type information>
    ...
    
  10. 次のコマンドを入力して、ブレークポイントを MmCreateProcessAddressSpace に設定します。

    bu nt!MmCreateProcessAddressSpace

    ブレークポイントが設定されていることを確認するには、次のコマンドを入力します。

    bl

    出力は次の例のようになります。

    0:000>0: kd> bu nt!MmCreateProcessAddressSpace
    0: kd> bl
    0 e fffff800`02e03904     0001 (0001) nt!MmCreateProcessAddressSpace
    

    g」を入力してターゲット コンピューターを実行します。

  11. ターゲット コンピューターがデバッガーを中断しない場合は、ターゲット コンピューター上でいくつかのアクションを実行します (メモ帳を開くなど)。 MmCreateProcessAddressSpace が呼び出されると、ターゲット コンピューターはデバッガーを中断します。 スタック トレースを表示するには、次のコマンドを入力します。

    .reload

    k

    出力は次の例のようになります。

    0:000>2: kd> k
    Child-SP          RetAddr           Call Site
    ffffd000`224b4c88 fffff800`02d96834 nt!MmCreateProcessAddressSpace
    ffffd000`224b4c90 fffff800`02dfef17 nt!PspAllocateProcess+0x5d4
    ffffd000`224b5060 fffff800`02b698b3 nt!NtCreateUserProcess+0x55b
    ...
    000000d7`4167fbb0 00007ffd`14b064ad KERNEL32!BaseThreadInitThunk+0xd
    000000d7`4167fbe0 00000000`00000000 ntdll!RtlUserThreadStart+0x1d
    
  12. [表示] メニューの [逆アセンブリ] をクリックします。

    [デバッグ] メニューの [ステップ オーバー] を選択します (または F10 キーを押します)。 [逆アセンブル] ウィンドウを見ながら、ステップ コマンドをさらに数回入力します。

  13. 次のコマンドを入力して、ブレークポイントをクリアします。

    bc *

    g」を入力してターゲット コンピューターを実行します。 もう一度中断するには、[デバッグ] メニューに移動して [中断] を選択するか、Ctrl キーを押しながら Break キーを押します。

  14. すべてのプロセスの一覧を取得するには、次のコマンドを入力します。

    !process 0 0

    出力は次の例のようになります。

    0:000>0: kd> !process 0 0
    **** NT ACTIVE PROCESS DUMP ****
    PROCESS ffffe000002287c0
        SessionId: none  Cid: 0004    Peb: 00000000  ParentCid: 0000
        DirBase: 001aa000  ObjectTable: ffffc00000003000  HandleCount: <Data Not Accessible>
        Image: System
    
    PROCESS ffffe00001e5a900
        SessionId: none  Cid: 0124    Peb: 7ff7809df000  ParentCid: 0004
        DirBase: 100595000  ObjectTable: ffffc000002c5680  HandleCount: <Data Not Accessible>
        Image: smss.exe
    ...
    PROCESS ffffe00000d52900
        SessionId: 1  Cid: 0910    Peb: 7ff669b8e000  ParentCid: 0a98
        DirBase: 3fdba000  ObjectTable: ffffc00007bfd540  HandleCount: <Data Not Accessible>
        Image: explorer.exe
    
  15. 1 つのプロセスのアドレスをコピーし、次のコマンドを入力します。

    !process Address 2

    例: !process ffffe00000d5290 2

    出力は、プロセス内のスレッドを示します。

    0:000>0:000>0: kd> !process ffffe00000d52900 2
    PROCESS ffffe00000d52900
        SessionId: 1  Cid: 0910    Peb: 7ff669b8e000  ParentCid: 0a98
        DirBase: 3fdba000  ObjectTable: ffffc00007bfd540  HandleCount:
        Image: explorer.exe
    
            THREAD ffffe00000a0d880  Cid 0910.090c  Teb: 00007ff669b8c000
                ffffe00000d57700  SynchronizationEvent
    
            THREAD ffffe00000e48880  Cid 0910.0ad8  Teb: 00007ff669b8a000
                ffffe00000d8e230  NotificationEvent
                ffffe00000cf6870  Semaphore Limit 0xffff
                ffffe000039c48c0  SynchronizationEvent
            ...
            THREAD ffffe00000e6d080  Cid 0910.0cc0  Teb: 00007ff669a10000
                ffffe0000089a300  QueueObject
    
  16. 1 つのスレッドのアドレスをコピーし、次のコマンドを入力します。

    !thread Address

    例: !thread ffffe00000e6d080

    出力は、個々のスレッドに関する情報を示します。

    0: kd> !thread ffffe00000e6d080
    THREAD ffffe00000e6d080  Cid 0910.0cc0  Teb: 00007ff669a10000 Win32Thread: 0000000000000000 WAIT: ...
        ffffe0000089a300  QueueObject
    Not impersonating
    DeviceMap                 ffffc000034e7840
    Owning Process            ffffe00000d52900       Image:         explorer.exe
    Attached Process          N/A            Image:         N/A
    Wait Start TickCount      13777          Ticks: 2 (0:00:00:00.031)
    Context Switch Count      2              IdealProcessor: 1
    UserTime                  00:00:00.000
    KernelTime                00:00:00.000
    Win32 Start Address ntdll!TppWorkerThread (0x00007ffd14ab2850)
    Stack Init ffffd00021bf1dd0 Current ffffd00021bf1580
    Base ffffd00021bf2000 Limit ffffd00021bec000 Call 0
    Priority 13 BasePriority 13 UnusualBoost 0 ForegroundBoost 0 IoPriority 2 PagePriority 5
    ...
    
  17. プラグ アンド プレイ デバイス ツリー内のデバイス ノードをすべて表示するには、次のコマンドを入力します。

    !devnode 0 1

    0:000>0: kd> !devnode 0 1
    Dumping IopRootDeviceNode (= 0xffffe000002dbd30)
    DevNode 0xffffe000002dbd30 for PDO 0xffffe000002dc9e0
      InstancePath is "HTREE\ROOT\0"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
      DevNode 0xffffe000002d9d30 for PDO 0xffffe000002daa40
        InstancePath is "ROOT\volmgr\0000"
        ServiceName is "volmgr"
        State = DeviceNodeStarted (0x308)
        Previous State = DeviceNodeEnumerateCompletion (0x30d)
        DevNode 0xffffe00001d49290 for PDO 0xffffe000002a9a90
          InstancePath is "STORAGE\Volume\{3007dfd3-df8d-11e3-824c-806e6f6e6963}#0000000000100000"
          ServiceName is "volsnap"
          TargetDeviceNotify List - f 0xffffc0000031b520  b 0xffffc0000008d0f0
          State = DeviceNodeStarted (0x308)
          Previous State = DeviceNodeStartPostWork (0x307)
    ...
    
  18. デバイス ノードとそのハードウェア リソースを表示するには、次のコマンドを入力します。

    !devnode 0 9

    0:000>...
            DevNode 0xffffe000010fa770 for PDO 0xffffe000010c2060
              InstancePath is "PCI\VEN_8086&DEV_2937&SUBSYS_2819103C&REV_02\3&33fd14ca&0&D0"
              ServiceName is "usbuhci"
              State = DeviceNodeStarted (0x308)
              Previous State = DeviceNodeEnumerateCompletion (0x30d)
              TranslatedResourceList at 0xffffc00003c78b00  Version 1.1  Interface 0x5  Bus #0
                Entry 0 - Port (0x1) Device Exclusive (0x1)
                  Flags (0x131) - PORT_MEMORY PORT_IO 16_BIT_DECODE POSITIVE_DECODE
                  Range starts at 0x3120 for 0x20 bytes
                Entry 1 - DevicePrivate (0x81) Device Exclusive (0x1)
                  Flags (0000) -
                  Data - {0x00000001, 0x00000004, 0000000000}
                Entry 2 - Interrupt (0x2) Shared (0x3)
                  Flags (0000) - LEVEL_SENSITIVE
                  Level 0x8, Vector 0x81, Group 0, Affinity 0xf
    ...
    
  19. ディスクのサービス名を持つデバイス ノードを表示するには、次のコマンドを入力します。

    !devnode 0 1 disk

    0: kd> !devnode 0 1 disk
    Dumping IopRootDeviceNode (= 0xffffe000002dbd30)
    DevNode 0xffffe0000114fd30 for PDO 0xffffe00001159610
      InstancePath is "IDE\DiskST3250820AS_____________________________3.CHL___\5&14544e82&0&0.0.0"
      ServiceName is "disk"
      State = DeviceNodeStarted (0x308)
      Previous State = DeviceNodeEnumerateCompletion (0x30d)
    ...
    
  20. !devnode 0 1 の出力には、ノードの物理デバイス オブジェクト (PDO) のアドレスが表示されます。 物理デバイス オブジェクト (PDO) のアドレスをコピーし、次のコマンドを入力します。

    !devstack PdoAddress

    例: <PdoAddress>!devstack 0xffffe00001159610

    0:000>0: kd> !devstack 0xffffe00001159610
      !DevObj           !DrvObj            !DevExt           ObjectName
      ffffe00001d50040  \Driver\partmgr    ffffe00001d50190  
      ffffe00001d51450  \Driver\disk       ffffe00001d515a0  DR0
      ffffe00001156e50  \Driver\ACPI       ffffe000010d8bf0  
    
  21. ドライバー disk.sysに関する情報を取得するには、次のコマンドを入力します。

    !drvobj disk 2

    0:000>0: kd> !drvobj disk 2
    Driver object (ffffe00001d52680) is for:
     \Driver\disk
    DriverEntry:   fffff800006b1270 disk!GsDriverEntry
    DriverStartIo: 00000000
    DriverUnload:  fffff800010b0b5c CLASSPNP!ClassUnload
    AddDevice:     fffff800010aa110 CLASSPNP!ClassAddDevice
    
    Dispatch routines:
    [00] IRP_MJ_CREATE                      fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    [01] IRP_MJ_CREATE_NAMED_PIPE           fffff80002b0ab24    nt!IopInvalidDeviceRequest
    [02] IRP_MJ_CLOSE                       fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    [03] IRP_MJ_READ                        fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    ...
    [1b] IRP_MJ_PNP                         fffff8000106d160    CLASSPNP!ClassGlobalDispatch
    
  22. !drvobj の出力には、ディスパッチ ルーチンのアドレスが表示されます。 たとえば、CLASSPNP!ClassGlobalDispatch のようにします。 ブレークポイントを ClassGlobalDispatch に設定して確認するには、次のコマンドを入力します。

    bu CLASSPNP!ClassGlobalDispatch

    bl

    g を入力してターゲット コンピューターを実行します。

    ターゲット コンピューターがデバッガーをすぐに中断しない場合は、ターゲット コンピューター上でいくつかのアクションを実行します (メモ帳を開いたり、ファイルを保存したりするなど)。 ClassGlobalDispatch が呼び出されると、ターゲット コンピューターはデバッガーを中断します。 スタック トレースを表示するには、次のコマンドを入力します。

    .reload

    k

    出力は次の例のようになります。

    2: kd> k
    Child-SP          RetAddr           Call Site
    ffffd000`21d06cf8 fffff800`0056c14e CLASSPNP!ClassGlobalDispatch
    ffffd000`21d06d00 fffff800`00f2c31d volmgr!VmReadWrite+0x13e
    ffffd000`21d06d40 fffff800`0064515d fvevol!FveFilterRundownReadWrite+0x28d
    ffffd000`21d06e20 fffff800`0064578b rdyboost!SmdProcessReadWrite+0x14d
    ffffd000`21d06ef0 fffff800`00fb06ad rdyboost!SmdDispatchReadWrite+0x8b
    ffffd000`21d06f20 fffff800`0085cef5 volsnap!VolSnapReadFilter+0x5d
    ffffd000`21d06f50 fffff800`02b619f7 Ntfs!NtfsStorageDriverCallout+0x16
    ...
    
  23. デバッグ セッションを終了するには、次のコマンドを入力します。

    qd

コマンドのまとめ

関連項目