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 で操作されるところだったことがわかった