Windbg/SOS を使用して、スタック上のローカル変数の値を変更することは可能ですか? もしそうなら、どのように?
1 に答える
簡単な答えは次のとおりです。
デフォルトでは、ローカル値型はスタックに格納されますが、最適化により、必要に応じてレジスタにのみ格納されることがよくあります。参照型は、スタック (またはレジスター) 上のインスタンスへの参照とともに、ヒープに格納されます。
ローカル値タイプを変更しようとしていると仮定します。簡単な例を見てみましょう。
[MethodImpl(MethodImplOptions.NoInlining)] // avoid inlining of short method
public static void Method(int x) {
Console.WriteLine("The answer is {0}", x + x);
}
ブレークポイントを設定して、ブレークポイントに到達するまで実行すると仮定するとMethod
、スタックは次のようになります。
0:000> !clrstack -a
OS Thread Id: 0x1abc (0)
Child SP IP Call Site
0035f290 003600e0 TestBench2010.Program.Method(Int32)*** WARNING: Unable to verify checksum for C:\workspaces\TestBench2010\TestBench2010\bin\Release\TestBench2010.exe
[C:\workspaces\TestBench2010\TestBench2010\Program.cs @ 17]
PARAMETERS:
x (<CLR reg>) = 0x00000002
0035f294 003600a2 TestBench2010.Program.Main(System.String[]) [C:\workspaces\TestBench2010\TestBench2010\Program.cs @ 24]
PARAMETERS:
args = <no data>
0035f4c0 636221bb [GCFrame: 0035f4c0]
localx
は としてリストされていますが、どのレジスターかはわかりません。レジスターを見て、値が 2 のレジスターを見つけることができましたが、複数ある可能性があります。代わりに、メソッドの JIT コンパイル コードを見てみましょう。
0:000> !u 001c37f0
Normal JIT generated code
TestBench2010.Program.Method(Int32)
Begin 003600e0, size 32
C:\workspaces\TestBench2010\TestBench2010\Program.cs @ 17:
003600e0 55 push ebp
003600e1 8bec mov ebp,esp
003600e3 56 push esi
003600e4 8bf1 mov esi,ecx
*** WARNING: Unable to verify checksum for C:\windows\assembly\NativeImages_v4.0.30319_32\mscorlib\658bbc023e2f4f4e802be9483e988373\mscorlib.ni.dll
003600e6 b9302be004 mov ecx,offset mscorlib_ni+0x322b30 (04e02b30) (MT: System.Int32)
003600eb e8301fe5ff call 001b2020 (JitHelp: CORINFO_HELP_NEWSFAST)
003600f0 8bd0 mov edx,eax
003600f2 03f6 add esi,esi <==== This is x + x
003600f4 897204 mov dword ptr [edx+4],esi
003600f7 8bf2 mov esi,edx
003600f9 e882709d04 call mscorlib_ni+0x257180 (04d37180)(System.Console.get_Out(), mdToken: 060008cd)
003600fe 56 push esi
003600ff 8bc8 mov ecx,eax
00360101 8b1534204c03 mov edx,dword ptr ds:[34C2034h] ("The answer is {0}")
00360107 8b01 mov eax,dword ptr [ecx]
00360109 8b403c mov eax,dword ptr [eax+3Ch]
0036010c ff5018 call dword ptr [eax+18h]
C:\workspaces\TestBench2010\TestBench2010\Program.cs @ 18:
0036010f 5e pop esi
00360110 5d pop ebp
00360111 c3 ret
コードを見ると、唯一のadd
命令がesi
レジスタを使用しているため、計算前に値がここに格納されていることがわかります。残念ながら、esi
は現時点では正しい値を保持していませんが、後ろから見るとmov esi,ecx
. つまり、値は最初に に保存されecx
ます。
の値を変更するには、 コマンドをecx
使用しr
ます。たとえば、値を 0x15 に設定するには、次のようにします。
0:000> r ecx=15
メソッドの出力は次のようになります。
答えは42です
上記の例は、考えられる多くのシナリオの 1 つにすぎないことに注意してください。ローカルは、デバッグ/リリース ビルドと 32/64 ビットに応じて異なる方法で処理されます。また、複雑なメソッドの場合、値の正確な位置を追跡するのが少し難しい場合があります。
インスタンスの状態を変更するには、スタック上で参照を見つける必要があります (例:!clrstack
またはを使用!dso
)。見つかったら、オフセットを使用してデータを保持するメモリを見つけ、必要に応じてe*
コマンドを使用して値を変更できます。その例も必要な場合はお知らせください。