Skip to content

Instantly share code, notes, and snippets.

@aeppert
Created August 8, 2017 18:31

Revisions

  1. aeppert created this gist Aug 8, 2017.
    128 changes: 128 additions & 0 deletions sym_test.cc
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,128 @@
    #include <stdio.h>
    #include <stdlib.h>
    #include <cxxabi.h>
    #include <link.h>

    #include <string>
    #include <vector>
    #include <iostream>

    using namespace std;

    // Reference:
    // https://stackoverflow.com/questions/15779185/list-all-the-functions-symbols-on-the-fly-in-c
    //
    /* 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 = NULL;
    char *sym_name = NULL;
    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);

    while(dyn->d_tag != DT_NULL) {
    switch(dyn->d_tag) {
    case DT_GNU_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];
    }
    break;
    case DT_STRTAB: {
    /* Get the pointer to the string table */
    strtab = (char *)dyn->d_un.d_ptr;
    }
    break;
    case 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));
    }
    }
    break;
    default:
    // Unsupported dyn->d_tag?
    break;
    }

    /* 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;

    }

    std::string demangle(std::string mangled_name)
    {
    int status = -1;

    char *demangled_name;
    demangled_name = abi::__cxa_demangle(mangled_name.c_str(), NULL, NULL, &status);
    if ( status == 0 ) {
    std::string ret(demangled_name);
    free(demangled_name);
    return ret;
    }
    free(demangled_name);
    return "";
    }

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

    std::cout << "Total number of symbolNames = " << symbolNames.size() << std::endl;
    for(std::vector<string>::iterator it = symbolNames.begin(); it != symbolNames.end(); ++it) {
    if ((*it).length() > 0 ) {
    std::cout << *it << std::endl;

    std::cout << demangle(*it) << std::endl;
    }
    }

    return 0;
    }