CDB (コマンドラインデバッガー)

CDB - デバッガの基本

Windows 2000 シンボリックデバッガには NTSD (ntsd.exe) と CDB (cdb.exe) の 2 種類あります。コマンドプロンプトから起動したとき、新しいウィンドウで起動するのが NTSD でコマンドプロンプト内で実行するのが CDB です。この二つはそれくらいの違いしかありません。私は新しいウィンドウが開くのがわずらわしいので主に CDB をメインに使っています。これらは各自の嗜好で選択してよいと思います。ここでは CDB として解説しますが、それは NTSD にも当てはまりますので NTSD をお使いの場合にもこの節は参考になるはずです。

デバッガのアタッチ

デバッグされるプログラムのことを一般的にデバッギ (debuggee) あるいはターゲットアプリケーション (target application) といいます。デバッグするプログラムをデバッガ (debugger) といいます。ターゲットアプリケーションにデバッガを接続することを、デバッガをアタッチ (attach) するといいます。

例えば実行中の電卓 (calc.exe) に CDB をアタッチするには次の手順に従います。

1. calc.exe のプロセス ID (PID) を調べます。 
2. > cdb -p <手順1 で取得したPID>

Note CDB -pn calc.exe でアタッチすることも可能です。 しかし、同じイメージ名でも複数のインスタンスがあることがしばしばあります。ここでは汎用的な方法として PID を探る手順を基本としました。慣れたらどちらでもよいと思います。

プロセス ID を調べる方法

タスクマネージャを利用する方法

[表示] メニューから [列の選択] を選択します。すると PID が表示されるようになります。

筆者の現在の環境では、calc.exe の PID は 1064 であることがわかりました。

tlist を利用する方法

Debugging Tools for Windows には tlist.exe というユーティリティが含まれています。tlist を実行すると次のようにプロセス一覧が表示されます。

> tlist
   0 System Process
   4 System
 824 smss.exe
 872 csrss.exe
 896 winlogon.exe      NetDDE Agent
 952 services.exe
 964 lsass.exe
1144 svchost.exe
1396 svchost.exe
1640 svchost.exe
1656 svchost.exe
1828 spoolsv.exe
 496 svchost.exe
1316 explorer.exe      Program Manager
1564 realplay.exe
1572 ctfmon.exe
1064 calc.exe          電卓
1856 cmd.exe           C:\WINXP\System32\cmd.exe - tlist
 436 conime.exe
1108 tlist.exe

この出力から calc.exe の PID が 1064 であることがわかります。

CDB のアタッチ

PID がわかればアタッチは簡単です。次のように -p オプションをつけて CDB を実行します。

> CDB -p 1064 

ここで、1064 という数字は上記の手順で調べた PID です。

必須ではない環境設定

CDB を使いやすくするために、コマンドプロンプトの環境設定を行うことをお勧めします。お勧めは二つの設定です。ひとつはコマンドプロンプトの簡易編集モードと画面のバッファのサイズの拡大です。

コマンドプロンプトのプロパティを選択して以下の箇所で設定します。

筆者は [画面バッファのサイズ] は [幅] = 150、[高さ] = 3000 くらいにしています。

筆者は [簡易編集モード] をチェックしています。こうすると、文字を選択して Enter キーを押すとコピーができ、右クリックで貼り付けることができます。

アタッチができると次のように表示されます。

> cdb -p 1064

Microsoft (R) Windows User-Mode Debugger  Version 3.0.0020.0
Copyright (c) Microsoft Corporation. All rights reserved.

*** wait with pending attach
Loaded dbghelp extension DLL
Loaded ext extension DLL
Loaded exts extension DLL
Loaded uext extension DLL
Loaded ntsdexts extension DLL
Symbol search path is: srv*\\keisukeo105\symbols ← シンボルパス
Executable search path is:
ModLoad: 01000000 0101f000   C:\WINXP\System32\calc.exe
ModLoad: 77f50000 77ff9000   C:\WINXP\System32\ntdll.dll
ModLoad: 77e20000 77f42000   C:\WINXP\system32\kernel32.dll
ModLoad: 77380000 77b74000   C:\WINXP\system32\SHELL32.dll
ModLoad: 77bc0000 77c13000   C:\WINXP\system32\msvcrt.dll
ModLoad: 77c20000 77c60000   C:\WINXP\system32\GDI32.dll
ModLoad: 77cf0000 77d7d000   C:\WINXP\system32\USER32.dll
ModLoad: 77d80000 77e19000   C:\WINXP\system32\ADVAPI32.dll
ModLoad: 77c70000 77ce5000   C:\WINXP\system32\RPCRT4.dll
ModLoad: 77280000 772e3000   C:\WINXP\system32\SHLWAPI.dll
ModLoad: 762e0000 762fa000   C:\WINXP\System32\IMM32.DLL
ModLoad: 60740000 60748000   C:\WINXP\System32\LPK.DLL
ModLoad: 72ef0000 72f4a000   C:\WINXP\System32\USP10.dll
ModLoad: 71950000 71a34000   C:\WINXP\WinSxS\x86_Microsoft.Windows.
Common-Controls_6595b64144ccf1df_6.0.0.0_x-ww_1382d70a\comctl32.dll
ModLoad: 58730000 58764000   C:\WINXP\system32\uxtheme.dll
ModLoad: 74660000 746ab000   C:\WINXP\System32\MSCTF.dll
ModLoad: 3a700000 3a754000   C:\WINXP\System32\imjp81.ime
ModLoad: 648f0000 649bc000   C:\WINXP\System32\IMJP81K.DLL
ModLoad: 3b100000 3b11c000   C:\WINXP\IME\IMJP8_1\Dicts\IMJPCD.DIC
ModLoad: 5e320000 5e32f000   C:\WINXP\System32\mslbui.dll
ModLoad: 770d0000 7715b000   C:\WINXP\system32\oleaut32.dll
ModLoad: 77160000 7727a000   C:\WINXP\system32\OLE32.DLL
Break instruction exception - code 80000003 (first chance)
eax=7ffdf000 ebx=00000001 ecx=00000002 edx=00000003 esi=00000004 edi=00000005
eip=77f7f570 esp=032affcc ebp=032afff4 iopl=0         nv up ei pl zr na po nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000246
ntdll!DbgBreakPoint:
77f7f570 cc               int     3
0:001>

ここで、前節でご説明したシンボルパスが設定されていることに注意してください。筆者の環境では _NT_SYMBOL_PATH 環境変数に srv*\\keisukeo105\symbols という値が設定してあります。

この状態がデバッガがターゲットアプリケーションにアタッチしている状態です。この状態になればさまざまなコマンドを用いてプログラムを診断することができるようになります。

よく使うコマンドを覚えよう

g - 実行

デバッガをアタッチしたままですと、ターゲットアプリケーションは停止したままです。これを実行するのが g コマンドです。

k - スタックバックトレースの表示

k コマンドでスタックバックトレースを確認することができます。k コマンドにはいつくかのバリエーションがあります。kv コマンドは FPO 情報を含め出力し、kn はフレームの番号を出力します。そのほかは kd などがありますが、詳細はデバッガのヘルプをご覧ください。

bp - ブレークポイントの設定

デバッガをあるタイミングで停止したいということがあります。例えば、CreateFile API を呼び出したタイミングでアプリケーションを停止して、どのようなファイルを開こうとしたのかを確認する場合などです。その場合は次のようにします。

例: CreateFile API にブレークポイントを仕掛ける場合

MSDN などで CreateFile API を調べます。すると Kernel32.dll に実装されていることがわかります。そこで、

> x kernel32!CreateFile* 

を実行します。 x コマンドでシンボルとアドレスを探し出します。

> bp kernel32!CreateFileW 

として CreateFileW にブレークポイントを設定します。 CreateFileW を選択したのは筆者の環境が Windows XP だからです。

実行例

これでブレークポイントの設定ができたはずです。それでは実際に CreateFileW を呼び出すタイミングでアプリケーションが停止することを確認しましょう。

電卓 の [ヘルプ] メニューから [トピックの検索] を選択します。すると筆者の環境では確かにブレークポイントがヒットしてスタックバックトレースから取得したアドレスから開こうとしていたファイルの名前がわかりました。ご参考のためデバッグの実際の表示を掲載します。

0:001> x kernel32!CreateFile* ←kernel32 にある CreateFile で始まるシンボルを検索
77e376d3  kernel32!CreateFileMappingW
77e379b1  kernel32!CreateFileW
77e37797  kernel32!CreateFileMappingA
77e3a837  kernel32!CreateFileA
0:001> bp kernel32!CreateFileW kernel32!CreateFileW にブレークポイントを設定
0:001> g プログラムの実行. ブレークポイントがヒットするのを待ちます
ModLoad: 5d300000 5d383000   C:\WINXP\System32\hhctrl.ocx
ModLoad: 76040000 760b8000   C:\WINXP\system32\urlmon.dll
ModLoad: 77bb0000 77bb7000   C:\WINXP\system32\VERSION.dll
ModLoad: 71a50000 71a61000   C:\WINXP\system32\MPR.dll
ModLoad: 63000000 63094000   C:\WINXP\system32\WININET.dll
ModLoad: 76210000 7629a000   C:\WINXP\system32\CRYPT32.dll
ModLoad: 761f0000 761ff000   C:\WINXP\system32\MSASN1.dll
ModLoad: 677d0000 677e8000   C:\WINXP\System32\mui\0411\hhctrlui.dll
ModLoad: 76f80000 76ff8000   C:\WINXP\System32\CLBCATQ.DLL
ModLoad: 77000000 770c5000   C:\WINXP\System32\COMRes.dll
ModLoad: 63bd0000 63bf1000   C:\WINXP\System32\itss.dll
Breakpoint 0 hit ブレークポイントがヒット
eax=7ffdcbf8 ebx=00000016 ecx=7ffdcc00 edx=032eed4e esi=00000080 edi=000c4abc
eip=77e379b1 esp=032eece8 ebp=032eed08 iopl=0         nv up ei pl nz na pe nc
cs=001b  ss=0023  ds=0023  es=0023  fs=0038  gs=0000             efl=00000202
kernel32!CreateFileW:
77e379b1 55               push    ebp
0:002> kv ←スタックバックトレースを表示
ChildEBP RetAddr  Args to Child
032eece4 77e3a864 7ffdcc00 80000000 00000001 kernel32!CreateFileW (FPO: [Non-Fpo])
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for 
C:\WINXP\System32\itss.dll -
032eed08 63bd99ca 032eed38 80000000 00000001 kernel32!CreateFileA+0x2e (FPO: [Non-Fpo])
032eee44 63bd9a1c 032eeed0 00000001 00000000 itss!DllGetClassObject+0x6725 (FPO: [Non-Fpo])
032eee54 63bd97f4 032eeed0 00000020 00000000 itss!DllGetClassObject+0x6777 (FPO: [2,0,0])
032eee68 63bd5a0f 00000000 032eeed0 00000020 itss!DllGetClassObject+0x654f (FPO: [Non-Fpo])
032eee8c 63be3655 00000000 032eeed0 00000020 itss!DllGetClassObject+0x276a (FPO: [Non-Fpo])
032eeea0 5d31996c 000c4a64 032eeed0 00000000 itss!DllGetClassObject+0x103b0 (FPO: [7,0,0])
032ef0d8 5d34420c 03310f70 00000020 00000001 hhctrl!CFileSystem__Open+0x61
032ef0f8 5d344047 03310f70 00000000 03310de0 hhctrl!CExTitle__exOpenFile+0x80
032ef224 5d342908 00000000 032a1e90 032a1e90 hhctrl!CExTitle__OpenTitle+0x143
032ef6c0 5d341ad9 03310de0 03310c7c 032a1e90 hhctrl!CExCollection__GetMergedTitles+0x34
032ef818 5d340738 03310c7c 03310c00 00000000 hhctrl!CExCollection__InitCollection+0x53
032efa9c 5d341428 03310be0 00000000 00000000 hhctrl!CHmData__ReadSystemFiles+0x4b
032efab8 5d341357 03310be0 0001d832 00000000 hhctrl!AddTitleToGlobalList+0x46
032efad4 5d32462d 03310ba0 00000000 00000000 hhctrl!FindCurFileData+0xa9
032efc1c 5d323ab3 00010014 03310a70 03310b30 hhctrl!OnDisplayTopic+0x209
032efc4c 5d323752 00010014 03310a70 00000000 hhctrl!xHtmlHelpA+0x56
032efd78 5d321a06 00010014 000957be 00000000 hhctrl!xHtmlHelpW+0x88
032efd9c 77cf3a5f 0011045e 00000687 0006f864 hhctrl!ApiWndProc+0x6e
032efdc8 77cf3b2e 5d321998 0011045e 00000687 USER32!InternalCallWinProc+0x1b
0:002> dc 7ffdcc00 ←MSDN を見ると CreateFile の第一引数は開こうとするファイル名
なのでそのアドレスを渡してメモリの内容を見る
7ffdcc00  003a0043 0057005c 004e0049 00500058  C.:.\.W.I.N.X.P.
7ffdcc10  0048005c 006c0065 005c0070 00610063  \.H.e.l.p.\.c.a.
7ffdcc20  0063006c 0063002e 006d0068 006c0000  l.c...c.h.m...l.
7ffdcc30  00000065 002e0063 00680063 0000006d  e...c...c.h.m...
7ffdcc40  00000000 00000000 00000000 00000000  ................
7ffdcc50  00000000 00000000 00000000 00000000  ................
7ffdcc60  00000000 00000000 00000000 00000000  ................
7ffdcc70  00000000 00000000 00000000 00000000  ................
0:002> du 7ffdcc00 ←003a0043 のようなパターンは Unicode なので同じアドレスを 
Unicode として出力してみる
7ffdcc00  "C:\WINXP\Help\calc.chm" ← このファイルが CreateFile で操作されるところだったことがわかった

WinDbg

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Web/DB プログラミング徹底解説