2013-09-08 14 views
5

w manualu, funkcja backtrace() Linux mówi:Alternatywa backtrace() na systemie Linux, które można znaleźć symbole funkcji statycznych

Należy pamiętać, że nazwy „statycznych” funkcje nie są narażone i wygrał nie będą dostępne w śledzeniu.

Jednak z symbolami debugowania włączony (-g), programy takie jak addr2line i gdb nadal może uzyskać nazwy funkcji statycznych. Czy istnieje sposób programowego wywoływania nazw funkcji statycznych z samego procesu?

Odpowiedz

2

Tak, poprzez sprawdzenie własnego pliku wykonywalnego (/proc/self/exe) za pomocą np. libbfd lub biblioteka parsowania plików ELF, aby przeanalizować rzeczywiste symbole. Zasadniczo, można napisać kod w C, który robi równowartość coś podobnego

env LANG=C LC_ALL=C readelf -s executable | awk '($5 == "LOCAL" && $8 ~ /^[^_]/ && $8 !~ /\./)' 

O ile mi wiadomo, dynamiczny interfejs łącznikiem w systemie Linux (<dlfcn.h>) nie zwraca adresy statyczne (lokalne) symbole.

Prostym i dość solidnym podejściem jest wykonanie z Twojego programu readelf lub objdump. Zauważ, że nie możesz podać ścieżki pseudo-pliku /proc/self/exe, ponieważ zawsze odnosi się ona do własnego pliku wykonywalnego procesu. Zamiast tego musisz użyć np. realpath("/proc/self/exe", NULL), aby uzyskać dynamicznie przydzieloną bezwzględną ścieżkę do bieżącego pliku wykonywalnego, który można dostarczyć do polecenia. Zdecydowanie chcesz również, aby środowisko zawierało wartości LANG=C i LC_ALL=C, tak aby dane wyjściowe polecenia były łatwo przetwarzalne (i nie były zlokalizowane w języku preferowanym przez bieżącego użytkownika). Może się to wydawać trochę kłopotliwe, ale wymaga tylko zainstalowania pakietu binutils i nie trzeba aktualizować programu lub biblioteki, aby nadążyć za najnowszymi osiągnięciami, więc uważam, że ogólnie rzecz biorąc to całkiem dobre podejście .

Chcesz na przykład?

Jednym ze sposobów na uproszczenie jest wygenerowanie oddzielnych tablic z informacjami o symbolu w czasie kompilacji. Zasadniczo, po pliki wynikowe są generowane osobny plik źródłowy jest generowana dynamicznie, uruchamiając objdump lub readelf nad powiązanych plików obiektowych, tworząc tablicę nazw i wskaźniki podobne do

const struct { 
    const char *const name; 
    const void *const addr; 
} local_symbol_names[] = { 
    /* Filled in using objdump or readelf and awk, for example */ 
    { NULL, NULL } 
}; 

może z prostej funkcji wyszukiwania eksportowanego w pliku nagłówkowym, aby po podłączeniu końcowego pliku wykonywalnego mógł on łatwo i wydajnie uzyskać dostęp do tablicy symboli lokalnych.

Powtarza niektóre dane, ponieważ ta sama informacja znajduje się już w pliku wykonywalnym, a jeśli dobrze pamiętam, musisz najpierw połączyć końcowy plik wykonywalny z tablicą pośrednią, aby uzyskać rzeczywiste adresy symboli, a następnie Połącz ponownie z tablicą symboli, co sprawia, że ​​jest to trochę kłopotliwe podczas kompilacji. Uniknie się jednak zależności od czasu wykonywania na binutils.

3

Jeśli twój plik wykonywalny (i połączone biblioteki) są kompilowane z informacjami debugowania (tj.z -g flagi do gcc lub g++), a następnie można użyć Ian Taylor libbacktrace (ogłoszone here) od wewnątrz GCC - patrz jego kod here

tej biblioteki (BSD na licencji wolnego oprogramowania) korzysta DWARF informacje debugowania z plików wykonywalnych i bibliotek współdzielonych połączony przez proces. Zobacz jego plik README.

Pamiętaj, że jeśli kompilujesz z optymalizacją, niektóre funkcje mogą być inline (nawet bez wyraźnego oznaczenia inline w kodzie źródłowym, afunkcje inline mogą nie mieć właściwego własnego kodu). W takim przypadku śledzenie w tle nie powie wiele na ich temat.