Author: [email protected]
Date: Wed Mar  4 01:42:51 2009
New Revision: 1411

Modified:
    branches/bleeding_edge/src/d8-debug.cc
    branches/bleeding_edge/src/d8-debug.h
    branches/bleeding_edge/src/d8.cc
    branches/bleeding_edge/src/flag-definitions.h

Log:
Add remote debugging front end to developer shell.

D8 now supports demote debuggign of a V8 instance with the debugger agent  
enabled. Running D8 with the option --remote-debugger will try to connect  
to a V8 debugger agent and process the debugging protocol. The command line  
UI is the same as for the D8 in-process debugger as the same code is used  
for processing the debugger JSON.
Review URL: http://codereview.chromium.org/40011

Modified: branches/bleeding_edge/src/d8-debug.cc
==============================================================================
--- branches/bleeding_edge/src/d8-debug.cc      (original)
+++ branches/bleeding_edge/src/d8-debug.cc      Wed Mar  4 01:42:51 2009
@@ -28,6 +28,8 @@

  #include "d8.h"
  #include "d8-debug.h"
+#include "platform.h"
+#include "debug-agent.h"


  namespace v8 {
@@ -138,6 +140,199 @@
      }
      running =
           
response_details->Get(String::New("running"))->ToBoolean()->Value();
+  }
+}
+
+
+void RunRemoteDebugger(int port) {
+  RemoteDebugger debugger(port);
+  debugger.Run();
+}
+
+
+void RemoteDebugger::Run() {
+  bool ok;
+
+  // Make sure that socket support is initialized.
+  ok = i::Socket::Setup();
+  if (!ok) {
+    printf("Unable to initialize socket support %d\n",  
i::Socket::LastError());
+    return;
+  }
+
+  // Connect to the debugger agent.
+  conn_ = i::OS::CreateSocket();
+  static const int kPortStrSize = 6;
+  char port_str[kPortStrSize];
+  i::OS::SNPrintF(i::Vector<char>(port_str, kPortStrSize), "%d", port_);
+  ok = conn_->Connect("localhost", port_str);
+  if (!ok) {
+    printf("Unable to connect to debug agent %d\n",  
i::Socket::LastError());
+    return;
+  }
+
+  // Start the receiver thread.
+  ReceiverThread receiver(this);
+  receiver.Start();
+
+  // Start the keyboard thread.
+  KeyboardThread keyboard(this);
+  keyboard.Start();
+
+  // Process events received from debugged VM and from the keyboard.
+  bool terminate = false;
+  while (!terminate) {
+    event_available_->Wait();
+    RemoteDebuggerEvent* event = GetEvent();
+    switch (event->type()) {
+      case RemoteDebuggerEvent::kMessage:
+        HandleMessageReceived(event->data());
+        break;
+      case RemoteDebuggerEvent::kKeyboard:
+        HandleKeyboardCommand(event->data());
+        break;
+      case RemoteDebuggerEvent::kDisconnect:
+        terminate = true;
+        break;
+
+      default:
+        UNREACHABLE();
+    }
+    delete event;
+  }
+
+  // Wait for the receiver thread to end.
+  receiver.Join();
+}
+
+
+void RemoteDebugger::MessageReceived(i::SmartPointer<char> message) {
+  RemoteDebuggerEvent* event =
+      new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
+  AddEvent(event);
+}
+
+
+void RemoteDebugger::KeyboardCommand(i::SmartPointer<char> command) {
+  RemoteDebuggerEvent* event =
+      new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
+  AddEvent(event);
+}
+
+
+void RemoteDebugger::ConnectionClosed() {
+  RemoteDebuggerEvent* event =
+      new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
+                              i::SmartPointer<char>());
+  AddEvent(event);
+}
+
+
+void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
+  i::ScopedLock lock(event_access_);
+  if (head_ == NULL) {
+    ASSERT(tail_ == NULL);
+    head_ = event;
+    tail_ = event;
+  } else {
+    ASSERT(tail_ != NULL);
+    tail_->set_next(event);
+    tail_ = event;
+  }
+  event_available_->Signal();
+}
+
+
+RemoteDebuggerEvent* RemoteDebugger::GetEvent() {
+  i::ScopedLock lock(event_access_);
+  ASSERT(head_ != NULL);
+  RemoteDebuggerEvent* result = head_;
+  head_ = head_->next();
+  if (head_ == NULL) {
+    ASSERT(tail_ == result);
+    tail_ = NULL;
+  }
+  return result;
+}
+
+
+void RemoteDebugger::HandleMessageReceived(char* message) {
+  HandleScope scope;
+
+  // Print the event details.
+  TryCatch try_catch;
+  Handle<Object> details =
+       
Shell::DebugMessageDetails(Handle<String>::Cast(String::New(message)));
+  if (try_catch.HasCaught()) {
+      Shell::ReportException(&try_catch);
+    return;
+  }
+  String::Utf8Value str(details->Get(String::New("text")));
+  if (str.length() == 0) {
+    // Empty string is used to signal not to process this event.
+    return;
+  }
+  if (*str != NULL) {
+    printf("%s\n", *str);
+  } else {
+    printf("???\n");
+  }
+  printf("dbg> ");
+}
+
+
+void RemoteDebugger::HandleKeyboardCommand(char* command) {
+  HandleScope scope;
+
+  // Convert the debugger command to a JSON debugger request.
+  TryCatch try_catch;
+  Handle<Value> request =
+      Shell::DebugCommandToJSONRequest(String::New(command));
+  if (try_catch.HasCaught()) {
+    Shell::ReportException(&try_catch);
+    return;
+  }
+
+  // If undefined is returned the command was handled internally and there  
is
+  // no JSON to send.
+  if (request->IsUndefined()) {
+    return;
+  }
+
+  // Send the JSON debugger request.
+  i::DebuggerAgentUtil::SendMessage(conn_, Handle<String>::Cast(request));
+}
+
+
+void ReceiverThread::Run() {
+  while (true) {
+    // Receive a message.
+    i::SmartPointer<char> message =
+      i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
+    if (*message == NULL) {
+      remote_debugger_->ConnectionClosed();
+      return;
+    }
+
+    // Pass the message to the main thread.
+    remote_debugger_->MessageReceived(message);
+  }
+}
+
+
+void KeyboardThread::Run() {
+  static const int kBufferSize = 256;
+  while (true) {
+    // read keyboard input.
+    char command[kBufferSize];
+    char* str = fgets(command, kBufferSize, stdin);
+    if (str == NULL) {
+      break;
+    }
+
+    // Pass the keyboard command to the main thread.
+    remote_debugger_->KeyboardCommand(
+        i::SmartPointer<char>(i::OS::StrDup(command)));
    }
  }


Modified: branches/bleeding_edge/src/d8-debug.h
==============================================================================
--- branches/bleeding_edge/src/d8-debug.h       (original)
+++ branches/bleeding_edge/src/d8-debug.h       Wed Mar  4 01:42:51 2009
@@ -41,6 +41,113 @@
                        Handle<Object> event_data,
                        Handle<Value> data);

+// Start the remove debugger connecting to a V8 debugger agent on the  
specified
+// port.
+void RunRemoteDebugger(int port);
+
+// Forward declerations.
+class RemoteDebuggerEvent;
+class ReceiverThread;
+
+
+// Remote debugging class.
+class RemoteDebugger {
+ public:
+  explicit RemoteDebugger(int port)
+      : port_(port),
+        event_access_(i::OS::CreateMutex()),
+        event_available_(i::OS::CreateSemaphore(0)),
+        head_(NULL), tail_(NULL) {}
+  void Run();
+
+  // Handle events from the subordinate threads.
+  void MessageReceived(i::SmartPointer<char> message);
+  void KeyboardCommand(i::SmartPointer<char> command);
+  void ConnectionClosed();
+
+ private:
+  // Add new debugger event to the list.
+  void AddEvent(RemoteDebuggerEvent* event);
+  // Read next debugger event from the list.
+  RemoteDebuggerEvent* GetEvent();
+
+  // Handle a message from the debugged V8.
+  void HandleMessageReceived(char* message);
+  // Handle a keyboard command.
+  void HandleKeyboardCommand(char* command);
+
+  // Get connection to agent in debugged V8.
+  i::Socket* conn() { return conn_; }
+
+  int port_;  // Port used to connect to debugger V8.
+  i::Socket* conn_;  // Connection to debugger agent in debugged V8.
+
+  // Linked list of events from debugged V8 and from keyboard input.  
Access to
+  // the list is guarded by a mutex and a semaphore signals new items in  
the
+  // list.
+  i::Mutex* event_access_;
+  i::Semaphore* event_available_;
+  RemoteDebuggerEvent* head_;
+  RemoteDebuggerEvent* tail_;
+
+  friend class ReceiverThread;
+};
+
+
+// Thread reading from debugged V8 instance.
+class ReceiverThread: public i::Thread {
+ public:
+  explicit ReceiverThread(RemoteDebugger* remote_debugger)
+      : remote_debugger_(remote_debugger) {}
+  ~ReceiverThread() {}
+
+  void Run();
+
+ private:
+  RemoteDebugger* remote_debugger_;
+};
+
+
+// Thread reading keyboard input.
+class KeyboardThread: public i::Thread {
+ public:
+  explicit KeyboardThread(RemoteDebugger* remote_debugger)
+      : remote_debugger_(remote_debugger) {}
+  ~KeyboardThread() {}
+
+  void Run();
+
+ private:
+  RemoteDebugger* remote_debugger_;
+};
+
+
+// Events processed by the main deubgger thread.
+class RemoteDebuggerEvent {
+ public:
+  RemoteDebuggerEvent(int type, i::SmartPointer<char> data)
+      : type_(type), data_(data), next_(NULL) {
+    ASSERT(type == kMessage || type == kKeyboard || type == kDisconnect);
+  }
+
+  static const int kMessage = 1;
+  static const int kKeyboard = 2;
+  static const int kDisconnect = 3;
+
+  int type() { return type_; }
+  char* data() { return *data_; }
+
+ private:
+  void set_next(RemoteDebuggerEvent* event) { next_ = event; }
+  RemoteDebuggerEvent* next() { return next_; }
+
+  int type_;
+  i::SmartPointer<char> data_;
+  RemoteDebuggerEvent* next_;
+
+  friend class RemoteDebugger;
+};
+

  }  // namespace v8


Modified: branches/bleeding_edge/src/d8.cc
==============================================================================
--- branches/bleeding_edge/src/d8.cc    (original)
+++ branches/bleeding_edge/src/d8.cc    Wed Mar  4 01:42:51 2009
@@ -574,16 +574,22 @@
        }
      }

+    // Run the remote debugger if requested.
+    if (i::FLAG_remote_debugger) {
+      RunRemoteDebugger(i::FLAG_debugger_port);
+      return 0;
+    }
+
      // Start the debugger agent if requested.
      if (i::FLAG_debugger_agent) {
        v8::Debug::EnableAgent(i::FLAG_debugger_port);
      }

      // Start the in-process debugger if requested.
-    if (i::FLAG_debugger && !i::FLAG_debugger_agent)
+    if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
        v8::Debug::SetDebugEventListener(HandleDebugEvent);
+    }
    }
-
    if (run_shell)
      RunShell();
    for (int i = 0; i < threads.length(); i++) {

Modified: branches/bleeding_edge/src/flag-definitions.h
==============================================================================
--- branches/bleeding_edge/src/flag-definitions.h       (original)
+++ branches/bleeding_edge/src/flag-definitions.h       Wed Mar  4 01:42:51 2009
@@ -226,6 +226,8 @@
  DEFINE_bool(help, false, "Print usage message, including flags, on  
console")
  DEFINE_bool(dump_counters, false, "Dump counters on exit")
  DEFINE_bool(debugger, true, "Enable JavaScript debugger")
+DEFINE_bool(remote_debugger, false, "Connect JavaScript debugger to the "
+                                    "debugger agent in another process")
  DEFINE_bool(debugger_agent, false, "Enable debugger agent")
  DEFINE_int(debugger_port, 5858, "Port to use for remote debugging")
  DEFINE_string(map_counters, false, "Map counters to a file")

--~--~---------~--~----~------------~-------~--~----~
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
-~----------~----~----~----~------~----~------~--~---

Reply via email to