Skip to content

Instantly share code, notes, and snippets.

@aeppert
Created August 8, 2017 18:31
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save aeppert/0b1a38d4364e2863d27a8a0ce2c97dc8 to your computer and use it in GitHub Desktop.
Save aeppert/0b1a38d4364e2863d27a8a0ce2c97dc8 to your computer and use it in GitHub Desktop.
Enumerate and demangle symbols within an executable's own symbol table.
#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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment