Debugger を利用したデバッグ - メソッドにブレークポイントを設定する方法
ここでは WinDbg/CDB といったデバッガでマネージドコード用のデバッガエクステンションを利用する方法を紹介します。
運よく CLR Debugger などの GUI 付きデバッガが利用可能な場合は、そういう便利なツールを使えばよいかもしれません。
しかしたとえ様々な便利ツールが使える場合でも、常に最も柔軟性がある方法として、デバッガでコツコツデータをチェックすることができるにこしたことはありません。
・・・というか、ほとんどの場合、サーバー上で使えるツールはデバッガ程度と思って準備しておいたほうが良いものです。
デバッガとデバッガエクステンションの準備
Windows SDK に含まれる Debugging Tools for Windows をインストールしてください。
それからデバッガエクステンションとして、今回の範囲では .NET Framework に付属する SOS.dll でも構いませんが、 マイクロソフトのダウンロードセンターから PSSCOR4.dll をダウンロードしておくと良いでしょう。
PSSCOR4.dll は .NET Framework 4 に対応したデバッガエクステンションです。
PSSCOR4 のパッケージには x86 用と amd64 用が含まれているので、環境に応じてデバッガのディレクトリに dll をコピーしておきます。
C# のメソッドにブレークポイントを設定する方法
ここでは ASP.NET (C#) のコードにブレークポイントを設定してみましょう。
具体的には例として、ASP.NET ページ test1.aspx 上のボタン (Button1) のクリックハンドラとしての Button1_Click メソッドが呼ばれたときに プログラムが停止するように、Button1_Click にブレークポイントを設定します。
ここでは test1.aspx のコードファイル test1.aspx.cs が次のようであるとします。(つまり何もしない・・・(笑))
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class test1 : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
}
}
ではさっそく試してみましょう。
今回はデバッガとして cdb を利用します。デバッガエクステンションは psscor4.dll を使いますので、 まだインストールしていない人はインストールしてください。
私の環境では C:\Program Files\Debugging Tools for Windows (x64) にデバッガがインストールされているので、 psscor4.dll もこのディレクトリにコピーしました。
さて、IIS のワーカープロセスの起動を確認します。デバッガのインストールディレクトリに移動してコマンドラインから次を実行。
> tlist | findstr w3wp
結果が返らなければプロセスが起動していないので一度ブラウザから同一 Web アプリケーション内のページに対してリクエストを行います。
ここでは次のようになりました。
>tlist | findstr w3wp 4068 w3wp.exe
これは w3wp.exe の PID が 4068 であることを示しています。
デバッガを PID 4068 のプロセスにアタッチします。
>cdb -p 4068
デバッガをプロセスにアタッチしたら、まだ設定していないならシンボルパスを設定しておきます。
0:030> .sympath srv*C:\websymbols*http://msdl.microsoft.com/download/symbols ... 0:030> .reload Reloading current modules ................................................................ ................................................................ .............
#あらかじめ環境変数 _NT_SYMBOL_PATH を設定しておく方が良いです。
同じようにコマンドを実行するなら C:\websymbols というディレクトリは作っておいてください。
さて次に test1.aspx のモジュール名を探すために name2ee コマンドを利用しましょう。 ASPX ページクラスはファイル名と同じ名前のクラスになるので、ページ名で EEClass を探せばそれに関連付くモジュールの情報などがわかります。
0:030> !psscor4.name2ee * test1 Module: 000007fee66a1000 Assembly: SMDiagnostics.dll -------------------------------------- Module: 000007fee66f1000 ... Assembly: Microsoft.JScript.dll -------------------------------------- Module: 000007ff001590d0 Assembly: App_Web_to3rnap3.dll Token: 0000000002000002 MethodTable: 000007ff001598b8 EEClass: 000007ff001c3360 Name: test1
モジュール名が分かったので、bpmd コマンドでブレークポイントを設定できます。
0:030> !psscor4.bpmd App_Web_to3rnap3 test1.Button1_Click Found 1 methods in module 000007ff001590d0... MethodDesc = 000007ff00159858 Adding pending breakpoints...
以上でブレークポイントは設定できました。
g してプログラムを実行して、ブラウザ上でボタンをクリックすることでクリックイベントハンドラを呼び、 実際にブレークするか確認しましょう。
0:030> g
ここでブラウザでボタンをクリックすると、デバッガには次のように出力されました。
(118.164): CLR notification exception - code e0444143 (first chance) JITTED App_Web_to3rnap3!test1.Button1_Click(System.Object, System.EventArgs) Setting breakpoint: bp 000007FF001E06F0 [test1.Button1_Click(System.Object, System.EventArgs)] Breakpoint 0 hit 000007ff`001e06f0 c3 ret 0:005>
これは App_Web_to3rnap3!test1.Button1_Click がコンパイルされて、 アドレス 000007FF001E06F0 のメソッドにブレークポイントが設定され、 引き続きそれが呼び出されてブレークポイント #0 がヒットした、ということです。
念のため CLRStack を見てみると、確かに次のように Button1_Click で停止していることが分かります。
0:005> !psscor4.clrstack OS Thread Id: 0x164 (5) Child SP IP Call Site 000000000422de08 000007ff001e06f0 test1.Button1_Click(System.Object, Sys 000000000422de10 000007fee045187a System.Web.UI.WebControls.Button.Raise ... 000000000422f110 000007fee0349ef1 DomainNeutralILStubClass.IL_STUB_Rever 000000000422f378 000007fee31acfeb [ContextTransitionFrame: 000000000422f
このように bpmd コマンドを使えばメソッドのステータスが JIT コンパイル前でもブレークポイントを設定できるので、大変便利です。