Configurable debug ports, and --debug-brk
authorZoran Tomicic <ztomicic@gmail.com>
Mon, 22 Feb 2010 05:15:44 +0000 (21:15 -0800)
committerRyan Dahl <ry@tinyclouds.org>
Mon, 22 Feb 2010 05:17:25 +0000 (21:17 -0800)
src/node.cc
src/node.js

index 648c4d1..3f00c53 100644 (file)
@@ -62,6 +62,8 @@ static Persistent<String> emit_symbol;
 
 static int option_end_index = 0;
 static bool use_debug_agent = false;
+static bool debug_wait_connect = false;
+static int debug_port=5858;
 
 
 static ev_async eio_want_poll_notifier;
@@ -909,6 +911,7 @@ void FatalException(TryCatch &try_catch) {
 
 
 static ev_async debug_watcher;
+volatile static bool debugger_msg_pending = false;
 
 static void DebugMessageCallback(EV_P_ ev_async *watcher, int revents) {
   HandleScope scope;
@@ -923,9 +926,49 @@ static void DebugMessageDispatch(void) {
 
   // Send a signal to our main thread saying that it should enter V8 to
   // handle the message.
+  debugger_msg_pending = true;
   ev_async_send(EV_DEFAULT_UC_ &debug_watcher);
 }
 
+static Handle<Value> CheckBreak(const Arguments& args) {
+  HandleScope scope;
+
+  // TODO FIXME This function is a hack to wait until V8 is ready to accept
+  // commands. There seems to be a bug in EnableAgent( _ , _ , true) which
+  // makes it unusable here. Ideally we'd be able to bind EnableAgent and
+  // get it to halt until Eclipse connects.
+
+  if (!debug_wait_connect)
+    return Undefined();
+
+  printf("Waiting for remote debugger connection...\n");
+
+  const int halfSecond = 50;
+  const int tenMs=10000;
+  debugger_msg_pending = false;
+  for (;;) {
+    if (debugger_msg_pending) {
+      Debug::DebugBreak();
+      Debug::ProcessDebugMessages();
+      debugger_msg_pending = false;
+
+      // wait for 500 msec of silence from remote debugger
+      int cnt = halfSecond;
+        while (cnt --) {
+        debugger_msg_pending = false;
+        usleep(tenMs);
+        if (debugger_msg_pending) {
+          debugger_msg_pending = false;
+          cnt = halfSecond;
+        }
+      }
+      break;
+    }
+    usleep(tenMs);
+  }
+  return Undefined();
+}
+
 
 static void Load(int argc, char *argv[]) {
   HandleScope scope;
@@ -995,6 +1038,7 @@ static void Load(int argc, char *argv[]) {
   NODE_SET_METHOD(process, "dlopen", DLOpen);
   NODE_SET_METHOD(process, "kill", Kill);
   NODE_SET_METHOD(process, "memoryUsage", MemoryUsage);
+  NODE_SET_METHOD(process, "checkBreak", CheckBreak);
 
   // Assign the EventEmitter. It was created in main().
   process->Set(String::NewSymbol("EventEmitter"),
@@ -1067,6 +1111,7 @@ static void Load(int argc, char *argv[]) {
   // Node's I/O bindings may want to replace 'f' with their own function.
 
   Local<Value> args[1] = { Local<Value>::New(process) };
+
   f->Call(global, 1, args);
 
 #ifndef NDEBUG
@@ -1077,12 +1122,43 @@ static void Load(int argc, char *argv[]) {
 #endif
 }
 
+static void PrintHelp();
+
+static void ParseDebugOpt(const char* arg) {
+  const char *p = 0;
+
+  use_debug_agent = true;
+  if (!strcmp (arg, "--debug-brk")) {
+    debug_wait_connect = true;
+    return;
+  } else if (!strcmp(arg, "--debug")) {
+    return;
+  } else if (strstr(arg, "--debug-brk=") == arg) {
+    debug_wait_connect = true;
+    p = 1 + strchr(arg, '=');
+    debug_port = atoi(p);
+  } else if (strstr(arg, "--debug=") == arg) {
+    p = 1 + strchr(arg, '=');
+    debug_port = atoi(p);
+  }
+  if (p && debug_port > 1024 && debug_port <  65536)
+      return;
+
+  fprintf(stderr, "Bad debug option.\n");
+  if (p) fprintf(stderr, "Debug port must be in range 1025 to 65535.\n");
+
+  PrintHelp();
+  exit(1);
+}
+
 static void PrintHelp() {
   printf("Usage: node [options] script.js [arguments] \n"
-         "  -v, --version    print node's version\n"
-         "  --debug          enable remote debugging\n" // TODO specify port
-         "  --cflags         print pre-processor and compiler flags\n"
-         "  --v8-options     print v8 command line options\n\n"
+         "  -v, --version      print node's version\n"
+         "  --debug[=port]     enable remote debugging via given TCP port\n"
+         "  --debug-brk[=port] as above, but break in node.js and\n"
+         "                     wait for remote debugger to connect\n"
+         "  --cflags           print pre-processor and compiler flags\n"
+         "  --v8-options       print v8 command line options\n\n"
          "Documentation can be found at http://nodejs.org/api.html"
          " or with 'man node'\n");
 }
@@ -1092,9 +1168,9 @@ static void ParseArgs(int *argc, char **argv) {
   // TODO use parse opts
   for (int i = 1; i < *argc; i++) {
     const char *arg = argv[i];
-    if (strcmp(arg, "--debug") == 0) {
+    if (strstr(arg, "--debug") == arg) {
+      ParseDebugOpt(arg);
       argv[i] = reinterpret_cast<const char*>("");
-      use_debug_agent = true;
       option_end_index = i;
     } else if (strcmp(arg, "--version") == 0 || strcmp(arg, "-v") == 0) {
       printf("%s\n", NODE_VERSION);
@@ -1191,12 +1267,12 @@ int main(int argc, char *argv[]) {
     ev_unref(EV_DEFAULT_UC);
 
     // Start the debug thread and it's associated TCP server on port 5858.
-    bool r = Debug::EnableAgent("node " NODE_VERSION, 5858);
+    bool r = Debug::EnableAgent("node " NODE_VERSION, node::debug_port);
+
     // Crappy check that everything went well. FIXME
     assert(r);
-    // Print out some information. REMOVEME
-    printf("debugger listening on port 5858\n"
-           "Use 'd8 --remote_debugger' to access it.\n");
+    // Print out some information.
+    printf("debugger listening on port %d\n", node::debug_port);
   }
 
   // Create the one and only Context.
index 66b9fe6..7ad28f2 100644 (file)
@@ -926,7 +926,10 @@ Module.prototype._loadContent = function (content, filename) {
 
   try {
     var compiledWrapper = process.compile(wrapper, filename);
-    compiledWrapper.apply(self.exports, [self.exports, require, self, filename, path.dirname(filename)]);
+    var dirName = path.dirname(filename);
+    if (filename === process.argv[1])
+      process.checkBreak();
+    compiledWrapper.apply(self.exports, [self.exports, require, self, filename, dirName]);
   } catch (e) {
     return e;
   }