开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜