Mam zainstalowany plik binarny w moim systemie i chciałbym przyjrzeć się dezasemblacji danej funkcji. Preferowane użycie objdump
, ale inne rozwiązania również byłyby dopuszczalne.
Z tych pytań dowiedziałem się, że mógłbym zdemontować część kodu, jeśli znam tylko adresy graniczne. Z tej odpowiedzi nauczyłem się, jak zamienić moje podzielone symbole debugowania z powrotem w pojedynczy plik.
Ale nawet działając na tym pojedynczym pliku, a nawet deasemblując cały kod (tj. Bez adresu początkowego lub końcowego, ale zwykły -d
parametr do objdump
), nadal nie widzę nigdzie tego symbolu. Ma to sens, o ile dana funkcja jest statyczna, więc nie jest eksportowana. Niemniej jednak valgrind
zgłosi nazwę funkcji, więc musi być gdzieś przechowywana.
Patrząc na szczegóły sekcji debugowania, znalazłem tę nazwę wymienioną w .debug_str
sekcji, ale nie znam narzędzia, które może przekształcić to w zakres adresów.
static
, może zostać wstawiona przez kompilator do witryn wywołań. Może to oznaczać, że nie może w rzeczywistości być dowolna funkcja demontować, per se . Jeśli możesz znaleźć symbole innych funkcji, ale nie funkcji, której szukasz, jest to silna wskazówka, że funkcja została wbudowana. Valgrind może nadal odwoływać się do oryginalnej, wstępnie wstawionej funkcji, ponieważ informacje debugowania pliku ELF przechowują skąd pochodzi każda indywidualna instrukcja, nawet jeśli instrukcje są przenoszone w inne miejsce.addr2line
zaakceptuje komputery / adresy IP zistdin
wydrukuje odpowiednie linie kodu źródłowego. Podobnie,objdump -l
będzie mieszać objdump z liniami źródłowymi; chociaż dla wysoce zoptymalizowanego kodu z ciężkim wstawianiem, wyniki obu programów nie zawsze są szczególnie pomocne.Odpowiedzi:
Sugerowałbym użycie gdb jako najprostszego podejścia. Możesz to zrobić nawet jako linijkę, na przykład:
źródło
-ex 'command'
nie ma wman gdb
!? Ale w rzeczywistości jest wymieniony w dokumentacji gdb . Również w przypadku innych rzeczy takie jak/bin/ls
mogą zostać usunięte, więc jeśli to dokładne polecenie nic nie wyświetla, spróbuj innego obiektu! Może również określić plik / obiekt jako argument gołego słowa; np.gdb -batch -ex 'disassemble main' /bin/ls
gdb /bin/ls -batch -ex 'disassemble main'
działa równieżcolumn -ts$'\t'
do filtrowania danych wyjściowych GDB, uzyskasz ładnie wyrównane surowe bajty i kolumny źródłowe. Ponadto,-ex 'set disassembly-flavor intel'
zanim inne-ex
s spowodują składnię zespołu Intel.disassemble fn
za pomocą powyższej metody. Ale wydaje się, że gdy w pliku binarnym znajduje się wiele funkcji o tej samej nazwie, tylko jedna jest dezasemblowana. Czy można je wszystkie zdemontować, czy powinienem je zdemontować na podstawie surowego adresu?gdb,
disassemble/rs
aby wyświetlić również bajty źródłowe i suroweW tym formacie bardzo zbliża się do
objdump -S
wyniku:main.c
Skompiluj i zdemontuj
Demontaż:
Testowano na Ubuntu 16.04, GDB 7.11.1.
objdump + awk obejścia
Wydrukuj akapit, jak wspomniano na: /unix/82944/how-to-grep-for-text-in-a-file-and-display-the-paragraph-that-has-the -tekst
na przykład:
daje tylko:
Podczas używania
-S
nie wydaje mi się, aby istniał sposób odporny na awarie, ponieważ komentarze do kodu mogą zawierać dowolną możliwą sekwencję ... Ale poniższe działa prawie cały czas:zaadaptowano z: Jak zaznaczyć linie między dwoma wzorami znaczników, które mogą wystąpić wielokrotnie w awk / sed
Odpowiedzi na listy mailingowe
Na liście mailingowej z 2010 roku jest wątek, który mówi, że to niemożliwe: https://sourceware.org/ml/binutils/2010-04/msg00445.html
Oprócz
gdb
obejścia zaproponowanego przez Toma, komentują również inne (gorsze) obejście kompilacji, w-ffunction-section
którym jedna funkcja jest umieszczana na sekcję, a następnie zrzucana jest sekcja.Nicolas Clifton dał mu WONTFIX https://sourceware.org/ml/binutils/2015-07/msg00004.html , prawdopodobnie dlatego, że obejście GDB obejmuje ten przypadek użycia.
źródło
Zdemontuj jedną funkcję za pomocą Objdump
Mam dwa rozwiązania:
1. Oparte na linii poleceń
Ta metoda działa doskonale i dodatkowo prosta. Używam objdump z flagą -d i przesyłam go potokiem przez awk . Wygląda jak zdemontowane wyjście
Na początek zacznę od opisu wyniku objdump. Sekcji lub funkcja jest oddzielona od pustej linii. Dlatego zmiana FS (Separator pól) na znak nowej linii i RS (Separator rekordów) na podwójny znak nowej linii umożliwia łatwe wyszukiwanie zalecanej funkcji, ponieważ można ją po prostu znaleźć w polu $ 1!
Oczywiście możesz zastąpić main dowolną inną funkcją, którą chciałbyś wydrukować.
2. Bash Script
Napisałem mały skrypt basha dla tego wydania. Wklej go, skopiuj i zapisz np. Jako plik dasm .
Zmień x-access i wywołaj go np:
Jest to znacznie szybsze niż wywołanie gdb za pomocą skryptu. Poza tym użycie objdump nie załaduje bibliotek do pamięci i dlatego jest bezpieczniejsze!
Witalij Fadeev zaprogramował automatyczne uzupełnianie tego skryptu, co jest naprawdę fajną funkcją i przyspiesza pisanie.
Skrypt można znaleźć tutaj .
źródło
objdump
czygdb
jest szybsze. Ponieważ ogromny plik binarny (libxul.so Firefoksa)objdump
trwa wiecznie, anulowałem go po godzinie, agdb
zajmuje mniej niż minutę.Aby uprościć użycie awk do analizowania wyniku objdump względem innych odpowiedzi:
źródło
Działa to tak samo, jak rozwiązanie gdb (w tym, że przesuwa przesunięcia w kierunku zera), z wyjątkiem tego, że nie jest opóźnione (wykonuje pracę w około 5 ms na moim komputerze, podczas gdy rozwiązanie gdb zajmuje około 150 ms):
objdump_func:
źródło
awk
robi pierwsza ) była jedyną funkcją w pliku obiektowym, to znaczy nawet jeśli funkcja zaczyna się na, powiedzmy0x2d
, drugi awk przesunie ją w kierunku0x00
(odejmując0x2d
z adresu każdej instrukcji), co jest przydatne, ponieważ kod asemblera często odwołuje się do początku funkcji i jeśli funkcja zaczyna się od 0, nie musisz robić odejmowań w głowie. Kod awk mógłby być lepszy, ale przynajmniej spełnia swoje zadanie i jest dość wydajny.-ffunction-sections
to łatwiejszy sposób na upewnienie się, że każda funkcja zaczyna się od 0.Jeśli masz bardzo niedawne binutils (2.32+), jest to bardzo proste.
Przekazanie
--disassemble=SYMBOL
do objdump spowoduje dezasemblację tylko określonej funkcji. Nie ma potrzeby podawania adresu początkowego i końcowego.LLVM objdump ma również podobną opcję (
--disassemble-symbols
).źródło
Uzupełnienie Bash dla
./dasm
Pełne nazwy symboli dla tego rozwiązania (wersja D lang):
dasm test
a następnie naciskając TabTab, otrzymasz listę wszystkich funkcji.dasm test m
a następnie naciśnięcie spowoduje wyświetlenie TabTab wszystkich funkcji zaczynających się od m , lub jeśli istnieje tylko jedna funkcja, zostanie ona automatycznie uzupełniona.Plik
/etc/bash_completion.d/dasm
:źródło