tags:

views:

591

answers:

3

Here's some code I have:

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

I want to look into this singleton's current values. But I'm currently paused three hours into execution, and the reason I'm paused is that I'm out of memory. So I can't put a breakpoint in this method there to see what the value is.

My question then is how to refer to this instance variable from a global scope. I've tried referring to it as MyClass::getInstance::instance but that doesn't work. I'm guessing getInstance has to be decorated somehow. Anyone know how?

This is in Visual Studio 2008.

+1  A: 

In gdb, you can put a watchpoint on the mangled name of the variable.

For example, with this function:

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

    return xyz;
}

I can watch _ZZ1fvE3xyz (as mangled by gcc 3.2.3 or gcc 4.0.1).

Nathan Kitchen
Awesome... That's the sort of thing I was looking for, only for the MS compiler. Good to know that it can be done.
Owen
+1  A: 

That code just looks dangerous... :-)

But anyway, your mangled name is going to depend on your Calling Convention So before you find your mangle name you need to know what your build environment is using as the calling convention. MSDN has a lot more information on calling convention.

Besides this, one way to find out all this information about your class is to inspect your VTable, which is found in the first 4 bytes of your object. A nifty trick that reversers use is a hidden VC++ Flag reportSingleClassLayout that prints the class structure in an ASCII art manner.

kervin
+2  A: 

Well, the function-scoped static instance variable doesn't show up in a .map file generated by cl.exe /Fm, and it doesn't show up when I use x programname!*MyClass* in WinDbg, so the mangled name doesn't seem to contain MyClass at all.

Option 1: Disassemble MyClass::getInstance

This approach seems easier:

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

From this we can tell that the compiler called the object $S1. Of course, this name will depend on how many function-scoped static variables your program has.

Option 2: Search memory for the object

To expand on @gbjbaanb's suggestion, if MyClass has virtual functions, you might be able to find its location the hard way:

  • Make a full memory dump of the process.
  • Load the full memory dump into WinDbg.
  • Use the x command to find the address of MyClass's vtable:
    0:000> x programname!MyClass::`vftable'
    00425c64 programname!MyClass::`vftable' = 
  • Use the s command to search the process's virtual address space (in this example, 0-2GB) for pointers to MyClass's 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.............
  • Use the dt command to find the class's vtable offset, and subtract that from the addresses returned from the search. These are possible addresses for the object.
    0:000> dt programname!MyClass
       +0x000 __VFN_table      : Ptr32 
       +0x008 x                : Int4B
       +0x010 y                : Float
  • Use dt programname!MyClass 0042b360 to examine the object's member variables, testing the hypothesis that the object is located at 0042b360 (or some other address). You will probably get some false positives, as I did above, but by inspecting the member variables you may be able to figure out which one is your singleton.

This is a general technique for finding C++ objects, and is kind of overkill when you could just disassemble MyClass::getInstance.

bk1e