| Index: runtime/bin/dbg_connection.cc
|
| diff --git a/runtime/bin/dbg_connection.cc b/runtime/bin/dbg_connection.cc
|
| deleted file mode 100644
|
| index 6bd0cda256d67e5e109ffefcf55b1910c1461fc4..0000000000000000000000000000000000000000
|
| --- a/runtime/bin/dbg_connection.cc
|
| +++ /dev/null
|
| @@ -1,526 +0,0 @@
|
| -// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
| -// for details. All rights reserved. Use of this source code is governed by a
|
| -// BSD-style license that can be found in the LICENSE file.
|
| -
|
| -#include "bin/dbg_connection.h"
|
| -#include "bin/dbg_message.h"
|
| -#include "bin/dartutils.h"
|
| -#include "bin/lockers.h"
|
| -#include "bin/log.h"
|
| -#include "bin/socket.h"
|
| -#include "bin/thread.h"
|
| -#include "bin/utils.h"
|
| -
|
| -#include "platform/globals.h"
|
| -#include "platform/json.h"
|
| -#include "platform/utils.h"
|
| -
|
| -#include "include/dart_api.h"
|
| -
|
| -
|
| -namespace dart {
|
| -namespace bin {
|
| -
|
| -bool trace_debug_protocol = false;
|
| -
|
| -intptr_t DebuggerConnectionHandler::listener_fd_ = -1;
|
| -Monitor* DebuggerConnectionHandler::handler_lock_ = new Monitor();
|
| -
|
| -// TODO(asiva): Remove this once we have support for multiple debugger
|
| -// connections. For now we just store the single debugger connection
|
| -// handler in a static variable.
|
| -static DebuggerConnectionHandler* singleton_handler = NULL;
|
| -
|
| -// The maximum message length to print when --trace_debug_protocol is
|
| -// specified.
|
| -static const int kMaxPrintMessageLen = 1024;
|
| -
|
| -class MessageBuffer {
|
| - public:
|
| - explicit MessageBuffer(intptr_t fd);
|
| - ~MessageBuffer();
|
| - void ReadData();
|
| - bool IsValidMessage() const;
|
| - void PopMessage();
|
| - int MessageId() const;
|
| - char* buf() const { return buf_; }
|
| - bool Alive() const { return connection_is_alive_; }
|
| -
|
| - private:
|
| - static const int kInitialBufferSize = 256;
|
| - char* buf_;
|
| - int buf_length_;
|
| - intptr_t fd_;
|
| - int data_length_;
|
| - bool connection_is_alive_;
|
| -
|
| - DISALLOW_COPY_AND_ASSIGN(MessageBuffer);
|
| -};
|
| -
|
| -
|
| -MessageBuffer::MessageBuffer(intptr_t fd)
|
| - : buf_(NULL),
|
| - buf_length_(0),
|
| - fd_(fd),
|
| - data_length_(0),
|
| - connection_is_alive_(true) {
|
| - buf_ = reinterpret_cast<char*>(malloc(kInitialBufferSize));
|
| - if (buf_ == NULL) {
|
| - FATAL("Failed to allocate message buffer\n");
|
| - }
|
| - buf_length_ = kInitialBufferSize;
|
| - buf_[0] = '\0';
|
| - data_length_ = 0;
|
| -}
|
| -
|
| -
|
| -MessageBuffer::~MessageBuffer() {
|
| - free(buf_);
|
| - buf_ = NULL;
|
| - fd_ = -1;
|
| -}
|
| -
|
| -
|
| -bool MessageBuffer::IsValidMessage() const {
|
| - if (data_length_ == 0) {
|
| - return false;
|
| - }
|
| - dart::JSONReader msg_reader(buf_);
|
| - return msg_reader.EndOfObject() != NULL;
|
| -}
|
| -
|
| -
|
| -int MessageBuffer::MessageId() const {
|
| - dart::JSONReader r(buf_);
|
| - r.Seek("id");
|
| - if (r.Type() == dart::JSONReader::kInteger) {
|
| - return atoi(r.ValueChars());
|
| - } else {
|
| - return -1;
|
| - }
|
| -}
|
| -
|
| -
|
| -void MessageBuffer::ReadData() {
|
| - ASSERT(data_length_ >= 0);
|
| - ASSERT(data_length_ < buf_length_);
|
| - int max_read = buf_length_ - data_length_ - 1;
|
| - if (max_read == 0) {
|
| - // TODO(hausner):
|
| - // Buffer is full. What should we do if there is no valid message
|
| - // in the buffer? This might be possible if the client sends a message
|
| - // that's larger than the buffer, of if the client sends malformed
|
| - // messages that keep piling up.
|
| - ASSERT(IsValidMessage());
|
| - return;
|
| - }
|
| - // TODO(hausner): Handle error conditions returned by Read. We may
|
| - // want to close the debugger connection if we get any errors.
|
| - int bytes_read =
|
| - DebuggerConnectionImpl::Receive(fd_, buf_ + data_length_, max_read);
|
| - if (bytes_read == 0) {
|
| - connection_is_alive_ = false;
|
| - return;
|
| - }
|
| - ASSERT(bytes_read > 0);
|
| - data_length_ += bytes_read;
|
| - ASSERT(data_length_ < buf_length_);
|
| - buf_[data_length_] = '\0';
|
| -}
|
| -
|
| -
|
| -void MessageBuffer::PopMessage() {
|
| - dart::JSONReader msg_reader(buf_);
|
| - const char* end = msg_reader.EndOfObject();
|
| - if (end != NULL) {
|
| - ASSERT(*end == '}');
|
| - end++;
|
| - data_length_ = 0;
|
| - while (*end != '\0') {
|
| - buf_[data_length_] = *end++;
|
| - data_length_++;
|
| - }
|
| - buf_[data_length_] = '\0';
|
| - ASSERT(data_length_ < buf_length_);
|
| - }
|
| -}
|
| -
|
| -
|
| -static bool IsValidJSON(const char* msg) {
|
| - dart::JSONReader r(msg);
|
| - return r.CheckMessage();
|
| -}
|
| -
|
| -
|
| -DebuggerConnectionHandler::DebuggerConnectionHandler(intptr_t debug_fd)
|
| - : debug_fd_(debug_fd), msgbuf_(NULL) {
|
| - msgbuf_ = new MessageBuffer(debug_fd_);
|
| -}
|
| -
|
| -
|
| -DebuggerConnectionHandler::~DebuggerConnectionHandler() {
|
| - CloseDbgConnection();
|
| - DebuggerConnectionHandler::RemoveDebuggerConnection(debug_fd_);
|
| -}
|
| -
|
| -
|
| -int DebuggerConnectionHandler::MessageId() {
|
| - ASSERT(msgbuf_ != NULL);
|
| - return msgbuf_->MessageId();
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::HandleUnknownMsg() {
|
| - int msg_id = msgbuf_->MessageId();
|
| - ASSERT(msg_id >= 0);
|
| - SendError(debug_fd_, msg_id, "unknown debugger command");
|
| -}
|
| -
|
| -
|
| -typedef void (*CommandHandler)(DbgMessage* msg);
|
| -
|
| -struct JSONDebuggerCommand {
|
| - const char* cmd_string;
|
| - CommandHandler handler_function;
|
| -};
|
| -
|
| -
|
| -void DebuggerConnectionHandler::HandleMessages() {
|
| - static JSONDebuggerCommand generic_debugger_commands[] = {
|
| - { "interrupt", HandleInterruptCmd },
|
| - { "getIsolateIds", HandleIsolatesListCmd },
|
| - { NULL, NULL }
|
| - };
|
| -
|
| - for (;;) {
|
| - // Read a message.
|
| - while (!msgbuf_->IsValidMessage() && msgbuf_->Alive()) {
|
| - msgbuf_->ReadData();
|
| - }
|
| - if (!msgbuf_->Alive()) {
|
| - if (trace_debug_protocol) {
|
| - Log::Print("Debugger is exiting HandleMessages loop.\n");
|
| - }
|
| - return;
|
| - }
|
| -
|
| - if (trace_debug_protocol) {
|
| - dart::JSONReader r(msgbuf_->buf());
|
| - const char* msg_end = r.EndOfObject();
|
| - if (msg_end != NULL) {
|
| - intptr_t msg_len = msg_end - msgbuf_->buf();
|
| - int print_len = ((msg_len > kMaxPrintMessageLen)
|
| - ? kMaxPrintMessageLen : msg_len);
|
| - Log::Print("[<<<] Receiving message from debug fd %" Pd ":\n%.*s%s\n",
|
| - debug_fd_, print_len, msgbuf_->buf(),
|
| - ((msg_len > print_len) ? "..." : ""));
|
| - }
|
| - }
|
| -
|
| - // Parse out the command portion from the message.
|
| - dart::JSONReader r(msgbuf_->buf());
|
| - bool found = r.Seek("command");
|
| - if (r.Error()) {
|
| - FATAL("Illegal JSON message received");
|
| - }
|
| - if (!found) {
|
| - Log::Print("'command' not found in JSON message: '%s'\n",
|
| - msgbuf_->buf());
|
| - msgbuf_->PopMessage();
|
| - }
|
| -
|
| - // Check if this is a generic command (not isolate specific).
|
| - int i = 0;
|
| - bool is_handled = false;
|
| - while (generic_debugger_commands[i].cmd_string != NULL) {
|
| - if (r.IsStringLiteral(generic_debugger_commands[i].cmd_string)) {
|
| - DbgMessage* msg = new DbgMessage(i,
|
| - msgbuf_->buf(),
|
| - r.EndOfObject(),
|
| - debug_fd_);
|
| - (*generic_debugger_commands[i].handler_function)(msg);
|
| - is_handled = true;
|
| - msgbuf_->PopMessage();
|
| - delete msg;
|
| - break;
|
| - }
|
| - i++;
|
| - }
|
| - if (!is_handled) {
|
| - // Check if this is an isolate specific command.
|
| - int32_t cmd_idx = DbgMsgQueueList::LookupIsolateCommand(r.ValueChars(),
|
| - r.ValueLen());
|
| - if (cmd_idx != DbgMsgQueueList::kInvalidCommand) {
|
| - const char* start = msgbuf_->buf();
|
| - const char* end = r.EndOfObject();
|
| - // Get debug message queue corresponding to isolate.
|
| - MessageParser msg_parser(start, (end - start));
|
| - Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
|
| - if (!DbgMsgQueueList::AddIsolateMessage(isolate_id,
|
| - cmd_idx,
|
| - msgbuf_->buf(),
|
| - r.EndOfObject(),
|
| - debug_fd_)) {
|
| - SendError(debug_fd_, MessageId(), "Invalid isolate specified");
|
| - }
|
| - msgbuf_->PopMessage();
|
| - continue;
|
| - }
|
| -
|
| - // This is an unrecognized command, report error and move on to next.
|
| - Log::Print("unrecognized command received: '%s'\n", msgbuf_->buf());
|
| - HandleUnknownMsg();
|
| - msgbuf_->PopMessage();
|
| - }
|
| - }
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::SendError(intptr_t debug_fd,
|
| - int msg_id,
|
| - const char* err_msg) {
|
| - dart::TextBuffer msg(64);
|
| - msg.Printf("{\"id\": %d, \"error\": \"Error: ", msg_id);
|
| - msg.AddEscapedString(err_msg);
|
| - msg.Printf("\"}");
|
| - SendMsg(debug_fd, &msg);
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::CloseDbgConnection() {
|
| - if (debug_fd_ >= 0) {
|
| - Socket::Close(debug_fd_);
|
| - }
|
| - if (msgbuf_ != NULL) {
|
| - delete msgbuf_;
|
| - msgbuf_ = NULL;
|
| - }
|
| - // TODO(hausner): Need to tell the VM debugger object to remove all
|
| - // breakpoints.
|
| -}
|
| -
|
| -
|
| -// The vm service relies on certain debugger functionality.
|
| -void DebuggerConnectionHandler::InitForVmService() {
|
| - MonitorLocker ml(handler_lock_);
|
| - DbgMsgQueueList::Initialize();
|
| -}
|
| -
|
| -
|
| -int DebuggerConnectionHandler::StartHandler(const char* address,
|
| - int port_number) {
|
| - ASSERT(handler_lock_ != NULL);
|
| - MonitorLocker ml(handler_lock_);
|
| - if (IsListening()) {
|
| - // The debugger connection handler was already started.
|
| - return Socket::GetPort(listener_fd_);
|
| - }
|
| -
|
| - // First setup breakpoint, exception and delayed breakpoint handlers.
|
| - DbgMsgQueueList::Initialize();
|
| -
|
| - // Initialize the socket implementation.
|
| - if (!Socket::Initialize()) {
|
| - FATAL("Failed initializing socket implementation.");
|
| - }
|
| -
|
| - // Now setup a listener socket and start a thread which will
|
| - // listen, accept connections from debuggers, read and handle/dispatch
|
| - // debugger commands received on these connections.
|
| - ASSERT(listener_fd_ == -1);
|
| - OSError *os_error;
|
| - AddressList<SocketAddress>* addresses =
|
| - Socket::LookupAddress(address, -1, &os_error);
|
| - RawAddr addr = addresses->GetAt(0)->addr();
|
| - SocketAddress::SetAddrPort(&addr, port_number);
|
| - listener_fd_ = ServerSocket::CreateBindListen(addr, 1);
|
| - delete addresses;
|
| - if (listener_fd_ < 0) {
|
| - fprintf(stderr, "%s", "Could not initialize debug socket\n");
|
| - fflush(stderr);
|
| - exit(255);
|
| - }
|
| -
|
| - port_number = Socket::GetPort(listener_fd_);
|
| - DebuggerConnectionImpl::StartHandler(port_number);
|
| - return port_number;
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::StopHandler() {
|
| - if (IsConnected()) {
|
| - DebuggerConnectionImpl::StopHandler(singleton_handler->debug_fd());
|
| - }
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::WaitForConnection() {
|
| - ASSERT(handler_lock_ != NULL);
|
| - MonitorLocker ml(handler_lock_);
|
| - if (!IsListening()) {
|
| - // If we are only running the vm service, don't wait for
|
| - // connections.
|
| - return;
|
| - }
|
| - while (!IsConnected()) {
|
| - Monitor::WaitResult res = ml.Wait();
|
| - ASSERT(res == Monitor::kNotified);
|
| - }
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::SendMsg(intptr_t debug_fd,
|
| - dart::TextBuffer* msg) {
|
| - ASSERT(handler_lock_ != NULL);
|
| - MonitorLocker ml(handler_lock_);
|
| - SendMsgHelper(debug_fd, msg);
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::BroadcastMsg(dart::TextBuffer* msg) {
|
| - ASSERT(handler_lock_ != NULL);
|
| - MonitorLocker ml(handler_lock_);
|
| - if (!IsListening()) {
|
| - // If we are only running the vm service, don't try to broadcast
|
| - // to debugger clients.
|
| - return;
|
| - }
|
| - // TODO(asiva): Once we support connection to multiple debuggers
|
| - // we need to send the message to all of them.
|
| - ASSERT(singleton_handler != NULL);
|
| - SendMsgHelper(singleton_handler->debug_fd(), msg);
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::SendMsgHelper(intptr_t debug_fd,
|
| - dart::TextBuffer* msg) {
|
| - ASSERT(debug_fd >= 0);
|
| - ASSERT(IsValidJSON(msg->buf()));
|
| -
|
| - if (trace_debug_protocol) {
|
| - int print_len = ((msg->length() > kMaxPrintMessageLen)
|
| - ? kMaxPrintMessageLen : msg->length());
|
| - Log::Print("[>>>] Sending message to debug fd %" Pd ":\n%.*s%s\n",
|
| - debug_fd, print_len, msg->buf(),
|
| - ((msg->length() > print_len) ? "..." : ""));
|
| - }
|
| -
|
| - // Sending messages in short pieces can be used to stress test the
|
| - // debugger front-end's message handling code.
|
| - const bool send_in_pieces = false;
|
| - if (send_in_pieces) {
|
| - intptr_t remaining = msg->length();
|
| - intptr_t sent = 0;
|
| - const intptr_t max_piece_len = 122; // Pretty arbitrary, not a power of 2.
|
| - Monitor sleep;
|
| - while (remaining > 0) {
|
| - intptr_t piece_len = remaining;
|
| - if (piece_len > max_piece_len) {
|
| - piece_len = max_piece_len;
|
| - }
|
| - intptr_t written =
|
| - DebuggerConnectionImpl::Send(debug_fd, msg->buf() + sent, piece_len);
|
| - ASSERT(written == piece_len);
|
| - sent += written;
|
| - remaining -= written;
|
| - // Wait briefly so the OS does not coalesce message fragments.
|
| - {
|
| - MonitorLocker ml(&sleep);
|
| - ml.Wait(10);
|
| - }
|
| - }
|
| - return;
|
| - }
|
| - intptr_t bytes_written =
|
| - DebuggerConnectionImpl::Send(debug_fd, msg->buf(), msg->length());
|
| - ASSERT(msg->length() == bytes_written);
|
| - // TODO(hausner): Error checking. Probably just shut down the debugger
|
| - // session if we there is an error while writing.
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::AcceptDbgConnection(intptr_t debug_fd) {
|
| - Socket::SetNoDelay(debug_fd, true);
|
| - AddNewDebuggerConnection(debug_fd);
|
| - {
|
| - ASSERT(handler_lock_ != NULL);
|
| - MonitorLocker ml(handler_lock_);
|
| - ml.NotifyAll();
|
| - }
|
| - // TODO(asiva): Once we implement support for multiple connections
|
| - // we should have a different callback for wakeups on fds which
|
| - // are not the listener_fd_.
|
| - // In that callback we would lookup the handler object
|
| - // corresponding to that fd and invoke HandleMessages on it.
|
| - // For now we run that code here.
|
| - DebuggerConnectionHandler* handler = GetDebuggerConnectionHandler(debug_fd);
|
| - if (handler != NULL) {
|
| - handler->HandleMessages();
|
| - delete handler;
|
| - }
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::HandleInterruptCmd(DbgMessage* in_msg) {
|
| - MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
|
| - int msg_id = msg_parser.MessageId();
|
| - Dart_IsolateId isolate_id = msg_parser.GetInt64Param("isolateId");
|
| - if (isolate_id == ILLEGAL_ISOLATE_ID || Dart_GetIsolate(isolate_id) == NULL) {
|
| - in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
|
| - return;
|
| - }
|
| - if (!DbgMsgQueueList::InterruptIsolate(isolate_id)) {
|
| - in_msg->SendErrorReply(msg_id, "Invalid isolate specified");
|
| - return;
|
| - }
|
| - dart::TextBuffer msg(64);
|
| - msg.Printf("{ \"id\": %d }", msg_id);
|
| - in_msg->SendReply(&msg);
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::HandleIsolatesListCmd(DbgMessage* in_msg) {
|
| - MessageParser msg_parser(in_msg->buffer(), in_msg->buffer_len());
|
| - int msg_id = msg_parser.MessageId();
|
| - ASSERT(msg_id >= 0);
|
| - dart::TextBuffer msg(64);
|
| - msg.Printf("{ \"id\": %d, \"result\": { \"isolateIds\": [", msg_id);
|
| - DbgMsgQueueList::ListIsolateIds(&msg);
|
| - msg.Printf("]}}");
|
| - in_msg->SendReply(&msg);
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::AddNewDebuggerConnection(intptr_t debug_fd) {
|
| - // TODO(asiva): Support multiple debugger connections, for now we just
|
| - // create one handler, store it in a static variable and use it.
|
| - ASSERT(singleton_handler == NULL);
|
| - singleton_handler = new DebuggerConnectionHandler(debug_fd);
|
| -}
|
| -
|
| -
|
| -void DebuggerConnectionHandler::RemoveDebuggerConnection(intptr_t debug_fd) {
|
| - // TODO(asiva): Support multiple debugger connections, for now we just
|
| - // set the static handler back to NULL.
|
| - ASSERT(singleton_handler != NULL);
|
| - singleton_handler = NULL;
|
| -}
|
| -
|
| -
|
| -DebuggerConnectionHandler*
|
| -DebuggerConnectionHandler::GetDebuggerConnectionHandler(intptr_t debug_fd) {
|
| - // TODO(asiva): Support multiple debugger connections, for now we just
|
| - // return the one static handler that was created.
|
| - ASSERT(singleton_handler != NULL);
|
| - return singleton_handler;
|
| -}
|
| -
|
| -
|
| -bool DebuggerConnectionHandler::IsConnected() {
|
| - // TODO(asiva): Support multiple debugger connections.
|
| - // Return true if a connection has been established.
|
| - return singleton_handler != NULL;
|
| -}
|
| -
|
| -} // namespace bin
|
| -} // namespace dart
|
|
|