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
-~----------~----~----~----~------~----~------~--~---