Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to list on-the-fly all the functions/symbols available in C code on a Linux architecture?

Tags:

Assume main.c uses symbols from shared libs and local functions declared in main.c.

Is there a nice and elegant way to print a list of all the available function names and symbols at run time?

It should be possible since the data is loaded to the .code segment.

like image 751
0x90 Avatar asked Apr 03 '13 04:04

0x90


People also ask

How to list the functions in a library on Linux?

How to list the functions in a .a library on Linux? The nm utility shall display symbolic information appearing in the object file, executable file, or object-file library named by file. If no symbolic information is available for a valid input file, the nm utility shall report that fact, but not consider it an error condition.

What is function in C programming with example?

C - Functions Defining a Function. A function definition in C programming consists of a function header and a function body. ... Example. Given below is the source code for a function called max (). ... Function Declarations. A function declaration tells the compiler about a function name and how ...

What is the standard function library in C?

The Standard Function Library in C is a huge library of sub-libraries, each of which contains the code for several functions. In order to make use of these libraries, link each library in the broader library through the use of header files. The definitions of these functions are present in their respective header files.

How does GNU nm show symbols in Linux?

GNU nm lists the symbols from object files objfile .... If no object files are listed as arguments, nm assumes the file a.out . For each symbol, nm shows: The symbol value, in the radix selected by options (see below), or hexadecimal by default.


1 Answers

Since I had the same need to retrieve all loaded symbol names at runtime, I did some research based upon R..'s answer. So here is a detailed solution for linux shared libraries in ELF format which works with my gcc 4.3.4, but hopefully also with newer versions.

I mostly used the following sources to develop this solution:

  • ELF Manpage
  • Some sample code (found it while searching for "dl_iterate_phdr")

And here's my code. I used self explaining variable names and added detailed comments to make it understandable. If something is wrong or missing, please let me know... (Edit: I just realized that the question was for C and my code is for C++. But if you leave out the vector and the string it should work for C as well)

#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; } 
like image 119
Kanalpiroge Avatar answered Nov 01 '22 12:11

Kanalpiroge