2010-02-10 6 views
6

Gdy 64-bitowa aplikacja VC 2005 zostanie skompilowana z włączoną optymalizacją, nie będzie można zobaczyć wszystkich zmiennych lokalnych w pliku zrzutu awaryjnego. W wielu przypadkach lokalne zmienne lub parametry są przechowywane w rejestrach zamiast na stosie. Kolejne wywołania innych funkcji, takich jak funkcje obsługi błędów, czasami nadpisują te wartości. Utrudnia to śledzenie przyczyny problemu. Czy istnieje sposób na wymuszenie zmiennych lokalnych i/lub parametrów na stosie w czasie wykonywania?Dowolny sposób wymuszania zmiennych lokalnych na stos w 64-bitowej aplikacji VC

Wyłączenie optymalizacji jest jednym ze sposobów, ale to sprawia, że ​​aplikacja jest wolna i generalnie nie jest dobrym pomysłem na kompilację wydania. Mam nadzieję, że istnieje wywołanie czasu wykonywania, który będzie zrzucić wszystkie lokalne zmienne i/lub rejestru gdzieś. Jeśli istnieje taka funkcja, możemy wywołać tę funkcję przed wywołaniem funkcji rejestrowania błędów i mamy nadzieję, że będziemy mogli zobaczyć więcej lokalnych zmiennych na stosie.

- Alex

+1

Wczoraj prawie rozwiązałem ten problem. Kłopot polega na tym, że w linii assembler nie jest obsługiwany w msvc na 64-bitowej platformie. Ideą jest użycie w linii montażowej do zapisania rejestrów do pewnej zmiennej globalnej przed wywołaniem procedury obsługi błędów, która generuje zrzut awaryjny.Na przykład: jeśli (x> y) { __asm ​​{ mov guqRegRBX, RBX // i inne rejestry } logError (__FILE__, __LINE__, ...) } Oczywiście, cały blok idzie być makrem, więc można go bardzo łatwo wykorzystać w kodzie. W ten sposób jestem pewien, że x i y można odzyskać. –

+0

Przykro mi, to wygląda brzydko. Nie wiem, jak sformatować komentarz. –

Odpowiedz

1

Zażycie adres zmiennej, kompilator będzie musiał przeznaczyć dla niego miejsca na stosie, więc można napisać trochę makro.

#ifdef DEBUG 
#define FORCE_ON_STACK(var) void * p##var##_dummy = (void *)&var 
#else 
#define FORCE_ON_STACK(var) (void)0 // eat the ; 
#endif 

Kompilator nadal może być leniwy o utrzymanie wartości na stosie w synchronizacji z rejestrów w niektórych przypadkach. Również przechowywanie argumentów w rejestrach jest ważną optymalizacją, którą to przynajmniej częściowo pokona, więc to nieco wpłynie na wydajność.

0

Czy istnieje sposób na wymuszenie zmiennych lokalnych i/lub parametrów na stosie w czasie wykonywania?

Takie coś jest całkowicie niepraktyczne; wymagałoby to ponownego skompilowania kodu. Odpowiedź Johna Knoellera jest najlepsza, w przeciwnym razie musisz złamać każdą pozycję i zarejestrować stan rejestru.

3

Myślę, że widzisz coś innego. Najczęściej spotykane konwencje wywoływania na x86 przekazują argumenty funkcji na stosie. Ale konwencja wywoływania x64 jest inna, jest podobna do __fastcall na x86, przekazuje pierwsze 4 argumenty funkcji w rejestrach (rcx, rdx, r8 i r9). Jeśli funkcja nie jest trywialna, kompilator generuje kod, aby od razu zapisać te rejestry na ramce stosu.

Niestety, debugger nie jest wystarczająco inteligentny, aby wiedzieć o zapisanych lokalizacjach rejestrów. Wyświetla wartość rejestru w stosie wywołań, wartość, która prawie zawsze się zmieniła. Możesz technicznie wykopać wartość argumentu z ramki stosu, ale naprawdę, naprawdę chcesz to zrobić. W zoptymalizowanym kodzie jest to przesunięcie z rsp, nie rbp, a wartość wskaźnika stosu również się zmieniła.

Nie znalazłem jeszcze żadnego dobrego rozwiązania tego problemu. Czekamy na usprawnienia w debugerze VS2010, nie mamy pojęcia, czy to rozwiązało problem.

+1

Dzięki za wyjaśnienie. Problem polega na tym, że (przy włączonym optymalizatorze) kompilator nie generuje kodu do zapisywania rejestrów (używanego dla zmiennych lokalnych), jeśli zmienne nie są używane dalej w funkcji. \ Na przykład w nieoczekiwanym stanie błędu w naszej aplikacji wywołujemy funkcję obsługi błędów, która generuje zrzut awaryjny, a następnie zwraca. Ponieważ nie ma dalszej realizacji jest bieżąca funkcja, wywołanie obsługi błędu z pewnością wymazuje większość zmiennych lokalnych przechowywanych w rejestrach. –

+0

Mój pomysł polega na wywołaniu makra wywołania funkcji obsługi błędu w celu zachowania wszystkich rejestrów (w zmiennych globalnych) przed wywołaniem funkcji obsługi błędu. Wtedy będę mógł wykopać wartości zmiennej z zachowanych wartości rejestru. Jeśli nie ma jednej funkcji do tego, jaki jest zestaw do pobierania każdej pojedynczej wartości rejestru? –

+0

To inny rodzaj problemu z debugowaniem. Zmienne lokalne, które są zapisywane w rejestrach i nie są zapisywane, są również w kodzie zoptymalizowanym dla x86. Zdecydowanie łatwiej jest sobie z tym poradzić, jeśli przełączysz się na widok kodu zespołu. –

1

Po uaktualnieniu do wersji VC++ 2013 i użyciu przełącznika/Zo uzyskasz znacznie lepsze wrażenia debugowania dzięki zoptymalizowanemu kodowi, zarówno 32-bitowemu, jak i 64-bitowemu. Nie odpowiada to na dosłowne pytanie, w jaki sposób wymusić zmienne na stosie, ale odpowiada ono na pytanie, jak ułatwić wyświetlanie wartości lokalnych i parametrów.

Powiązane problemy