Skip to content

Commit d0270f3

Browse files
gireeshpunathilBethGriggs
authored andcommitted
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: #24825 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Joyee Cheung <joyeec9h3@gmail.com>
1 parent dbdea36 commit d0270f3

File tree

2 files changed

+124
-0
lines changed

2 files changed

+124
-0
lines changed

src/debug_utils.cc

+123
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,27 @@
3030

3131
#endif // __POSIX__
3232

33+
#if defined(__linux__) || defined(__sun)
34+
#include <link.h>
35+
#endif // (__linux__) || defined(__sun)
36+
37+
#ifdef __APPLE__
38+
#include <mach-o/dyld.h> // _dyld_get_image_name()
39+
#endif // __APPLE__
40+
41+
#ifdef _AIX
42+
#include <sys/ldr.h> // ld_info structure
43+
#endif // _AIX
44+
45+
#ifdef _WIN32
46+
#include <Lm.h>
47+
#include <Windows.h>
48+
#include <dbghelp.h>
49+
#include <process.h>
50+
#include <psapi.h>
51+
#include <tchar.h>
52+
#endif // _WIN32
53+
3354
namespace node {
3455

3556
#ifdef __POSIX__
@@ -299,6 +320,108 @@ void CheckedUvLoopClose(uv_loop_t* loop) {
299320
CHECK(0 && "uv_loop_close() while having open handles");
300321
}
301322

323+
std::vector<std::string> NativeSymbolDebuggingContext::GetLoadedLibraries() {
324+
std::vector<std::string> list;
325+
#ifdef __linux__
326+
dl_iterate_phdr(
327+
[](struct dl_phdr_info* info, size_t size, void* data) {
328+
auto list = static_cast<std::vector<std::string>*>(data);
329+
if (*info->dlpi_name != '\0') {
330+
list->push_back(info->dlpi_name);
331+
}
332+
return 0;
333+
},
334+
&list);
335+
#elif __APPLE__
336+
uint32_t i = 0;
337+
for (const char* name = _dyld_get_image_name(i); name != nullptr;
338+
name = _dyld_get_image_name(++i)) {
339+
list.push_back(name);
340+
}
341+
342+
#elif _AIX
343+
// We can't tell in advance how large the buffer needs to be.
344+
// Retry until we reach too large a size (1Mb).
345+
const unsigned int kBufferGrowStep = 4096;
346+
MallocedBuffer<char> buffer(kBufferGrowStep);
347+
int rc = -1;
348+
do {
349+
rc = loadquery(L_GETINFO, buffer.data, buffer.size);
350+
if (rc == 0) break;
351+
buffer = MallocedBuffer<char>(buffer.size + kBufferGrowStep);
352+
} while (buffer.size < 1024 * 1024);
353+
354+
if (rc == 0) {
355+
char* buf = buffer.data;
356+
ld_info* cur_info = nullptr;
357+
do {
358+
std::ostringstream str;
359+
cur_info = reinterpret_cast<ld_info*>(buf);
360+
char* member_name = cur_info->ldinfo_filename +
361+
strlen(cur_info->ldinfo_filename) + 1;
362+
if (*member_name != '\0') {
363+
str << cur_info->ldinfo_filename << "(" << member_name << ")";
364+
list.push_back(str.str());
365+
str.str("");
366+
} else {
367+
list.push_back(cur_info->ldinfo_filename);
368+
}
369+
buf += cur_info->ldinfo_next;
370+
} while (cur_info->ldinfo_next != 0);
371+
}
372+
#elif __sun
373+
Link_map* p;
374+
375+
if (dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &p) != -1) {
376+
for (Link_map* l = p; l != nullptr; l = l->l_next) {
377+
list.push_back(l->l_name);
378+
}
379+
}
380+
381+
#elif _WIN32
382+
// Windows implementation - get a handle to the process.
383+
HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION|PROCESS_VM_READ,
384+
FALSE, GetCurrentProcessId());
385+
if (process_handle == nullptr) {
386+
// Cannot proceed, return an empty list.
387+
return list;
388+
}
389+
// Get a list of all the modules in this process
390+
DWORD size_1 = 0;
391+
DWORD size_2 = 0;
392+
// First call to get the size of module array needed
393+
if (EnumProcessModules(process_handle, nullptr, 0, &size_1)) {
394+
MallocedBuffer<HMODULE> modules(size_1);
395+
396+
// Second call to populate the module array
397+
if (EnumProcessModules(process_handle, modules.data, size_1, &size_2)) {
398+
for (DWORD i = 0;
399+
i < (size_1 / sizeof(HMODULE)) && i < (size_2 / sizeof(HMODULE));
400+
i++) {
401+
WCHAR module_name[MAX_PATH];
402+
// Obtain and report the full pathname for each module
403+
if (GetModuleFileNameExW(process_handle,
404+
modules.data[i],
405+
module_name,
406+
arraysize(module_name) / sizeof(WCHAR))) {
407+
DWORD size = WideCharToMultiByte(
408+
CP_UTF8, 0, module_name, -1, nullptr, 0, nullptr, nullptr);
409+
char* str = new char[size];
410+
WideCharToMultiByte(
411+
CP_UTF8, 0, module_name, -1, str, size, nullptr, nullptr);
412+
list.push_back(str);
413+
}
414+
}
415+
}
416+
}
417+
418+
// Release the handle to the process.
419+
CloseHandle(process_handle);
420+
#endif
421+
return list;
422+
}
423+
424+
302425
} // namespace node
303426

304427
extern "C" void __DumpBacktrace(FILE* fp) {

src/debug_utils.h

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ class NativeSymbolDebuggingContext {
113113
= delete;
114114
NativeSymbolDebuggingContext operator=(NativeSymbolDebuggingContext&&)
115115
= delete;
116+
static std::vector<std::string> GetLoadedLibraries();
116117
};
117118

118119
// Variant of `uv_loop_close` that tries to be as helpful as possible

0 commit comments

Comments
 (0)