使用 Windbg/SOS,可以在堆栈上更改本地变量的值吗?如果有怎么办?
问问题
2198 次
1 回答
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
命令的值。例如,要将值设置为 0x15,请执行以下操作:
0:000> r ecx=15
该方法的输出现在是:
答案是 42
请记住,上面的示例只是许多可能的场景之一。根据调试/发布版本以及 32/64 位,本地变量的处理方式不同。此外,对于复杂的方法,跟踪值的确切位置可能会有点困难。
要更改实例的状态,您必须在堆栈上找到引用(例如使用!clrstack
或!dso
)。定位后,您可以使用偏移量找到保存数据的内存并使用e*
命令根据需要更改值。如果你也想要一个例子,请告诉我。
于 2011-04-18T07:04:41.710 回答