change local stack variable value
Using Windbg/SOS, it possible to change value of a local varible on stack? If so ho开发者_开发技巧w?
The short answer is: It depends.
Per default local value types are stored on the stack but due to optimization they will often be stored only in registers as needed. Reference types are stored on the heap, with a reference to the instance on the stack (or in a register).
I am going to assume that you're looking to change a local value type. Let's look at a simple example.
[MethodImpl(MethodImplOptions.NoInlining)] // avoid inlining of short method
public static void Method(int x) {
Console.WriteLine("The answer is {0}", x + x);
}
Assuming we set a breakpoint on Method
and run until the breakpoint is hit, the stack looks like this:
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]
Notice that the local x
is listed as , but it doesn't tell us which register. We could look at the registers and find the one with the value 2, but there could be more than one. Instead let's look at the JIT compiled code for the method.
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
Looking at the code, we see that the only add
instruction uses the esi
register, so our value is stored here prior to the calculation. Unfortunately, esi
doesn't hold the correct value at this point, but looking backwards we find mov esi,ecx
. I.e. the value is initially stored in ecx
.
To change the value of ecx
use the r
command. E.g. to set the value to 0x15 do the following:
0:000> r ecx=15
The output of the method is now:
The answer is 42
Please keep in mind that the example above is only one of many possible scenarios. Locals are handled differently depending on debug/release build as well as 32/64 bit. Also, for complex methods it may be a bit harder tracking the exact location of the value.
To change the state of an instance, you have to locate the reference on the stack (e.g. using !clrstack
or !dso
). Once located you can use the offsets to find the memory, that holds the data and use the e*
commands to change the values as needed. Let me know if you want an example for that as well.
精彩评论