Mój program działa tak:
exe -p param1 -i param2 -o param3
Rozbił się i wygenerowany plik zrzutu pamięci, core.pid
.
Chcę przeanalizować plik zrzutu pamięci wg
gdb ./exe -p param1 -i param2 -o param3 core.pid
Ale GDB rozpoznaje parametry pliku EXE jako dane wejściowe GDB.
Jak przeanalizować plik zrzutu pamięci w tej sytuacji?
exe
nie jest to skrypt powłoki (do ustawiania niektórych zmiennych itp.), Jak np. Wfirefox
systemie Linux?Odpowiedzi:
Możesz używać jądra z GDB na wiele sposobów, ale przekazywanie parametrów, które mają być przekazane do pliku wykonywalnego do GDB, nie jest sposobem na użycie pliku core. Może to być również powód wystąpienia tego błędu. Możesz użyć pliku podstawowego na następujące sposoby:
gdb <executable> <core-file>
lubgdb <executable> -c <core-file>
lubUżywając pliku core nie musisz przekazywać argumentów. Scenariusz awarii jest wyświetlany w GDB (sprawdzany z GDB w wersji 7.1 na Ubuntu).
Na przykład:
Jeśli chcesz przekazać parametry do pliku wykonywalnego w celu debugowania w GDB, użyj
--args
.Na przykład:
Strony podręcznika będą pomocne przy przeglądaniu innych opcji GDB.
źródło
Proste użycie GDB do debugowania plików coredump:
Plik coredump dla „procesu” jest tworzony jako plik „core.pid”.
Po wejściu do znaku zachęty GDB (po wykonaniu powyższego polecenia) wpisz:
W ten sposób uzyskasz informacje o stosie, w którym możesz przeanalizować przyczynę awarii / usterki. Innym poleceniem do tych samych celów jest:
To jest to samo, co powyżej. Zgodnie z konwencją wyświetla wszystkie informacje o stosie (co ostatecznie prowadzi do lokalizacji awarii).
źródło
Po prostu pomiń parametry. GDB ich nie potrzebuje:
źródło
objdump
+gdb
minimalny przykład do uruchomieniaTL; DR:
objdump -s core
może służyć do zbiorczego zrzucania pamięciA teraz pełna konfiguracja testu edukacyjnego:
main.c
Skompiluj i uruchom, aby wygenerować rdzeń:
Wynik:
GDB wskazuje nam dokładną linię, w której wystąpił błąd segmentacji, czego większość użytkowników chce podczas debugowania:
następnie:
co wskazuje nam bezpośrednio linię buggy 7.
Argumenty CLI są przechowywane w pliku podstawowym i nie muszą być ponownie przekazywane
Aby odpowiedzieć na konkretne pytania dotyczące argumentów CLI, widzimy, że jeśli zmienimy argumenty CLI, np. Za pomocą:
to zostanie odzwierciedlone w poprzednim bactrace bez żadnych zmian w naszych poleceniach:
Więc zwróć uwagę, jak teraz
argc=3
. Dlatego musi to oznaczać, że plik podstawowy przechowuje te informacje. Zgaduję, że po prostu przechowuje to jako argumentymain
, tak jak przechowuje argumenty innych funkcji.Ma to sens, jeśli weźmie się pod uwagę, że zrzut pamięci musi przechowywać całą pamięć i stan rejestru programu, a więc zawiera wszystkie informacje potrzebne do określenia wartości argumentów funkcji na bieżącym stosie.
Mniej oczywiste jest to, jak sprawdzić zmienne środowiskowe: Jak uzyskać zmienną środowiskową ze zrzutu pamięci Zmienne środowiskowe są również obecne w pamięci, więc objdump zawiera te informacje, ale nie jestem pewien, jak wygodnie wyświetlić je wszystkie za jednym razem , jeden po drugim działał na moich testach:
Analiza Binutils
Używając narzędzi binutils, takich jak
readelf
iobjdump
, możemy zbiorczo zrzucić informacje zawarte wcore
pliku, takie jak stan pamięci.Większość / całość musi być również widoczna przez GDB, ale te narzędzia binutils oferują bardziej masowe podejście, które jest wygodne w niektórych przypadkach, podczas gdy GDB jest wygodniejszy do bardziej interaktywnej eksploracji.
Pierwszy:
mówi nam, że
core
plik jest w rzeczywistości plikiem ELF :dlatego jesteśmy w stanie sprawdzić go bardziej bezpośrednio za pomocą zwykłych narzędzi binutils.
Szybkie spojrzenie na standard ELF pokazuje, że w rzeczywistości istnieje typ ELF do niego dedykowany:
Więcej informacji o formacie można znaleźć pod adresem:
Następnie:
podaje kilka wskazówek dotyczących struktury plików. Wydaje się, że pamięć jest zawarta w zwykłych nagłówkach programów:
a w obszarze notatek znajduje się więcej metadanych, w szczególności
prstatus
komputer :objdump
może łatwo zrzucić całą pamięć za pomocą:który zawiera:
który dokładnie pasuje do wartości stdout w naszym przebiegu.
Zostało to przetestowane na Ubuntu 16.04 amd64, GCC 6.4.0 i binutils 2.26.1.
źródło
Z samouczka dotyczącego debuggera GDB RMS :
Upewnij się, że plik naprawdę jest
core
obrazem - sprawdź go za pomocąfile
.źródło
Nieco inne podejście pozwoli Ci całkowicie pominąć GDB. Jeśli chcesz tylko śledzenia wstecznego, specyficzne dla Linuksa narzędzie „catchsegv” przechwyci SIGSEGV i wyświetli ślad.
źródło
Nie ma znaczenia, czy plik wykonywalny ma argumenty, czy nie. Aby uruchomić GDB na dowolnym pliku binarnym z wygenerowanym plikiem core, składnia jest poniżej.
Dla lepszego zrozumienia przedstawię poniższy przykład.
Z powyższego wyniku można się domyślić, co dotyczy jądra, czy jest to dostęp NULL, SIGABORT itp.
Te liczby od 0 do 10 to ramki stosu GDB. Te ramki stosu nie należą do Twojego pliku binarnego. W powyższych klatkach 0-10, jeśli podejrzewasz, że coś jest nie tak, wybierz tę klatkę
Teraz, aby zobaczyć więcej szczegółów na ten temat:
Aby dokładniej zbadać problem, możesz teraz wydrukować podejrzane wartości zmiennych tutaj.
źródło
Po prostu wpisz polecenie:
Lub
Nie ma potrzeby podawania żadnego argumentu wiersza poleceń. Zrzut kodu wygenerowany w wyniku wcześniejszego ćwiczenia.
źródło
Możesz przeanalizować plik zrzutu pamięci za pomocą polecenia „gdb”.
źródło