From 814b4f7581738565c2b4cf3149099d80be3b79c1 Mon Sep 17 00:00:00 2001 From: Martin Olivier Date: Thu, 1 Aug 2024 12:15:08 +0200 Subject: [PATCH] feat: new loadable param for symbols function Now, the symbols function takes a struct as parameter that contains 'demangle' and 'loadable' booleans. If 'loadable' is set to true, the function will only return symbols that can be loaded using dlsym or GetProcAddress. Signed-off-by: Martin Olivier --- include/dylib.hpp | 17 ++++++++++++++++- src/dylib.cpp | 20 +++++++++++++++----- src/symbols.cpp | 32 ++++++++++++++++++-------------- 3 files changed, 49 insertions(+), 20 deletions(-) diff --git a/include/dylib.hpp b/include/dylib.hpp index 4829155..ee1ef76 100644 --- a/include/dylib.hpp +++ b/include/dylib.hpp @@ -62,6 +62,11 @@ class dylib { static constexpr bool add_filename_decorations = true; static constexpr bool no_filename_decorations = false; + struct symbol_params { + bool demangle = false; + bool loadable = false; + }; + /** * This exception is raised when the library failed to load a dynamic library or a symbol * @@ -211,7 +216,17 @@ class dylib { return get_variable(symbol_name.c_str()); } - std::vector symbols(bool demangle = false) const; + /** + * Get the list of symbols from the dynamic library currently loaded in the object + * + * @throws dylib::symbol_error if an error occured during symbols collection + * + * @param demangle if true, returns unmangled symbols + * @param loadable if true, returns only loadable symbols + * + * @return the list of symbols + */ + std::vector symbols(symbol_params params = {}) const; /** * @return the dynamic library handle diff --git a/src/dylib.cpp b/src/dylib.cpp index 643fd6b..97d3fdf 100644 --- a/src/dylib.cpp +++ b/src/dylib.cpp @@ -36,10 +36,13 @@ #define DYLIB_WIN_OTHER(win_def, other_def) other_def #endif -using lib_fd_t = DYLIB_WIN_OTHER(HMODULE, int); - std::string get_demangled_name(const char *symbol); -std::vector get_symbols(lib_fd_t fd, bool demangle); + +#if (defined(_WIN32) || defined(_WIN64)) +std::vector get_symbols(HMODULE handle, bool demangle, bool loadable); +#else +std::vector get_symbols(void *handle, int fd, bool demangle, bool loadable); +#endif static dylib::native_handle_type open_lib(const char *path) noexcept { #if (defined(_WIN32) || defined(_WIN64)) @@ -179,9 +182,16 @@ dylib::native_handle_type dylib::native_handle() noexcept { return m_handle; } -std::vector dylib::symbols(bool demangle) const { +std::vector dylib::symbols(symbol_params params) const { try { - return get_symbols(DYLIB_WIN_OTHER(m_handle, m_fd), demangle); + return get_symbols( + m_handle, +#if !(defined(_WIN32) || defined(_WIN64)) + m_fd, +#endif + params.demangle, + params.loadable + ); } catch (const std::string &e) { throw symbol_error(e); } diff --git a/src/symbols.cpp b/src/symbols.cpp index 4da6614..ec0e364 100644 --- a/src/symbols.cpp +++ b/src/symbols.cpp @@ -42,16 +42,16 @@ static void add_symbol(std::vector &result, const char *name, bool #include #include -std::vector get_symbols(HMODULE hModule, bool demangle) { +std::vector get_symbols(HMODULE handle, bool demangle, bool loadable) { std::vector result; // Get the DOS header - PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)hModule; + PIMAGE_DOS_HEADER pDosHeader = (PIMAGE_DOS_HEADER)handle; if (pDosHeader->e_magic != IMAGE_DOS_SIGNATURE) throw std::string("Invalid DOS header"); // Get the NT headers - PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)hModule + pDosHeader->e_lfanew); + PIMAGE_NT_HEADERS pNTHeaders = (PIMAGE_NT_HEADERS)((BYTE *)handle + pDosHeader->e_lfanew); if (pNTHeaders->Signature != IMAGE_NT_SIGNATURE) throw std::string("Invalid NT headers"); @@ -60,17 +60,18 @@ std::vector get_symbols(HMODULE hModule, bool demangle) { if (exportDirRVA == 0) throw std::string("No export directory found"); - PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)((BYTE *)hModule + exportDirRVA); + PIMAGE_EXPORT_DIRECTORY pExportDir = (PIMAGE_EXPORT_DIRECTORY)((BYTE *)handle + exportDirRVA); // Get the list of exported function names - DWORD *pNames = (DWORD *)((BYTE *)hModule + pExportDir->AddressOfNames); - DWORD *pFunctions = (DWORD *)((BYTE *)hModule + pExportDir->AddressOfFunctions); - WORD *pNameOrdinals = (WORD *)((BYTE *)hModule + pExportDir->AddressOfNameOrdinals); + DWORD *pNames = (DWORD *)((BYTE *)handle + pExportDir->AddressOfNames); + DWORD *pFunctions = (DWORD *)((BYTE *)handle + pExportDir->AddressOfFunctions); + WORD *pNameOrdinals = (WORD *)((BYTE *)handle + pExportDir->AddressOfNameOrdinals); for (DWORD i = 0; i < pExportDir->NumberOfNames; ++i) { - const char *name = (const char *)((BYTE *)hModule + pNames[i]); + const char *name = (const char *)((BYTE *)handle + pNames[i]); - add_symbol(result, name, demangle); + if (!loadable || GetProcAddress(handle, name)) + add_symbol(result, name, demangle); } return result; @@ -84,7 +85,7 @@ std::vector get_symbols(HMODULE hModule, bool demangle) { #include #include -static std::vector get_symbols_at_off(int fd, bool demangle, off_t offset, bool is_64_bit) { +static std::vector get_symbols_at_off(int fd, bool demangle, bool loadable, off_t offset, bool is_64_bit) { std::vector result; lseek(fd, offset, SEEK_SET); @@ -144,7 +145,8 @@ static std::vector get_symbols_at_off(int fd, bool demangle, off_t strx = symbols[j].n_un.n_strx; const char *name = &strtab[strx]; - add_symbol(result, name, demangle); + if (!loadable || dlsym(handle, name)) + add_symbol(result, name, demangle); } free(symbols64); @@ -158,7 +160,7 @@ static std::vector get_symbols_at_off(int fd, bool demangle, off_t return result; } -std::vector get_symbols(int fd, bool demangle) { +std::vector get_symbols(void *handle, int fd, bool demangle, bool loadable) { std::vector result; std::vector tmp; uint32_t magic; @@ -180,6 +182,7 @@ std::vector get_symbols(int fd, bool demangle) { tmp = get_symbols_at_off( fd, demangle, + loadable, ntohl(fat_arches[i].offset), ntohl(fat_arches[i].cputype) == CPU_TYPE_X86_64); std::move(tmp.begin(), tmp.end(), std::back_inserter(result)); @@ -204,7 +207,7 @@ std::vector get_symbols(int fd, bool demangle) { #include #include -std::vector get_symbols(int fd, bool demangle) { +std::vector get_symbols(void *handle, int fd, bool demangle, bool loadable) { std::vector result; if (elf_version(EV_CURRENT) == EV_NONE) @@ -245,7 +248,8 @@ std::vector get_symbols(int fd, bool demangle) { } const char *name = elf_strptr(elf, shdr.sh_link, sym.st_name); - add_symbol(result, name, demangle); + if (!loadable || dlsym(handle, name)) + add_symbol(result, name, demangle); } } }