изменить значение переменной локального стека - PullRequest
1 голос
/ 18 апреля 2011

Используя Windbg / SOS, можно ли изменить значение локальной переменной на стеке? Если так, то как?

1 Ответ

1 голос
/ 18 апреля 2011

Краткий ответ: это зависит.

По умолчанию локальные типы значений хранятся в стеке, но из-за оптимизации они часто будут храниться только в регистрах по мере необходимости. Типы ссылок хранятся в куче со ссылкой на экземпляр в стеке (или в регистре).

Я предполагаю, что вы хотите изменить тип локального значения. Давайте посмотрим на простой пример.

[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* для изменения значений по мере необходимости. Дайте мне знать, если вы хотите пример для этого.

...