Skip to content
This repository was archived by the owner on Jun 18, 2021. It is now read-only.

Commit 082b370

Browse files
hhellyerrnchamberlain
authored andcommitted
Add the list of library files loaded by the process to nodereport.
This adds an extra section to the System Information nodereport provides that shows the libraries loaded by the application. This allows the user to identify any native libraries loaded by node modules as well as any other system libraries that have been loaded by node. It provides the information reported by the operating system. This is similar to the output of ldd however it includes libraries loaded at runtime rather than just those that the executable is linked against. PR-URL: #38 Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com> Reviewed-By: Richard Lau <riclau@uk.ibm.com>
1 parent c28fdaa commit 082b370

3 files changed

Lines changed: 119 additions & 3 deletions

File tree

binding.gyp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"cflags": [ "-g", "-O2", "-std=c++11", ],
1111
}],
1212
["OS=='win'", {
13-
"libraries": [ "dbghelp.lib", "Netapi32.lib" ],
14-
"dll_files": [ "dbghelp.dll", "Netapi32.dll" ],
13+
"libraries": [ "dbghelp.lib", "Netapi32.lib", "PsApi.lib" ],
14+
"dll_files": [ "dbghelp.dll", "Netapi32.dll", "PsApi.dll" ],
1515
}],
1616
["OS=='mac'", {
1717
"xcode_settings": {

src/node_report.cc

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <process.h>
1818
#include <dbghelp.h>
1919
#include <Lm.h>
20+
#include <tchar.h>
21+
#include <psapi.h>
2022
#else
2123
#include <sys/time.h>
2224
#include <sys/resource.h>
@@ -27,9 +29,13 @@
2729
#include <inttypes.h>
2830
#include <cxxabi.h>
2931
#include <dlfcn.h>
32+
#ifdef __linux__
33+
#include <link.h>
34+
#endif
3035
#ifndef _AIX
3136
#include <execinfo.h>
3237
#else
38+
#include <sys/ldr.h>
3339
#include <sys/procfs.h>
3440
#endif
3541
#include <sys/utsname.h>
@@ -46,6 +52,7 @@
4652
#ifdef __APPLE__
4753
// Include _NSGetArgv and _NSGetArgc for command line arguments.
4854
#include <crt_externs.h>
55+
#include <mach-o/dyld.h>
4956
#endif
5057

5158
#ifndef _WIN32
@@ -74,6 +81,7 @@ static void PrintResourceUsage(FILE* fp);
7481
#endif
7582
static void PrintGCStatistics(FILE* fp, Isolate* isolate);
7683
static void PrintSystemInformation(FILE* fp, Isolate* isolate);
84+
static void PrintLoadedLibraries(FILE* fp, Isolate* isolate);
7785
static void WriteInteger(FILE* fp, size_t value);
7886

7987
// Global variables
@@ -1003,6 +1011,108 @@ const static struct {
10031011
}
10041012
}
10051013
#endif
1014+
1015+
fprintf(fp, "\nLoaded libraries\n");
1016+
PrintLoadedLibraries(fp, isolate);
1017+
}
1018+
1019+
/*******************************************************************************
1020+
* Functions to print a list of loaded native libraries.
1021+
*
1022+
******************************************************************************/
1023+
#ifdef __linux__
1024+
static int LibraryPrintCallback(struct dl_phdr_info *info, size_t size, void *data) {
1025+
FILE* fp = (FILE*)data;
1026+
if (info->dlpi_name != nullptr && *info->dlpi_name != '\0') {
1027+
fprintf(fp, " %s\n", info->dlpi_name);
1028+
}
1029+
return 0;
1030+
}
1031+
#endif
1032+
1033+
static void PrintLoadedLibraries(FILE* fp, Isolate* isolate) {
1034+
#ifdef __linux__
1035+
dl_iterate_phdr(LibraryPrintCallback, fp);
1036+
#elif __APPLE__
1037+
int i = 0;
1038+
const char *name = _dyld_get_image_name(i);
1039+
while (name != nullptr) {
1040+
fprintf(fp, " %s\n", name);
1041+
i++;
1042+
name = _dyld_get_image_name(i);
1043+
}
1044+
#elif _AIX
1045+
// We can't tell in advance how large the buffer needs to be.
1046+
// Retry until we reach too large a size (1Mb).
1047+
const unsigned int buffer_inc = 4096;
1048+
unsigned int buffer_size = buffer_inc;
1049+
char* buffer = (char*) malloc(buffer_size);
1050+
int rc = -1;
1051+
while (buffer != nullptr && rc != 0 && buffer_size < 1024 * 1024) {
1052+
rc = loadquery(L_GETINFO, buffer, buffer_size);
1053+
if (rc == 0) {
1054+
break;
1055+
}
1056+
free(buffer);
1057+
buffer_size += buffer_inc;
1058+
buffer = (char*) malloc(buffer_size);
1059+
}
1060+
if (buffer == nullptr) {
1061+
return; // Don't try to free the buffer.
1062+
}
1063+
if (rc == 0) {
1064+
char* buf = buffer;
1065+
ld_info* cur_info = nullptr;
1066+
do {
1067+
cur_info = (ld_info*) buf;
1068+
char* member_name = cur_info->ldinfo_filename
1069+
+ strlen(cur_info->ldinfo_filename) + 1;
1070+
if (*member_name != '\0') {
1071+
fprintf(fp, " %s(%s)\n", cur_info->ldinfo_filename, member_name);
1072+
} else {
1073+
fprintf(fp, " %s\n", cur_info->ldinfo_filename);
1074+
}
1075+
buf += cur_info->ldinfo_next;
1076+
} while (cur_info->ldinfo_next != 0);
1077+
}
1078+
free(buffer);
1079+
1080+
#elif _WIN32
1081+
// Windows implementation - get a handle to the process.
1082+
HANDLE process_handle = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,
1083+
FALSE, GetCurrentProcessId());
1084+
if (process_handle == NULL) {
1085+
fprintf(fp, "No library information available\n");
1086+
return;
1087+
}
1088+
// Get a list of all the modules in this process
1089+
DWORD size_1 = 0, size_2 = 0;
1090+
// First call to get the size of module array needed
1091+
if (EnumProcessModules(process_handle, NULL, 0, &size_1)) {
1092+
HMODULE* modules = (HMODULE*) malloc(size_1);
1093+
if (modules == NULL) {
1094+
return; // bail out if malloc failed
1095+
}
1096+
// Second call to populate the module array
1097+
if (EnumProcessModules(process_handle, modules, size_1, &size_2)) {
1098+
for (int i = 0;
1099+
i < (size_1 / sizeof(HMODULE)) && i < (size_2 / sizeof(HMODULE));
1100+
i++) {
1101+
TCHAR module_name[MAX_PATH];
1102+
// Obtain and print the full pathname for each module
1103+
if (GetModuleFileNameEx(process_handle, modules[i], module_name,
1104+
sizeof(module_name) / sizeof(TCHAR))) {
1105+
fprintf(fp," %s\n", module_name);
1106+
}
1107+
}
1108+
}
1109+
free(modules);
1110+
} else {
1111+
fprintf(fp, "No library information available\n");
1112+
}
1113+
// Release the handle to the process.
1114+
CloseHandle(process_handle);
1115+
#endif
10061116
}
10071117

10081118
/*******************************************************************************

test/common.js

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ exports.validate = (t, report, options) => {
3636
const expectedVersions = options ?
3737
options.expectedVersions || nodeComponents :
3838
nodeComponents;
39-
var plan = REPORT_SECTIONS.length + nodeComponents.length + 2;
39+
var plan = REPORT_SECTIONS.length + nodeComponents.length + 3;
4040
if (options.commandline) plan++;
4141
t.plan(plan);
4242
// Check all sections are present
@@ -88,6 +88,12 @@ exports.validate = (t, report, options) => {
8888
t.match(nodeReportSection,
8989
new RegExp('NodeReport version: ' + nodereportMetadata.version),
9090
'NodeReport section contains expected NodeReport version');
91+
const sysInfoSection = getSection(reportContents, 'System Information');
92+
// Find a line which ends with "/api.node" or "\api.node"
93+
// (Unix or Windows paths) to see if the library for node report was
94+
// loaded.
95+
t.match(sysInfoSection, / .*(\/|\\)api\.node/,
96+
'System Information section contains nodereport library.');
9197
});
9298
});
9399
};

0 commit comments

Comments
 (0)