Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP

Comparing changes

Choose two branches to see what's changed or to start a new pull request. If you need to, you can also compare across forks.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also compare across forks.
base fork: regality/node
...
head fork: regality/node
Checking mergeability… Don't worry, you can still create the pull request.
  • 1 commit
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Commits on Nov 03, 2011
@piscisaureus piscisaureus process._debugProcess 72c736d
Showing with 242 additions and 141 deletions.
  1. +240 −139 src/node.cc
  2. +2 −2 test/simple/test-debugger-client.js
View
379 src/node.cc
@@ -54,6 +54,7 @@
#include <io.h>
#define umask _umask
typedef int mode_t;
+#include <psapi.h>
#endif
#include <errno.h>
#include <sys/types.h>
@@ -2014,136 +2015,6 @@ static Handle<Object> GetFeatures() {
}
-Handle<Object> SetupProcessObject(int argc, char *argv[]) {
- HandleScope scope;
-
- int i, j;
-
- Local<FunctionTemplate> process_template = FunctionTemplate::New();
-
- process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
-
-
- process->SetAccessor(String::New("title"),
- ProcessTitleGetter,
- ProcessTitleSetter);
-
- // process.version
- process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
-
-#ifdef NODE_PREFIX
- // process.installPrefix
- process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
-#endif
-
- // process.moduleLoadList
- module_load_list = Persistent<Array>::New(Array::New());
- process->Set(String::NewSymbol("moduleLoadList"), module_load_list);
-
- Local<Object> versions = Object::New();
- char buf[20];
- process->Set(String::NewSymbol("versions"), versions);
- // +1 to get rid of the leading 'v'
- versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1));
- versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));
- versions->Set(String::NewSymbol("ares"), String::New(ARES_VERSION_STR));
- snprintf(buf, 20, "%d.%d", UV_VERSION_MAJOR, UV_VERSION_MINOR);
- versions->Set(String::NewSymbol("uv"), String::New(buf));
-#if HAVE_OPENSSL
- // Stupid code to slice out the version string.
- int c, l = strlen(OPENSSL_VERSION_TEXT);
- for (i = j = 0; i < l; i++) {
- c = OPENSSL_VERSION_TEXT[i];
- if ('0' <= c && c <= '9') {
- for (j = i + 1; j < l; j++) {
- c = OPENSSL_VERSION_TEXT[j];
- if (c == ' ') break;
- }
- break;
- }
- }
- versions->Set(String::NewSymbol("openssl"),
- String::New(OPENSSL_VERSION_TEXT + i, j - i));
-#endif
-
-
-
- // process.arch
- process->Set(String::NewSymbol("arch"), String::New(ARCH));
-
- // process.platform
- process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
-
- // process.argv
- Local<Array> arguments = Array::New(argc - option_end_index + 1);
- arguments->Set(Integer::New(0), String::New(argv[0]));
- for (j = 1, i = option_end_index; i < argc; j++, i++) {
- Local<String> arg = String::New(argv[i]);
- arguments->Set(Integer::New(j), arg);
- }
- // assign it
- process->Set(String::NewSymbol("argv"), arguments);
-
- // create process.env
- Local<ObjectTemplate> envTemplate = ObjectTemplate::New();
- envTemplate->SetNamedPropertyHandler(EnvGetter,
- EnvSetter,
- EnvQuery,
- EnvDeleter,
- EnvEnumerator,
- Undefined());
- Local<Object> env = envTemplate->NewInstance();
- process->Set(String::NewSymbol("env"), env);
-
- process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
- process->Set(String::NewSymbol("features"), GetFeatures());
-
- // -e, --eval
- if (eval_string) {
- process->Set(String::NewSymbol("_eval"), String::New(eval_string));
- }
-
- size_t size = 2*PATH_MAX;
- char* execPath = new char[size];
- if (uv_exepath(execPath, &size) != 0) {
- // as a last ditch effort, fallback on argv[0] ?
- process->Set(String::NewSymbol("execPath"), String::New(argv[0]));
- } else {
- process->Set(String::NewSymbol("execPath"), String::New(execPath, size));
- }
- delete [] execPath;
-
-
- // define various internal methods
- NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
- NODE_SET_METHOD(process, "reallyExit", Exit);
- NODE_SET_METHOD(process, "chdir", Chdir);
- NODE_SET_METHOD(process, "cwd", Cwd);
-
- NODE_SET_METHOD(process, "umask", Umask);
-
-#ifdef __POSIX__
- NODE_SET_METHOD(process, "getuid", GetUid);
- NODE_SET_METHOD(process, "setuid", SetUid);
-
- NODE_SET_METHOD(process, "setgid", SetGid);
- NODE_SET_METHOD(process, "getgid", GetGid);
-
- NODE_SET_METHOD(process, "_kill", Kill);
-#endif // __POSIX__
-
- NODE_SET_METHOD(process, "dlopen", DLOpen);
-
- NODE_SET_METHOD(process, "uptime", Uptime);
- NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
- NODE_SET_METHOD(process, "uvCounters", UVCounters);
-
- NODE_SET_METHOD(process, "binding", Binding);
-
- return process;
-}
-
-
static void AtExit() {
uv_tty_reset_mode();
}
@@ -2295,6 +2166,7 @@ static void ParseArgs(int argc, char **argv) {
option_end_index = i;
}
+
static volatile bool debugger_running = false;
static void EnableDebug(bool wait_connect) {
@@ -2314,13 +2186,14 @@ static void EnableDebug(bool wait_connect) {
// Print out some information.
fprintf(stderr, "debugger listening on port %d\n", debug_port);
+ fflush(stderr);
debugger_running = true;
}
#ifdef __POSIX__
-static void EnableDebugSignalHandler(int signal) {
+static bool EnableDebugSignalHandler(int signal) {
// Break once process will return execution to v8
v8::Debug::DebugBreak();
@@ -2331,29 +2204,45 @@ static void EnableDebugSignalHandler(int signal) {
}
#endif // __POSIX__
-#if defined(__MINGW32__) || defined(_MSC_VER)
-static bool EnableDebugSignalHandler(DWORD signal) {
+
+#ifdef _WIN32
+static BOOL WINAPI CtrlBreakHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) exit(1);
if (signal != CTRL_BREAK_EVENT) return false;
- // Break once process will return execution to v8
- v8::Debug::DebugBreak();
-
if (!debugger_running) {
- fprintf(stderr, "Hit Ctrl+Break - starting debugger agent.\n");
+ // Break once process will return execution to v8
+ v8::Debug::DebugBreak();
+
+ fprintf(stderr, "Hit Ctrl+Break - starting debugger agent.\r\n");
EnableDebug(false);
return true;
} else {
// Run default system action (terminate)
return false;
}
+}
+
+
+DWORD WINAPI EnableDebugThreadProc(void* arg) {
+ // Break once process will return execution to v8
+ v8::Debug::DebugBreak();
+
+ if (!debugger_running) {
+ for (int i = 0; i < 1; i++) {
+ fprintf(stderr, "Starting debugger agent.\r\n");
+ fflush(stderr);
+ EnableDebug(false);
+ }
+ return true;
+ }
+ return 0;
}
#endif
#ifdef __POSIX__
-
static int RegisterSignalHandler(int signal, void (*handler)(int)) {
struct sigaction sa;
@@ -2365,6 +2254,86 @@ static int RegisterSignalHandler(int signal, void (*handler)(int)) {
#endif // __POSIX__
+Handle<Value> DebugProcess(const Arguments& args) {
+ HandleScope scope;
+
+ if (args.Length() != 1) {
+ return ThrowException(Exception::Error(String::New("Invalid numnber of arguments.")));
+ }
+
+#ifdef __POSIX__
+ pid_t pid;
+ int r;
+
+ pid = args[0]->IntegerValue();
+ r = kill(pid, SIGUSR1);
+ if (r != 0) {
+ return ThrowException(ErrnoException(errno, "kill"));
+ }
+#else
+ DWORD pid;
+ HANDLE process = NULL;
+ HANDLE thread = NULL;
+ WCHAR own_path[MAX_PATH];
+ WCHAR debuggee_path[MAX_PATH];
+
+ pid = (DWORD) args[0]->IntegerValue();
+
+ process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
+ PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
+ PROCESS_VM_READ,
+ FALSE,
+ pid);
+ if (process == NULL) {
+ // Fail
+ }
+
+ // Check that the debugger and the debuggee use exactly the same image, so
+ // we are sure it's address space layout requirements are met. Trying to
+ // debug anything else will just crash the debuggee.
+ if (GetProcessImageFileNameW(GetCurrentProcess(),
+ own_path,
+ MAX_PATH) == 0) {
+ // Fail
+ }
+ if (GetProcessImageFileNameW(process,
+ debuggee_path,
+ MAX_PATH) == 0) {
+ // Fail
+ };
+ if (wcsncmp(own_path, debuggee_path, MAX_PATH) != 0) {
+ // Fail
+ }
+
+ // The start address of the thread must be valid in the debuggee's address
+ // space. DLL rebasing and ASLR could still break that, but it's unlikely.
+ // Layout randomization is only done at boot time, and DLL rebasing is only
+ // used when collisions occur, which is unlikely since the .exe is loaded
+ // very early in the process.
+ thread = CreateRemoteThread(process,
+ NULL,
+ 0,
+ EnableDebugThreadProc,
+ NULL,
+ 0,
+ NULL);
+ if (thread == NULL) {
+ // Fail
+ }
+
+ // Wait for the thread to terminate
+ if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
+ // Fail
+ }
+
+ CloseHandle(thread);
+ CloseHandle(process);
+#endif
+
+ return Undefined();
+}
+
+
char** Init(int argc, char *argv[]) {
// Hack aroung with the argv pointer. Used for process.title = "blah".
argv = node::Platform::SetupArgs(argc, argv);
@@ -2454,7 +2423,7 @@ char** Init(int argc, char *argv[]) {
RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
#endif // __POSIX__
#if defined(__MINGW32__) || defined(_MSC_VER)
- SetConsoleCtrlHandler((PHANDLER_ROUTINE) EnableDebugSignalHandler, TRUE);
+ SetConsoleCtrlHandler(CtrlBreakHandler, TRUE);
#endif
}
@@ -2476,6 +2445,138 @@ void EmitExit(v8::Handle<v8::Object> process) {
}
+Handle<Object> SetupProcessObject(int argc, char *argv[]) {
+ HandleScope scope;
+
+ int i, j;
+
+ Local<FunctionTemplate> process_template = FunctionTemplate::New();
+
+ process = Persistent<Object>::New(process_template->GetFunction()->NewInstance());
+
+
+ process->SetAccessor(String::New("title"),
+ ProcessTitleGetter,
+ ProcessTitleSetter);
+
+ // process.version
+ process->Set(String::NewSymbol("version"), String::New(NODE_VERSION));
+
+#ifdef NODE_PREFIX
+ // process.installPrefix
+ process->Set(String::NewSymbol("installPrefix"), String::New(NODE_PREFIX));
+#endif
+
+ // process.moduleLoadList
+ module_load_list = Persistent<Array>::New(Array::New());
+ process->Set(String::NewSymbol("moduleLoadList"), module_load_list);
+
+ Local<Object> versions = Object::New();
+ char buf[20];
+ process->Set(String::NewSymbol("versions"), versions);
+ // +1 to get rid of the leading 'v'
+ versions->Set(String::NewSymbol("node"), String::New(NODE_VERSION+1));
+ versions->Set(String::NewSymbol("v8"), String::New(V8::GetVersion()));
+ versions->Set(String::NewSymbol("ares"), String::New(ARES_VERSION_STR));
+ snprintf(buf, 20, "%d.%d", UV_VERSION_MAJOR, UV_VERSION_MINOR);
+ versions->Set(String::NewSymbol("uv"), String::New(buf));
+#if HAVE_OPENSSL
+ // Stupid code to slice out the version string.
+ int c, l = strlen(OPENSSL_VERSION_TEXT);
+ for (i = j = 0; i < l; i++) {
+ c = OPENSSL_VERSION_TEXT[i];
+ if ('0' <= c && c <= '9') {
+ for (j = i + 1; j < l; j++) {
+ c = OPENSSL_VERSION_TEXT[j];
+ if (c == ' ') break;
+ }
+ break;
+ }
+ }
+ versions->Set(String::NewSymbol("openssl"),
+ String::New(OPENSSL_VERSION_TEXT + i, j - i));
+#endif
+
+
+
+ // process.arch
+ process->Set(String::NewSymbol("arch"), String::New(ARCH));
+
+ // process.platform
+ process->Set(String::NewSymbol("platform"), String::New(PLATFORM));
+
+ // process.argv
+ Local<Array> arguments = Array::New(argc - option_end_index + 1);
+ arguments->Set(Integer::New(0), String::New(argv[0]));
+ for (j = 1, i = option_end_index; i < argc; j++, i++) {
+ Local<String> arg = String::New(argv[i]);
+ arguments->Set(Integer::New(j), arg);
+ }
+ // assign it
+ process->Set(String::NewSymbol("argv"), arguments);
+
+ // create process.env
+ Local<ObjectTemplate> envTemplate = ObjectTemplate::New();
+ envTemplate->SetNamedPropertyHandler(EnvGetter,
+ EnvSetter,
+ EnvQuery,
+ EnvDeleter,
+ EnvEnumerator,
+ Undefined());
+ Local<Object> env = envTemplate->NewInstance();
+ process->Set(String::NewSymbol("env"), env);
+
+ process->Set(String::NewSymbol("pid"), Integer::New(getpid()));
+ process->Set(String::NewSymbol("features"), GetFeatures());
+
+ // -e, --eval
+ if (eval_string) {
+ process->Set(String::NewSymbol("_eval"), String::New(eval_string));
+ }
+
+ size_t size = 2*PATH_MAX;
+ char* execPath = new char[size];
+ if (uv_exepath(execPath, &size) != 0) {
+ // as a last ditch effort, fallback on argv[0] ?
+ process->Set(String::NewSymbol("execPath"), String::New(argv[0]));
+ } else {
+ process->Set(String::NewSymbol("execPath"), String::New(execPath, size));
+ }
+ delete [] execPath;
+
+
+ // define various internal methods
+ NODE_SET_METHOD(process, "_needTickCallback", NeedTickCallback);
+ NODE_SET_METHOD(process, "reallyExit", Exit);
+ NODE_SET_METHOD(process, "chdir", Chdir);
+ NODE_SET_METHOD(process, "cwd", Cwd);
+
+ NODE_SET_METHOD(process, "umask", Umask);
+
+#ifdef __POSIX__
+ NODE_SET_METHOD(process, "getuid", GetUid);
+ NODE_SET_METHOD(process, "setuid", SetUid);
+
+ NODE_SET_METHOD(process, "setgid", SetGid);
+ NODE_SET_METHOD(process, "getgid", GetGid);
+
+ NODE_SET_METHOD(process, "_kill", Kill);
+#endif // __POSIX__
+
+ NODE_SET_METHOD(process, "_debugProcess", DebugProcess);
+
+ NODE_SET_METHOD(process, "dlopen", DLOpen);
+
+ NODE_SET_METHOD(process, "uptime", Uptime);
+ NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
+ NODE_SET_METHOD(process, "uvCounters", UVCounters);
+
+ NODE_SET_METHOD(process, "binding", Binding);
+
+ return process;
+}
+
+
int Start(int argc, char *argv[]) {
// This needs to run *before* V8::Initialize()
argv = Init(argc, argv);
View
4 test/simple/test-debugger-client.js
@@ -147,8 +147,8 @@ function doTest(cb, done) {
nodeProcess.stdout.once('data', function() {
console.log('>>> new node process: %d', nodeProcess.pid);
- process.kill(nodeProcess.pid, 'SIGUSR1');
- console.log('>>> signaling it with SIGUSR1');
+ process._debugProcess(nodeProcess.pid);
+ console.log('>>> starting debugger session');
});
var didTryConnect = false;

No commit comments for this range

Something went wrong with that request. Please try again.