2011-04-17 73 views
1

使用Windbg/SOS,可以更改堆棧上本地變量的值?如果是這樣如何?更改本地堆棧變量值

+0

您是否正在尋找在託管代碼或非託管內部執行此操作的方式? – 2011-04-18 06:26:05

+0

@Seva:由於問題被標記爲SOS,因此它很可能是託管代碼。 – 2011-04-18 07:05:16

+0

@Seva:@Brain是正確的,它的託管代碼 – 2011-04-18 13:09:46

回答

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] 

注意當地x被列爲,但它並沒有告訴我們註冊。我們可以查看寄存器並找到值爲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命令。例如。該值設置爲0×15做到以下幾點:

0:000> r ecx=15 

方法的輸出,現在是:

答案是42

請記住,上面的例子是隻有許多可能的情況之一。根據調試/發佈版本以及32/64位,本地處理方式不同。另外,對於複雜的方法,可能會更難以跟蹤值的確切位置。

要更改實例的狀態,您必須在堆棧中找到參考(例如使用!clrstack!dso)。一旦找到,您就可以使用偏移量來查找存儲數據的存儲器,並使用e*命令根據需要更改值。讓我知道你是否也想要一個例子。