Как VC ++ искажает имена локальных статических переменных? - PullRequest
6 голосов
/ 14 ноября 2008

Вот код, который у меня есть:

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

Я хочу посмотреть текущие значения этого синглтона. Но в настоящее время я на три часа приостановлен, и причина в том, что у меня не хватает памяти. Поэтому я не могу поставить точку останова в этом методе, чтобы увидеть, каково значение.

Мой вопрос заключается в том, как ссылаться на эту переменную instance из глобальной области видимости. Я пытался назвать это MyClass::getInstance::instance, но это не работает. Я предполагаю, что getInstance должен быть как-то украшен. Кто-нибудь знает как?

Это в Visual Studio 2008.

Ответы [ 3 ]

4 голосов
/ 15 ноября 2008

Ну, статическая переменная instance в функциональной области не отображается в .map файле, сгенерированном cl.exe /Fm, и не отображается, когда я использую x programname!*MyClass* в WinDbg, поэтому искажение имя, кажется, не содержит MyClass вообще.

Вариант 1. Разборка MyClass::getInstance

Этот подход кажется более простым:

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

Отсюда можно сказать, что компилятор назвал объект $S1. Конечно, это имя будет зависеть от того, сколько в вашей программе статических переменных в области функций.

Вариант 2: Поиск в памяти объекта

Чтобы расширить предложение @ gbjbaanb, если MyClass имеет виртуальные функции, вы можете найти его местоположение трудным способом:

  • Сделать полный дамп памяти процесса.
  • Загрузить полный дамп памяти в WinDbg.
  • Используйте команду x, чтобы найти адрес виртуальной таблицы MyClass:
    0:000> x programname!MyClass::`vftable'
    00425c64 programname!MyClass::`vftable' = 
  • Используйте команду s для поиска в виртуальном адресном пространстве процесса (в данном примере 0-2 ГБ) указателей на vtable 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.............
  • Используйте команду dt, чтобы найти смещение класса vtable и вычесть его из адресов, возвращаемых при поиске. Это возможные адреса для объекта.
    0:000> dt programname!MyClass
       +0x000 __VFN_table      : Ptr32 
       +0x008 x                : Int4B
       +0x010 y                : Float
  • Используйте dt programname!MyClass 0042b360 для проверки переменных-членов объекта, проверяя гипотезу о том, что объект расположен по адресу 0042b360 (или по какому-то другому адресу). Вы, вероятно, получите некоторые ложные срабатывания, как я делал выше, но, изучив переменные-члены, вы сможете определить, какой из них является вашим синглтоном.

Это общая методика поиска объектов C ++, и она немного излишня, когда вы можете просто разобрать MyClass::getInstance.

1 голос
/ 14 ноября 2008

Этот код выглядит опасно ...: -)

Но в любом случае ваше искаженное имя будет зависеть от вашего Соглашения о вызовах Поэтому, прежде чем вы найдете свое искаженное имя, вам необходимо знать, какая среда сборки используется в качестве соглашения о вызовах. MSDN имеет гораздо больше информации о соглашении о вызовах.

Помимо этого, один из способов узнать всю эту информацию о вашем классе - это проверить ваш VTable, который находится в первых 4 байтах вашего объекта. Изюминкой, которую используют реверсоры, является скрытый флаг VC ++ reportSingleClassLayout , который печатает структуру класса в художественном стиле ASCII.

1 голос
/ 14 ноября 2008

В gdb вы можете поставить точку наблюдения на искаженное имя переменной.

Например, с помощью этой функции:

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

    return xyz;
}

Я могу смотреть _ZZ1fvE3xyz (как искажено gcc 3.2.3 или gcc 4.0.1).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...