Comment VC ++ gère-t-il les noms de variables statiques locaux?
Question
Voici un code que j'ai:
MyClass* MyClass::getInstance()
{
static MyClass instance;
return &instance;
}
Je veux examiner les valeurs actuelles de ce singleton. Mais je suis actuellement arrêté trois heures avant l'exécution, et la raison pour laquelle je suis en pause est que je n'ai plus de mémoire. Donc, je ne peux pas mettre un point d'arrêt dans cette méthode pour voir quelle est la valeur.
Ma question est donc de savoir comment faire référence à cette variable instance
à partir d'une portée globale. J'ai essayé de s'y référer en tant que MyClass :: getInstance :: instance
mais cela ne fonctionne pas. Je suppose que getInstance
doit être décoré d’une manière ou d’une autre. Quelqu'un sait comment?
Ceci est dans Visual Studio 2008.
La solution
La variable statique instance
, dont la portée est fonction, n'apparaît pas dans un fichier .map
généré par cl.exe / Fm
. , et cela ne s'affiche pas lorsque j'utilise x nom_programme! * MyClass *
dans WinDbg, de sorte que le nom mutilé ne semble pas contenir du tout MyClass
.
Option 1: désassemblez MyClass :: getInstance
Cette approche semble plus facile:
0:000> uf programname!MyClass::getInstance programname!MyClass::getInstance [programname.cpp @ 14]: 14 00401050 55 push ebp 14 00401051 8bec mov ebp,esp 15 00401053 a160b34200 mov eax,dword ptr [programname!$S1 (0042b360)] 15 00401058 83e001 and eax,1 15 0040105b 7526 jne funcstat!MyClass::getInstance+0x33 (00401083) programname!MyClass::getInstance+0xd [programname.cpp @ 15]: 15 0040105d 8b0d60b34200 mov ecx,dword ptr [programname!$S1 (0042b360)] 15 00401063 83c901 or ecx,1 15 00401066 890d60b34200 mov dword ptr [programname!$S1 (0042b360)],ecx 15 0040106c b9b0be4200 mov ecx,offset programname!instance (0042beb0) 15 00401071 e88fffffff call programname!ILT+0(??0MyClassQAEXZ) (00401005) 15 00401076 68e03e4200 push offset programname!`MyClass::getInstance'::`2'::`dynamic atexit destructor for 'instance'' (00423ee0) 15 0040107b e8f3010000 call programname!atexit (00401273) 15 00401080 83c404 add esp,4 programname!MyClass::getInstance+0x33 [programname.cpp @ 16]: 16 00401083 b8b0be4200 mov eax,offset programname!instance (0042beb0) 17 00401088 5d pop ebp 17 00401089 c3 ret
À partir de cela, nous pouvons dire que le compilateur a appelé l'objet $ S1
. Bien entendu, ce nom dépendra du nombre de variables statiques à portée de fonction de votre programme.
Option 2: rechercher dans la mémoire l'objet
Pour approfondir la suggestion de @ gbjbaanb, si MyClass
a des fonctions virtuelles, vous pourrez peut-être trouver son emplacement de la manière la plus difficile qui soit:
- Effectuez une sauvegarde complète de la mémoire du processus.
- Chargez le vidage de la mémoire complète dans WinDbg.
- Utilisez la commande
x
pour trouver l'adresse de la table vtable de MyClass:
0:000> x programname!MyClass::`vftable' 00425c64 programname!MyClass::`vftable' =
- Utilisez la commande
s
pour rechercher dans l'espace d'adressage virtuel du processus (dans cet exemple, 0 à 2 Go) des pointeurs vers la table vtable de MyClass:
0:000> s -d 0 L?7fffffff 00425c64 004010dc 00425c64 c35de58b cccccccc cccccccc d\B...]......... 0040113c 00425c64 8bfc458b ccc35de5 cccccccc d\B..E...]...... 0042b360 00425c64 00000000 00000000 00000000 d\B.............
- Utilisez la commande
dt
pour rechercher le décalage vtable de la classe et soustrayez-le des adresses renvoyées par la recherche. Ce sont des adresses possibles pour l'objet.
0:000> dt programname!MyClass +0x000 __VFN_table : Ptr32 +0x008 x : Int4B +0x010 y : Float
- Utilisez
dt nom_programme! MyClass 0042b360
pour examiner les variables membres de l’objet, en testant l’hypothèse selon laquelle l’objet est situé en 0042b360 (ou une autre adresse). Vous obtiendrez probablement des faux positifs, comme je l’ai déjà mentionné, mais en inspectant les variables membres, vous pourrez peut-être déterminer laquelle est votre singleton.
C’est une technique générale pour rechercher des objets C ++. C’est une sorte de surcharge lorsque vous pouvez simplement désassembler MyClass :: getInstance
.
Autres conseils
Dans gdb, vous pouvez placer un point de contrôle sur le nom mutilé de la variable.
Par exemple, avec cette fonction:
int f() {
static int xyz = 0;
++xyz;
return xyz;
}
Je peux regarder _ZZ1fvE3xyz (comme mutilé par gcc 3.2.3 ou gcc 4.0.1).
Ce code a l'air dangereux ...: -)
Quoi qu'il en soit, votre nom mutilé dépendra de votre Convention d'appel Ainsi, avant de trouver votre nom mangle, vous devez savoir ce que votre environnement de génération utilise comme convention d'appel. MSDN contient beaucoup plus d’informations sur la convention d’appel.
En outre, une façon de connaître toutes ces informations sur votre classe consiste à inspecter votre VTable, qui se trouve dans les 4 premiers octets de votre objet. Un astuce astucieuse utilisée par les inverseurs est un indicateur VC ++ caché reportSingleClassLayout qui affiche la structure de classe de manière artistique ASCII.