Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
Implement process._debugProcess
Browse files Browse the repository at this point in the history
  • Loading branch information
piscisaureus committed Nov 4, 2011
1 parent 35f4182 commit 829735e
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 32 deletions.
2 changes: 1 addition & 1 deletion lib/_debugger.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -1538,7 +1538,7 @@ Interface.prototype.trySpawn = function(cb) {
// TODO Do we really need to handle it? // TODO Do we really need to handle it?
} }
}; };
process.kill(parseInt(this.args[2], 10), 'SIGUSR1'); process._debugProcess(parseInt(this.args[2], 10));
} }
} }


Expand Down
225 changes: 196 additions & 29 deletions src/node.cc
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -801,11 +801,11 @@ Local<Value> ErrnoException(int errorno,


#ifdef _WIN32 #ifdef _WIN32
Local<Value> WinapiErrnoException(int errorno, Local<Value> WinapiErrnoException(int errorno,
const char *syscall, const char* syscall,
const char *msg, const char* msg,
const char *path) { const char* path) {
Local<Value> e; Local<Value> e;
if (!msg[0]) { if (!msg || !msg[0]) {
msg = winapi_strerror(errorno); msg = winapi_strerror(errorno);
} }
Local<String> message = String::NewSymbol(msg); Local<String> message = String::NewSymbol(msg);
Expand Down Expand Up @@ -1823,6 +1823,8 @@ static Handle<Object> GetFeatures() {
} }




static Handle<Value> DebugProcess(const Arguments& args);

Handle<Object> SetupProcessObject(int argc, char *argv[]) { Handle<Object> SetupProcessObject(int argc, char *argv[]) {
HandleScope scope; HandleScope scope;


Expand Down Expand Up @@ -1941,6 +1943,8 @@ Handle<Object> SetupProcessObject(int argc, char *argv[]) {


NODE_SET_METHOD(process, "_kill", Kill); NODE_SET_METHOD(process, "_kill", Kill);


NODE_SET_METHOD(process, "_debugProcess", DebugProcess);

NODE_SET_METHOD(process, "dlopen", DLOpen); NODE_SET_METHOD(process, "dlopen", DLOpen);


NODE_SET_METHOD(process, "uptime", Uptime); NODE_SET_METHOD(process, "uptime", Uptime);
Expand Down Expand Up @@ -2104,9 +2108,15 @@ static void ParseArgs(int argc, char **argv) {
option_end_index = i; option_end_index = i;
} }



static Isolate* node_isolate = NULL;
static volatile bool debugger_running = false; static volatile bool debugger_running = false;


static void EnableDebug(bool wait_connect) { static void EnableDebug(bool wait_connect) {
// If we're called from another thread, make sure to enter the right
// v8 isolate.
node_isolate->Enter();

// Start the debug thread and it's associated TCP server on port 5858. // Start the debug thread and it's associated TCP server on port 5858.
bool r = Debug::EnableAgent("node " NODE_VERSION, debug_port); bool r = Debug::EnableAgent("node " NODE_VERSION, debug_port);


Expand All @@ -2123,55 +2133,209 @@ static void EnableDebug(bool wait_connect) {


// Print out some information. // Print out some information.
fprintf(stderr, "debugger listening on port %d\n", debug_port); fprintf(stderr, "debugger listening on port %d\n", debug_port);
fflush(stderr);


debugger_running = true; debugger_running = true;

node_isolate->Exit();
} }




#ifdef __POSIX__ #ifdef __POSIX__
static void EnableDebugSignalHandler(int signal) { static void EnableDebugSignalHandler(int signal) {
// Break once process will return execution to v8 // Break once process will return execution to v8
v8::Debug::DebugBreak(); v8::Debug::DebugBreak(node_isolate);


if (!debugger_running) { if (!debugger_running) {
fprintf(stderr, "Hit SIGUSR1 - starting debugger agent.\n"); fprintf(stderr, "Hit SIGUSR1 - starting debugger agent.\n");
EnableDebug(false); EnableDebug(false);
} }
} }


static void RegisterSignalHandler(int signal, void (*handler)(int)) {
struct sigaction sa;

memset(&sa, 0, sizeof(sa));
sa.sa_handler = handler;
sigfillset(&sa.sa_mask);
sigaction(signal, &sa, NULL);
}


Handle<Value> DebugProcess(const Arguments& args) {
HandleScope scope;

if (args.Length() != 1) {
return ThrowException(Exception::Error(
String::New("Invalid number of arguments.")));
}

pid_t pid;
int r;

pid = args[0]->IntegerValue();
r = kill(pid, SIGUSR1);
if (r != 0) {
return ThrowException(ErrnoException(errno, "kill"));
}

return Undefined();
}
#endif // __POSIX__ #endif // __POSIX__


#if defined(__MINGW32__) || defined(_MSC_VER)
static bool EnableDebugSignalHandler(DWORD signal) {
if (signal == CTRL_C_EVENT) exit(1);
if (signal != CTRL_BREAK_EVENT) return false;


#ifdef _WIN32
DWORD WINAPI EnableDebugThreadProc(void* arg) {
// Break once process will return execution to v8 // Break once process will return execution to v8
if (!debugger_running) {
for (int i = 0; i < 1; i++) {
fprintf(stderr, "Starting debugger agent.\r\n");
fflush(stderr);
EnableDebug(false);
}
}

v8::Debug::DebugBreak(); v8::Debug::DebugBreak();


if (!debugger_running) { return 0;
fprintf(stderr, "Hit Ctrl+Break - starting debugger agent.\n"); }
EnableDebug(false);
return true;
} else { static int GetDebugSignalHandlerMappingName(DWORD pid, char* buf, size_t buf_len) {
// Run default system action (terminate) return snprintf(buf, buf_len, "node-debug-handler-%u", pid);
return false; }


static int RegisterDebugSignalHandler() {
char mapping_name[32];
HANDLE mapping_handle;
DWORD pid;
LPTHREAD_START_ROUTINE* handler;

pid = GetCurrentProcessId();

if (GetDebugSignalHandlerMappingName(pid,
mapping_name,
sizeof mapping_name) < 0) {
return -1;
}

mapping_handle = CreateFileMappingA(INVALID_HANDLE_VALUE,
NULL,
PAGE_READWRITE,
0,
sizeof *handler,
mapping_name);
if (mapping_handle == NULL) {
return -1;
} }


handler = (LPTHREAD_START_ROUTINE*) MapViewOfFile(mapping_handle,
FILE_MAP_ALL_ACCESS,
0,
0,
sizeof *handler);
if (handler == NULL) {
CloseHandle(mapping_handle);
return -1;
}

*handler = EnableDebugThreadProc;

UnmapViewOfFile((void*) handler);

return 0;
} }
#endif




#ifdef __POSIX__ static Handle<Value> DebugProcess(const Arguments& args) {
HandleScope scope;
Handle<Value> rv = Undefined();
DWORD pid;
HANDLE process = NULL;
HANDLE thread = NULL;
HANDLE mapping = NULL;
char mapping_name[32];
LPTHREAD_START_ROUTINE* handler = NULL;


static int RegisterSignalHandler(int signal, void (*handler)(int)) { if (args.Length() != 1) {
struct sigaction sa; rv = ThrowException(Exception::Error(String::New("Invalid number of arguments.")));
goto out;
}


memset(&sa, 0, sizeof(sa)); pid = (DWORD) args[0]->IntegerValue();
sa.sa_handler = handler;
sigfillset(&sa.sa_mask); process = OpenProcess(PROCESS_CREATE_THREAD | PROCESS_QUERY_INFORMATION |
return sigaction(signal, &sa, NULL); PROCESS_VM_OPERATION | PROCESS_VM_WRITE |
PROCESS_VM_READ,
FALSE,
pid);
if (process == NULL) {
rv = ThrowException(WinapiErrnoException(GetLastError(), "OpenProcess"));
goto out;
}

if (GetDebugSignalHandlerMappingName(pid,
mapping_name,
sizeof mapping_name) < 0) {
rv = ThrowException(ErrnoException(errno, "sprintf"));
goto out;
}

mapping = OpenFileMapping(FILE_MAP_READ, FALSE, mapping_name);
if (mapping == NULL) {
rv = ThrowException(WinapiErrnoException(GetLastError(), "sprintf"));
goto out;
}

handler = (LPTHREAD_START_ROUTINE*) MapViewOfFile(mapping,
FILE_MAP_READ,
0,
0,
sizeof *handler);
if (handler == NULL || *handler == NULL) {
rv = ThrowException(WinapiErrnoException(GetLastError(), "MapViewOfFile"));
goto out;
}

thread = CreateRemoteThread(process,
NULL,
0,
*handler,
NULL,
0,
NULL);
if (thread == NULL) {
rv = ThrowException(WinapiErrnoException(GetLastError(),
"CreateRemoteThread"));
goto out;
}

// Wait for the thread to terminate
if (WaitForSingleObject(thread, INFINITE) != WAIT_OBJECT_0) {
rv = ThrowException(WinapiErrnoException(GetLastError(),
"WaitForSingleObject"));
goto out;
}

out:
if (process != NULL) {
CloseHandle(process);
}
if (thread != NULL) {
CloseHandle(thread);
}
if (handler != NULL) {
UnmapViewOfFile(handler);
}
if (mapping != NULL) {
CloseHandle(mapping);
}

return Undefined();
} }
#endif // __POSIX__ #endif // _WIN32




char** Init(int argc, char *argv[]) { char** Init(int argc, char *argv[]) {
Expand Down Expand Up @@ -2245,6 +2409,7 @@ char** Init(int argc, char *argv[]) {
// Set the callback DebugMessageDispatch which is called from the debug // Set the callback DebugMessageDispatch which is called from the debug
// thread. // thread.
Debug::SetDebugMessageDispatchHandler(node::DebugMessageDispatch); Debug::SetDebugMessageDispatchHandler(node::DebugMessageDispatch);

// Initialize the async watcher. DebugMessageCallback() is called from the // Initialize the async watcher. DebugMessageCallback() is called from the
// main thread to execute a random bit of javascript - which will give V8 // main thread to execute a random bit of javascript - which will give V8
// control so it can handle whatever new message had been received on the // control so it can handle whatever new message had been received on the
Expand All @@ -2254,17 +2419,19 @@ char** Init(int argc, char *argv[]) {
// unref it so that we exit the event loop despite it being active. // unref it so that we exit the event loop despite it being active.
uv_unref(uv_default_loop()); uv_unref(uv_default_loop());


// Fetch a reference to the main isolate, so we have a reference to it
// even when we need it to access it from another (debugger) thread.
node_isolate = Isolate::GetCurrent();


// If the --debug flag was specified then initialize the debug thread. // If the --debug flag was specified then initialize the debug thread.
if (node::use_debug_agent) { if (node::use_debug_agent) {
EnableDebug(debug_wait_connect); EnableDebug(debug_wait_connect);
} else { } else {
#ifdef __POSIX__ #ifdef _WIN32
RegisterDebugSignalHandler();
#else // Posix
RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler); RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler);
#endif // __POSIX__ #endif // __POSIX__
#if defined(__MINGW32__) || defined(_MSC_VER)
SetConsoleCtrlHandler((PHANDLER_ROUTINE) EnableDebugSignalHandler, TRUE);
#endif
} }


return argv; return argv;
Expand Down
4 changes: 2 additions & 2 deletions test/simple/test-debugger-client.js
Original file line number Original file line Diff line number Diff line change
Expand Up @@ -147,8 +147,8 @@ function doTest(cb, done) {


nodeProcess.stdout.once('data', function() { nodeProcess.stdout.once('data', function() {
console.log('>>> new node process: %d', nodeProcess.pid); console.log('>>> new node process: %d', nodeProcess.pid);
process.kill(nodeProcess.pid, 'SIGUSR1'); process._debugProcess(nodeProcess.pid);
console.log('>>> signaling it with SIGUSR1'); console.log('>>> starting debugger session');
}); });


var didTryConnect = false; var didTryConnect = false;
Expand Down

0 comments on commit 829735e

Please sign in to comment.