2013-04-03 12 views
14

Załóżmy, że main.c używa symboli z udostępnionych bibliotek i funkcji zadeklarowanych w main.c.Lista wszystkich funkcji/symboli w locie w C?

Czy istnieje ładny i elegancki sposób drukowania listy wszystkich dostępnych nazw funkcji lub symboli w czasie wykonywania?

Powinno być możliwe, ponieważ dane znajdują się w segmencie .code, ale trzeba je przeanalizować.

+1

funkcje biblioteki 'C' ale API z/sekcji import eksport jest możliwy. Gdzie Funkcja C jest możliwa, jeśli używają jako etykiet w sekcji Kod –

Odpowiedz

12

Ponieważ miałem taką samą potrzebę pobierania wszystkich wczytanych nazw symboli w czasie wykonywania, wykonałem kilka badań w oparciu o odpowiedź R .. Oto szczegółowe rozwiązanie dla bibliotek współdzielonych Linuksa w formacie ELF, który działa z moim gcc 4.3.4, ale mam nadzieję, że również z nowszymi wersjami.

Najczęściej stosowane następujące źródła do opracowania tego rozwiązania:

i tu jest mój kod. Użyłem samo wyjaśniających się nazw zmiennych i dodałem szczegółowe komentarze, aby było to zrozumiałe. Jeśli coś jest nie tak lub nie, proszę dać mi znać ... (Edycja: Właśnie zdałem sobie sprawę, że pytanie dotyczyło C, a mój kod dotyczy C++.Ale jeśli pominąć wektor a łańcuch powinien pracować dla C, jak również)

#include <link.h> 
#include <string> 
#include <vector> 

using namespace std; 

/* Callback for dl_iterate_phdr. 
* Is called by dl_iterate_phdr for every loaded shared lib until something 
* else than 0 is returned by one call of this function. 
*/ 
int retrieve_symbolnames(struct dl_phdr_info* info, size_t info_size, void* symbol_names_vector) 
{ 

    /* ElfW is a macro that creates proper typenames for the used system architecture 
    * (e.g. on a 32 bit system, ElfW(Dyn*) becomes "Elf32_Dyn*") */ 
    ElfW(Dyn*) dyn; 
    ElfW(Sym*) sym; 
    ElfW(Word*) hash; 

    char* strtab = 0; 
    char* sym_name = 0; 
    ElfW(Word) sym_cnt = 0; 

    /* the void pointer (3rd argument) should be a pointer to a vector<string> 
    * in this example -> cast it to make it usable */ 
    vector<string>* symbol_names = reinterpret_cast<vector<string>*>(symbol_names_vector); 

    /* Iterate over all headers of the current shared lib 
    * (first call is for the executable itself) */ 
    for (size_t header_index = 0; header_index < info->dlpi_phnum; header_index++) 
    { 

     /* Further processing is only needed if the dynamic section is reached */ 
     if (info->dlpi_phdr[header_index].p_type == PT_DYNAMIC) 
     { 

      /* Get a pointer to the first entry of the dynamic section. 
      * It's address is the shared lib's address + the virtual address */ 
      dyn = (ElfW(Dyn)*)(info->dlpi_addr + info->dlpi_phdr[header_index].p_vaddr); 

      /* Iterate over all entries of the dynamic section until the 
      * end of the symbol table is reached. This is indicated by 
      * an entry with d_tag == DT_NULL. 
      * 
      * Only the following entries need to be processed to find the 
      * symbol names: 
      * - DT_HASH -> second word of the hash is the number of symbols 
      * - DT_STRTAB -> pointer to the beginning of a string table that 
      *     contains the symbol names 
      * - DT_SYMTAB -> pointer to the beginning of the symbols table 
      */ 
      while(dyn->d_tag != DT_NULL) 
      { 
       if (dyn->d_tag == DT_HASH) 
       { 
        /* Get a pointer to the hash */ 
        hash = (ElfW(Word*))dyn->d_un.d_ptr; 

        /* The 2nd word is the number of symbols */ 
        sym_cnt = hash[1]; 

       } 
       else if (dyn->d_tag == DT_STRTAB) 
       { 
        /* Get the pointer to the string table */ 
        strtab = (char*)dyn->d_un.d_ptr; 
       } 
       else if (dyn->d_tag == DT_SYMTAB) 
       { 
        /* Get the pointer to the first entry of the symbol table */ 
        sym = (ElfW(Sym*))dyn->d_un.d_ptr; 


        /* Iterate over the symbol table */ 
        for (ElfW(Word) sym_index = 0; sym_index < sym_cnt; sym_index++) 
        { 
         /* get the name of the i-th symbol. 
         * This is located at the address of st_name 
         * relative to the beginning of the string table. */ 
         sym_name = &strtab[sym[sym_index].st_name]; 

         symbol_names->push_back(string(sym_name)); 
        } 
       } 

       /* move pointer to the next entry */ 
       dyn++; 
      } 
     } 
    } 

    /* Returning something != 0 stops further iterations, 
    * since only the first entry, which is the executable itself, is needed 
    * 1 is returned after processing the first entry. 
    * 
    * If the symbols of all loaded dynamic libs shall be found, 
    * the return value has to be changed to 0. 
    */ 
    return 1; 

} 

int main() 
{ 
    vector<string> symbolNames; 
    dl_iterate_phdr(retrieve_symbolnames, &symbolNames); 

    return 0; 
} 
+2

Używanie DT_HASH do uzyskania liczby symboli wydaje się niewiarygodne. Kiedy uruchamiam powyższy kod, nie ma interesującego elementu DT_HASH. Ponadto, symbol_count powinien być zainicjalizowany do 0 lub następować po nim. –

+0

Okazuje się, że możliwe jest uzyskanie DT_GNU_HASH zamiast DT_HASH. Czy ktoś wie, jak zamiast tego uzyskać 'sym_cnt' z mieszania GNU? –

+0

@ justin.m.chase: 'DT_GNU_HASH' nie zapewnia łatwego sposobu na zliczanie symboli bez chodzenia po wszystkich haszach i liczenia. Możesz zobaczyć mój kod, aby to zrobić tutaj: http://git.musl-libc.org/cgit/musl/tree/src/ldso/dynlink.c?id=c5ab5bd3be15eb9d49222df132a51ae8e8f78cbc#n1554 –

10

W systemach z dynamicznym połączeniem ELF dostępna może być funkcja dl_iterate_phdr. Jeśli tak, można go użyć do zbierania informacji o każdym wczytanym pliku biblioteki współużytkowanej, a informacje, które otrzymasz, wystarczają do sprawdzenia tabel symboli. Proces jest zasadniczo następujący:

  1. Uzyskaj adres nagłówków programu ze struktury dl_phdr_info przekazanej do Ciebie.
  2. Skorzystaj z nagłówka programu PT_DYNAMIC, aby znaleźć tabelę _DYNAMIC dla modułu.
  3. Użyj pozycji DT_SYMTAB, DT_STRTAB i DT_HASH do znalezienia listy symboli. DT_HASH jest potrzebny tylko do uzyskania długości tablicy symboli, ponieważ nie wydaje się być przechowywany nigdzie indziej.

Wszystkie potrzebne typy to <elf.h> i <link.h>.

+0

Co z symbolami, które nie są dynamicznie połączone? Czy jest coś takiego jak libc, a także wspólna biblioteka? – dcow

+0

Tak, zakładając, że korzystasz z dynamicznego łączenia, "libc" jest biblioteką współdzieloną i możesz uzyskać jej tabelę symboli w ten sposób. –

6

To naprawdę nie jest C specyficzne, ale system operacyjny i format binarny oraz (dla debugowania symboli i niezmienionych nazw symboli C++) nawet pytanie dotyczące kompilatora. Nie ma ogólnej drogi, a także nie ma naprawdę eleganckiego sposobu.

Najbardziej przenośnym i przyszłościowym sposobem jest prawdopodobnie uruchomienie zewnętrznego programu, takiego jak nm, który znajduje się w POSIX. GNU version znalezione w Linuksie prawdopodobnie ma kilka rozszerzeń, których powinieneś unikać, jeśli chcesz mieć przenośność i odporność na przyszłość.

Jego wyjście powinno pozostać stabilne, a nawet jeśli zmieni się format binarny, również zostanie zaktualizowane i będzie działać. Po prostu uruchom go prawymi przełącznikami, przechwyć jego wyjście (prawdopodobnie uruchamiając je poprzez popen, aby uniknąć pliku tymczasowego) i parsuj to.

1

Należy dl_iterate_phdr(retrieve_symbolnames, &symbolNames);

nie
+2

Zastanów się nad udostępnieniem fragmentu kodu. – chanchal118

+0

Edytowałem oryginalny post z twoją poprawką, dziękuję. –

Powiązane problemy