From 0dcbe3f74a0d92a399c508c92110648e76917d9b Mon Sep 17 00:00:00 2001 From: Ryan Dahl Date: Wed, 22 Dec 2010 17:17:34 -0800 Subject: [PATCH] Fork out to debugger on debugger statements Also implement continue in Client. --- lib/_debugger.js | 36 +++++++++++++++++++++++++---- lib/readline.js | 2 ++ src/node.cc | 59 +++++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 92 insertions(+), 5 deletions(-) diff --git a/lib/_debugger.js b/lib/_debugger.js index 25f82e72e1..83bc6c8fba 100644 --- a/lib/_debugger.js +++ b/lib/_debugger.js @@ -212,6 +212,13 @@ Client.prototype.reqScripts = function(cb) { }; +Client.prototype.reqContinue = function(cb) { + this.req({ command: 'continue' } , function (res) { + if (cb) cb(res.body); + }); +}; + + var helpMessage = "Commands: scripts, backtrace, version, eval, help, quit"; @@ -223,18 +230,33 @@ function startInterface() { i.write(chunk); }); - var prompt = '> '; + var prompt = 'debug> '; i.setPrompt(prompt); i.prompt(); - i.on('SIGINT', function() { + var quitTried = false; + + function tryQuit() { + if (quitTried) return; + quitTried = true; i.close(); - }); + console.log("debug done\n"); + if (c.writable) { + c.reqContinue(function (res) { + process.exit(0); + }); + } else { + process.exit(0); + } + } + + i.on('SIGINT', tryQuit); + i.on('close', tryQuit); i.on('line', function(cmd) { if (cmd == 'quit') { - process.exit(0); + tryQuit(); } else if (/^help/.test(cmd)) { console.log(helpMessage); i.prompt(); @@ -251,6 +273,12 @@ function startInterface() { i.prompt(); }); + } else if ('continue' == cmd || 'c' == cmd) { + c.reqContinue(function (res) { + console.log(res); + i.prompt(); + }); + } else if (/^scripts/.test(cmd)) { c.reqScripts(function (res) { var text = res.map(function (x) { return x.text; }); diff --git a/lib/readline.js b/lib/readline.js index 341b20b479..3ae43f4735 100644 --- a/lib/readline.js +++ b/lib/readline.js @@ -160,6 +160,8 @@ Interface.prototype._refreshLine = function() { Interface.prototype.close = function(d) { + if (this._closing) return; + this._closing = true; if (this.enabled) { tty.setRawMode(false); } diff --git a/src/node.cc b/src/node.cc index 04a96a4187..d81aab841a 100644 --- a/src/node.cc +++ b/src/node.cc @@ -17,6 +17,11 @@ #include /* getpwnam() */ #include /* getgrnam() */ +// waitpid +#include +#include + + #include "platform.h" #include @@ -1908,6 +1913,57 @@ static int RegisterSignalHandler(int signal, void (*handler)(int)) { } +static bool debugger_slave_running = false; + +static void HandleDebugEvent(DebugEvent event, + Handle exec_state, + Handle event_data, + Handle data) { + HandleScope scope; + + if (debugger_slave_running) return; + + if (event != Break) { + return; + } + + // Then we take one of two actions + // 1. Inspect the environ variable NODE_DEBUG_PROG; if it is not empty // + // then start it. (TODO) + // 2. Start the built-in debugger. + + + size_t size = 2*PATH_MAX; + char node_path[size]; + OS::GetExecutablePath(node_path, &size); + + int pid = vfork(); + + if (pid == -1) { + perror("vfork()"); + return; + } + + if (pid == 0) { + // Child process + char *argv[] = { node_path, "debug", NULL }; + execvp(node_path, argv); + perror("execvp()"); + _exit(127); + } + + debugger_slave_running = true; + + // We've hit some debugger event. First we will enable the debugger agent. + EnableDebug(true); + + // TODO probably need to waitpid here or something to avoid zombies. + // int status; + // waitpid(pid, &status, 0); + Debug::DebugBreak(); +} + + int Start(int argc, char *argv[]) { // Hack aroung with the argv pointer. Used for process.title = "blah". argv = node::Platform::SetupArgs(argc, argv); @@ -2022,7 +2078,8 @@ int Start(int argc, char *argv[]) { // If the --debug flag was specified then initialize the debug thread. if (node::use_debug_agent) { - EnableDebug(debug_wait_connect); + // XXX: only use if debug flag enabled? + Debug::SetDebugEventListener(HandleDebugEvent); } else { RegisterSignalHandler(SIGUSR1, EnableDebugSignalHandler); ev_async_init(&enable_debug, EnableDebug2);