WinDbg. From A to Z!
Everything you need to know about WinDbg.
And nothing you don’t.

By Robert Kuster
December 2007. All rights reserved.
www.windbg.info

Japanese Edition By Tsuyoshi Oguni, February 2009
日本語版 小國 健 (NTT DATA)
1WinDbgを選ぶ理由
なぜなら、WinDbgは...


マイクロソフトのWindowsプロダクトチームが、Windowsの開発に利用している

よく使われているVisual Studioのデバッガよりも高機能

拡張DLLによる、機能の拡張が可能



Windows OS自⾝がもつデバッグエンジンを利用

Windows XP以降では、dbgeng.dllとdbghelp.dllが「C:¥Windows¥System32」にイ
ンストールされている。

2
www.windbg.info

「WinDbg. From A to Z」の目的


WinDbgのドキュメントは、入門者には分かりづらい

優れたドキュメントや使用例がないと、WinDbgの習得は非常に困難

インストールしたものの、すぐにあきらめてしまう人も多い。

「WinDbg. From A to Z!」は、WinDbgの簡単な導入マニュアルである。本資料を読めば、WinDbgとは何なのか、何ができるのかが分かる。

「WinDbg. From A to Z!」は、ユーザーモードでの使用例をもとに説明しているが、カーネルモードでの開発にも役⽴つ。ユーザーモードのデバッグでも、カーネルモードのデバッグでも、裏で動いているデバッグエンジンは変わらない。基本的に、カーネル
モードでは、使用する拡張コマンドが違うに過ぎない。

3
www.windbg.info

目次 – ロードマップ
 WinDbgの裏側• WinDbgの使い方• グローバルフラグ• アプリケーション検証• プロセスダンプ
4
www.windbg.info

Windows XP用のデバッグツール• WinDbg.exe• ntsd.exe• cdb.exe• kd.exe• dbgsrv.exe• userdump.exe• drwtsn32.exe

dbgeng.dll• livekd.exe• OlyDbg.exe• ProcessExplorer.exe• ...

dbghelp.dll

5
www.windbg.info

デバッグヘルプライブラリ: dbghelp.dll


MSDNにドキュメントありWindows 2000以降に同梱されている



以下のサポートルーチンを含む

a) プロセスのダンプ取得(MiniDumpWriteDump, DbgHelpCreateUserDump, ...)b) スタックトレースの取得(StackWalk64, ...)c) シンボルの操作(SymFromAddr, Sym*, ...)d) 実⾏イメージからの情報取得(ImageNtHeader, FindDebugInfoFile, ...)
c)やd)の関数の多くは、まったく同じ宣言のものが、imagehlp.dllでもエクスポートされている。

imagehlpの関数は、単にdbghelpの関数にフォワードされているものが多いが、逆アセンブルしてみると、同じソースから作られているものもあることが分かる（次のスライドの逆アセンブルを参照）。マイクロソフトのツールには、DbgHelp.dllを優先的に使っているものもあれば、Visual

StudioやDependency Walkerのようにimagehlp.dllを使っているものもある。両方を使っているものもある。

6www.windbg.info

dbghelp!ImageNtHeaderとimagehlp!ImageNtHeaderの比較

7
www.windbg.info

ImageHlpの依存関係

8
www.windbg.info

デバッガエンジンAPI: dbgeng.dll


WinDbgのドキュメントに説明あり

dbgeng.dllのヘッダファイルとlibファイルは、WinDbgのインストール時にカスタムイ

ンストールを選び「SDK」コンポーネントを選択すると入手できる。



Windows XP 以降に同梱されている



COMインタフェースを使ってアクセス IDebugAdvanced, IDebugControl, IDebugSystemObjects, ...



デバッガが実現している動作はすべて、COMインタフェース
で公開されている

事実1: WinDbgは、デバッグエンジン上のシェルに過ぎない。
事実2: このエンジンを利用して、独自に新ツールを開発することも可能。
9
www.windbg.info

DbgEngの依存関係

10
www.windbg.info

デバッグシンボル

実⾏可能ファイルは、単なるバイトの羅列

デバッガにシンボルを与えると...



実⾏可能ファイルのアドレスと、ソースコードの⾏が関連付けられる

アプリケーションの内部の配置やデータを分析プログラムデータベース  PDBファイル


最新のマイクロソフトデバッグ情報フォーマット
COFFとCodeViewは非推奨



PDBの情報は、実⾏可能ファイルとは別のファイルに格納される



PDBのフォーマットは非公開



PDBを扱う特別なAPIあり: DbgHelp.dllやMsDiaXY.dll

11
www.windbg.info

デバッグ情報の種類
情報の種類

説明

パブリックな関数と変数

さまざまなコンパイル単位から参照される関数
や変数

FPO情報

FPO最適化（フレームポインタ省略）を指定してコンパイルされた場合にスタックフレームを取り出すための追加情報

プライベートな関数と変数

ローカル変数や、関数のパラメータなどを含む、すべての関数や変数

ソースファイルと⾏情報

ソースファイルと⾏の情報

型情報

関数と変数の追加情報
変数: 型(int, string, ...)
関数: パラメータの個数と型, 呼び出し規約,
戻り値

リンカ:

/pdbstripped

マイクロソフトのモジュール(kernel32.dll, user32.dll, ...)では、常にパブリックなシンボルが取り除かれている。

12
www.windbg.info

デバッグ情報の生成

ビルドの処理は、次の2段階から成る

1) コンパイラ: マシン語の命令を生成し、.OBJファイルに格納

2) リンカ: 関連する.OBJファイルや.LIBファイルを、最終的な実⾏可能ファイルにまとめる



デバッグ情報の生成も、次の2段階から成る

1) コンパイラ: ソースファイルごとに、デバッグ情報を生成

2) リンカ: 関連するデバッグ情報を、実⾏可能ファイルに対する最終的なデバッグ情報としてまとめる

コンパイラオプション: /Z7, /Zi, /ZI

リンカオプション: /debug, /pdb, /pdbstripped
スタティックライブラリに関する注意: /Z7 オプションを使用すると、生成される.LIBファイルにデバッグ情報を格納できる。

13
www.windbg.info

デバッグ情報のマッチング

ビルド時に、署名が、実⾏可能ファイ
ルとPDBファイルに埋め込まれる
PDB 2.0 ファイル: タイムスタンプ

PDB 7.0 ファイル: ビルド時に生成されたGUID

デバッガの突き合わせ処理では、この署名が同一のものである必要がある



PDBファイルの検索アルゴリズム

1. モジュール（EXEやDLL）のフォルダを検索

2. PEファイル（NB10またはRSDSデバッグヘッダ）内で指定された名前とパスを検索
3. 環境変数_NT_SYMBOL_PATHや_NT_ALT_SYMBOL_PATH内を検索

14
www.windbg.info

コールスタック

有効なシンボルなし

002df350
002df43c
002df544
002df550
002df57c
002df5f8002df648
002df668
002df694002df70c
002df744002df764002df788002df7a4
002df7c8002df900002df920
002df99c
002df9bc
002df9f8

ntdll!DbgBreakPoint
TestApplication+0x127eb
TestApplication+0x12862
MFC80UD!AfxDlgProc+0x3e
USER32!InternalCallWinProc+0x28
USER32!UserCallDlgProcCheckWow+0x102
USER32!DefDlgProcWorker+0xb2
USER32!DefDlgProcW+0x29
USER32!InternalCallWinProc+0x28
USER32!UserCallWinProcCheckWow+0x16a
USER32!CallWindowProcAorW+0xab
USER32!CallWindowProcW+0x1b
MFC80UD!CWnd::DefWindowProcW+0x32
MFC80UD!CWnd::Default+0x3b
MFC80UD!CDialog::HandleInitDialog+0xd3
MFC80UD!CWnd::OnWndMsg+0x817
MFC80UD!CWnd::WindowProc+0x30
MFC80UD!AfxCallWndProc+0xee
MFC80UD!AfxWndProc+0xa4
MFC80UD!AfxWndProcBase+0x59



有効なシンボルあり

002df350
002df43c
002df544
002df550
002df57c
002df5f8002df648
002df668
002df694002df70c
002df744002df764002df788002df7a4
002df7c8002df900002df920
002df99c
002df9bc
002df9f8

ntdll!DbgBreakPoint
TestApplication!CMyDlg::PreInit+0x3b [MyDlg.cpp @ 75]
TestApplication!CMyDlg::OnInitDialog+0x52 [MyDlg.cpp @ 91]
MFC80UD!AfxDlgProc+0x3e
USER32!InternalCallWinProc+0x28
USER32!UserCallDlgProcCheckWow+0x102
USER32!DefDlgProcWorker+0xb2
USER32!DefDlgProcW+0x29
USER32!InternalCallWinProc+0x28
USER32!UserCallWinProcCheckWow+0x16a
USER32!CallWindowProcAorW+0xab
USER32!CallWindowProcW+0x1b
MFC80UD!CWnd::DefWindowProcW+0x32
MFC80UD!CWnd::Default+0x3b
MFC80UD!CDialog::HandleInitDialog+0xd3
MFC80UD!CWnd::OnWndMsg+0x817
MFC80UD!CWnd::WindowProc+0x30
MFC80UD!AfxCallWndProc+0xee
MFC80UD!AfxWndProc+0xa4
MFC80UD!AfxWndProcBase+0x59

15
www.windbg.info

侵入的アタッチと非侵入的アタッチ


侵入的アタッチ–––DebugActiveProcessが呼び出される
break-inスレッドが生成される

Windows XP以前では、デバッガ終了時やデタッチ時に、デバッグ対象アプリケーションが強制終了される–

侵入的デバッガとしてアタッチできるのは、プロセス当たり一度にひとつだけ–

OpenProcessが呼び出される

非侵入的アタッチ
–
–
–
–
–
–
–
–
–

break-inスレッドは生成されないプロセスに対し、デバッガとして真のアタッチをするわけではない
デバッグ対象アプリケーションのスレッドはすべて凍結状態
メモリの内容の変更や確認は可能

ブレークポイントはセットできない

アプリケーションのステップ実⾏はできない

デバッグ対象アプリケーションを終了することなく、デバッガの終了やデタッチが可能

ひとつのプロセスに、複数の非侵入的デバッガ（＋ひとつの侵入的デバッガ）をアタッチできる
こんな場合に便利...
Visual Studioなどの侵入的デバッガでアプリケーションをデバッグ中でも、WinDbgを非侵入的デバッガとしてアタッチし、追加の情報を取得できる。
デバッグ対象アプリケーションは完全に凍結しており、真のアタッチに必要なbreak-inス
レッドが生成されることはない。

16
www.windbg.info

例外

言語に依存しない、システムが提供する機能

例外は、言語の拡張機能を使って処理
例: C++の__try & __except構造

処理時間が重視される箇所で、try-catch-exceptを条件チェックに使わないこと

例外発生のたびに、システムは例外レコードを生成し、全スタックフレームを通してフ

レームベースの例外ハンドラ(catch-except)を逆向きに検索し、それからようやくプロ

グラムの実⾏を継続する。この処理には何百もの命令を要するため、性能が低下する。

17
www.windbg.info

例外のディスパッチ

1) システムはまず、プロセスのデバッガがあれば、そこに例外を通知しようとする。

2) プロセスがデバッグ中でない場合や、関連付けられているデバッガが例外をハンドリングしない（WinDbg  gN == 例外をハンドリングしないで実⾏する）場合は、システムはフレームベースの例外ハンドラを探す。

3) フレームベースのハンドラが⾒つからない場合や、その例外をハンドリングする例外ハンドラがない

場合は、UnhandledExceptionFilterがプロセスのデバッガに再度例外を通知しようとする。この例外

は、セカンドチャンスまたはラストチャンスの通知として知られている。

4) プロセスがデバッグ中でない場合や、関連付けられているデバッガが例外をハンドリングしない場合
は、AeDebugで指定された事後分析デバッガが起動される。

18
www.windbg.info

例外のディスパッチとSetUnhandledExceptionFilter

19
www.windbg.info

AeDebug? 事後分析デバッグ！


事後分析デバッガの指定と変更


WinDbg -I

drwtsn32 -i

事後分析デバッガの設定

HKLM¥SOFTWARE¥Microsoft¥Windows NT¥CurrentVersion¥AeDebug
AeDebugに指定したプログラムは、何でも実⾏される。

そのプログラムが本当にデバッガなのかどうかは、検証されない。

20
www.windbg.info

目次 – ロードマップ
 WinDbgの裏側

 WinDbgの使い方• グローバルフラグ• アプリケーション検証• プロセスダンプ
21
www.windbg.info

WinDbgのコマンド

標準コマンド––

例: k, lm, g

メタコマンド（ドットコマンド）––

プロセスのデバッグに使われる

通常、デバッガの制御に使われる

例: .sympath, .cls, .lastevent, .detach, .if

拡張コマンド–––––拡張DLL内に、エクスポート関数として実装されている
WinDbgが強⼒なデバッガである大きな理由

拡張DLL一式がインストール済み: exts.dll, ntsdexts.dll, uext.dll,
wow64exts.dll, kdexts.dll, ...
独自に拡張DLLを開発することも可能

例: !analyze, !address, !handle, !peb22
www.windbg.info

おもな拡張DLL









!exts.help

 一般的な拡張コマンド!Ntsdexts.help

 ユーザーモードの拡張コマンド（OS依存）!Uext.help!Kdexts.help!logexts.help!clr10¥sos.help!wow64exts.help...

 ユーザーモードの拡張コマンド（OS非依存） カーネルモードの拡張コマンド
 ログ取得拡張コマンド

 マネージコードのデバッグ Wow64デバッガ拡張

23
www.windbg.info

WinDbgにおけるシンボルの設定
_NT_SYMBOL_PATH環境変数の設定は必須

WinDbgのGUIからも、シンボルの設定が可能

マイクロソフト用シンボルの設定例:_NT_SYMBOL_PATH=srv*c:¥Symbols¥MsSymbols*http://msdl.microsoft.com/dow
nload/symbols;
この設定を⾏うと、WinDbgは、マイクロソフトのコンポーネント（kernel32など）用のシ
ンボルを、マイクロソフトのサーバーから必要に応じて自動的にダウンロードする。

–

（メニュー）File  Symbol File Path...（Ctrl+S）

便利なコマンド
–
–
–
–
–
–
–
–
–

.sympath シンボルの検索パスの取得と設定!sym noisy

 シンボルの検索情報を表⽰するようデバッガに指⽰.sympath+ XY
ld kernel32
ld *.reloadx kernel32!*

 シンボルの検索パスに、XYディレクトリを追加
 kernel32.dllのシンボルを読み込む

 すべてのモジュールのシンボルを読み込む シンボル情報を読み直す kernel32の全シンボルを調べて一覧表⽰

x kernel32!*LoadLibrary*  LoadLibraryという⽂字列を含むkernel32の全シンボルを一覧表⽰
dt ntdll!*

 ntdll内の全変数を表⽰

24www.windbg.info

WinDbgにおけるソースの設定
_NT_SOURCE_PATH環境変数の設定は必須
例: _NT_SOURCE_PATH=C:¥Sources

WinDbgのGUIからも、ソースの設定が可能–（メニュー）File  Source File Path...（Ctrl+P）

便利なコマンド––.srcpath.srcpath+ XY

 ソースファイルの検索パスの取得と設定

 ソースの検索パスに、XYディレクトリを追加

重要: WinDbgに、シンボルとソースを正しく設定すること。これが、WinDbgの入門者がミスしやすい、最初の重要なステップである。マイク
ロソフトのコンポーネント(kernel32.dll, ntdll.dll,...)のシンボルがなけ
れば、以下のセクションで⽰すコマンドの大半が動作しないので注意。

25
www.windbg.info

Windows NTのプロセスとスレッド



すべてのWindowsプロセスは、カーネルモードのエグゼクティブプロセスブロック(EPROCESS)で表される。



EPROCESSは、プロセスに関連のあるデータ構造を、数多く指し⽰している。たとえば、各プロセスは、エグゼクティブスレッドブロック(ETHREAD)で表されるスレッドをひとつ以上持っている。



EPROCESSは、プロセスのアドレス空間にあるプロセス環境ブロック(PEB)を指す。



ETHREADは、プロセスのアドレス空間にあるスレッド環境ブロック(TEB)を指す。

26
www.windbg.info

PEBとTEBPEB=プロセス環境ブロック
–
–
–
–
–
–



イメージの基本情報（ベースアドレス, バージョン番号, モジュール一覧）
プロセスヒープの情報
環境変数

コマンドライン引数
DLL検索パス

PEBの表⽰方法: !peb, dt nt!_PEB

TEB=スレッド環境ブロック–––

スタック情報（スタック下限, スタック上限）
TLS（スレッドローカルストレージ）配列
TEBの表⽰方法: !teb, dt nt!_TEB

事実: 多くのWinDbgのコマンド(lm, !dlls, !imgreloc, !tls, !gle)は、PEBやTEBから取得したデータを利用している。
27
www.windbg.info

例 - PEBの「ダンプ」
0:001> dt nt!_PEB -r @$peb // @$peb = プロセスのPEBのアドレス（疑似レジスタの文法を参照）+0x000 InheritedAddressSpace : 0 ''+0x001 ReadImageFileExecOptions : 0 ''+0x002 BeingDebugged : 0x1 ''...
+0x008 ImageBaseAddress : 0x00400000+0x00c Ldr : 0x7d6a01e0 _PEB_LDR_DATA+0x000 Length : 0x28
+0x004 Initialized : 0x1 ''+0x008 SsHandle : (null)+0x00c InLoadOrderModuleList : _LIST_ENTRY [ 0x2d1eb0 - 0x2da998 ]+0x000 Flink : 0x002d1eb0 _LIST_ENTRY [ 0x2d1f08 - 0x7d6a01ec ]+0x004 Blink : 0x002da998 _LIST_ENTRY [ 0x7d6a01ec - 0x2d9f38 ]+0x014 InMemoryOrderModuleList : _LIST_ENTRY [ 0x2d1eb8 - 0x2da9a0 ]...
+0x01c InInitializationOrderModuleList : _LIST_ENTRY [ 0x2d1f18 - 0x2da9a8 ]...
+0x024 EntryInProgress : (null)+0x010 ProcessParameters : 0x001c0000 _RTL_USER_PROCESS_PARAMETERS+0x000 MaximumLength : 0x102c+0x004 Length : 0x102c+0x008 Flags : 0x4001+0x00c DebugFlags : 0...
+0x024 CurrentDirectory : _CURDIR+0x000 DosPath : _UNICODE_STRING "D:¥Development¥Utils¥"+0x008 Handle : 0x00000024+0x030 DllPath : _UNICODE_STRING "C:¥WINDOWS¥system32;C:¥WINDOWS¥system;C:¥WINDOWS;...”...

28
www.windbg.info

プロセスやモジュールの情報を取得するためのWinDbgコマンド
コマンド

説明

!peb

プロセス環境ブロック(PEB)の情報を整形して表⽰

dt nt!_PEB Addr

PEBの全ダンプlm

ロードモジュールやアンロードモジュールの一覧

lmD

上に同じ。デバッガマークアップ言語で出⼒。

lm vm kernel32

kernel32の詳細を出⼒（イメージやシンボルの情報を含む）!lmi kernel32

上に同じ。DLL拡張による実装。

!dlls

ロードモジュールの一覧。ローダーに関する情報（エントリポイ
ント, ロードカウント）を含む。

!dlls -c kernel32

上に同じ。ただしkernel32のみ。

!imgreloc

再配置情報の表⽰!dh kernel32

kernel32のヘッダを表⽰

29
www.windbg.info

例 - モジュール情報
0:001>!dlls -c msvcrt
Dump dll containing 0x77ba0000:
0x002d40c0: C:¥WINDOWS¥system32¥msvcrt.dll
Base 0x77ba0000
EntryPoint 0x77baf78b
Flags 0x80084006
LoadCount 0x00000007
LDRP_STATIC_LINKLDRP_IMAGE_DLL
LDRP_ENTRY_PROCESSEDLDRP_PROCESS_ATTACH_CALLED
0:001> lm vm msvcrt
start
end
77ba0000 77bfa000
Image path:
Image name:Timestamp:
CheckSum:
ImageSize:
File version:
Product version:...
CompanyName:
ProductName:
InternalName:
OriginalFilename:ProductVersion:
FileVersion:
FileDescription:
LegalCopyright:

Size
TlsIndex

0x0005a000
0x00000000

module namemsvcrt (deferred)
C:¥WINDOWS¥system32¥msvcrt.dll
msvcrt.dll
Fri Mar 25 03:33:02 2005 (4243785E)
0006288A
0005A000
7.0.3790.1830
6.1.8638.1830
Microsoft Corporation
Microsoft® Windows® Operating System
msvcrt.dll
msvcrt.dll
7.0.3790.1830
7.0.3790.1830 (srv03_sp1_rtm.050324-1447)
Windows NT CRT DLL© Microsoft Corporation. All rights reserved.

30
www.windbg.info

スレッドの情報を取得するためのWinDbgコマンド
コマンド

説明

~

全スレッドのスレッド状態~0

スレッド0のスレッド状態~.

現在アクティブなスレッドのスレッド状態~*

全スレッドのスレッド状態。追加情報あり（プライオリティ, 開始アドレス）。

~*k

全スレッドのコールスタック（~ と !uniqstack）~<thread>s

カレントスレッドの設定!gle

ラストエラーの取得!runaway 各スレッドの消費時間を表⽰
 どのスレッドが制御不能になっているのか、CPUタイムを大量に消費しているのかを調べる簡便な方法!teb

スレッド環境ブロック(TEB)の情報を整形して表⽰

dt nt!_TEB Addr

TEBの全ダンプ
31
www.windbg.info

例 - スレッド
0:001> !runaway 7
User Mode TimeThreadTime
0:d28
0 days 0:00:00.015
1:2b0
0 days 0:00:00.000
Kernel Mode TimeThreadTime
0:d28
0 days 0:00:00.093
1:2b0
0 days 0:00:00.000
Elapsed TimeThreadTime
0:d28
0 days 0:04:04.156
1:2b0
0 days 0:03:53.328
0:000> ~*.0
Id: dac.d28 Suspend: 1 Teb: 7efdd000 Unfrozen
Start: TestApp!ILT+1415(_wWinMainCRTStartup) (0041158c)
Priority: 0 Priority class: 32 Affinity: 3
1
Id: dac.2b0 Suspend: 1 Teb: 7efda000 Unfrozen
Start: 00000001
Priority: 0
Priority class: 32 Affinity: 3

0:000> !gle
LastErrorValue: (Win32) 0 (0) - The operation completed successfully.
LastStatusValue: (NTSTATUS) 0 - STATUS_WAIT_0

32
www.windbg.info

WinDbgのウィンドウとメニュー
WinDbgのウィンドウは、ドッキングやフローティングが可能。

1) ドッキングウィンドウ = 複数のウィンドウ使用時におすすめ






WinDbgの枠に合わせて伸び縮みする。

枠を変えると、それに合わせて位置やサイズが相対的に変わる。
タブ化できる。タブ付きのウィンドウは前後に重なり合う。
WinDbgは複数のドックを提供。マルチモニタ環境に重宝。

Ctrl-Tabで、全ドック内の全ウィンドウが順次切り替わる。

2) フローティングウィンドウ（ドッキングなし）


常にWinDbgのウィンドウの前面に表⽰される。

WinDbgの各ウィンドウは、それぞれ独自のメニューをもつ。
メニューの表⽰方法

メニューボタン（［閉じる］ボタンの隣）を左クリック
ウィンドウのタイトルバーを右クリック
タブ付きウィンドウのタブを右クリック

各メニューを試してみるとよい。興味深い隠し機能があることが多い。
33
www.windbg.info

WinDbgでのインスタンス実⾏例

34
www.windbg.info

デバッガマークアップ言語(DML)DMLを使うと、タグ形式の中に指⽰や追加の非表⽰情報を埋め込み、デバッガに出⼒できる。

デバッガのユーザーインタフェースが追加の情報を抜き出し、それに応じて動作する。
DMLのおもな目的を次に⽰す。






関連情報へのリンク

デバッガや拡張DLLがもつ機能の情報提⽰
デバッガや拡張DLLの出⼒の強化

DMLはデバッギングツールのバージョン6.6.0.7で導入された。
DMLコマンド説明.prefer_dml 1

グローバルな設定: すべてのDML強化コマンドがDMLを出⼒。

.help /D a*.helpをDMLモードで実⾏。先頭にリンクを表⽰。

.chain /D.chainをDMLモードで実⾏。拡張DLLを.extmatchコマンドにリンク。

.dml_start

各種DMLコマンドの開始。

その他の各種コマンドについては「..¥Debugging Tools for Windows¥dml.doc」を参照。
35
www.windbg.info

WinDbgのDML

リンクをクリックできる。

リンクを右クリックすると、新しいウィンドウでコマンドを実⾏できる。

36

www.windbg.info

メモリ: スタックの詳細



MSDNより–––新しいスレッドには、コミットメモリと予約メモリから構成される独自のスタック空間が与えられる。

デフォルトでは、各スレッドは1MBの予約メモリと1ページのコミットメモリを使用。
システムは、必要に応じて、予約スタックメモリから1ページずつコミットしていく。
（MSDNのCreateThread > dwStacksize > 「Thread Stack Size」を参照）

37

www.windbg.info

例 - スレッドのスタックサイズ
0:000> !teb
TEB at 7ffdf000
ExceptionList:
StackBase:
StackLimit:…

0012f784
00130000
0012c000

0:000> dt ntdll!_TEB DeallocationStack 7ffdf000+0xe0c DeallocationStack : 0x00030000
0:000> !address esp
AllocBase : SubRegionBase - SubRegionSize
00030000 : 0012c000 - 00004000
Type
00020000 MEM_PRIVATE
Protect
00000004 PAGE_READWRITE
State
00001000 MEM_COMMIT
UsageRegionUsageStack
Pid.Tid
e34.e78
0:000> ? 00130000 - 0012c000
Evaluate expression: 16384 = 00004000
0:000> ? 00130000 - 00030000
Evaluate expression: 1048576 = 00100000
0x004000  本スレッドは4ページ（16KB）のコミットメモリをもつ。
0x100000  本スレッドは256ページ（1MB）の予約メモリをもつ。

38
www.windbg.info

メモリ：スタックの成⻑ESPレジスタは、スレッドの現在のスタックの位置を指す。

プログラムがガードページ内のアドレスにアクセスしようとすると、システムは
STATUS_GUARD_PAGE_VIOLATION(0x80000001)例外を発生させる。ガードページは、
ページのアクセスに対して、一度だけアラームを上げる。
スタックが予約メモリの最後に達すると、STATUS_STACK_OVERFLOWが発生する。

39
www.windbg.info

例 - スタックの成⻑
0:000> !teb
TEB at 7ffdf000
ExceptionList:
StackBase:
StackLimit:…

0012f784
00130000
0012c000

0:000> dt ntdll!_TEB DeallocationStack 7ffdf000+0xe0c DeallocationStack : 0x00030000
0:000> ? 00130000 - 0012c000
Evaluate expression: 16384 = 00004000
0x004000 本スレッドは4ページ（16KB）のコミットメモリをもつ。
0x100000 本スレッドは256ページ（1MB）の予約メモリをもつ。
------------------------------------------------------------------0:000> !teb
TEB at 7ffdf000
ExceptionList:
StackBase:
StackLimit:…

0012f784
00130000
00033000

0:000> ? 00130000 - 00033000
Evaluate expression: 1036288 = 000fd000
0x0fd000  本スレッドのコミットメモリが253ページになった。
さらにページを要求すると、システムはスタックオーバーフロー例外を投げる。

40
www.windbg.info

コールスタック情報を取得するためのWinDbgコマンド
コマンド

説明

!uniqstack

カレントプロセスの全スレッドのコールスタックを表⽰!findstack MySymbol 2

MySymbolを含む全コールスタックを探す

K

カレントスレッドのコールスタックを表⽰kP

P == 各関数呼び出しの全パラメータKf

f == 隣り合うフレームの距離を表⽰（各フレームのスタック消費量のチェックに便利）

Kvv == FOP情報と呼び出し規約を表⽰

Kbb == 各関数に渡された最初の3つのパラメータを表⽰

kM

DML形式で出⼒。
フレーム番号に.frame/dvコマンドがリンクされているため、
そのフレームのローカル変数を表⽰できる。

41
www.windbg.info

例 - UniqStack
0:000> !uniqstack
Processing 2 threads, please wait.0
Id: dac.154c Suspend: 1 Teb: 7efdd000 Unfrozen
Start: TestApp!ILT+1415(_wWinMainCRTStartup) (0041158c)
Priority: 0 Priority class: 32 Affinity: 3
ChildEBP RetAddr
002df44c 00411eeb ntdll!DbgBreakPoint
002df52c 783c2100 TestApp!CMyDialog::OnBnClicked_ExecuteBreakPoint+0x2b [d:¥TestApp¥MyDialog.cpp @ 72]
002df570 783c2842 MFC80UD!_AfxDispatchCmdMsg+0xb0
002df5d4 7839d671 MFC80UD!CCmdTarget::OnCmdMsg+0x2e2
002df610 7836142d MFC80UD!CDialog::OnCmdMsg+0x21…
002dffb8 0041371d TestApp!__tmainCRTStartup+0x289 [f:¥sp¥vctools¥crt_bld¥self_x86¥crt¥src¥crtexe.c @ 589]
002dffc0 7d4e992a TestApp!wWinMainCRTStartup+0xd [f:¥sp¥vctools¥crt_bld¥self_x86¥crt¥src¥crtexe.c @ 414]002dfff0 00000000 kernel32!BaseProcessStart+0x28.1

Id: dac.127c Suspend: 1 Teb: 7efda000 Unfrozen
Start: 00000001
Priority: 0 Priority class: 32 Affinity: 3

ChildEBP RetAddr
0242f550 7d626c3f ntdll!NtQueryAttributesFile+0x12…
0242ff08 7d62b958 ntdll!LdrpCallInitRoutine+0x14
0242ffbc 7d674613 ntdll!LdrShutdownThread+0xd2
0242ffc4 7d665017 ntdll!RtlExitUserThread+0xa
0242fff4 00000000 ntdll!DbgUiRemoteBreakin+0x41
Total threads: 242
www.windbg.info

メモリ操作のためのWinDbgコマンド
コマンド

説明

d, dd, da, du, ...

メモリの表⽰dd == ダブルワード値
da == ASCII⽂字を表⽰
du == UNICODE⽂字を表⽰

f

メモリを指定の値で埋める!vprot MyAddr

アドレスMyAddrの仮想メモリ保護情報を表⽰!address MyAddr

アドレスMyAddrが⽰すメモリの情報（タイプ、保護、使用状況, ...）を表⽰!address –RegionUsageStack

プロセスの全スレッドのスタック領域を表⽰

dds

メモリの内容と、対応するシンボルを表⽰

ddp

メモリの内容と、参照先のメモリの内容を表⽰。
既知のシンボルと一致した場合は、そのシンボルも表⽰。

43
www.windbg.info

例 - プロセスのメモリ情報
0:000> !address
00000000 : 00000000 - 00010000
Type
00000000
Protect
00000001 PAGE_NOACCESS
State
00010000 MEM_FREE
Usage
RegionUsageFree
00010000 : 00010000 - 00001000
Type
00020000 MEM_PRIVATE
Protect
00000004 PAGE_READWRITE
State
00001000 MEM_COMMIT
UsageRegionUsageEnvironmentBlock…
-------------------- Usage SUMMARY -------------------------TotSize (KB)
Pct(Tots) Pct(Busy) Usage
1950000 (25920) : 01.24%
36.03%: RegionUsageIsVAD
7b9b1000 ( 2025156) : 96.57%
00.00%: RegionUsageFree
12e2000 (19336) : 00.92%
26.88%: RegionUsageImage
110000 (1088) : 00.05%
01.51%: RegionUsageStack
2000 (
8) : 00.00%
00.01%: RegionUsageTeb
2a0000 (2688) : 00.13%
03.74%: RegionUsageHeap
1658000 (22880) : 01.09%
31.81%: RegionUsagePageHeap
1000 (
4) : 00.00%
00.01%: RegionUsagePeb
1000 (
4) : 00.00%
00.01%: RegionUsageProcessParametrs
1000 (
4) : 00.00%
00.01%: RegionUsageEnvironmentBlock
Tot: 7fff0000 (2097088 KB) Busy: 0463f000 (71932 KB)…
-------------------- State SUMMARY -------------------------TotSize (KB)
Pct(Tots) Usage
2efa000 (48104) : 02.29%: MEM_COMMIT
7b9b1000 ( 2025156) : 96.57%: MEM_FREE
1745000 (23828) : 01.14%: MEM_RESERVE

44
www.windbg.info

ヒープ情報取得のためのWinDbgコマンド
コマンド

説明

!heap -?

簡単なヘルプ!heap -h

ヒープのインデックスや範囲（=開始アドレス, 終了アドレス）を一覧表⽰!heap -s 0

全ヒープの要約= 予約メモリ, コミットメモリ, ...

!heap -flt s Size

指定のサイズ(Size)に一致する割り当てを表⽰!heap -stat

ヒープハンドルを一覧表⽰
ヒープハンドル = HeapCreateやGetProcessHeapの戻り値!heap -stat -h 0

メモリ割り当てサイズごとに使用状況の統計を表⽰= 各割り当てサイズごとの、サイズ、ブロック数、合計メモリ!heap -p

GFlgasの設定, ヒープハンドルの一覧!heap -p -all

プロセスの全ヒープの全割り当ての詳細= すべてのHeapAlloc呼び出しの一覧!heap -p -a UserAddr

UserAddr（HeapAllocが返却したアドレス）を含むヒープ割り
当ての詳細。取得できれば、バックトレースも表⽰。
45
www.windbg.info

ヒープの構造アプリケーションのページヒープが無効な場合の構造は次の通り。
デフォルトでは、ページヒープは無効。
_HEAP構造–––ntdll.dllで定義: dt ntdll!_HEAP

HeapCreateごとに、一意の_HEAPが存在"!heap -p -all"により、プロセス内の全_HEAP構造のアドレスが取得できる_HEAP_ENTRY構造–––

ntdll.dllで定義: dt ntdll!_HEAP_ENTRY

HeapAllocごとに、一意の_HEAP_ENTRYが存在"!heap -p -all"により、プロセス内の全ヒープエントリのアドレスが取得できる

46
www.windbg.info

ページヒープの構造
アプリケーションのページヒープが有効な場合の構造は次の通り。
ページヒープは、グローバルフラグ(gflags.exe)で有効にできる。
_DPH_HEAP_ROOT構造–––

ntdll.dllで定義: dt ntdll!_DPH_HEAP_ROOT

HeapCreateごとに、一意の_DPH_HEAP_ROOTが存在"!heap -p -all"により、プロセス内の全ヒープのルートのアドレスが取得できる


_DPH_HEAP_ROOTのアドレスは、通常、ヒープハンドルの値 + 0x1000_DPH_HEAP_BLOCK構造–––

ntdll.dll で定義: dt ntdll!_DPH_HEAP_BLOCKHeapAllocごとに、一意の_DPH_HEAP_BLOCKが存在"!heap -p -all"により、プロセス内の全ヒープブロックのアドレスが取得できる

47
www.windbg.info

48
www.windbg.info

HeapAllocの呼び出し元は？


アプリケーションのスタックトレースとページヒープを有効化する––

GFlagsを起動し、目的のイメージに対して「Create user mode stack trace database」と「Enable page heap」を選択
または、コマンドラインから次のように入⼒: gflags.exe /i <IMAGE.EXE> +ust +hpa

アプリケーションを再起動し、WinDbgをアタッチ

WinDbgのコマンドラインにて!heap -p -a <UserAddr>

コールスタックを一覧表⽰。ソース情報なし。

dt ntdll!_DPH_HEAP_BLOCK StackTrace <MyHeapBlockAddr><UserAddr> = 割り当てアドレス（HeapAlloc, newなどの戻り値）<MyHeapBlockAddr> = 事前に取得しておいたDPH_HEAP_BLOCKのアドレス
StackTrace = HeapAllocのコールスタックが格納されている、
DPH_HEAP_BLOCKのメンバー

dds <StackTrace><StackTrace> = 事前に取得しておいた値

コールスタックを一覧表⽰。ソース情報付き。
49
www.windbg.info

例 - HeapAllocの呼び出し元は？
// HeapAlloc( 0x00150000, 8, dwBytes =0x00A00000 ) -->> 0x025F1000;
0:000> !heap -p -a 0x025F1000
address 025f1000 found in_DPH_HEAP_ROOT @ 151000
in busy allocation ( DPH_HEAP_BLOCK:UserAddr
UserSize 15449c:
25f1000
a00000 7c91b298 ntdll!RtlAllocateHeap+0x00000e64
0045b8b1 TestApp!CMyDlg::OnBnClicked_HeapAlloc+0x00000051
004016e0 TestApp!_AfxDispatchCmdMsg+0x00000043
004018ed TestApp!CCmdTarget::OnCmdMsg+0x00000118
00408f7f TestApp!CDialog::OnCmdMsg+0x0000001b…

VirtAddr
25f0000

VirtSize)
a02000

0:000> dt ntdll!_DPH_HEAP_BLOCK StackTrace 15449c+0x024 StackTrace : 0x0238e328 _RTL_TRACE_BLOCK
0:000> dds 0x0238e328
0238e328 abcdaaaa…
0238e334 00000001
0238e338 00a00000
0238e33c 00151000
0238e340 01b17b1c
0238e344 0238e348
0238e348 7c91b298 ntdll!RtlAllocateHeap+0xe64
0238e34c 0045b8b1 TestApp!CMyDlg::OnBnClicked_HeapAlloc+0x51 [d:¥development¥sources¥TestApp¥MyDlg.cpp @ 366]
0238e350 004016e0 TestApp!_AfxDispatchCmdMsg+0x43 [f:¥sp¥vctools¥vc7libs¥ship¥atlmfc¥src¥mfc¥cmdtarg.cpp @ 82]
0238e354 004018ed TestApp!CCmdTarget::OnCmdMsg+0x118 [f:¥sp¥vctools¥vc7libs¥ship¥atlmfc¥src¥mfc¥cmdtarg.cpp @ 381]
0238e358 00408f7f TestApp!CDialog::OnCmdMsg+0x1b [f:¥sp¥vctools¥vc7libs¥ship¥atlmfc¥src¥mfc¥dlgcore.cpp @ 85]…

50
www.windbg.info

HeapCreateの呼び出し元は？


アプリケーションのスタックトレースとページヒープを有効化する––

GFlagsを起動し、目的のイメージに対して、「Create user mode stack trace database」と「Enable page heap」を選択
または、コマンドラインから次のように入⼒: gflags.exe /i <IMAGE.EXE> +ust +hpa

アプリケーションを再起動し、WinDbgをアタッチ

WinDbgのコマンドラインにて!heap -p -h <HeapHandle>"!heap -stat"または"!heap -p"で、プロセスのヒープとそのハンドルが一覧表⽰
できる

dt ntdll!_DPH_HEAP_ROOT CreateStackTrace <MyHeapRootAddr><HeapHandle> = HeapCreateの戻り値<MyHeapRootAddr> = 事前に取得しておいたDPH_HEAP_ROOTのアドレス
CreateStackTrace = HeapCreateのコールスタックが格納されている、
DPH_HEAP_ROOTのメンバー

dds <CreateStackTrace><CreateStackTrace> = 事前に取得しておいた値
コールスタックを一覧表⽰。ソース情報付き。

51
www.windbg.info

例 - HeapCreateの呼び出し元は？
// HeapCreate( 0x0000000A, 0, 0 ) -->> 0x03000000;
0:000> !heap -p -h 0x03000000_DPH_HEAP_ROOT @ 3001000
Freed and decommitted blocks
DPH_HEAP_BLOCK : VirtAddr VirtSize
Busy allocations
DPH_HEAP_BLOCK : UserAddr UserSize - VirtAddr VirtSize…
0:000> dt ntdll!_DPH_HEAP_ROOT CreateStackTrace 3001000+0x08c CreateStackTrace : 0x0238e328 _RTL_TRACE_BLOCK
0:000> dds 0x0238e328
0238e328 abcdaaaa
0238e32c 00000001
0238e330 00000010
0238e334 00000000
0238e338 00000000
0238e33c 00000000
0238e340 00000000
0238e344 0238e348
0238e348 7c93a874 ntdll!RtlCreateHeap+0x41
0238e34c 7c812bff kernel32!HeapCreate+0x55
0238e350 0045b841 TestApp!CMyDlg::OnBnClicked_HeapCreate+0x31 [d:¥development¥sources¥TestApp¥MyDlg.cpp @ 345]
0238e354 0040b122 TestApp!_AfxDispatchCmdMsg+0x43 [f:¥sp¥vctools¥vc7libs¥ship¥atlmfc¥src¥mfc¥cmdtarg.cpp @ 82]
0238e358 0040b32f TestApp!CCmdTarget::OnCmdMsg+0x118 [f:¥sp¥vctools¥vc7libs¥ship¥atlmfc¥src¥mfc¥cmdtarg.cpp @ 381]
0238e35c 00408838 TestApp!CDialog::OnCmdMsg+0x1b [f:¥sp¥vctools¥vc7libs¥ship¥atlmfc¥src¥mfc¥dlgcore.cpp @ 85]…

52
www.windbg.info

ヒープ上のメモリリークの検出

!address -summary

プロセスのメモリ使用状況を要約。RegionUsageHeapやRegionUsagePageHeapが常に増加している場合は、ヒープのメモリリークがあるかもしれない。以下のステップへ。

アプリケーションのスタックトレースとページヒープを有効にする。
アプリケーションを再起動し、WinDbgをアタッチ。

WinDbgのコマンドラインにて!heap -stat -h 0!heap -flt -s <size>

メモリ割り当てサイズごとに使用状況の統計を表⽰。各割り当てサイズごとに、サイズ、ブロック数、合計メモリが表⽰される。
<size> = HeapAllocで割り当てられたサイズ。事前に取得しておいた値。

!heap -p -a <UserAddr><UserAddr> = 割り当てアドレス（HeapAlloc, newなどの戻り値）

コールスタックを一覧表⽰。ソース情報なし。ソース情報付きのコールスタックを表⽰するには、「HeapAllocの呼び出し元は？」のスライドを参照のこと。
53
www.windbg.info

例 - ヒープ上のメモリリークの検出
0:001> !heap -stat -h 0
Allocations statistics forheap @ 00150000
group-by: TOTSIZE max-display: 20
size#blocks
total( %) (percent of total busy bytes)
100000101- 10100000(99.99)
 0x101 * 1MB 割り当てられている。メモリリークの発生が推測される。
928
2- 1250(0.00)
6424- e10 (0.00)…
 サイズが100000の割り当てについて表示
0:001> !heap -flt s 100000_DPH_HEAP_ROOT @ 151000
Freed and decommitted blocks
DPH_HEAP_BLOCK : VirtAddr VirtSize
Busy allocations
DPH_HEAP_BLOCK :UserAddr UserSize- VirtAddr VirtSize
024f0698 :
13831000 00100000 - 13830000 00102000
024f0620 :
13721000 00100000 - 13720000 00102000…  ここに、サイズが100000のエントリが0x101個表示される。
最初のエントリUserAddr=0x13831000について調査。
0:001> !heap -p -a 13831000
address 13831000 found in_DPH_HEAP_ROOT @ 151000
in busy allocation ( DPH_HEAP_BLOCK:UserAddr UserSize - VirtAddr
24f0698:
13831000 100000 13830000
7c91b298 ntdll!RtlAllocateHeap+0x00000e64
0045b74e TestApp!CMyDlg ::OnBnClicked_DoMemoryLeak+0x0000003e
0040b122 TestApp!_AfxDispatchCmdMsg+0x00000043
0040b32f TestApp!CCmdTarget ::OnCmdMsg+0x00000118
00408838 TestApp!CDialog ::OnCmdMsg+0x0000001b…

VirtSize)
10200054
www.windbg.info

クリティカルセクション関連のコマンド
コマンド

説明

!locks

プロセス内のロックされているクリティカルセクションを一覧表⽰!locks -v

プロセス内の全クリティカルセクションを表⽰!cs [オプション] [クリティカルセクションのアドレス]

ひとつ以上のクリティカルセクション、あるいは全クリティ
カルセクションのツリーを表⽰
オプション:-l == ロックされたクリティカルセクションのみを表⽰-s == 各クリティカルセクションの初期化スタックを表⽰-o == 所有者のスタックを表⽰-t == クリティカルセクションのツリーを表⽰
 EnterCntr, WaitCnt, ...

!avrf -cs

削除されたクリティカルセクションを表⽰(DeleteCriticalSection API)55
www.windbg.info

例 - クリティカルセクション
0:000> !cs -s -o 0x0012fe08----------------------------------------Critical section= 0x0012fe08 (+0x12FE08)
DebugInfo= 0x031c4fe0
LOCKED
LockCount= 0x0
OwningThread= 0x00000c8c…
OwningThread Stack =ChildEBP RetAddr Args to Child
0012f488 004badd9 0012f810 02854f10 00000000 ntdll!DbgBreakPoint
0012f568 0054fd2c 00000000 004bb621 00681d70 TestApp!CMyDialog::OnBnClicked_EnterCs+0x39
0012f594 00550365 0012fd78 0000001c 00000000 TestApp!_AfxDispatchCmdMsg+0x9c
0012f5f0 005517f1 0000001c 00000000 00000000 TestApp!CCmdTarget::OnCmdMsg+0x285…
Stack trace for DebugInfo (Initialization Stack)= 0x031c4fe0:
0x7c911a93: ntdll!RtlInitializeCriticalSectionAndSpinCount+0xC9
0x7c809eff: kernel32!InitializeCriticalSection+0xE
0x004c101d: TestApp!CCriticalSection::Init+0x3D
0x004c10a0: TestApp!CCriticalSection::CCriticalSection+0x40…
0:000> !cs -t
Verifier package version >= 3.00
Tree root 02fd8fd0
Level
Node
CS
Debug InitThr EnterThr WaitThr TryEnThr LeaveThr EnterCnt WaitCnt----------------------------------------------------------------------------------------------0 02fd8fd0 0012fe08 031c4fe0
c8c
c8c
0
0
0
1
0
1 02fa8fd0 006807f4 03148fe0
c8c
0
0
0
0
0
0
2 02fa2fd0 00680f70 02850fe0
c8c
c8c
0
0
c8c
4848
0
…

56
www.windbg.info

その他の便利なWinDbgコマンド
コマンド

説明

dt

ローカル変数、関数のパラメータ、グローバル変数、データ型の情報を表⽰

dt ntdll!*peb*

pebという⽂字を含むntdll.dllの全変数を一覧表⽰

dt ntdll!_PEB

PEBの型を表⽰

dt ntdll!_PEB 7efde000

アドレス7efde000のPEBを表⽰

dv

ローカル変数を表⽰

dv /t /i /V

ローカル変数を表⽰/i == カテゴリで分類（パラメータかローカル変数か）/V == アドレスと、フレームのベースレジスタからのオフセットを表⽰（通常はEBP）/t == 型情報を表⽰

57
www.windbg.info

例 - dt と dv
0:000> dt TestApp!CMyDialog+0x000 __VFN_table=00400000 classCObject=00400000 classCCmdTarget=00400000 _commandEntries=00400000 commandMap=00400000 _dispatchEntries...
+0x004 m_dwRef+0x008 m_pOuterUnknown+0x00c m_xInnerUnknown+0x010 m_xDispatch+0x014 m_bResultExpected+0x018 m_xConnPtContainer+0x01c m_pModuleState=00400000 classCWnd+0x020 m_hWnd...
+0x064 m_lpDialogInit+0x068 m_pParentWnd+0x06c m_hWndTop+0x070 m_pOccDialogInfo+0x074 m_hIcon+0x078 m_nn

: Ptr32: CRuntimeClass: CRuntimeClass: [0] AFX_OLECMDMAP_ENTRY: AFX_OLECMDMAP: [0] AFX_DISPMAP_ENTRY: Int4B: Ptr32 IUnknown: Uint4B: CCmdTarget::XDispatch: Int4B: CCmdTarget::XConnPtContainer: Ptr32 AFX_MODULE_STATE: CRuntimeClass: Ptr32 HWND__: Ptr32 Void
: Ptr32 CWnd
: Ptr32 HWND__: Ptr32 _AFX_OCC_DIALOG_INFO: Ptr32 HICON__: Int4B

0:000> dv /t /i /V
prv local 002df440 @ebp-0x08 class CMyDialog * this = 0x002dfe24
prv param 002df450 @ebp+0x08 int nn = 1

58
www.windbg.info

WinDbgの疑似レジスタ

デバッガが仮想的なレジスタを提供
ドル記号($)で始まる

1) 自動疑似レジスタ

デバッガが、便利な値を設定
例: $ra, $peb, $teb, ...

2) ユーザー定義の疑似レジスタ

20個のユーザー定義レジスタ: $t0, $t1, ..., $t19
中間データの格納には整数型の変数が使われる
型情報も保持できる

r?は、型付きの結果を左辺値(lvalue)に割り当てる

r? $t0=@$peb->ProcessParameters––

型付きの値を$t0に割り当て$t0の型が記憶されており、後の式で利用可能?? @$t0->CommandLine

59
www.windbg.info

自動疑似レジスタ
コマンド

説明

$ip

命令ポインタx86 = EIP, Itanium = IIP, x64 = RIP$exentry

カレントプロセスで最初に実⾏されるエントリポイント$retreg

戻り値のレジスタ
x86 = EAX, Itanium = ret0, x64 = rax$csp

コールスタックのポインタ
x86 = ESP, Itanium = BSP, x64 = RSP$peb

プロセス環境ブロック(PEB)のアドレス$teb

カレントスレッドのスレッド環境ブロック(TEB)のアドレス$tpid

プロセスID(PID)$tid

スレッドID(TID)$ptrsize

ポインタのサイズ$pagesize

1ページ分のメモリのバイト数...

WinDbgのヘルプの「Pseudo-Registry Syntax」を参照$ra

スタック上にあるリターンアドレス
実⾏コマンドで便利, 例: "g $ra"60
www.windbg.info

WinDbgの式
1) MASM式
–
–
–
–
–
–

? コマンドで評価

各シンボルはアドレスとして扱われる（シンボルの値は、そのシンボルのメモリアドレ
ス  値を取り出すにはpoiオペレータで逆参照する）`ソース：⾏番号`の式が利用可能(`myfile.c:43`)

レジスタには、アットマークを付けても付けなくてもよい（eaxでも@eaxでも可）WinDbgのヘルプでは、ほとんどすべてにMASM式が使われている
WinDbg 4.0より前のバージョンでは、これが唯一の式

2) C++式––––?? コマンドで評価

シンボルは適切なデータ型で解釈される`ソース:⾏番号`の式は利用不可

レジスタにはアットマークが必要（eaxは不可）

MASMの演算は、常にバイト単位で⾏われる。C++の演算は、C++型のルールに従う（ポインタ演算時のスケーリングを含む）。いずれも、内部では数値はULONG64値で処理される。
61
www.windbg.info

さらに式について


MASM
–
–
–

シンボルの値は、そのシンボルのメモリアドレス
任意の数に対して、任意の演算子が使用可能

数字: 現在の基数にしたがって解釈される：n [8 | 10 | 16]

接頭辞で基数を変更可能: 0x(16進), 0n(10進), 0t(8進), 0y(2進)



C++
–
–
–
–
–
–

変数の値は、その変数がもつ実際の値そのもの
演算子は、対応するデータ型でのみ使用可能

対応するC++データ型をもたないシンボルは、⽂法エラーになる

データ構造は、実際の構造体として適切に使用すること。数値はもたない。

関数名やその他のエントリポイントはメモリアドレスであり、関数のポインタとして扱われる
数字: デフォルトは、常に10進数接頭辞で変更可能: 0x(16進), 0(8進)62
www.windbg.info

例 - 変数の値// ------------------------------------------------------------------void MyFunction() {int nLocalVar = 7;... }// ------------------------------------------------------------------0:000> dd nLocal1 L10012f830 00000007// MASM syntax// ------------0:000> ? nLocalVar// nLocalVarのアドレス（メモリ上の位置）を取得
Evaluate expression: 1243184 = 0012f830
0:000> ? dwo(nLocalVar)
Evaluate expression: 7 = 00000007// nLocalVarの値を取得 - 逆参照// (dwo = ダブルワード, poi = ポインタサイズのデータ)

0:000> ? poi(nLocalVar)
Evaluate expression: 7 = 00000007// C++ syntax// ------------0:000> ?? nLocalVar
int 7
0:000> ?? & nLocalVar
int * 0x0012f830// nLocalVarの値を取得// nLocalVarのアドレス（メモリ上の位置）を取得

63
www.windbg.info

例 - MASM式 対 C++式// -----------------------------------------------------------// 以下の例では、次の値を返す://
eax == ebx ? 0//
eax > ebx ? 1//
eax < ebx ? -1//// C++⽂法の次の点に注意://-> レジスタの値を表すには@が必要//-> BOOLをintに変換するには明⽰的なキャストが必要//-> 等価演算子は、二重のイコール記号// -----------------------------------------------------------0:000> r eax = 4, ebx = 3
0:000> ? 0*(eax = ebx) + 1*(eax > ebx) + -1*(eax < ebx)
Evaluate expression: 1 = 00000001
0:000> ?? 0*(int)(@eax == @ebx) + 1*(int)(@eax > @ebx) + -1*(int)(@eax < @ebx)
int 1
0:000> r eax = 3, ebx = 4
0:000> ? 0*(eax = ebx) + 1*(eax > ebx) + -1*(eax < ebx)
Evaluate expression: -1 = ffffffff
0:000> ?? 0*(int)(@eax == @ebx) + 1*(int)(@eax > @ebx) + -1*(int)(@eax < @ebx)
int -164
www.windbg.info

MASMの一般的な数値演算子
単項演算子
演算子

説明

dwo, qwo, poi

dwo = 指定のアドレスからDWORD分を取得
qwo = 指定のアドレスからQWORD分を取得
poi = 指定のアドレスからポインタサイズ分を取得

wo, bywo = 指定のアドレスから下位WORD分を取得
by = 指定のアドレスから下位BYTE分を取得

二項演算子
演算子

説明

= (または ==), !=等しい, 等しくない<, >, <=, >=より小さい, より大きい, 以下, 以上

and (または &), xor (または ^), or (または |)ビットごとの論理積, ビットごとの排他的論理和, ビットごとの
論理和+, -, *, /加算, 減算, 乗算, 除算<<, >>, >>>左シフト, 右シフト, 算術右シフト
65
www.windbg.info

MASMの非数値演算子
演算子

説明$iment(Address)

イメージのエントリポイント。Address=イメージのベースアドレス$scmp("String1", "String2")-1, 0, 1のいずれかを返却。strcmpを参照。

$sicmp("String1", "String2")-1, 0, 1のいずれかを返却。stricmpを参照。

$spat("String", "Pattern")

TRUE  StringがPatternにマッチする
FALSE  StringがPatternにマッチしない
Pattern = エイリアスまたは⽂字列の定数。メモリポ
インタは指定不可（すなわち、$spatの引数に直接"poi(address)"を指定することはできない。最初にその結果をエイリアスに格納のこと）。Patternに、各種
ワイルドカードを使用可能。

$vvalid(Address, Length)1  指定範囲のメモリは有効
0  メモリは無効

66
www.windbg.info

最適化
シンボルの検索に無駄な時間をかけないために


MASM
–



レジスタに@を付けることを推奨。そうしないと、シンボルとして解釈されるかもしれない。

C++
–
–

ローカルなシンボルのための接頭辞: $!MySymbol
グローバルなシンボルのための接頭辞:<モジュール名>!MySymbol67
www.windbg.info

例 - C++⽂法の構造体// ------------------------------------------------------------------// 処理の高速化に有効: $!symName… ローカルシンボルの場合//<ModuleName>!symName … グローバルシンボルの場合// ------------------------------------------------------------------0:000> ?? dlg.m_nn
int 0
0:000> ?? $!dlg.m_nn
int 0
0:000> ?? sizeof($!dlg.m_nn)
unsigned int 0xac
0:000> ?? ((MyModule!CMyDlg*) 0x12f878)->m_nn
int 0
0:000> ?? ((ntdll!_TEB*) 0x7ffdf000)->ClientId
struct _CLIENT_ID+0x000 UniqueProcess : 0x000017d8//  PID+0x004 UniqueThread : 0x00000ea8//  TID
0:000> ?? @$teb->ClientId
struct _CLIENT_ID+0x000 UniqueProcess : 0x000017d8+0x004 UniqueThread : 0x00000ea8// C++の式評価器は、// 疑似レジスタを適切な型にキャストする

0:001> r? $t0 = @$peb->ProcessParameters // ユーザー定義の議事レジスタには
0:001> ?? @$t0->CommandLine// 型情報が保持される点に注意
struct _UNICODE_STRING""D:¥Development¥Sources¥CrashMe¥release¥CrashMe.exe" "+0x000 Length : 0x6a
+0x002 MaximumLength : 0x6c
+0x004 Buffer : 0x00020724 ""D:¥Development¥Sources¥CrashMe¥release¥CrashMe.exe" "68
www.windbg.info

例 - ポインタ演算// -----------------------------------------------------------// int myInt[2] = { 1,2 };// MASMの演算は常にバイト単位で⾏われる点に注意。
// 一方、ポインタの計算はC++の方式で⾏われている。
// -----------------------------------------------------------// MASM 文法// ------------0:000> ? myInt
Evaluate expression: 1243256 = 0012f878
0:000> ? dwo(myInt)
Evaluate expression: 1 = 00000001
0:000> ? myInt+4
Evaluate expression: 1243260 = 0012f87c
0:000> ? dwo(myInt+4)
Evaluate expression: 2 = 00000002// C++ 文法// ------------0:000> ?? (&myInt)
int * 0x0012f878
0:000> ?? myInt
int [2] 0x0012f878
1
0:000> ?? (&myInt+1)
int * 0x0012f87c
0:000> ?? *(&myInt+1)
int 2

69
www.windbg.info

デフォルトの式評価器


次の場合は常にC++の評価器が使われる
–
–
–





?? コマンド（C++式を評価）
watchウィンドウ
localsウィンドウ

上記以外のすべてのコマンドやデバッグ情報ウィンドウでは、
デフォルトの式評価器が使われる.exprコマンドでデフォルトの評価器を変更可能
–
–
–
–

.expr

 現在の評価器を表⽰.expr /s c++

 デフォルトの式評価器としてC++を設定.expr /q

.expr /s masm

 使用可能な評価器を表⽰

 デフォルトの式評価器としてMASMを設定
70
www.windbg.info

両評価器の混在

ひとつのコマンド内で両方の式評価器を使用可能



両モードを混在させるには: @@(...)
–
–
–



式の一部が、@@とそれに続く丸カッコに囲まれていた場合、その中は現在の式評価器とは逆の式評価器で評価される。
これにより、ひとつのコマンド内の異なるパラメータで、2つの異なる式評価器が使用可能。

この記号を入れ子で使うことも可能。記号が現れるたびに、式評価器が切り替わる。

式評価器の明⽰的な指定
 @@c++(...)

 @@masm(...)

71
www.windbg.info

例 - 式評価器の混在// ------------------------------------------------------------------// 以下のコマンドは、デフォルトの式評価器をMASMに設定する。
// そのため、Expression1とExpression3をMASM式として評価される。
// 一方、Expression2はC++式として評価される。
// ------------------------------------------------------------------0:000> .expr /s masm
0:000> ? Expression1 + @@( Expression2) + Expression3
0:000> ? `myFile.cpp:118`
Evaluate expression: 4570359 = 0045bcf7// myFile.cppの118⾏目のアドレスを取得// ------------------------------------------------------------------// ソース:⾏番号の式は、C++式では使えないので、// C++式の中でMASM式を入れ子にするとよい。
//  myFile.cppの118⾏目のアドレスを、nLocalVerに格納。
// ------------------------------------------------------------------0:000> ?? nLocalVar = @@(`myFile.cpp:118`)
int 4570359

72
www.windbg.info

WinDbgのエイリアス

⽂字列を、自動的にほかの⽂字列に置き換える
エイリアス名 + 対応する値から構成される

1) ユーザー命名エイリアス––

ユーザーが名前と値を設定（いずれも大⽂字小⽂字が区別される）

as または aS(エイリアスの設定)、ad（エイリアスの削除）、al（エイリアスの一覧表⽰）で操作

2) 固定名エイリアス––

ユーザーが値を設定。名前は$u0, $u1, ...,$u9r（登録）コマンド + "u"の前の.（ドット）で設定

3) 自動エイリアス–––

例: r $.u0 = "dd esp+8;g"

デバッガが名前と値を設定

自動疑似レジスタに類似。ただし、${...}といったエイリアス関連のトークンが使える点が異なる（疑似レジスタでは使えない）。
例: $ntsym, $CurrentDumpFile, $CurrentDumpPath, ...

73
www.windbg.info

ユーザー命名エイリアスと固定名エイリアス
1) ユーザー命名エイリアス–

デフォルトでは、ユーザー命名エイリアスは、ほかの⽂字と離さなければならない。
エイリアス名の最初と最後の⽂字は、次のいずれかの条件を満たすこと。
–
–

–
–

前後が、空白かセミコロンかクエスチョンマーク

ユーザー命名エイリアスがほかのテキストと隣接する場合は、${ }（エイリアスイン
タープリタ）で囲まなければならない
固定名エイリアスの定義内で使用可能
–

⾏頭または⾏末

ユーザー命名エイリアスを、ほかのユーザー命名エイリアスの定義内で使う場合は、asコマン
ドまたはaSコマンドの前にセミコロンを付ける（そうしないと、⾏内でのエイリアスの置き換
えは⾏われない）。解説: as, aS, ad, alで始まる⾏内のテキストは、エイリアスの置き換えが⾏われない。置き換えが必要な場合は、先頭にセミコロンを付けること。

固定名エイリアスより使いやすい

エイリアス定義の⽂法が単純

al(List Aliases)コマンドで一覧表⽰が可能

2) 固定名エイリアス––

ほかのテキストと隣接していても、自動的に置き換えられる
任意のエイリアス定義内で使用可能

74
www.windbg.info

ユーザー命名エイリアスのコマンド
演算子

説明

as Name Equivalentas /ma Name Address
as /mu Name Address...

エイリアスの設定
Addressにあるnullで終わるASCII⽂字列にエイリアスを設定
Addressにあるnullで終わるUnicode⽂字列にエイリアスを設定

ad Namead *名前(Name)を指定してエイリアスを削除
すべてのエイリアスの削除

al

ユーザー命名エイリアスを一覧表⽰${Alias}

ほかのテキストに隣接している場合も、${Alias}をエイリアスの値に置き換える。エイリアスが未定義の場合は、${Alias}の置き換えは⾏われない。
上と同様だが、エイリアスが未定義の場合は、${/f:Alias}が空の⽂字列に置き換えられる。
エイリアス名自体を返す。
評価: 1=エイリアス定義済み, 0=エイリアス未定義${/f:Alias}${/n:Alias}${/d:Alias}

75
www.windbg.info

例 - エイリアス
0:001> as Short kernel32!CreateRemoteThread
0:001> uf Short//  ユーザー命名エイリアス

0:001> r $.u0 = kernel32!CreateRemoteThread
0:001> uf $u0//  固定名エイリアス

0:001> as DoInc r eax=eax+1; r ebx=ebx+1
0:001> DoInc
0:001> DoInc//  エイリアスをコマンドのマクロとして使用// ------------------------------------------------------------------// エイリアスを使用するとその場で置き換えらる// ------------------------------------------------------------------0:001> r $.u2 = 2
0:001> r $.u1 = 1+$u2
0:001> r $.u2 = 6
0:001> ? $u1
Evaluate expression: 3 = 00000003
0:001> as two 2
0:001> r $.u1 = 1+ two
0:001> as two 6
0:001> ? $u1
Evaluate expression: 3 = 00000003//  twoの前に空白があるので注意// ------------------------------------------------------------------// エイリアスをほかのエイリアスの中で使う// ------------------------------------------------------------------0:001> as two 2
0:001> as xy1 two + 1//  xy1 = two + 1
0:001> ;as xy2 two + 1//  xy2 = 2 + 1 (エイリアスを置き換えるにはasの前にセミコロンが必要)

76
www.windbg.info

デバッガコマンドプログラム


構成




デバッガコマンド

フロー制御トークン(.if, .for, .while, ...)



ユーザー命名エイリアスまたは固定名エイリアスを、「ローカル変数」として使用

変数

疑似レジスタ($t0, ...)を、数値や型付きの変数として使用

コメントは $${任意のテキスト} のように記述



中カッコ { } で、ステートメントのブロックを囲む

各ブロックに入る際に、ブロック内の全エイリアスが評価される
開きカッコの前に、フロー制御トークンが必要

エイリアスの評価のために単なるブロックを作るには、.block {...} を使用

ほかのテキストと隣接するユーザー命名エイリアスには、${Alias}（エイリアスイ
ンタープリタ）を使用
77
www.windbg.info

フロー制御トークン

繰り返しや条件分岐の作成に使用

各条件は式でなければならない（コマンドは許可されていない）
コマンド

説明

.if, .else, .elseif

C言語のキーワードのif, else, else ifとほぼ同じ.block何の動作も⾏わない。単にブロックの導入にのみ使われる。
{ }だけではブロックを作成できないので注意。

.for, .while,.break, .continue

C言語のキーワードのfor, while, break, continueとほぼ同じ.foreach

デバッガコマンド（⽂字列またはテキストファイル）の出⼒を解析し、解析で得た各項目を後続のデバッガコマンドの入⼒に使用する。

78
www.windbg.info

コマンドプログラムの実⾏
プログラムの実⾏方法

全ステートメントを、デバッガウィンドウに、ひとつの⽂字列として入⼒（コマンドはセミコロンで区切る）
全ステートメントをスクリプトファイルに保存し、$$><を使ってファイルを実⾏$$><（スクリプトファイルの実⾏）:
 指定のファイルを開く

 すべての改⾏をセミコロンに置き換える その結果を、ひとつのコマンドブロックとして実⾏

79
www.windbg.info

例 - デバッガコマンドプログラム$$ ------------------------------------------------------------------$$ WinDbgのヘルプ「Debugger Command Program Examples」から引用$$ 説明はヘルプ内にあり。
$$ ------------------------------------------------------------------$$ モジュールリストLIST_ENTRY を$t0に取得
r? $t0 = &@$peb->Ldr->InLoadOrderModuleList$$ リスト内の全モジュールを列挙.for (r? $t1 = *(ntdll!_LDR_DATA_TABLE_ENTRY**)@$t0;(@$t1 != 0) & (@$t1 != @$t0);
r? $t1 = (ntdll!_LDR_DATA_TABLE_ENTRY*)@$t1->InLoadOrderLinks.Flink){$$ ベースアドレスを$Baseに取得
as /x ${/v:$Base} @@c++(@$t1->DllBase)$$ フルネームを$Modに取得
as /msu ${/v:$Mod} @@c++(&@$t1->FullDllName).block{}}.echo ${$Mod} at ${$Base}ad ${/v:$Base}ad ${/v:$Mod}80
www.windbg.info

便利なブレークポイントコマンド
コマンド

説明

bl

ブレークポイントの一覧表⽰

bp

ブレークポイントの設定

bu

未解決のブレークポイントの設定。
ブレークポイントの実際の設定を、モジュールロード時まで
保留する。

ba

メモリアクセス時に中断

bc

ブレークポイントの消去

be, bdブレークポイントの有効化, 無効化

81www.windbg.info

例 - 単純なブレークポイントの設定
0:000> bu kernel32!LoadLibraryExW
0:000> bu kernel32!CreateProcessW
0:000> bu kernel32!CreateThread
0:000> ba r4 0012fe34
0:000> ba w2 0012fe38
0:000> bl
0 e 7c801af1
1 e 7c802332
2 e 7c810637
3 e 0012fe34 r 4
4 e 0012fe38 2 2
0:000> bd 0,2
0:000> bc 4
0:000> bl
0 d 7c801af1
1 e 7c802332
2 d 7c810637
3 e 0012fe38 r 4

 アクセス時に中断(read or write); 4バイト監視 アクセス時に中断(write); 2バイト監視

0001 (0001) 0:**** kernel32!LoadLibraryExW
0001 (0001) 0:**** kernel32!CreateProcessW
0001 (0001) 0:**** kernel32!CreateThread
0001 (0001) 0:****
0001 (0001) 0:****
 0番と2番のブレークポイントを無効化
 4番のブレークポイントを消去

0001 (0001) 0:**** kernel32!LoadLibraryExW
0001 (0001) 0:**** kernel32!CreateProcessW
0001 (0001) 0:**** kernel32!CreateThread
0001 (0001) 0:****

82
www.windbg.info

例 - より複雑なブレークポイント


指定したソースの指定した⾏で中断
0:000> bp `mod!source.c:12`



5回通過後からヒットするブレークポイント
0:000> bu kernel32!LoadLibraryExW 5
0:001> bl//  3回通過後 (0002=残りカウント)0 e 7c801af1
0002 (0005) 0:**** kernel32!LoadLibraryExW



スレッド1から呼び出された場合にのみ中断
0:000> ~1 bu kernel32!LoadLibraryExW
0:001> bl
0 e 7c801af1
0001 (0001) 0:~001 kernel32!LoadLibraryExW

パターンmyFunc*にマッチする全シンボルで中断
0:000> bm /a mod!myFunc*–

xコマンドのシンボルパターンと同様メンバーのメソッドで中断
0:000> bp @@c++( MyClass::MyMethod )–同じメソッドがオーバーロードされているため複数のアドレスが存在する場合に便利

83
www.windbg.info

例 - コマンド付きブレークポイントWinMainの実⾏をスキップ
0:000> bu MyApp!WinMain "r eip = poi(@esp); r esp = @esp + 0x14; .echo WinSpy!WinMain entered; gc"–関数のエントリポイントに入った瞬間、スタックの先頭にリターンアドレスがセットされて
いる。


–

WinMainのパラメータ4個×各4バイト（=0x10バイト）+リターンアドレス4バイト=0x14


r eip=poi(@esp)  EIP（命令ポインタ）にスタックのオフセット0の内容をセット
r esp=@esp + 0x14  ESPに0x14を加算し、スタックポインタを適切に巻き戻す

スレッド1から呼び出された場合のみ中断
0:000> bu kernel32!LoadLibraryExW ";as /mu ${/v:MyAlias} poi(@esp+4); .if ( $spat(¥"${MyAlias}¥",¥"*MYDLL*¥" ) != 0 ) { kn; } .else { gc }"

–
–
–
–

LoadLibraryの最初のパラメータ（アドレスESP+4）は、当該DLL名へのポインタ。

このポインタと、所定のワイルドカード付き⽂字列（この例では *MYDLL*）を、MASMの$spat演算子で比較。

$spatはエイリアスや定数は受け取れるものの、メモリのポインタは受け取れない。そこで、当該ポインタをあらかじめエイリアス(MyAlias)に格納しておく。

このkernel32!LoadLibraryExWブレークポイントは、$spatのパターンマッチングに成功した場合にのみヒットする。それ以外の場合は、アプリケーションは実⾏を継続する。

84
www.windbg.info

例外分析コマンド
コマンド

説明.lastevent

ファーストチャンスかセカンドチャンスか!analyze -v

現在の例外に関する詳細情報を表⽰.exr -1

直近の例外を表⽰.exr Addr

アドレスAddrの例外レコードを表⽰!cppexr

C++の例外レコードを表⽰

g, gH

例外をハンドリングして実⾏

gN

例外をハンドリングせずに実⾏

85www.windbg.info

例 - 例外
0:000> .lastevent
Last event: dac.154c: Stack overflow - code c00000fd (first chance)
debugger time: Wed Aug 29 16:04:15.367 2007 (GMT+2)

0:000> .exr -1
ExceptionAddress: 00413fb7 (TestApp!_chkstk+0x00000027)
ExceptionCode: c00000fd (Stack overflow)
ExceptionFlags: 00000000
NumberParameters: 2
Parameter[0]: 00000000
Parameter[1]: 001e2000

0:000> !analyze –v
FAULTING_IP:
TestApp!_chkstk+27 [F:¥SP¥vctools¥crt_bld¥SELF_X86¥crt¥src¥intel¥chkstk.asm @ 99]
00413fb7 8500
test dword ptr [eax],eax...

86
www.windbg.info

WinDbgによるリモートデバッグターゲットコンピュータ（サーバー）–

dbgsrv.exe, dbgeng.dll, dbghelp.dllをリモートコンピュータにコピーする「dbgsrv.exe」に対するファイアウォールを無効化する–

実⾏  dbgsrv.exe -t tcp:port=1025–

Windows Vista: 全プロセスが参照できるようdbgsrv.exeを管理者権限で開始

ホストコンピュータ（クライアント）– 実⾏  WinDbg.exe -premote tcp:server=ターゲットのIPアドレス
または名前,port=1025–

File（メニュー）  Attach to Process  ターゲットコンピュータのデバッグ対象プロセスを選択

87
www.windbg.info

リモートデバッグのためのWinDbgコマンド
コマンド

説明

Cdb.exe -QR サーバー（IPアドレスまたは名前）

指定のネットワークサーバー上のすべてのデバッグサーバーを一覧表⽰.detach

プロセスからデタッチ.endpsrv

リモートコンピュータ上のdbgsrv.exeを終了。
デバッグ中のプロセスは、事前にデタッチしていない場合、強制終了される。

.tlist（リモート）システム上で実⾏中の全プロセス
を一覧表⽰

88
www.windbg.info

イベントの監視

デバッガエンジンが、対象アプリケーション内のイベントの監視機能と応答機能を提供
イベントは大きく二種類に分けられる–

例外イベント–非例外イベント

ブレークポイント、アクセス違反、スタックオーバーフロー、0除算など。
すべての一覧は、ヘルプの「Specific Exceptions」を参照。

プロセスの生成、スレッドの生成、モジュールのロード、モジュールのアンロード。
すべての一覧は、ヘルプの「DEBUG_FILTER_XXX」を参照。

次のコマンドで最後に発生したイベントを取得。デバッグ時には必ず何らかの値がセットされている。
–

コマンド: .lastevent

89
www.windbg.info

WinDbgのイベントフィルタ

簡単なイベントフィルタを提供
ターゲットにてイベント発生後の、デバッガエンジンの動作に影響
全イベントの一覧表⽰: sx

中断または実⾏状態–

イベント発生時にデバッガがターゲットを中断するかどうかに影響







ファーストチャンスで中断(sxe)
セカンドチャンスで中断(sxd)
イベントに関するデバッガのメッセージを出⼒(sxn)
イベントを無視(sxi)

ハンドリングまたは継続状態–

ターゲット内の例外イベントをハンドリングするか(gH)しないか(gN)を決定
90
www.windbg.info

イベントフィルタダイアログ

実⾏:
 Enabled - ファーストチャンスで中断(sxe) Disabled - セカンドチャンスで中断(sxd) Output - イベント発生でメッセージ出⼒(sxn) Ignore - イベントを無視(sxi)継続: Handled- 実⾏再開時、イベントをハンドリングする Not-Handled - 実⾏再開時、イベントをハンド
リングしない91
www.windbg.info

イベントの引数

いくつかのフィルタは、マッチするイベントを制限するための引数をもつ
引数なし  制限なし
イベント

マッチの基準ExitProcess

終了プロセスの名前が、引数にマッチすること。

ロードモジュール

ロードモジュールの名前が、引数にマッチすること。

ターゲットの出⼒

ターゲットからのデバッグ出⼒が、引数にマッチすること。

アンロードモジュール

アンロードモジュールのベースアドレス
が、引数と一致すること。

CreateProcess

生成プロセスの名前が、引数にマッチす
ること。
ワイルド

カード⽂字
列の⽂法

92
www.windbg.info

目次 – ロードマップ
 WinDbgの裏側

 WinDbgの使い方 グローバルフラグ• アプリケーション検証• プロセスダンプ
93
www.windbg.info

フラグ？ Gフラグ？ グローバルフラグ！
GFlagsは、Windowsのレジストリの編集により、機能を有効化・無効化する
GFlagsは、システム全体に対する設定も、イメージに特化した設定も可能
イメージに特化した設定は、次の場所に格納される
–






HKLM¥SOFTWARE¥Microsoft¥Windows NT¥CurrentVersion¥Image File
Execution Options¥ImageFileName¥GlobalFlag

OSはこれらの設定を読み、その内容に応じて動作する

GFlagsは、コマンドラインからも、ダイアログボックスからも設定できる
WinDbg内でも !gflags により、グローバルフラグの設定や表⽰が可能
GFlagsで次の機能を有効にできる
–
–
–
–
–
–

ヒープのチェック
ヒープのタグ付け

ローダーのスナップ表⽰

イメージに対するデバッガ指定（イメージ開始のたびに自動的にアタッチされる）
アプリケーション検証
その他

94
www.windbg.info

GFlagsダイアログ







System Registry: システム全体の設定。Windowsで実⾏中の全プロセスに影響する。設定内容は、設定を変更するまでずっと効果を発揮。設定内容を実際に有効にするには、Windowsの再起動が必要。

Kernel Flags: 実⾏時の設定。システム全体に影響する。再起動しなくても、すぐに効果を発揮。シス
テムのシャットダウンや再起動により、設定内容は失われる。

Image File:コマンド完了後に起動した指定プログラムのインスタンスに影響。設定内容はレジストリに格納され、設定変更するまでずっと効果を発揮。

95

www.windbg.info

GFlags:「Show loader snaps」有効化
WinDbg の出⼒:
LDR: LdrLoadDll, loading samlib.dll fromC:¥WINDOWS¥system32;C:¥WINDOWS¥system;C:¥WINDOWS;.;C:¥WINDOWS¥System32¥Wbem;C:¥WINDOWS¥system32¥kktools
LDR: Loading (DYNAMIC, NON_REDIRECTED) C:¥WINDOWS¥system32¥samlib.dll
ModLoad: 71bf0000 71c03000 C:¥WINDOWS¥system32¥samlib.dll
LDR: samlib.dll bound to ntdll.dll
LDR: samlib.dll has correct binding to ntdll.dll
LDR: samlib.dll bound to ADVAPI32.dll
LDR: samlib.dll has correct binding to ADVAPI32.dll
LDR: samlib.dll bound to RPCRT4.dll
LDR: samlib.dll has correct binding to RPCRT4.dll
LDR: samlib.dll bound to KERNEL32.dll
LDR: samlib.dll has stale binding to KERNEL32.dll
LDR: samlib.dll bound to ntdll.dll via forwarder(s) from kernel32.dll
LDR: samlib.dll has correct binding to ntdll.dll
LDR: Stale Bind KERNEL32.dll from samlib.dll
LDR: LdrGetProcedureAddress by NAME - RtlAllocateHeap
LDR: LdrGetProcedureAddress by NAME - RtlFreeHeap
LDR: LdrGetProcedureAddress by NAME - RtlGetLastWin32Error
LDR: LdrGetProcedureAddress by NAME - RtlReAllocateHeap
LDR: samlib.dll bound to USER32.dll
LDR: samlib.dll has stale binding to USER32.dll
LDR: Stale Bind USER32.dll from samlib.dll[d58,690] LDR: Real INIT LIST for process C:¥Development¥Sources¥TestApp¥Release¥TestApp.exe pid 3416 0xd58[d58,690] C:¥WINDOWS¥system32¥samlib.dll init routine 003A0F30[d58,690] LDR: samlib.dll loaded - Calling init routine at 003A0F30

96
www.windbg.info

目次 – ロードマップ
 WinDbgの裏側

 WinDbgの使い方 グローバルフラグ

 アプリケーション検証• プロセスダンプ

97
www.windbg.info

アプリケーション検証の有効化


アプリケーション検証Windowsアプリケーションの実⾏時検証ツール

アプリケーションとOSのインタラクションを監視
プロファイルと追跡








マイクロソフトWin32 API（ヒープ、ハンドル、ロック、スレッド、
DLLロード/アンロード、ほか多数）
例外

カーネルオブジェクト
レジストリ

ファイルシステム!avrfにより、この追跡情報を入手

注意: アプリケーション検証は、裏側で、対象アプリケーションに多くのDLL(verifier.dll, vrfcore.dll,
vfbasics.dll, vfcompat.dll, ほか多数)を注入する。より正確に言うと、選択したテスト項目にしたがって、
該当イメージのレジストリキーを設定し、Windowsローダーがこのレジストリキーを読み込み、アプリ
ケーションの開始時にそのアドレス空間に所定のDLLをロードする。

98
www.windbg.info

アプリケーション検証の種類
GFlagsアプリケーション検証

対象プロセスに、verifier.dllのみを注入

verifier.dllはWindows XPにインストール済み

アプリケーション検証オプションの機能制限版

GFlagsのこのオプションは旧式なため、将来削除されるかもしれない

アプリケーション検証

マイクロソフトのウェブサイトから無料でダウンロードし、インストール
できる
vrfcore.dll, vfbasics.dll, vfcompat.dllなども、Windows¥System32に追加インストールされる
GFlagsより多くのテストオプションが利用でき、!avrf拡張の全機能が使える

99
www.windbg.info

アプリケーション検証のシンボル
アプリケーション検証は、全シンボル情報を含むPDBとともにインストールされる

逆アセンブリに含まれるソース情報に注目

私の知る限り、全シンボル情報付きで配布されたマイクロソフトのモジュールはこれだけ

WinDbgは、サーバーに公開されているシンボルではなく、これらのシンボルを使う必要がある。そうしないと、!avrf拡張は機能しない。
.reload /f @"C:¥Windows¥System32¥verifier.pdb"

100
www.windbg.info

一般的な !avrf パラメータ
コマンド

説明

!avrf

現在のアプリケーション検証オプションを表⽰。アプリケーション検証停止が発生した場合は、停止の状況が表⽰される。

!avrf -cs

クリティカルセクションの削除(*)ログを表⽰!avrf -hp 5

ヒープの操作ログ（直近の5つのエントリ）を表⽰!avrf -dlls

DLLのロード／アンロードのログを表⽰!avrf -ex

例外のログを表⽰!avrf -cnt

グローバルカウンタを一覧表⽰(WaitForSingleObject呼び出し,
CreateEvent呼び出し, ヒープ割り当て呼び出し, ...)

!avrf -threads

対象プロセスのスレッドの情報を表⽰。子スレッドについては、スタックサ
イズや親が指定したCreateThreadフラグも表⽰。

!avrf -trm

すべての終了(*)スレッドや中断されたスレッドのログを表⽰* DeleteCriticalSection API.~CCriticalSectionはこれを暗黙的に呼び出す。
* HeapAlloc, HeapFree, delete* TerminateThread API

101
www.windbg.info

例 - !avrf// アプリケーションが以下の命令を実⾏した直後:// HeapAlloc( 0x00140000, 8, dwBytes =0x00A00000 ) -->> 0x033D1000;
0:000> !avrf -hp 1
Verifier package version >= 3.00
Dumping last 1 entries from tracker @ 01690fd8 with 1291 valid entries ...
-------------------------------------------------------------HeapAlloc: 33D1000 A00000 0 0004019cf: TestApp!CMyDialog::OnBnClicked_HeapAlloc+0x4F
0041a0c1: TestApp!_AfxDispatchCmdMsg+0x3D
0041a2a6: TestApp!CCmdTarget::OnCmdMsg+0x10A
0041a76c: TestApp!CDialog::OnCmdMsg+0x1B
0041d05c: TestApp!CWnd::OnCommand+0x51
0041d92b: TestApp!CWnd::OnWndMsg+0x2F
0041b2eb: TestApp!CWnd::WindowProc+0x22…
0:000> !avrf -threads===================================================
Thread ID = 0xDE4
Parent thread ID = 0xE3C
Start address = 0x004a7d82: TestApp!ILT+11645(?ThreadProcYGKPAXZ)
Parameter = 0x0061833c===================================================
Thread ID = 0xE3C
Initial thread===================================================
Number of threads displayed: 0x2

102
www.windbg.info

目次 – ロードマップ
 WinDbgの裏側

 WinDbgの使い方 グローバルフラグ

 アプリケーション検証

 プロセスダンプ

103
www.windbg.info

プロセスダンプ

プロセスのダンプ–––

プロセスのある瞬間のスナップショット含んでいるコンテンツや情報によって、サイズが異なる

ダンプを使って––



非侵入的アタッチに類似

メモリやプロセスの内部構造の観察が可能
ブレークポイントの設定や、プログラムのステップ実⾏はできない

ダンプをダンプ––

情報を多く含むダンプを、情報の少ないダンプに縮小できる
動作中のプロセスをダンプするように、.dumpコマンドを使ってダンプをダンプできる
104
www.windbg.info

ダンプの種類
1) カーネルモードダンプ

種類: 完全メモリダンプ、カーネルメモリダンプ、最小メモリダンプ

2) フルユーザーモードダンプ–––

WinDbgの".dump /f"コマンドや、Windows 2000のDr.Watsonで生成されるプロセスのメモリ空間全体、プログラム自⾝の実⾏イメージ、ハンドルテーブルを含む
従来は広く使われたが、マイクロソフトはサポートを止めつつある

3) ミニダンプ––––.dump /m??

最新のダンプフォーマット

ダンプに含まれる情報を、細かい単位で制御できる（MSDNのMINIDUMP_TYPEを参照）
その名前に反して、最大のミニダンプファイルには、フルユーザーモードダンプよりも多くの情報が含まれる。たとえば、.dump /mfや.dump /maは、".dump /f"よりも大きく、より完全なダンプファイルを生成する。

105
www.windbg.info

ダンプの種類の判定

目的のダンプをWinDbgでロード。ミニダンプであれば「User Mini Dump File」と表⽰され、古いスタイルのクラッシュダンプであれば「User Dump File」と表⽰される。
106
www.windbg.info

例 - ".dump"コマンド
0:000> .dump /ma d:¥large.dmp Creating d:¥large.dmp - mini user dump
Dump successfully written すべての情報: 全メモリ、コードセクション、PEBとTEB、
ハンドルデータ、スレッド時間の情報、アンロードモジュールの一覧など

0:000> .dump /m d:¥small.dmp Creating d:¥small.dmp - mini user dump
Dump successfully written 基本情報のみ: モジュール情報（署名）,スレッドとスタックの情報

107
www.windbg.info

最適なツールの選択
シナリオ／選択肢

ADPlusDr.
WatsonCDBとWinDbgUserDump

アプリケーションのクラッシュ（事後分析デバッグ）

〇

〇

〇

〇

アプリケーションのハング（無応答だが、クラッシュしているわけではない）

〇

×

〇

〇

アプリケーションで例外発生

〇

〇

〇

〇

アプリケーションが正常に実⾏中

×

×

〇

〇

アプリケーションが起動時に失敗（依存しているDLLがない）

×

×

〇

〇

既存のダンプファイルの縮小

×

×

〇

×

同じイメージ名のすべての実⾏中アプリケーション
に対して、ダンプを一度に取得

×

×

×

〇

ダンプファイルに含める情報を制御

×

×1

〇

×2

1: 常に基本情報のみの小さなミニダンプ(MiniDumpNormal)を生成。サイズは通常20KB未満。
2: 常に、全メモリ情報の入ったミニダンプを生成する。サイズは通常20〜200MB。

108
www.windbg.info

宿題

WinDbgのドキュメントを読むことメモリリーク、ハンドル、デッドロック、条件付きブレークポイ
ントなどについて、すべて説明してある。



アセンブリ言語を学ぶこと

デバッグの技術が大幅に向上する。



デバッグが必要な状況においては、WinDbgのアセンブリが最良の友となるだろう。

109
www.windbg.info

ご質問、ご提案は？

？




？？

WinDbgに関するご質問はありませんか。

WinDbgラボやセミナーに興味をお持ちいただけましたか。

「WinDbg. From Ato Z!」に改善すべき点はありましたか。



それとも「スゴイ！ このプレゼンは実に役に⽴つ」と言ってもらえるでしょうか。



お気軽にメールをお寄せください: mailrkuster@windbg.info
実際のメールアドレスは先頭の"mail" を除く（スパム防止用）



日本語のメールはこちらまで: mailogunity@nttdata.co.jp
実際のメールアドレスは先頭の"mail" を除く（スパム防止用）

110
www.windbg.info

参考⽂献


WinDbgのドキュメント, MSDNCommon WinDbg Commands (Thematically Grouped)
http://software.rkuster.com/windbg/printcmd.htm

Matching Debug Information



Generating Debug Information with Visual C++

Microsoft Windows Internals, Fourth Edition

Advanced Kernel Debugging



アプリケーション検証のドキュメント

http://www.debuginfo.com/articles/debuginfomatch.html

http://www.debuginfo.com/articles/gendebuginfo.html

M.E. Russinovich, D.A. Solomon, ISBN 0-7356-1917-4

Andre Vachon, PowerPoint, WinHec 2004

111www.windbg.info