Skip to content
This repository was archived by the owner on Jun 18, 2021. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/module.cc
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ void Initialize(v8::Local<v8::Object> exports) {

SetLoadTime();
SetVersionString(isolate);
SetCommandLine();

const char* verbose_switch = secure_getenv("NODEREPORT_VERBOSE");
if (verbose_switch != nullptr) {
Expand Down
88 changes: 86 additions & 2 deletions src/node_report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@
#include <dlfcn.h>
#ifndef _AIX
#include <execinfo.h>
#else
#include <sys/procfs.h>
#endif
#include <sys/utsname.h>
#endif
Expand All @@ -41,6 +43,11 @@
#define UNKNOWN_NODEVERSION_STRING "Unable to determine Node.js version\n"
#endif

#ifdef __APPLE__
// Include _NSGetArgv and _NSGetArgc for command line arguments.
#include <crt_externs.h>
#endif

#ifndef _WIN32
extern char** environ;
#endif
Expand All @@ -58,6 +65,7 @@ using v8::String;
using v8::V8;

// Internal/static function declarations
static void PrintCommandLine(FILE* fp);
static void PrintVersionInformation(FILE* fp, Isolate* isolate);
static void PrintJavaScriptStack(FILE* fp, Isolate* isolate, DumpEvent event, const char* location);
static void PrintStackFromStackTrace(FILE* fp, Isolate* isolate, DumpEvent event);
Expand All @@ -77,6 +85,7 @@ static bool report_active = false; // recursion protection
static char report_filename[NR_MAXNAME + 1] = "";
static char report_directory[NR_MAXPATH + 1] = ""; // defaults to current working directory
static std::string version_string = UNKNOWN_NODEVERSION_STRING;
static std::string commandline_string = "";
#ifdef _WIN32
static SYSTEMTIME loadtime_tm_struct; // module load time
#else // UNIX, OSX
Expand Down Expand Up @@ -299,6 +308,67 @@ void SetLoadTime() {
localtime_r(&time_val.tv_sec, &loadtime_tm_struct);
#endif
}

/*******************************************************************************
* Function to save the process command line
*******************************************************************************/
void SetCommandLine() {
#ifdef __linux__
// Read the command line from /proc/self/cmdline
char buf[64];
FILE* cmdline_fd = fopen("/proc/self/cmdline", "r");
if (cmdline_fd == nullptr) {
return;
}
commandline_string = "";
int bytesread = fread(buf, 1, sizeof(buf), cmdline_fd);
while (bytesread > 0) {
for (int i = 0; i < bytesread; i++) {
// Arguments are null separated.
if (buf[i] == '\0') {
commandline_string += " ";
} else {
commandline_string += buf[i];
}
}
bytesread = fread(buf, 1, sizeof(buf), cmdline_fd);
}
fclose(cmdline_fd);
#elif __APPLE__
char **argv = *_NSGetArgv();
int argc = *_NSGetArgc();

commandline_string = "";
std::string separator = "";
for (int i = 0; i < argc; i++) {
commandline_string += separator + argv[i];
separator = " ";
}
#elif _AIX
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The indentation for this #elif block is different from the rest of this function, please can you make it consistent?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The rest of the function was wrong and didn't match the file. I'd indented when starting #ifdef sections. I've adjusted the rest of the function to be correct.

// Read the command line from /proc/self/cmdline
char procbuf[64];
snprintf(procbuf, sizeof(procbuf), "/proc/%d/psinfo", getpid());
FILE* psinfo_fd = fopen(procbuf, "r");
if (psinfo_fd == nullptr) {
return;
}
psinfo_t info;
int bytesread = fread(&info, 1, sizeof(psinfo_t), psinfo_fd);
fclose(psinfo_fd);
if (bytesread == sizeof(psinfo_t)) {
commandline_string = "";
std::string separator = "";
char **argv = *((char ***) info.pr_argv);
for (uint32_t i = 0; i < info.pr_argc; i++) {
commandline_string += separator + argv[i];
separator = " ";
}
}
#elif _WIN32
commandline_string = GetCommandLine();
#endif
}

/*******************************************************************************
* Main API function to write a NodeReport to file.
*
Expand All @@ -311,7 +381,7 @@ void SetLoadTime() {
******************************************************************************/
void TriggerNodeReport(Isolate* isolate, DumpEvent event, const char* message, const char* location, char* name) {
// Recursion check for NodeReport in progress, bail out
if (report_active) return;
if (report_active) return;
report_active = true;

// Obtain the current time and the pid (platform dependent)
Expand Down Expand Up @@ -414,6 +484,10 @@ void TriggerNodeReport(Isolate* isolate, DumpEvent event, const char* message, c
fprintf(fp, "Process ID: %d\n", pid);
fflush(fp);

// Print out the command line.
PrintCommandLine(fp);
fflush(fp);

// Print Node.js and OS version information
PrintVersionInformation(fp, isolate);
fflush(fp);
Expand Down Expand Up @@ -463,6 +537,16 @@ void TriggerNodeReport(Isolate* isolate, DumpEvent event, const char* message, c
report_active = false;
}

/*******************************************************************************
* Function to print process command line.
*
******************************************************************************/
static void PrintCommandLine(FILE* fp) {
if (commandline_string != "") {
fprintf(fp, "Command line: %s\n", commandline_string.c_str());
}
}

/*******************************************************************************
* Function to print Node.js version, OS version and machine information
*
Expand Down Expand Up @@ -688,7 +772,7 @@ void PrintNativeStack(FILE* fp) {
SymInitialize(hProcess, nullptr, TRUE);

WORD numberOfFrames = CaptureStackBackTrace(2, 64, frames, nullptr);

// Walk the frames printing symbolic information if available
for (int i = 0; i < numberOfFrames; i++) {
DWORD64 dwOffset64 = 0;
Expand Down
1 change: 1 addition & 0 deletions src/node_report.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ unsigned int ProcessNodeReportVerboseSwitch(const char* args);

void SetLoadTime();
void SetVersionString(Isolate* isolate);
void SetCommandLine();

// Local implementation of secure_getenv()
inline const char* secure_getenv(const char* key) {
Expand Down
20 changes: 17 additions & 3 deletions test/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,16 +36,16 @@ exports.validate = (t, report, options) => {
const expectedVersions = options ?
options.expectedVersions || nodeComponents :
nodeComponents;
const plan = REPORT_SECTIONS.length + nodeComponents.length + 2;
var plan = REPORT_SECTIONS.length + nodeComponents.length + 2;
if (options.commandline) plan++;
t.plan(plan);

// Check all sections are present
REPORT_SECTIONS.forEach((section) => {
t.match(reportContents, new RegExp('==== ' + section),
'Checking report contains ' + section + ' section');
});

// Check NodeReport section
// Check NodeReport header section
const nodeReportSection = getSection(reportContents, 'NodeReport');
t.match(nodeReportSection, new RegExp('Process ID: ' + pid),
'NodeReport section contains expected process ID');
Expand All @@ -57,6 +57,20 @@ exports.validate = (t, report, options) => {
new RegExp('Node.js version: ' + process.version),
'NodeReport section contains expected Node.js version');
}
if (options && options.commandline) {
if (this.isWindows()) {
// On Windows we need to strip double quotes from the command line in
// the report, and escape backslashes in the regex comparison string.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

n.b. I'm not seeing any double quotes in the reported command line in the reports generated from the tests on Windows.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might depend on the shell or the executable path. This is what I am seeing on Windows:

==== NodeReport ================================================================

Event: JavaScript API, location: "TriggerReport"
Filename: NodeReport.20170110.113318.2184.001.txt
Dump event time:  2017/01/10 11:33:18
Module load time: 2017/01/10 11:33:18
Process ID: 2184
Command line: "C:\Program Files\nodejs6\node.exe" C:\tmp\nodereport\test\test-api-bad-processobj.js child

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah I think it might be spaces in the paths -- I get the same if I use Node.js installed under C:\Program Files

t.match(nodeReportSection.replace(/"/g,''),
new RegExp('Command line: '
+ (options.commandline).replace(/\\/g,'\\\\')),
'Checking report contains expected command line');
} else {
t.match(nodeReportSection,
new RegExp('Command line: ' + options.commandline),
'Checking report contains expected command line');
}
}
nodeComponents.forEach((c) => {
if (c !== 'node') {
if (expectedVersions.indexOf(c) === -1) {
Expand Down
3 changes: 2 additions & 1 deletion test/test-api-bad-processobj.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ if (process.argv[2] === 'child') {
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
const validateOpts = { pid: child.pid, expectedVersions: [] };
const validateOpts = { pid: child.pid, expectedVersions: [],
commandline: child.spawnargs.join(' '), };
common.validate(tap, report, validateOpts);
});
}
3 changes: 2 additions & 1 deletion test/test-api-bad-processversion.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ if (process.argv[2] === 'child') {
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
const validateOpts = { pid: child.pid, expectNodeVersion: true };
const validateOpts = { pid: child.pid, expectNodeVersion: true,
commandline: child.spawnargs.join(' '), };
common.validate(tap, report, validateOpts);
});
}
3 changes: 2 additions & 1 deletion test/test-api-bad-processversions.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ if (process.argv[2] === 'child') {
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
const validateOpts = { pid: child.pid,
expectedVersions: Object.keys(process.versions).filter((c) => c !== 'uv')
expectedVersions: Object.keys(process.versions).filter((c) => c !== 'uv'),
commandline: child.spawnargs.join(' ')
};
common.validate(tap, report, validateOpts);
});
Expand Down
4 changes: 3 additions & 1 deletion test/test-api-nohooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ if (process.argv[2] === 'child') {
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
common.validate(tap, report, {pid: child.pid});
common.validate(tap, report, {pid: child.pid,
commandline: child.spawnargs.join(' ')
});
});
}
3 changes: 2 additions & 1 deletion test/test-api-noversioninfo.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ if (process.argv[2] === 'child') {
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
const validateOpts = { pid: child.pid, expectNodeVersion: false,
expectedVersions: [] };
expectedVersions: [], commandline: child.spawnargs.join(' ')
};
common.validate(tap, report, validateOpts);
});
}
4 changes: 3 additions & 1 deletion test/test-api.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ if (process.argv[2] === 'child') {
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
common.validate(tap, report, {pid: child.pid});
common.validate(tap, report, {pid: child.pid,
commandline: child.spawnargs.join(' ')
});
});
}
4 changes: 3 additions & 1 deletion test/test-exception.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ if (process.argv[2] === 'child') {
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
common.validate(tap, report, {pid: child.pid});
common.validate(tap, report, {pid: child.pid,
commandline: child.spawnargs.join(' ')
});
});
}
4 changes: 3 additions & 1 deletion test/test-fatal-error.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ if (process.argv[2] === 'child') {
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
common.validate(tap, report, {pid: child.pid});
common.validate(tap, report, {pid: child.pid,
commandline: child.spawnargs.join(' ')
});
});
}
4 changes: 3 additions & 1 deletion test/test-signal.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ if (process.argv[2] === 'child') {
const reports = common.findReports(child.pid);
tap.equal(reports.length, 1, 'Found reports ' + reports);
const report = reports[0];
common.validate(tap, report, {pid: child.pid});
common.validate(tap, report, {pid: child.pid,
commandline: child.spawnargs.join(' ')
});
});
}