From 1cc58341803405071909de3d48b6a9773a378fa7 Mon Sep 17 00:00:00 2001 From: Gireesh Punathil Date: Tue, 4 Dec 2018 11:53:07 +0530 Subject: [PATCH] src: add GetLoadedLibraries routine Add a static function GetLoadedLibraries under NativeSymbolDebuggingContext abstraction that provides a list of shared objects - either the current process depended on or loaded. PR-URL: https://github.com/nodejs/node/pull/24825 Reviewed-By: Anna Henningsen Reviewed-By: Ben Noordhuis Reviewed-By: Joyee Cheung --- src/debug_utils.cc | 123 +++++++++++++++++++++++++++++++++++++++++++++ src/debug_utils.h | 1 + 2 files changed, 124 insertions(+) diff --git a/src/debug_utils.cc b/src/debug_utils.cc index 77ea219bfc880a..4f086106b66ca7 100644 --- a/src/debug_utils.cc +++ b/src/debug_utils.cc @@ -30,6 +30,27 @@ #endif // __POSIX__ +#if defined(__linux__) || defined(__sun) +#include +#endif // (__linux__) || defined(__sun) + +#ifdef __APPLE__ +#include // _dyld_get_image_name() +#endif // __APPLE__ + +#ifdef _AIX +#include // ld_info structure +#endif // _AIX + +#ifdef _WIN32 +#include +#include +#include +#include +#include +#include +#endif // _WIN32 + namespace node { #ifdef __POSIX__ @@ -299,6 +320,108 @@ void CheckedUvLoopClose(uv_loop_t* loop) { CHECK(0 && "uv_loop_close() while having open handles"); } +std::vector NativeSymbolDebuggingContext::GetLoadedLibraries() { + std::vector list; +#ifdef __linux__ + dl_iterate_phdr( + [](struct dl_phdr_info* info, size_t size, void* data) { + auto list = static_cast*>(data); + if (*info->dlpi_name != '\0') { + list->push_back(info->dlpi_name); + } + return 0; + }, + &list); +#elif __APPLE__ + uint32_t i = 0; + for (const char* name = _dyld_get_image_name(i); name != nullptr; + name = _dyld_get_image_name(++i)) { + list.push_back(name); + } + +#elif _AIX + // We can't tell in advance how large the buffer needs to be. + // Retry until we reach too large a size (1Mb). + const unsigned int kBufferGrowStep = 4096; + MallocedBuffer buffer(kBufferGrowStep); + int rc = -1; + do { + rc = loadquery(L_GETINFO, buffer.data, buffer.size); + if (rc == 0) break; + buffer = MallocedBuffer(buffer.size + kBufferGrowStep); + } while (buffer.size < 1024 * 1024); + + if (rc == 0) { + char* buf = buffer.data; + ld_info* cur_info = nullptr; + do { + std::ostringstream str; + cur_info = reinterpret_cast(buf); + char* member_name = cur_info->ldinfo_filename + + strlen(cur_info->ldinfo_filename) + 1; + if (*member_name != '\0') { + str << cur_info->ldinfo_filename << "(" << member_name << ")"; + list.push_back(str.str()); + str.str(""); + } else { + list.push_back(cur_info->ldinfo_filename); + } + buf += cur_info->ldinfo_next; + } while (cur_info->ldinfo_next != 0); + } +#elif __sun + Link_map* p; + + if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &p) != -1) { + for (Link_map* l = p; l != nullptr; l = l->l_next) { + list.push_back(l->l_name); + } + } + +#elif _WIN32 + // Windows implementation - get a handle to the process. + HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ, + FALSE, GetCurrentProcessId()); + if (process_handle == nullptr) { + // Cannot proceed, return an empty list. + return list; + } + // Get a list of all the modules in this process + DWORD size_1 = 0; + DWORD size_2 = 0; + // First call to get the size of module array needed + if (EnumProcessModules(process_handle, nullptr, 0, &size_1)) { + MallocedBuffer modules(size_1); + + // Second call to populate the module array + if (EnumProcessModules(process_handle, modules.data, size_1, &size_2)) { + for (DWORD i = 0; + i < (size_1 / sizeof(HMODULE)) && i < (size_2 / sizeof(HMODULE)); + i++) { + WCHAR module_name[MAX_PATH]; + // Obtain and report the full pathname for each module + if (GetModuleFileNameExW(process_handle, + modules.data[i], + module_name, + arraysize(module_name) / sizeof(WCHAR))) { + DWORD size = WideCharToMultiByte( + CP_UTF8, 0, module_name, -1, nullptr, 0, nullptr, nullptr); + char* str = new char[size]; + WideCharToMultiByte( + CP_UTF8, 0, module_name, -1, str, size, nullptr, nullptr); + list.push_back(str); + } + } + } + } + + // Release the handle to the process. + CloseHandle(process_handle); +#endif + return list; +} + + } // namespace node extern "C" void __DumpBacktrace(FILE* fp) { diff --git a/src/debug_utils.h b/src/debug_utils.h index c6c8e03b51fd64..034d8a9ab331dc 100644 --- a/src/debug_utils.h +++ b/src/debug_utils.h @@ -113,6 +113,7 @@ class NativeSymbolDebuggingContext { = delete; NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&) = delete; + static std::vector GetLoadedLibraries(); }; // Variant of `uv_loop_close` that tries to be as helpful as possible