summaryrefslogtreecommitdiffstats
path: root/chromium/v8/src/debug-agent.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/v8/src/debug-agent.cc')
-rw-r--r--chromium/v8/src/debug-agent.cc503
1 files changed, 0 insertions, 503 deletions
diff --git a/chromium/v8/src/debug-agent.cc b/chromium/v8/src/debug-agent.cc
deleted file mode 100644
index 51823aaf24c..00000000000
--- a/chromium/v8/src/debug-agent.cc
+++ /dev/null
@@ -1,503 +0,0 @@
-// Copyright 2012 the V8 project authors. All rights reserved.
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are
-// met:
-//
-// * Redistributions of source code must retain the above copyright
-// notice, this list of conditions and the following disclaimer.
-// * Redistributions in binary form must reproduce the above
-// copyright notice, this list of conditions and the following
-// disclaimer in the documentation and/or other materials provided
-// with the distribution.
-// * Neither the name of Google Inc. nor the names of its
-// contributors may be used to endorse or promote products derived
-// from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
-#ifdef ENABLE_DEBUGGER_SUPPORT
-
-#include "v8.h"
-#include "debug.h"
-#include "debug-agent.h"
-#include "platform/socket.h"
-
-namespace v8 {
-namespace internal {
-
-// Public V8 debugger API message handler function. This function just delegates
-// to the debugger agent through it's data parameter.
-void DebuggerAgentMessageHandler(const v8::Debug::Message& message) {
- Isolate* isolate = reinterpret_cast<Isolate*>(message.GetIsolate());
- DebuggerAgent* agent = isolate->debugger_agent_instance();
- ASSERT(agent != NULL);
- agent->DebuggerMessage(message);
-}
-
-
-DebuggerAgent::DebuggerAgent(Isolate* isolate, const char* name, int port)
- : Thread(name),
- isolate_(isolate),
- name_(StrDup(name)),
- port_(port),
- server_(new Socket),
- terminate_(false),
- session_(NULL),
- terminate_now_(0),
- listening_(0) {
- ASSERT(isolate_->debugger_agent_instance() == NULL);
- isolate_->set_debugger_agent_instance(this);
-}
-
-
-DebuggerAgent::~DebuggerAgent() {
- isolate_->set_debugger_agent_instance(NULL);
- delete server_;
-}
-
-
-// Debugger agent main thread.
-void DebuggerAgent::Run() {
- // Allow this socket to reuse port even if still in TIME_WAIT.
- server_->SetReuseAddress(true);
-
- // First bind the socket to the requested port.
- bool bound = false;
- while (!bound && !terminate_) {
- bound = server_->Bind(port_);
-
- // If an error occurred wait a bit before retrying. The most common error
- // would be that the port is already in use so this avoids a busy loop and
- // make the agent take over the port when it becomes free.
- if (!bound) {
- const TimeDelta kTimeout = TimeDelta::FromSeconds(1);
- PrintF("Failed to open socket on port %d, "
- "waiting %d ms before retrying\n", port_,
- static_cast<int>(kTimeout.InMilliseconds()));
- if (!terminate_now_.WaitFor(kTimeout)) {
- if (terminate_) return;
- }
- }
- }
-
- // Accept connections on the bound port.
- while (!terminate_) {
- bool ok = server_->Listen(1);
- listening_.Signal();
- if (ok) {
- // Accept the new connection.
- Socket* client = server_->Accept();
- ok = client != NULL;
- if (ok) {
- // Create and start a new session.
- CreateSession(client);
- }
- }
- }
-}
-
-
-void DebuggerAgent::Shutdown() {
- // Set the termination flag.
- terminate_ = true;
-
- // Signal termination and make the server exit either its listen call or its
- // binding loop. This makes sure that no new sessions can be established.
- terminate_now_.Signal();
- server_->Shutdown();
- Join();
-
- // Close existing session if any.
- CloseSession();
-}
-
-
-void DebuggerAgent::WaitUntilListening() {
- listening_.Wait();
-}
-
-static const char* kCreateSessionMessage =
- "Remote debugging session already active\r\n";
-
-void DebuggerAgent::CreateSession(Socket* client) {
- LockGuard<RecursiveMutex> session_access_guard(&session_access_);
-
- // If another session is already established terminate this one.
- if (session_ != NULL) {
- int len = StrLength(kCreateSessionMessage);
- int res = client->Send(kCreateSessionMessage, len);
- delete client;
- USE(res);
- return;
- }
-
- // Create a new session and hook up the debug message handler.
- session_ = new DebuggerAgentSession(this, client);
- isolate_->debugger()->SetMessageHandler(DebuggerAgentMessageHandler);
- session_->Start();
-}
-
-
-void DebuggerAgent::CloseSession() {
- LockGuard<RecursiveMutex> session_access_guard(&session_access_);
-
- // Terminate the session.
- if (session_ != NULL) {
- session_->Shutdown();
- session_->Join();
- delete session_;
- session_ = NULL;
- }
-}
-
-
-void DebuggerAgent::DebuggerMessage(const v8::Debug::Message& message) {
- LockGuard<RecursiveMutex> session_access_guard(&session_access_);
-
- // Forward the message handling to the session.
- if (session_ != NULL) {
- v8::String::Value val(message.GetJSON());
- session_->DebuggerMessage(Vector<uint16_t>(const_cast<uint16_t*>(*val),
- val.length()));
- }
-}
-
-
-void DebuggerAgent::OnSessionClosed(DebuggerAgentSession* session) {
- // Don't do anything during termination.
- if (terminate_) {
- return;
- }
-
- // Terminate the session.
- LockGuard<RecursiveMutex> session_access_guard(&session_access_);
- ASSERT(session == session_);
- if (session == session_) {
- session_->Shutdown();
- delete session_;
- session_ = NULL;
- }
-}
-
-
-void DebuggerAgentSession::Run() {
- // Send the hello message.
- bool ok = DebuggerAgentUtil::SendConnectMessage(client_, *agent_->name_);
- if (!ok) return;
-
- while (true) {
- // Read data from the debugger front end.
- SmartArrayPointer<char> message =
- DebuggerAgentUtil::ReceiveMessage(client_);
-
- const char* msg = *message;
- bool is_closing_session = (msg == NULL);
-
- if (msg == NULL) {
- // If we lost the connection, then simulate a disconnect msg:
- msg = "{\"seq\":1,\"type\":\"request\",\"command\":\"disconnect\"}";
-
- } else {
- // Check if we're getting a disconnect request:
- const char* disconnectRequestStr =
- "\"type\":\"request\",\"command\":\"disconnect\"}";
- const char* result = strstr(msg, disconnectRequestStr);
- if (result != NULL) {
- is_closing_session = true;
- }
- }
-
- // Convert UTF-8 to UTF-16.
- unibrow::Utf8Decoder<128> decoder(msg, StrLength(msg));
- int utf16_length = decoder.Utf16Length();
- ScopedVector<uint16_t> temp(utf16_length + 1);
- decoder.WriteUtf16(temp.start(), utf16_length);
-
- // Send the request received to the debugger.
- v8::Debug::SendCommand(temp.start(),
- utf16_length,
- NULL,
- reinterpret_cast<v8::Isolate*>(agent_->isolate()));
-
- if (is_closing_session) {
- // Session is closed.
- agent_->OnSessionClosed(this);
- return;
- }
- }
-}
-
-
-void DebuggerAgentSession::DebuggerMessage(Vector<uint16_t> message) {
- DebuggerAgentUtil::SendMessage(client_, message);
-}
-
-
-void DebuggerAgentSession::Shutdown() {
- // Shutdown the socket to end the blocking receive.
- client_->Shutdown();
-}
-
-
-const char* const DebuggerAgentUtil::kContentLength = "Content-Length";
-
-
-SmartArrayPointer<char> DebuggerAgentUtil::ReceiveMessage(Socket* conn) {
- int received;
-
- // Read header.
- int content_length = 0;
- while (true) {
- const int kHeaderBufferSize = 80;
- char header_buffer[kHeaderBufferSize];
- int header_buffer_position = 0;
- char c = '\0'; // One character receive buffer.
- char prev_c = '\0'; // Previous character.
-
- // Read until CRLF.
- while (!(c == '\n' && prev_c == '\r')) {
- prev_c = c;
- received = conn->Receive(&c, 1);
- if (received == 0) {
- PrintF("Error %d\n", Socket::GetLastError());
- return SmartArrayPointer<char>();
- }
-
- // Add character to header buffer.
- if (header_buffer_position < kHeaderBufferSize) {
- header_buffer[header_buffer_position++] = c;
- }
- }
-
- // Check for end of header (empty header line).
- if (header_buffer_position == 2) { // Receive buffer contains CRLF.
- break;
- }
-
- // Terminate header.
- ASSERT(header_buffer_position > 1); // At least CRLF is received.
- ASSERT(header_buffer_position <= kHeaderBufferSize);
- header_buffer[header_buffer_position - 2] = '\0';
-
- // Split header.
- char* key = header_buffer;
- char* value = NULL;
- for (int i = 0; header_buffer[i] != '\0'; i++) {
- if (header_buffer[i] == ':') {
- header_buffer[i] = '\0';
- value = header_buffer + i + 1;
- while (*value == ' ') {
- value++;
- }
- break;
- }
- }
-
- // Check that key is Content-Length.
- if (strcmp(key, kContentLength) == 0) {
- // Get the content length value if present and within a sensible range.
- if (value == NULL || strlen(value) > 7) {
- return SmartArrayPointer<char>();
- }
- for (int i = 0; value[i] != '\0'; i++) {
- // Bail out if illegal data.
- if (value[i] < '0' || value[i] > '9') {
- return SmartArrayPointer<char>();
- }
- content_length = 10 * content_length + (value[i] - '0');
- }
- } else {
- // For now just print all other headers than Content-Length.
- PrintF("%s: %s\n", key, value != NULL ? value : "(no value)");
- }
- }
-
- // Return now if no body.
- if (content_length == 0) {
- return SmartArrayPointer<char>();
- }
-
- // Read body.
- char* buffer = NewArray<char>(content_length + 1);
- received = ReceiveAll(conn, buffer, content_length);
- if (received < content_length) {
- PrintF("Error %d\n", Socket::GetLastError());
- return SmartArrayPointer<char>();
- }
- buffer[content_length] = '\0';
-
- return SmartArrayPointer<char>(buffer);
-}
-
-
-bool DebuggerAgentUtil::SendConnectMessage(Socket* conn,
- const char* embedding_host) {
- static const int kBufferSize = 80;
- char buffer[kBufferSize]; // Sending buffer.
- bool ok;
- int len;
-
- // Send the header.
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "Type: connect\r\n");
- ok = conn->Send(buffer, len);
- if (!ok) return false;
-
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "V8-Version: %s\r\n", v8::V8::GetVersion());
- ok = conn->Send(buffer, len);
- if (!ok) return false;
-
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "Protocol-Version: 1\r\n");
- ok = conn->Send(buffer, len);
- if (!ok) return false;
-
- if (embedding_host != NULL) {
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "Embedding-Host: %s\r\n", embedding_host);
- ok = conn->Send(buffer, len);
- if (!ok) return false;
- }
-
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "%s: 0\r\n", kContentLength);
- ok = conn->Send(buffer, len);
- if (!ok) return false;
-
- // Terminate header with empty line.
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
- ok = conn->Send(buffer, len);
- if (!ok) return false;
-
- // No body for connect message.
-
- return true;
-}
-
-
-bool DebuggerAgentUtil::SendMessage(Socket* conn,
- const Vector<uint16_t> message) {
- static const int kBufferSize = 80;
- char buffer[kBufferSize]; // Sending buffer both for header and body.
-
- // Calculate the message size in UTF-8 encoding.
- int utf8_len = 0;
- int previous = unibrow::Utf16::kNoPreviousCharacter;
- for (int i = 0; i < message.length(); i++) {
- uint16_t character = message[i];
- utf8_len += unibrow::Utf8::Length(character, previous);
- previous = character;
- }
-
- // Send the header.
- int len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "%s: %d\r\n", kContentLength, utf8_len);
- if (conn->Send(buffer, len) < len) {
- return false;
- }
-
- // Terminate header with empty line.
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
- if (conn->Send(buffer, len) < len) {
- return false;
- }
-
- // Send message body as UTF-8.
- int buffer_position = 0; // Current buffer position.
- previous = unibrow::Utf16::kNoPreviousCharacter;
- for (int i = 0; i < message.length(); i++) {
- // Write next UTF-8 encoded character to buffer.
- uint16_t character = message[i];
- buffer_position +=
- unibrow::Utf8::Encode(buffer + buffer_position, character, previous);
- ASSERT(buffer_position <= kBufferSize);
-
- // Send buffer if full or last character is encoded.
- if (kBufferSize - buffer_position <
- unibrow::Utf16::kMaxExtraUtf8BytesForOneUtf16CodeUnit ||
- i == message.length() - 1) {
- if (unibrow::Utf16::IsLeadSurrogate(character)) {
- const int kEncodedSurrogateLength =
- unibrow::Utf16::kUtf8BytesToCodeASurrogate;
- ASSERT(buffer_position >= kEncodedSurrogateLength);
- len = buffer_position - kEncodedSurrogateLength;
- if (conn->Send(buffer, len) < len) {
- return false;
- }
- for (int i = 0; i < kEncodedSurrogateLength; i++) {
- buffer[i] = buffer[buffer_position + i];
- }
- buffer_position = kEncodedSurrogateLength;
- } else {
- len = buffer_position;
- if (conn->Send(buffer, len) < len) {
- return false;
- }
- buffer_position = 0;
- }
- }
- previous = character;
- }
-
- return true;
-}
-
-
-bool DebuggerAgentUtil::SendMessage(Socket* conn,
- const v8::Handle<v8::String> request) {
- static const int kBufferSize = 80;
- char buffer[kBufferSize]; // Sending buffer both for header and body.
-
- // Convert the request to UTF-8 encoding.
- v8::String::Utf8Value utf8_request(request);
-
- // Send the header.
- int len = OS::SNPrintF(Vector<char>(buffer, kBufferSize),
- "Content-Length: %d\r\n", utf8_request.length());
- if (conn->Send(buffer, len) < len) {
- return false;
- }
-
- // Terminate header with empty line.
- len = OS::SNPrintF(Vector<char>(buffer, kBufferSize), "\r\n");
- if (conn->Send(buffer, len) < len) {
- return false;
- }
-
- // Send message body as UTF-8.
- len = utf8_request.length();
- if (conn->Send(*utf8_request, len) < len) {
- return false;
- }
-
- return true;
-}
-
-
-// Receive the full buffer before returning unless an error occours.
-int DebuggerAgentUtil::ReceiveAll(Socket* conn, char* data, int len) {
- int total_received = 0;
- while (total_received < len) {
- int received = conn->Receive(data + total_received, len - total_received);
- if (received == 0) {
- return total_received;
- }
- total_received += received;
- }
- return total_received;
-}
-
-} } // namespace v8::internal
-
-#endif // ENABLE_DEBUGGER_SUPPORT