2008-11-13 5 views
6

Aquí hay un código que tengo:¿Cómo funciona nombres estáticos locales mangle VC++ variables?

MyClass* MyClass::getInstance() 
{ 
    static MyClass instance; 
    return &instance; 
} 

Quiero mirar en los valores actuales de este producto único. Pero actualmente estoy pausado tres horas en la ejecución, y la razón por la que estoy en pausa es que me he quedado sin memoria. Así que no puedo poner un punto de interrupción en este método allí para ver cuál es el valor.

Mi pregunta entonces es cómo hacer referencia a esta variable instance desde un ámbito global. He intentado refiriéndose a ella como MyClass::getInstance::instance pero que no funciona. Supongo getInstance tiene que ser decorado de alguna manera. Alguien sabe como?

Esto es en Visual Studio 2008.

+0

¿Por qué simplemente no lo hace el miembro de la clase? Las variables estáticas locales no son lo mejor para depurar –

+0

¿Qué clase de miembro? – Owen

+0

clase MyClass { instancia de MyClass *; MyClass * getInstance() { instancia de devolución; } } –

Respuesta

4

Bueno, la función de ámbito estática instance variable no aparece en un archivo generado por .mapcl.exe /Fm, y no aparece cuando se utiliza x programname!*MyClass* en WinDbg, por lo que no parece que el nombre revuelto para contener MyClass en absoluto.

Opción 1: Desmontar MyClass::getInstance

Este enfoque parece más fácil:

 
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 

De esto podemos decir que el compilador llama el objeto $S1. Por supuesto, este nombre dependerá de la cantidad de variables estáticas con función de función que tenga su programa.

Opción 2: Memoria de búsqueda del objeto

Para ampliar la sugerencia de @ gbjbaanb, si MyClass tiene funciones virtuales, es posible que pueda encontrar su ubicación de la manera difícil:

  • Hacer un volcado de memoria completo del proceso.
  • Cargar la memoria completa volcado en WinDbg.
  • utilizar el comando x para encontrar la dirección de vtable de MiClase:
 
    0:000> x programname!MyClass::`vftable' 
    00425c64 programname!MyClass::`vftable' = 
  • utilizar el comando s para buscar espacio de direcciones virtual del proceso (en este ejemplo, 0-2GB) para los punteros a de MiClase vtable:
 
    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............. 
  • Utilice la dt comando para encontrar el desplazamiento vtable de la clase, y reste eso de las direcciones devueltas desde la búsqueda. Estas son direcciones posibles para el objeto.
 
    0:000> dt programname!MyClass 
     +0x000 __VFN_table  : Ptr32 
     +0x008 x    : Int4B 
     +0x010 y    : Float 
  • Uso dt programname!MyClass 0042b360 para examinar las variables miembro del objeto, poniendo a prueba la hipótesis de que el objeto se encuentra en 0042b360 (o alguna otra dirección). Es probable que obtenga algunos resultados positivos falsos, como hice anteriormente, pero al inspeccionar las variables de los miembros puede averiguar cuál es su singleton.

Esta es una técnica general para encontrar objetos C++, y es un poco exagerado cuando podrías desensamblar MyClass::getInstance.

+0

Como no se menciona en ninguna parte, podría recomendar la herramienta 'undname', que se incluye en VS, que se puede usar para descifrar los símbolos – EFraim

+0

@EFraim: estoy de acuerdo,' undname' es muy útil para tratar con símbolos decorados. Sin embargo, no creo que hubiera sido útil encontrar variables estáticas con función de ámbito, porque MSVC no parece decorarlas tanto como cambiarles el nombre por completo (a '$ S1',' $ S2', etc.). – bk1e

+0

Si usa 'dumpbin/symbols' en el archivo' .obj', es probable que encuentre '$ S1' y' instance' como variables estáticas, con nombres realmente feos como '? Instance @? 1 ?? getInstance @ MyClass @@ SAPAV2 @ XZ @ 4V2 @ A' y '? $ S1 @? 1 ?? getInstance @ MyClass @@ SAPAV2 @ XZ @ 4IA'. No estoy seguro de cuál es el motivo para tenerlos, pero parece que se genera una variable '$ Sx' si se inicializa una variable estática local a partir de un parámetro de función. [Tenga en cuenta que probé con Studio 2010, que puede haber cambiado las convenciones desde 2008.] –

1

En GDB, se puede poner un punto de observación en el nombre revuelto de la variable.

Por ejemplo, con esta función:

int f() { 
    static int xyz = 0; 
    ++xyz; 

    return xyz; 
} 

puedo ver _ZZ1fvE3xyz (como destrozado por gcc 3.2.3 o 4.0.1 gcc).

+0

Impresionante ... Esa es la clase de cosa que estaba buscando, solo para el compilador de MS. Es bueno saber que se puede hacer. – Owen

1

Este código sólo se ve peligroso ... :-)

Pero de todos modos, su nombre revuelto va a depender de su Calling Convention Así que antes de encontrar su nombre de mangle que necesita saber cuál es su entorno de compilación está utilizando como la convención de llamadas. MSDN tiene mucha más información sobre convenciones de llamadas.

Además de esto, una forma de averiguar toda esta información sobre su clase es inspeccionar su VTable, que se encuentra en los primeros 4 bytes de su objeto. Un truco ingenioso que utilizan inversores es un oculto bandera VC++ reportSingleClassLayout que imprime la estructura de clases de una forma de arte ASCII.

Cuestiones relacionadas