この記事は、
PowerShell Advent Calendar 2013用です。本当は、誰も触れてないPowerShell v4.0の新機能について触れる予定だったのですが、新機能以外の部分で挫折したので実用的な内容に方針転換します。
今回の話題は、WinDbgの操作をオートメーションするスクリプト、
PowerDbgの使い方です。これはなにかというと、WinDbgのコンソール版、cdb.exeのフロントエンドです。PowerShellがデバッガになるというよりは、windbgをコントロールできる感じです。
インストール方法
http://powerdbg.codeplex.com/ に行き、Downloadボタンを押すと、zipが落ちてくるので開きます。その中に「Install_PowerDbg.bat」というファイルがあるので、実行するとインストールされます。
といっても、横に置いてある「PowerDbg.psm1」を「%USERPROFILE%\Documents\WindowsPowerShell\Modules\PowerDbg」にコピーするだけなので、手でやっても変わらないです(もっと言うと、好きな場所に置いて毎回Import-Module .\PowerDbg.psm1でもいいです)。
あとは、いくつかの方法のどれかでcdb.exeのあるフォルダを指定します。でも一番簡単なのは.psm1の頭、param(...)のあとに以下のように記述することなので、ここではそれだけ書きます(どうせスクリプトは更新されなさそうだし)。
$debuggerRoot = "C:\Program Files (x86)\Windows Kits\8.0\Debuggers\x64"
使い方
「New-DbgSession」コマンドレットで、デバッガを起動できます。-command "コマンド..."で新コマンド起動、-process "プロセス名" でアタッチ、-dump "dumpファイルのパス" でダンプ読み込みです。
PS> New-DbgSession -command "C:\Program Files (x86)\MsbuildLauncher\MsbuildLauncher.exe"
そして、「Invoke-DbgCommand」でデバッガコマンドを送れます。
PS> Invoke-DbgCommand 'bp $exentry'
「g」は「Send-DbgGo」というコマンドレットが用意されているので使えます。
PS> Send-DbgGo
Send-DbgGoすると、止まるまでブロックします。Ctrl+Cで抜けることも可能。
終わりたいときは、「Exit-DbgSession」で終われます。
PS> Exit-DbgSession
.loadby sos clrみたいに拡張をロードしたいときは、Load-DbgExtensionが使えます。
PS> Load-DbgExtension sos clr
Invoke-DbgCommandで何を送るかが肝で、PowerShell固有の操作はほとんどありません。(引数名がcamelCaseなのがいけてない感じですがスルーでおねがいします…)
実用例1: 異常終了したときに.NETのスタックトレース等を表示するスクリプト
前にやった「
WinDbgとSOS拡張でVSを使わずに.NETアプリをデバッグ - 異常終了時の調査」を自動でやれます。
実行するとこんな感じ。
PS> > .\PrintExceptionSecondChance.ps1 -Command "C:\temp\MsbuildLauncher-0.1.1\MsbuildLauncher\MsbuildLauncher.exe"
ModLoad: 000007fe`f7200000 000007fe`f7b60000 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clr.dll
ntdll!ZwMapViewOfSection+0xa:
00000000`7755153a c3 ret
(1340.8e8): Unknown exception - code 04242420 (first chance)
ModLoad: 000007fe`f5a60000 000007fe`f5b8e000 C:\Windows\Microsoft.NET\Framework64\v4.0.30319\clrjit.dll
ntdll!ZwMapViewOfSection+0xa:
00000000`7755153a c3 ret
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): C++ EH exception - code e06d7363 (first chance)
(1340.8e8): CLR exception - code e0434352 (first chance) ←ここでエディタパスをおかしくして「Edit」ボタンをクリック
(1340.16c0): Unknown exception - code 000006ba (first chance)
(1340.8e8): CLR exception - code e0434352 (first chance)
(1340.8e8): CLR exception - code e0434352 (!!! second chance !!!)
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\system32\KERNELBASE.dll -
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Windows\Microsoft.NET\Framework64\v4.0.3
0319\clr.dll -
KERNELBASE!RaiseException+0x3d:
000007fe`fd6a940d 4881c4c8000000 add rsp,0C8h
PDB symbol for clr.dll not loaded
Exception object: 0000000002b0eeb8
Exception type: System.ComponentModel.Win32Exception
Message: 指定されたファイルが見つかりません。
InnerException:
StackTrace (generated):
(略)
実用例2: .NETなプログラムのプロセスのダンプファイルを読み取ってスタックトレースを出力するスクリプト
実はいつもやってる「clr.dllが読み込まれるまで進める」という処理が必要なければ、New-DbgSessionは-sosというオプションでsos.dllを自動で読んでくれるのです。それを利用すると、これだけ簡潔にできます。
どうでしょうか?今回の例はとくにPowerShellらしさはないですが、特定のブレイクポイントを一気に仕掛けるとか、結果に応じてどうこうするなんて用途には便利かと思います。
蛇足
WDK 8.1についてるWinDbgでSOS拡張をロードして、SOS系のコマンドを打つと、一発目がExceptionになって、二発目以降に成功するようになる。8.0ではそんなことはないので、WDK 8.0についてるWinDbgがおすすめ。