Autor Wątek: Crash Dump - plik DMP - problem z symbolami PDB  (Przeczytany 6384 razy)

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Październik 03, 2008, 22:02:35
Trafiłem ostatnio na fajny mechanizm w Visual C++. Otóż można sobie zrobić __try { } __except() { } i w ten sposób złapać błąd Windows (dzielenie przez zero, Access Violation), a potem zrobić z niego Crash Dump funkcją MiniDumpWriteDump z biblioteki systemowej Dbghelp. Powstaje plik DMP, który domyślnie skojarzony jest z Visual C++ i można w nim odtworzyć miejsce wystąpienia problemu.

Mój problem polega na tym, że nie wiem, jak wczytać plik PDB z symbolami, żeby w Visualu (np. w okienku Call Stack) zamiast adresów były nazwy funkcji mojego kodu (a najlepiej jeszcze dostęp do kodu źródłowego). Jeśli Crash Dump powstał w tej samej wersji gry do której mam kod i plik PDB w podkatalogu Debug/Release, to działa. Ale jeśli - powiedzmy - dam kolegom swoją grę, potem sam zmieniam coś w jej kodzie i potem oni zgłaszają mi błąd i przysyłają Crash Dump, to już plik PDB się nie zgadza i symboli nie mam.

Mógłbym trzymać sobie stary plik PDB i kod źródłowy z wersji którą dostali koledzy. Pytanie jak go wskazać. Z tego co wyczytałem w Sieci to w okienku Call Stack albo Modules powinno się dać kliknąć PPM, wybrać z menu Load Symbols i tam w okienku wyboru pliku wskazać plik PDB. W praktyce niestety żadne okienko mi się nie pokazuje i pliku PDB wskazać nie mogę.

PS: Zainstalowałem też "Debugging Tools for Windows", stworzyłem katalog który jest jako "Symbol Server" i wgrałem tam plik PDB i EXE mojej gry specjalnym magicznym poleceniem, w opcjach Visual C++ ustawiłem ścieżkę do tego katalogu i nie pomogło :P

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

st3tc

  • Gość
# Październik 03, 2008, 22:13:38
To się wczas obudziłeś z tym minidump-em ... :)

Jak robisz builda i dajesz release, to musisz sobie zapisać PDB do tej wersji i gdzieś zachować. Albo - commit w repozytorium i tag wersji release. Można potem się cofnąć i przebudować (oczywiście pod warunkiem użycia takiego samego środowiska).


Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Październik 03, 2008, 22:16:15
Ale ja mogę mieć ten plik PDB i nawet całe źródło w wersji z której powstała skompilowana gra wysłana kolegom, która zgadza się z wersją z której powstał Crash Dump. Mój problem polega na tym, że nie wiem, jak w Visual C++ wskazać gdzie to leży na moim dysku, po tym jak w Visual C++ otworzyłem plik DMP.

Offline yarpen

  • Użytkownik

# Październik 03, 2008, 22:50:45
Najlepiej PDB trzymac w tym samym miejscu co execa. Zasadniczo nie powinno to miec zadnego znaczenia, bo w execu jest zapisana pelna sciezka do PDB. Zajrzyj tam i upewnij sie, ze wskazuje w dobre miejsce. Jezeli natomiast chcesz miec symbol server z prawdziwego zdarzenia, to musisz tam uploadowac pliki uzywajac symsrv a nie po prostu kopiujac.
PS. Zamiast sie bawic z try/except, ustaw lepiej SetUnhandledExceptionFilter czy cos w tym guscie (klepie z pamieci).
« Ostatnia zmiana: Październik 03, 2008, 23:01:14 wysłana przez yarpen »

st3tc

  • Gość
# Październik 03, 2008, 22:55:44
Sorki za delayka, Jericho leciało :). 

Yarpen juz w sumie wszystko powiedział.
Ja tylko dodam, że specjalnie dla Ciebie Regedit zrobiłem test - app. która się sypie. Później ukryłem folder, do innego skopiowałem dumpa, dll-ki, exe i pdb i nie było żadnych problemów. Tylko tyle co poprosił mnie o podanie ścieżki do pliku *.cpp. SetUnhandledExceptionFilter jest prawidłową metodą do użycia tego mechanizmy a nie try except (chyba, że chcesz selektywnie chronić ofkoz).
« Ostatnia zmiana: Październik 03, 2008, 23:02:34 wysłana przez st3tc »

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Październik 04, 2008, 01:17:04
yarpen: Wiem, że do używania symbol servera trzeba używać tych konsolowych programów, a nie wgrywać pliki bezpośrednio. Napisałem wyżej, że tak robię.

st3tc: Dzięki za fatygę, ale nadal nie rozumiem jak to zrobiłeś i dlaczego u mnie nie działa. Próbowałem też skopiować plik PDB do tego katalogu gdzie leży DMP i nie znajduje go. Zrób może taki test: skompiluj program który się wysypuje, zachowaj gdzieś jego EXE i PDB w innym katalogu, tam gdzie masz źródło zmień coś w kodzie i przekompiluj, a potem odpal tamten pierwszy program i spróbuj otworzyć DMP z symbolami.

Co do SetUnhandledExceptionFilter, czytałem gdzieś że potrafi nieprawidłowo zrzucić stos wątku na którym wystąpił błąd i dlatego lepiej jest używać __try __except i tam pobierać strukturę EXCEPTION_POINTERS funkcją GetExceptionInformation.

st3tc

  • Gość
# Październik 04, 2008, 10:28:34
st3tc: Dzięki za fatygę, ale nadal nie rozumiem jak to zrobiłeś i dlaczego u mnie nie działa. Próbowałem też skopiować plik PDB do tego katalogu gdzie leży DMP i nie znajduje go. Zrób może taki test: skompiluj program który się wysypuje, zachowaj gdzieś jego EXE i PDB w innym katalogu, tam gdzie masz źródło zmień coś w kodzie i przekompiluj, a potem odpal tamten pierwszy program i spróbuj otworzyć DMP z symbolami.
Ale po co mam się tak bawić ? :).

Patrz:
EXE ma pełną ściężkę do PDB. PDB Mają pełne ścieżki do pliczków z kodem. Jak zrobisz tak jak robisz to użyjesz nowego PDB na starym exe na 99.99% .

Ja napisałem wyżej - zmień np nazwę katalogu z Twoim projektem. Tak aby być pewnym że VC++ go nie znajdzie i zostanie użyty ten stary pdb. Musisz też mieć oryginalne (dla tego starego builda) źródełka - ale od tego są SCM.

Co do SetUnhandledExceptionFilter, czytałem gdzieś że potrafi nieprawidłowo zrzucić stos wątku na którym wystąpił błąd i dlatego lepiej jest używać __try __except i tam pobierać strukturę EXCEPTION_POINTERS funkcją GetExceptionInformation.

Serio ? ;) ...

Cytat: MSDN Library
MiniDumpWriteDump may not produce a valid stack trace for the calling thread. To work around this problem, you must capture the state of the calling thread before calling MiniDumpWriteDump and use it as the ExceptionParam parameter. One way to do this is to force an exception inside a __try/__except block and use the EXCEPTION_POINTERS information provided by GetExceptionInformation. Alternatively, you can call the function from a new worker thread and filter this worker thread from the dump.
« Ostatnia zmiana: Październik 04, 2008, 10:45:41 wysłana przez st3tc »

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Październik 04, 2008, 11:31:42
Co do SetUnhandledExceptionFilter, czytałem gdzieś że potrafi nieprawidłowo zrzucić stos wątku na którym wystąpił błąd i dlatego lepiej jest używać __try __except i tam pobierać strukturę EXCEPTION_POINTERS funkcją GetExceptionInformation.

Serio ? ;) ...

Cytat: MSDN Library
MiniDumpWriteDump may not produce a valid stack trace for the calling thread. To work around this problem, you must capture the state of the calling thread before calling MiniDumpWriteDump and use it as the ExceptionParam parameter. One way to do this is to force an exception inside a __try/__except block and use the EXCEPTION_POINTERS information provided by GetExceptionInformation. Alternatively, you can call the function from a new worker thread and filter this worker thread from the dump.
No właśnie, zacytowałeś z MSDN dokładnie to co i ja przeczytałem. To tylko potwierdza, że jeśli nie chcę robić osobnego wątku do zrzucania Crash Dump, to powinienem użyć __try/__except a nie SetUnhandledExceptionFilter. Chyba że źle to rozumiem?

st3tc: Dzięki za fatygę, ale nadal nie rozumiem jak to zrobiłeś i dlaczego u mnie nie działa. Próbowałem też skopiować plik PDB do tego katalogu gdzie leży DMP i nie znajduje go. Zrób może taki test: skompiluj program który się wysypuje, zachowaj gdzieś jego EXE i PDB w innym katalogu, tam gdzie masz źródło zmień coś w kodzie i przekompiluj, a potem odpal tamten pierwszy program i spróbuj otworzyć DMP z symbolami.
Ale po co mam się tak bawić ? :).

Patrz:
EXE ma pełną ściężkę do PDB. PDB Mają pełne ścieżki do pliczków z kodem. Jak zrobisz tak jak robisz to użyjesz nowego PDB na starym exe na 99.99% .

Ja napisałem wyżej - zmień np nazwę katalogu z Twoim projektem. Tak aby być pewnym że VC++ go nie znajdzie i zostanie użyty ten stary pdb. Musisz też mieć oryginalne (dla tego starego builda) źródełka - ale od tego są SCM.
Nie wiem co masz na myśli. Wyobraź sobie taką sytuację, że piszę grę, pewną wersję daję kolegom do przetestowania, zachowuję sobie z tej wersji też plik PDB w jakimś katalogu Backup, a dalej nad swoją grą pracuję, zmieniam jej kod i przekompilowuję. Potem jeden z kolegów przysyła mi Crash Dump. Jak mam go przeanalizować? Na czas otwierania pliku DMP zmienić nazwę albo przenieść katalog z kodem tylko po to, żeby Visual go nie znalazł? Jeśli tak, to czy wtedy pozwoli mi wybrać plik PDB z mojego dysku?

Co to są SCM?

Offline yarpen

  • Użytkownik

# Październik 04, 2008, 11:34:30
Wrzucasz po prostu otrzymany plik PDB na miejsce Twojego.
SetUnhandledFilter nie musi isc z innego watku. Uzywalismy tego systemu przez ponad 3 lata w Wiedzminie, na naprawde duzej ilosci crashy w pewnych momentach i nigdy nie bylo problemow.

Offline Zene

  • Użytkownik
    • Zenedith’s dev blog

# Październik 04, 2008, 22:22:51
Co to są SCM?

Zapewne chodzi o systemy kontroli wersji,

Offline mINA87

  • Użytkownik

# Październik 05, 2008, 00:25:04
A ja się zastanawiam nad wdrożeniem w robocie czegoś takiego:
http://msdn.microsoft.com/en-us/magazine/cc163563.aspx
Co do Twoich probemów Reg to Source Server powinien rozwiązać Twoje problemy automatycznie, ale
1. Piszesz coś o zmienaie nazwy. Po co? PDBki są sygnowane i każdy build ma inną sumę kontrolną przez co nie zostanie wczytany PDB nie pasujący do EXE.
2. Jakim cudem nie pojawia Ci się okno wyboru PDBka? Jesli w modules przy pauzie klikniesz prawym na moduł, który nie posiada załadowanego pliku PDB to masz opcję Load symbols, pojawia się requester i wybierasz PDB - przerabiane wiele razy i działa dla EXE, dla DMP nie widze powodu dla którego miałoby być inaczej.
Spróbuj pobawić się jeszcze WinDBGiem - jak to tam będzie wyglądać?

Offline Reg

  • Administrator
    • Adam Sawicki - Home Page

# Październik 05, 2008, 13:18:57
A ja się zastanawiam nad wdrożeniem w robocie czegoś takiego:
http://msdn.microsoft.com/en-us/magazine/cc163563.aspx
Co do Twoich probemów Reg to Source Server powinien rozwiązać Twoje problemy automatycznie, ale
1. Piszesz coś o zmienaie nazwy. Po co? PDBki są sygnowane i każdy build ma inną sumę kontrolną przez co nie zostanie wczytany PDB nie pasujący do EXE.
2. Jakim cudem nie pojawia Ci się okno wyboru PDBka? Jesli w modules przy pauzie klikniesz prawym na moduł, który nie posiada załadowanego pliku PDB to masz opcję Load symbols, pojawia się requester i wybierasz PDB - przerabiane wiele razy i działa dla EXE, dla DMP nie widze powodu dla którego miałoby być inaczej.
Spróbuj pobawić się jeszcze WinDBGiem - jak to tam będzie wyglądać?
Właśnie o to chodzi że to nie działa tak jak powinno. Inaczej nie pisałbym tu na forum z moim problemem. Postawiłem Source Server, wgrałem tam tym magicznym poleceniem plik PDB do tej wersji EXE którą dałem kolegom i Visual mimo tego nie znajduje symboli. Podobnie, klikam prawym, wybieram z menu Load symbols i Visual po chwili namysłu... nie robi nic, nie pokazuje okienka w którym mógłbym wskazać plik PDB.

st3tc

  • Gość
# Październik 05, 2008, 14:14:01
Straszne... kiedys wystarczyło skopiować pdb itp i bylo po sprawie - zadanie było wykonane, błąd znaleziony a teraz im się zachwiewa Source Serverów i innych cudów :) (tak - to ironia ;p).

Offline Pierdek

  • Użytkownik

# Październik 05, 2008, 14:36:35
Lepiej sypnac kodem bez bledow ;) Btw w gemsach 7 jest fajny art o zaawansowanym debugowaniu ;0

Offline mINA87

  • Użytkownik

# Październik 05, 2008, 15:36:51
Symbol Server czy Source Server?
Jaki masz status symboli dla tego modułu?
Coś ciekawego jest napisane w Symbol Load Information?
Przy normalnym debugowaniu (nie DMP)  jest ok?
No i jeszcze raz - spróbuj WinDBG - co on robi? Znajduje i wczytuje symbole?