.NET Framework デバッグ ~ マネージドコードのメソッド名を指定してブレークポイントを設定する方法
.NET Framework デバッグ ~ 例外オブジェクトの捕まえ方 で使ったコードで、 もう少し遊んでみましょう。
サンプルコードでは button1_Click というメソッドで問題を発生させていました。 そこで、このメソッドにブレークポイントを設定してみましょう。
マネージドコードは基本的に、メソッド毎の JIT コンパイルで実行されます。つまり、 Foo メソッド、Bar メソッドがあったとすると、Foo メソッドが初めて呼び出されたところで初めてコンパイルされて、 呼び出されるのです。この時点で初めてブレークポイントを設定するべきアドレスが決まるわけです。 そのため bp コマンドで直ちにブレークポイントを設定することが出来ません。
ちなみに、Foo メソッドがコンパイルされたからといって、他のメソッドもコンパイルされるわけではありません。 あくまでメソッド毎に JIT コンパイルされます。
JIT 前のブレークポイント設定例
メソッド名でブレークさせるには、!sos.bpmd コマンドを使用します。
0:004> !sos.bpmd exceptiontest1.exe ExceptionTest1.Form1.button1_Click
Found 1 methods...
MethodDesc = 003859d8
Adding pending breakpoints...
処理を流します。
0:004> g (133c.1768): CLR notification exception - code e0444143 (first chance) JITTED ExceptionTest1!ExceptionTest1.Form1 .button1_Click(System.Object, System.EventArgs) Setting breakpoint: bp 00420328 [ExceptionTest1.Form1.button1_Click(System.Object, System.EventArgs)] Breakpoint 0 hit eax=003859d8 ebx=01cd0b54 ecx=01cb3a5c edx=01cb7aec esi=01cb8cc4 edi=01cb7aec eip=00420328 esp=0024e974 ebp=0024e98c iopl=0 nv up ei ng nz ac po cy cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000293 00420328 55 push ebp
すると上記のように、JIT コンパイルが発生したタイミングで適切なアドレス (ここでは 00420328) にブレークポイントが設定されたことがわかります。 さらに、ブレークポイントがヒットしてブレークしました。
マネージドスタックをみると次のように、確かに button1_Click にいます。
0:000> !sos.clrstack
OS Thread Id: 0x1768 (0)
ESP EIP
0024e974 00420328 ExceptionTest1.Form1.button1_Click(System.Object, System.EventArgs)
0024e97c 64404170 System.Windows.Forms.Control.OnClick(System.EventArgs)
0024e994 643ff55a System.Windows.Forms.Button.OnClick(System.EventArgs)
0024e9a4 64996da4 System.Windows.Forms.Button.OnMouseUp(System.Windows.Forms.MouseEventArgs)
0024e9c0 649675d3 System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef,
System.Windows.Forms.MouseButtons, Int32)
0024ea4c 64c99b66 System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)
0024ea50 64c98325 [InlinedCallFrame: 0024ea50]
0024eae8 64432550 System.Windows.Forms.Button.WndProc(System.Windows.Forms.Message ByRef)
0024eaf4 64438640 System.Windows.Forms.Control+ControlNativeWindow.OnMessage(System.Windows
.Forms.Message ByRef)
0024eafc 644385c1 System.Windows.Forms.Control+ControlNativeWindow.WndProc(System.Windows.
Forms.Message ByRef)
0024eb10 6443849a System.Windows.Forms.NativeWindow.Callback(IntPtr, Int32, IntPtr, IntPtr)
0024ecb8 002709dc [NDirectMethodFrameStandalone: 0024ecb8] System.Windows.Forms
.UnsafeNativeMethods.DispatchMessageW(MSG ByRef)
0024ecc8 64448cce System.Windows.Forms.Application+ComponentManager.System.Windows.Forms
.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(Int32, Int32, Int32)
0024ed64 64448937 System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32,
System.Windows.Forms.ApplicationContext)
0024edb8 64448781 System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32,
System.Windows.Forms.ApplicationContext)
0024ede8 64405911 System.Windows.Forms.Application.Run(System.Windows.Forms.Form)
0024edfc 0042009a ExceptionTest1.Program.Main()
0024f028 71401b4c [GCFrame: 0024f028]
これでブレークできたので、目的は達成です。
おまけ JIT コンパイルの様子をみる
さて、JIT コンパイルの状態について少しだけみてみましょう。続きを読む