Skip to content

Commit

Permalink
symbols: parse symbols using dlinfo() instead of libelf on linux
Browse files Browse the repository at this point in the history
Signed-off-by: Martin Olivier <[email protected]>
  • Loading branch information
martin-olivier committed Jan 6, 2025
1 parent ef4fb5f commit 6e9ca66
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 52 deletions.
3 changes: 0 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ add_library(dylib STATIC ${SOURCES})
target_include_directories(dylib PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
if(UNIX)
target_link_libraries(dylib PRIVATE dl)
if(NOT APPLE)
target_link_libraries(dylib PRIVATE elf)
endif()
endif()

option(DYLIB_BUILD_TESTS "When set to ON, build unit tests" OFF)
Expand Down
75 changes: 26 additions & 49 deletions src/symbols.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,6 @@
* This library is released under MIT license
*/

#include <stdio.h>
#include <stdlib.h>

#include <vector>
#include <string>
#include <cstring>
Expand Down Expand Up @@ -222,63 +219,43 @@ std::vector<std::string> get_symbols(void *handle, int fd, bool demangle, bool l

#else /************************ Linux ************************/

#include <libelf.h>
#include <gelf.h>
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <link.h>
#include <elf.h>

std::vector<std::string> get_symbols(void *handle, int fd, bool demangle, bool loadable) {
std::vector<std::string> result;
Elf_Scn *scn = nullptr;
Elf *elf;

if (elf_version(EV_CURRENT) == EV_NONE)
throw std::string("ELF library is out of date");

elf = elf_begin(fd, ELF_C_READ, nullptr);
if (!elf)
throw std::string("elf_begin() failed");

while ((scn = elf_nextscn(elf, scn))) {
GElf_Shdr shdr;

if (gelf_getshdr(scn, &shdr) == nullptr) {
elf_end(elf);
throw std::string("gelf_getshdr() failed");
}

if (shdr.sh_type == SHT_SYMTAB || shdr.sh_type == SHT_DYNSYM) {
Elf_Data *data = elf_getdata(scn, nullptr);

if (!data) {
elf_end(elf);
throw std::string("elf_getdata() failed");
}
struct link_map *map = nullptr;
Elf64_Sym *symtab = nullptr;
char *strtab = nullptr;
int symentries = 0;
int size = 0;

if (dlinfo(handle, RTLD_DI_LINKMAP, &map) != 0)
throw std::string("dlinfo failed: ") + dlerror();

for (auto section = map->l_ld; section->d_tag != DT_NULL; ++section) {
if (section->d_tag == DT_SYMTAB)
symtab = (Elf64_Sym *)section->d_un.d_ptr;
else if (section->d_tag == DT_STRTAB)
strtab = (char*)section->d_un.d_ptr;
else if (section->d_tag == DT_SYMENT)
symentries = section->d_un.d_val;
}

for (int i = 0; i < (shdr.sh_size / shdr.sh_entsize); i++) {
GElf_Sym sym;
char *name;
size = strtab - (char *)symtab;

if (!gelf_getsym(data, i, &sym)) {
elf_end(elf);
throw std::string("gelf_getsym() failed");
}
for (int i = 0; i < size / symentries; ++i) {
Elf64_Sym* sym = &symtab[i];

name = elf_strptr(elf, shdr.sh_link, sym.st_name);
if (!name) {
elf_end(elf);
throw std::string("elf_strptr() failed");
}
if (ELF64_ST_TYPE(symtab[i].st_info) == STT_FUNC) {
const char *name = &strtab[sym->st_name];

if (!loadable || dlsym(handle, name))
add_symbol(result, name, demangle);
}
if (!loadable || dlsym(handle, name))
add_symbol(result, name, demangle);
}
}

elf_end(elf);

return result;
}

Expand Down

0 comments on commit 6e9ca66

Please sign in to comment.