Open棟梁Project - マイクロソフト系技術情報 Wiki
目次  †
概要  †
ダンプ解析やライブデバッグなどができます。
ダンプ解析は高度な技術を要しますが、クラッシュダンプに以下のコマンドを実行することで
スタックトレースを取得しプロセスをクラッシュさせたプログラムの特定などができます。
ダンプの分析例  †
クラッシュ・ダンプをWinDbgのKコマンドで確認した所、
以下の様にスタックトレースが出力された。
ChildEBP RetAddr
1c2fd0b8 774a5620 ntdll!KiFastSystemCallRet 1c2fd0bc 774d3c62 
ntdll!NtWaitForSingleObject+0xc
1c2fd140 774d3d4b ntdll!RtlReportExceptionEx+0x14b
1c2fd180 774efa87 ntdll!RtlReportException+0x3c
1c2fd194 774efb0d ntdll!RtlpTerminateFailureFilter+0x14
1c2fd1a0 77449bdc ntdll!RtlReportCriticalFailure+0x6b
1c2fd1b4 77444067 ntdll!_EH4_CallFilterFunc+0x12 1c2fd1dc 
774a5f79 ntdll!_except_handler4+0x8e
1c2fd200 774a5f4b ntdll!ExecuteHandler2+0x26
1c2fd2b0 774a5dd7 ntdll!ExecuteHandler+0x24
1c2fd2b0 774efaf8 ntdll!KiUserExceptionDispatcher+0xf
1c2fd624 774f0704 ntdll!RtlReportCriticalFailure+0x5b
1c2fd634 774f07f2 ntdll!RtlpReportHeapFailure+0x21
1c2fd668 774afc25 ntdll!RtlpLogHeapFailure+0xa1
1c2fd694 763b9a26 ntdll!RtlFreeHeap+0x60
1c2fd6a8 76079c03 kernel32!HeapFree+0x14 Unable to load image 
C:\YYYYY\XXXXX.dll, Win32 error 0n2
*** WARNING: Unable to verify timestamp for XXXXX.dll
*** ERROR: Module load completed but symbols could not be loaded 
for XXXXX.dll
これにより、"C:\YYYYY\XXXXX.dll" がプロセスをクラッシュさせていることが解る。
基本的な使い方  †
インストール  †
Debugging Tools for Windowsに同梱されているためこれをインストールする。
注意点  †
- ダンプ解析は同一CPUアーキテクチャのPCを利用する。
 
- システム・モジュールのシンボルをインストールしてシンボルへのパスを指定する。
- UPモジュールについてはPDBファイルを配置(PDBファイルへのパス指定)
 
 
ポイント解説  †
プロダクト・チームも利用  †
- MSのWindowsプロダクト・チームも利用している。
 
- VSデバッガは言語+ブレークの機能が中心だが、
WinDbgはカーネルモードのプロセス、スレッドスタックの分析まで可能。 
ユーザモードのデバッグでも、カーネルモードのデバッグでも利用可能。
- 裏で動いているデバッグ・エンジン(dbgeng.dll→COM)は変わらない。
 
- カーネル・モード?は使用する拡張コマンドが違うだけ。
 
- なお、dbgeng.dll(デバッグ・エンジン)は、
他の色々なツールで利用されている。
- ntsd.exe
 
- cdb.exe
 
- kd.exe
 
- dbgsrv.exe
 
- userdump.exe
 
- drwtsn32.exe
 
 
非侵入的アタッチ  †
非侵入的アタッチが可能。
- 侵入的アタッチ
- DebugActiveProcess?が呼び出される
 
- break-inスレッドが生成される
 
- Windows XP以前では、デバッガ終了時やデタッチ時に、デバッグ対象アプリケーションが強制終了される
 
- 侵入的デバッガとしてアタッチできるのは、プロセス当たり一度にひとつだけ
 
 
- 非侵入的アタッチ
- OpenProcess?が呼び出される
 
- break-inスレッドは生成されない
 
- プロセスに対し、デバッガとして真のアタッチをするわけではない
 
- デバッグ対象アプリケーションのスレッドはすべて凍結状態
 
- メモリの内容の変更や確認は可能
 
- ブレークポイントはセットできない
 
- アプリケーションのステップ実行はできない
 
- デバッグ対象アプリケーションを終了することなく、デバッガの終了やデタッチが可能
 
- ひとつのプロセスに、複数の非侵入的デバッガ( + ひとつの侵入的デバッガ)をアタッチできる
 
 
- Visual Studioなどの侵入的デバッガでアプリケーションをデバッグ中でも、
WinDbgを非侵入的デバッガとしてアタッチし、追加の情報を取得できる。 
- デバッグ対象アプリケーションは完全に凍結しており、
真のアタッチに必要なbreak-inスレッドが生成されることはない。 
コマンド  †
コマンドの種類  †
標準コマンド  †
- プロセスのデバッグに使われる
 
- 例 : k, lm, g
 
メタコマンド(ドットコマンド)  †
- 通常、デバッガの制御に使われる。
 
- 例 : .sympath, .cls, .lastevent, .detach, .if
 
拡張コマンド  †
- 独自に拡張DLLを開発することも可能
 
- 拡張DLLに、エクスポート関数として実装。
 
- 以下の拡張DLL一式がインストール済み
- exts.dll
 
- ntsdexts.dll
 
- uext.dll
 
- wow64exts.dll
 
- kdexts.dll
 
- ,etc.
 
 
- 拡張DLLとそのヘルプ
- !exts.help一般的な拡張コマンド
 
- !Uext.helpユーザーモードの拡張コマンド(OS非依存)
 
- !Ntsdexts.helpユーザーモードの拡張コマンド(OS依存)
 
- !Kdexts.helpカーネルモードの拡張コマンド
 
- !logexts.helpログ取得拡張コマンド
 
- !clr10¥sos.helpマネージコードのデバッグ
 
- !wow64exts.helpWow64デバッガ拡張
 
 
- WinDbgが協力なデバッガである大きな理由
- 例 : !analyze, !address, !handle, !peb
 
 
取得情報別コマンド  †
システム情報取得コマンド  †
- コマンド
- !vm
システムの仮想メモリ使用統計要約情報を表示 
- !process
指定プロセスの情報を表示(一覧も可能) 
 
プロセス、モジュール情報取得コマンド(PEB)  †
- PEB(Process Environment Block : プロセス環境ブロック)
カーネルモード:EPROCESS ---> ユーザモード:PEB
- イメージ基本情報
 
- プロセスヒープの情報
 
- 環境変数、コマンドライン引数
 
- DLL検索パス
 
 
- コマンド
- !peb
PEBの情報を整形して表示 
- dt nt!_PEB addr
PEBの全ダンプ 
- lm
ロードモジュール、アンロードモジュールの一覧 
- lmD
上記をデバッガマークアップで出力 
- lmvm kernel32
kernel32の詳細を出力。kernel32はモジュール名 
- !lmi kernel32
上記のDLL拡張コマンド 
- !dlls
ロードモジュールの一覧、ローダに関する情報 
- !dlls -c kernel32
上記のkernel32のみ。kernel32はモジュール名 
- imgreloc
再配置情報の表示 
- !dh kernel32
kernel32ヘッダを表示kernel32はモジュール名 
 
- 以下は、プロセスの変更と、シンボルのリロードを行う場合のコマンド。
 
スレッド情報取得コマンド(TEB)  †
- TEB(Thread Environment Block : スレッド環境ブロック)
カーネルモード:ETHREAD ---> ユーザモード:TEB
 
- コマンド
- 「~」
プロセス内の全スレッドのスレッド状態 
- 「~0」
スレッド0(主スレッド)のスレッド状態 ---> ~Number 
- 「~.」
カレントのアクティブなスレッド状態 
- 「~*」
プロセス内の全スレッドのスレッド状態( + 追加情報) 
- 「~*k」
プロセス内の全スレッドのコールスタック(~、!uniqstack) 
- 「~<thread>s」
カレントスレッドの設定 
- !gle
ラストエラーの取得 
- runaway
各スレッドの消費時間を表示。 
- !teb
TEBの情報を整形して表示 
- dt nt!_TEB addr
TEBの全ダンプ 
 
コールスタックのサイズ取得コマンド  †
↓
- dt ntdll!_TEB DeallocationStack? xxxxx
TEB at xxxx の値を指定。 
↓
- !address esp
esp(ESPレジスタ)は、カレントスレッドのスタック位置 
↓
- ? xxxx - yyyy
- xxxx = stackbase
 
- yyyy = stacklimit
 
- スタックがコミットしたバイト数
 
 
↓
- ? xxxx - zzzz
- zzzz = DeallocationStack?
 
- スタックの予約したバイト数
 
 
- 補足説明
- Stackbaseスタックの始点
 
- Stacklimitスタックの使用量(コミット・サイズ)
 
- DeallocationStack?スタックの終点(予約サイズ)
 
- ?コマンドは、さまざまな計算が可能。また10進数の表示ができる。
 
 
コールスタックの情報取得コマンド  †
- コマンド
- !uniqstack
プロセス内の全スレッドのコールスタック(~、~*k) 
- !findstack MySymbol? 2
MySymbol?を含む全コールスタックを探して表示。 
 
- K
カレントスレッドのコールスタックを表示。 
- kP
+ 呼び出しの全パラメータ 
- Kf
+ 隣接フレーム(サブルーチン毎にコールスタックに格納する情報)との距離 
- Kv
+ FOP(frame pointer omission)情報と呼び出し規約を表示。 
- Kb
+ first three parameters情報を表示。 
- kM
上記をデバッガマークアップで出力 
トラップフレームのコマンド  †
- コマンド
- .trap
kvコマンドで取得したFOPのアドレスを入力してトラップフレームを復元する。 
 
トラップフレームとは・・・
プロセスのメモリ情報、操作コマンド  †
- コマンド
- d
メモリ表示 
- dd
メモリ表示:ダブルワード 
- da
メモリ表示:ASCIII 
- du
メモリ表示:UNICODE 
 
- !vprot addr
指定アドレスの仮想メモリ保護情報 
- !address addr
指定アドレスのメモリ情報(タイプ、保護、使用状況など) 
- !address -RegionUsageStack?
プロセスの全スレッドスタック領域を表示 
- dds
メモリ内容と対応するシンボル 
- ddp
メモリ内容と参照先メモリ内容、またそのシンボル。 
- 参考リファレンス
- d, da, db, dc, dd, dD, df, dp, dq, du, dw (Display Memory)
http://msdn.microsoft.com/en-us/library/ff542790.aspx 
- dda, ddp, ddu, dpa, dpp, dpu, dqa, dqp, dqu (Display Referenced Memory)
http://msdn.microsoft.com/en-us/library/ff540451.aspx 
- dds, dps, dqs (Display Words and Symbols)
http://msdn.microsoft.com/en-us/library/ff540455.aspx 
 
ヒープ情報取得コマンド  †
下記コマンドを実行する場合、グローバルフラグを設定する。
- コマンド
- !heap -?
ヘルプ 
- !heap -h
ヒープのインデックスの範囲(開始-終了アドレス)を一覧 
- !heap -s 0
全ヒープの要約(=予約メモリ、コミットメモリ) 
- !heap -flt s Size
指定サイズに一致する割り当てを表示。 
- !heap -stat
ヒープのハンドルを一覧表示 
- !heap -stat -h 0
メモリ割り当てサイズ毎に使用状況の統計を表示。 
 
- !heap -l
デバッガにリーク原因とされたheapエントリを知らせる。 
- !heap -p
Gflagsの設定と、ヒープハンドルの一覧 
- !heap -p -all
プロセスの全ヒープの割り当ての詳細(全てのHeapAlloc?呼び出しの一覧 
- !heap -p -a heapentryaddr
heapentryaddr(HeapAlloc?の返却アドレス)を含むヒープ割り当ての詳細(スタックトレース)
※ リークのチェックの際は「!heap -l」で取得したheapentryaddr(Entry列)を指定する。 
シンボルの設定など  †
- .sympath
シンボルの検索パスの取得と設定 
- .sympath+ XY
シンボルの検索パスに、XY 
- !sym noisy
シンボルの検索パス情報を表示 
- ld kernel32
kernel32.dllのシンボルを読み込む。 
- ld *
全モジュールのシンボルを読み込む。 
- .reload
シンボル情報を読み直す。 
- x kernel32!*
kernel32.dllのシンボルを一覧表示。 
- x kernel32!*LoadLibrary?*
kernel32.dllの(例)「LoadLibrary?」文字列を含むシンボルを一覧表示。 
- dt ntdll!*
ntdll.dll内の全変数を表示。 
スレッド・スタック、例外分析  †
アンマネージでもマネージでも利用可能。  †
「!analyze -v」コマンド  †
クラッシュ分析ヒューリスティックにより現在の例外に関する詳細情報を表示
「~」コマンド  †
スレッド一覧表示
「~*k」コマンド  †
スレッドのコール・スタックを表示
~<thread>s  †
カレント・スレッドの設定
「KN, .Frame , DV, and DT 」コマンド  †
現在のコール・スタックの引数、ローカル変数を確認できる。
マネージで利用可能  †
「!PrintException? -nested」コマンド  †
クラッシュ分析ヒューリスティックにより現在の例外に関する詳細情報を表示
「!thread」コマンド  †
スレッドの状態を表示
- アンマネージスレッドか?
 
- マネージスレッドか?
- ファイナライザスレッドか?
 
- ステータス情報を確認できる。
 
 
「!ClrStack? -a」コマンド  †
- マネージドコードのコールスタック
 
- 「~*k」コマンドより若干詳しい。
 
なお、ここに表示される
は、以下のコマンドを使用して値を確認できる。
- 変数がStringである場合、
!DumpObj?コマンドに指定すれば、文字列情報を取得できる。 
- 変数が配列である場合、
!DumpArray?コマンドを使用して、各要素の情報を取得できる。 
- 参照渡しの引数である場合
ddコマンドを使用してアドレス情報を確認できる。
(ddコマンドではポインタ(オブジェクト参照)の指す値を確認できる) 
メモリ・リーク分析  †
- プロセスのスレッドのヒープの使用状況のログを取得できる。
 
- このログを比較することで、どのスタックトーレスがメモリ・リークに関係しているかを絞り込むことができる。
 
- javaや.netのマネージ・リソースのメモリ・リークは検出できないことがあるので注意する。
 
- これは、マネージド・ヒープがガベージ・コレクタによって管理されているため。
 
準備  †
ヒープマネージャに管理されるヒープ内の利用状況に関する情報を所得したい場合、ダンプ取得コマンドを実行する前に、グローバルフラグを設定する。
※ [ダンプの種類と概要、取得ツール]のシートの[メモリリーク分析用のダンプ]を参照のこと。
なお、リークを疑っている場合、同じダンプを見ても解らないので、差分を見るなどする。
若しくは、UMDHツールを使用してログ出力してヒープの差分を確認するなどする。
ダンプ取得  †
任意のツールを使用してユーザモード・プロセスダンプを取得する。
ダンプ分析  †
仮想アドレス空間の情報  †
- !addressコマンドから仮想アドレス空間の全情報を取得できる。
- !address
プロセスの仮想アドレス空間の全情報を表示 
- !address -summary
プロセスの仮想アドレス空間のサマリを表示 
- !address –RegionUsageStack?
プロセスの全スレッドのスタック領域を表示 
 
- ただし、ヒープ・マネージャに管理される
ヒープ内のメモリ利用状況に関する情報は取得できない。 
ヒープ内の利用状況の情報  †
下記を実行してヒープ内のメモリ利用状況を確認する。
- ヒープリーク検出(ページ ヒープ)
!heap -p -a コマンドコマンドでstacktraceを出力 
- ユーザモード スタックトレース データベース
!heap -a コマンドでstacktraceを出力 
準備と取得  †
分析  †
参考  †
参考  †
- Windbg  Hoster-JP
http://www.hoster.jp/tag/windbg
- [Windbg 第1回] Windbgを知っていますか?
 
- [Windbg 第2回] Windbgはどこにありますか?
 
- [Windbg 第3回] ツールはどのようにインストールしますか。
 
- [Windbg 第4回] カーネルメモリ空間のダンプを取得する。
 
- [Windbg 第5回] ユーザメモリ空間のダンプを取得する。
 
- [Windbg 第6回] 取得したダンプをWindbgで開く
 
- [Windbg 第7回] 取得したダンプをkanalyzeで開く
 
- [Windbg 第8回] Windbgでよく使うコマンド
(その1)クラッシュ時に起動しているアプリケーションを確認する 
- [Windbg 第9回] Windbgでよく使うコマンド
(その2)クラッシュ時に読み込まれていたドライバーを確認する 
- [Windbg 第10回] Windbgでよく使うコマンド
(その3)クラッシュしたサーバのハードウェア情報を確認する