Debugger を利用したデバッグ - 例外ハンドラにブレークポイントを設定する方法
プログラムがクラッシュするような場合は、明らかにウェブサイトに繋がらなくなったり、エラーが表示されるなどして、 運用上のみためのインパクトが大きいですよね。
ただしクラッシュする分には意外と「ハイ、今エラー発生!」ということが分かりやすくて、トラブルシューティングも速やかにいく場合も多いものです。
その反対に try-catch でエラー箇所がくくられており、本来クラッシュして(落ちて)しまうような状況でも、 クラッシュしないで見かけ上動いているように見える場合は、問題の発生ポイントが見えにくくなって、トラブルシューティングにも手間取る場合があります。
この資料ではデバッガを使って try-catch の catch、すなわち例外ハンドラにブレークポイントを設定する方法、および、そこで例外オブジェクトを確認する方法を紹介します。
トラブルシューティングのサンプルコード
ここでは test2.aspx 上に置いたボタン (Button1) のクリックイベントハンドラを次のように記述します。
using System;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class test2 : System.Web.UI.Page
{
protected void Button1_Click(object sender, EventArgs e)
{
try
{
int i = 0;
int j = 1;
int z = j / i;
Label1.Text = "Hello";
}
catch (Exception ex)
{
}
}
}
0 で除算しているので問題が発生するはずですね。
この catch に入るところで止める方法をみてみましょう。
まずはデバッガをアタッチして、シンボルパスを設定します。tlist を使う方法など、 分からないという方は以前の記事 (Debugger を利用したデバッグ - メソッドにブレークポイントを設定する方法) 等をみてください。
0:029> .sympath srv*c:\websymbols*http://msdl.microsoft.com/download/symbols ... 0:029> .reload Reloading current modules ................................................................ ................................................................ ..................................
ここでは clr の例外でブレークするようにしておきます。
0:029> sxe clr
処理を流して、問題のある操作(ここではボタンのクリック)を行います。
0:029> g (630.61c): Integer divide-by-zero - code c0000094 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. 000007ff`00211067 41f7f8 idiv eax,r8d
Button1_Click メソッドの情報を探します。
0:027> !psscor4.name2ee * test2.Button1_Click
Module: 000007fef10f1000
Assembly: SMDiagnostics.dll
...
--------------------------------------
Module: 000007ff001f8738
Assembly: App_Web_hcpk5hem.dll
Token: 0000000006000004
MethodDesc: 000007ff001f8ed0
Name: test2.Button1_Click(System.Object, System.EventArgs)
JITTED Code Address: 000007ff00211050
メソッドディスクリプタのアドレスが分かったので、それを ehinfo コマンドに渡すことで、 例外ハンドラの情報をダンプできます。
0:027> !psscor4.ehinfo 000007ff001f8ed0
MethodDesc: 000007ff001f8ed0
Method Name: test2.Button1_Click(System.Object, System.EventArgs)
Class: 000007ff001ecb78
MethodTable: 000007ff001f8f30
mdToken: 0000000006000004
Module: 000007ff001f8738
IsJitted: yes
CodeAddr: 000007ff00211050
Transparency: Critical
EHHandler 0: TYPED catch(System.Exception)
Clause: [000007ff0021105e, 000007ff0021108d] [e, 3d]
Handler: [000007ff00211096, 000007ff002110b5] [46, 65]
例外ハンドラのアドレスが 000007ff00211096 であるので、 ここにブレークポイントを設定...
0:027> bp 000007ff00211096 ...
実際にブレークするか確認します。g して処理を流します。
0:027> g
確かにブレークポイントがヒットしました。
Breakpoint 0 hit 000007ff`00211096 55 push rbp 0:027> bl 0 e 000007ff`00211096 0001 (0001) 0:****
例外ハンドラに入ったところで、スタック上のオブジェクトをダンプすると確かに例外オブジェクトがありました。
0:027> !psscor4.dumpstackobjects OS Thread Id: 0x61c (27) RSP/REG Object Name rdx 000000013f4ea140 System.DivideByZeroException 0000000003D4BC90 000000013f4ea140 System.DivideByZeroException ... 0000000003D4F110 000000013f4bcfe8 System.Web.Hosting.IIS7WorkerRequest 0:027> !psscor4.pe 000000013f4ea140 Exception object: 000000013f4ea140 Exception type: System.DivideByZeroException Message: Attempted to divide by zero. InnerException: <none> StackTrace (generated): SP IP Function 0000000003D4DE80 000007FF00211067 App_Web_hcpk5hem! test2.Button1_Click(System.Object, System.EventArgs)+0x17 StackTraceString: <none> HResult: 80020012 0:027>