2011-04-17 3 views
1

En utilisant Windbg/SOS, est-il possible de changer la valeur d'une variable locale sur la pile? Si c'est le cas, comment?changer la valeur de la pile locale

+0

Cherchez-vous le moyen de le faire dans le code managé ou non géré? –

+0

@Seva: Comme la question est étiquetée SOS, il s'agit probablement d'un code géré. –

+0

@Seva: @Brain est correct, son code managé –

Répondre

1

La réponse courte est: Cela dépend.

Par défaut, les types de valeur locale sont stockés sur la pile, mais en raison de l'optimisation, ils seront souvent stockés uniquement dans des registres si nécessaire. Les types de références sont stockés sur le tas, avec une référence à l'instance sur la pile (ou dans un registre). Je vais supposer que vous cherchez à changer un type de valeur locale. Regardons un exemple simple.

[MethodImpl(MethodImplOptions.NoInlining)] // avoid inlining of short method 
public static void Method(int x) { 
    Console.WriteLine("The answer is {0}", x + x); 
} 

En supposant que nous fixons un point d'arrêt sur Method et exécuter jusqu'à ce que le point de rupture est atteint, la pile ressemble à ceci:

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] 

Notez que la x locale est répertorié comme, mais il ne dit pas nous qui registre. Nous pourrions regarder les registres et trouver celui avec la valeur 2, mais il pourrait y en avoir plus d'un. Au lieu de cela, regardons le code compilé JIT pour la méthode.

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 

En regardant le code, nous voyons que la seule instruction add utilise le registre esi, notre valeur est stockée ici avant le calcul. Malheureusement, esi ne détient pas la valeur correcte à ce stade, mais en regardant en arrière, nous trouvons mov esi,ecx. C'est à dire. la valeur est initialement stockée dans ecx.

Pour modifier la valeur de ecx, utilisez la commande r. Par exemple. pour définir la valeur à 0x15 effectuer les opérations suivantes:

0:000> r ecx=15 

La sortie de la méthode est maintenant:

La réponse est 42

S'il vous plaît garder à l'esprit que l'exemple ci-dessus est seulement un des nombreux scénarios possibles. Les sections locales sont traitées différemment en fonction de la version de débogage/lancement ainsi qu'en 32/64 bits. En outre, pour les méthodes complexes, il peut être un peu plus difficile de suivre l'emplacement exact de la valeur. Pour changer l'état d'une instance, vous devez localiser la référence sur la pile (par exemple, en utilisant !clrstack ou !dso). Une fois localisé, vous pouvez utiliser les décalages pour trouver la mémoire qui contient les données et utiliser les commandes e* pour modifier les valeurs si nécessaire. Faites-moi savoir si vous voulez un exemple pour cela aussi.

Questions connexes