Remove DebuggerAgent.

R=svenpanne@chromium.org

Review URL: https://codereview.chromium.org/279423004

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21315 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-05-14 16:28:46 +00:00
parent c0ec7f20c8
commit 33fba3bfa1
17 changed files with 92 additions and 1445 deletions

View File

@ -201,20 +201,6 @@ class V8_EXPORT Debug {
const uint16_t* command, int length,
ClientData* client_data = NULL);
/**
* Register a callback function to be called when a debug message has been
* received and is ready to be processed. For the debug messages to be
* processed V8 needs to be entered, and in certain embedding scenarios this
* callback can be used to make sure V8 is entered for the debug message to
* be processed. Note that debug messages will only be processed if there is
* a V8 break. This can happen automatically by using the option
* --debugger-auto-break.
* \param provide_locker requires that V8 acquires v8::Locker for you before
* calling handler
*/
static void SetDebugMessageDispatchHandler(
DebugMessageDispatchHandler handler, bool provide_locker = false);
/**
* Run a JavaScript function in the debugger.
* \param fun the function to call
@ -241,22 +227,6 @@ class V8_EXPORT Debug {
*/
static Local<Value> GetMirror(v8::Handle<v8::Value> obj);
/**
* Enable the V8 builtin debug agent. The debugger agent will listen on the
* supplied TCP/IP port for remote debugger connection.
* \param name the name of the embedding application
* \param port the TCP/IP port to listen on
* \param wait_for_connection whether V8 should pause on a first statement
* allowing remote debugger to connect before anything interesting happened
*/
static bool EnableAgent(const char* name, int port,
bool wait_for_connection = false);
/**
* Disable the V8 builtin debug agent. The TCP/IP connection will be closed.
*/
static void DisableAgent();
/**
* Makes V8 process all pending debug messages.
*
@ -275,10 +245,6 @@ class V8_EXPORT Debug {
* until V8 gets control again; however, embedding application may improve
* this by manually calling this method.
*
* It makes sense to call this method whenever a new debug message arrived and
* V8 is not already running. Method v8::Debug::SetDebugMessageDispatchHandler
* should help with the former condition.
*
* Technically this method in many senses is equivalent to executing empty
* script:
* 1. It does nothing except for processing all pending debug messages.

View File

@ -109,28 +109,6 @@ bool RunCppCycle(v8::Handle<v8::Script> script,
v8::Persistent<v8::Context> debug_message_context;
void DispatchDebugMessages() {
// We are in some random thread. We should already have v8::Locker acquired
// (we requested this when registered this callback). We was called
// because new debug messages arrived; they may have already been processed,
// but we shouldn't worry about this.
//
// All we have to do is to set context and call ProcessDebugMessages.
//
// We should decide which V8 context to use here. This is important for
// "evaluate" command, because it must be executed some context.
// In our sample we have only one context, so there is nothing really to
// think about.
v8::Isolate* isolate = v8::Isolate::GetCurrent();
v8::HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate, debug_message_context);
v8::Context::Scope scope(context);
v8::Debug::ProcessDebugMessages();
}
int RunMain(int argc, char* argv[]) {
v8::V8::SetFlagsFromCommandLine(&argc, argv, true);
v8::Isolate* isolate = v8::Isolate::New();
@ -142,10 +120,6 @@ int RunMain(int argc, char* argv[]) {
v8::Handle<v8::Value> script_name;
int script_param_counter = 0;
int port_number = -1;
bool wait_for_connection = false;
bool support_callback = false;
MainCycleType cycle_type = CycleInCpp;
for (int i = 1; i < argc; i++) {
@ -158,13 +132,6 @@ int RunMain(int argc, char* argv[]) {
cycle_type = CycleInCpp;
} else if (strcmp(str, "--main-cycle-in-js") == 0) {
cycle_type = CycleInJs;
} else if (strcmp(str, "--callback") == 0) {
support_callback = true;
} else if (strcmp(str, "--wait-for-connection") == 0) {
wait_for_connection = true;
} else if (strcmp(str, "-p") == 0 && i + 1 < argc) {
port_number = atoi(argv[i + 1]); // NOLINT
i++;
} else if (strncmp(str, "--", 2) == 0) {
printf("Warning: unknown flag %s.\nTry --help for options\n", str);
} else if (strcmp(str, "-e") == 0 && i + 1 < argc) {
@ -214,14 +181,6 @@ int RunMain(int argc, char* argv[]) {
debug_message_context.Reset(isolate, context);
if (support_callback) {
v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
}
if (port_number != -1) {
v8::Debug::EnableAgent("lineprocessor", port_number, wait_for_connection);
}
bool report_exceptions = true;
v8::Handle<v8::Script> script;

View File

@ -6824,22 +6824,11 @@ void Debug::SendCommand(Isolate* isolate,
int length,
ClientData* client_data) {
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
internal_isolate->debugger()->ProcessCommand(
internal_isolate->debugger()->EnqueueCommandMessage(
i::Vector<const uint16_t>(command, length), client_data);
}
void Debug::SetDebugMessageDispatchHandler(
DebugMessageDispatchHandler handler, bool provide_locker) {
i::Isolate* isolate = i::Isolate::Current();
EnsureInitializedForIsolate(isolate,
"v8::Debug::SetDebugMessageDispatchHandler");
ENTER_V8(isolate);
isolate->debugger()->SetDebugMessageDispatchHandler(
handler, provide_locker);
}
Local<Value> Debug::Call(v8::Handle<v8::Function> fun,
v8::Handle<v8::Value> data) {
i::Isolate* isolate = i::Isolate::Current();
@ -6891,17 +6880,6 @@ Local<Value> Debug::GetMirror(v8::Handle<v8::Value> obj) {
}
bool Debug::EnableAgent(const char* name, int port, bool wait_for_connection) {
return i::Isolate::Current()->debugger()->StartAgent(name, port,
wait_for_connection);
}
void Debug::DisableAgent() {
return i::Isolate::Current()->debugger()->StopAgent();
}
void Debug::ProcessDebugMessages() {
i::Execution::ProcessDebugMessages(i::Isolate::Current(), true);
}

View File

@ -4,27 +4,16 @@
#include "d8.h"
#include "d8-debug.h"
#include "debug-agent.h"
#include "platform/socket.h"
namespace v8 {
static bool was_running = true;
void PrintPrompt(bool is_running) {
const char* prompt = is_running? "> " : "dbg> ";
was_running = is_running;
printf("%s", prompt);
fflush(stdout);
}
void PrintPrompt() {
PrintPrompt(was_running);
}
void HandleDebugEvent(const Debug::EventDetails& event_details) {
// TODO(svenpanne) There should be a way to retrieve this in the callback.
Isolate* isolate = Isolate::GetCurrent();
@ -140,208 +129,4 @@ void HandleDebugEvent(const Debug::EventDetails& event_details) {
}
}
void RunRemoteDebugger(Isolate* isolate, int port) {
RemoteDebugger debugger(isolate, port);
debugger.Run();
}
void RemoteDebugger::Run() {
bool ok;
// Connect to the debugger agent.
conn_ = new i::Socket;
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::GetLastError());
return;
}
// Start the receiver thread.
ReceiverThread receiver(this);
receiver.Start();
// Start the keyboard thread.
KeyboardThread keyboard(this);
keyboard.Start();
PrintPrompt();
// 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;
}
delete conn_;
conn_ = NULL;
// Wait for the receiver thread to end.
receiver.Join();
}
void RemoteDebugger::MessageReceived(i::SmartArrayPointer<char> message) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kMessage, message);
AddEvent(event);
}
void RemoteDebugger::KeyboardCommand(i::SmartArrayPointer<char> command) {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kKeyboard, command);
AddEvent(event);
}
void RemoteDebugger::ConnectionClosed() {
RemoteDebuggerEvent* event =
new RemoteDebuggerEvent(RemoteDebuggerEvent::kDisconnect,
i::SmartArrayPointer<char>());
AddEvent(event);
}
void RemoteDebugger::AddEvent(RemoteDebuggerEvent* event) {
i::LockGuard<i::Mutex> lock_guard(&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::LockGuard<i::Mutex> lock_guard(&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) {
Locker lock(isolate_);
HandleScope scope(isolate_);
// Print the event details.
TryCatch try_catch;
Handle<Object> details = Shell::DebugMessageDetails(
isolate_, Handle<String>::Cast(String::NewFromUtf8(isolate_, message)));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate_, &try_catch);
PrintPrompt();
return;
}
String::Utf8Value str(details->Get(String::NewFromUtf8(isolate_, "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");
}
bool is_running = details->Get(String::NewFromUtf8(isolate_, "running"))
->ToBoolean()
->Value();
PrintPrompt(is_running);
}
void RemoteDebugger::HandleKeyboardCommand(char* command) {
Locker lock(isolate_);
HandleScope scope(isolate_);
// Convert the debugger command to a JSON debugger request.
TryCatch try_catch;
Handle<Value> request = Shell::DebugCommandToJSONRequest(
isolate_, String::NewFromUtf8(isolate_, command));
if (try_catch.HasCaught()) {
Shell::ReportException(isolate_, &try_catch);
PrintPrompt();
return;
}
// If undefined is returned the command was handled internally and there is
// no JSON to send.
if (request->IsUndefined()) {
PrintPrompt();
return;
}
// Send the JSON debugger request.
i::DebuggerAgentUtil::SendMessage(conn_, Handle<String>::Cast(request));
}
void ReceiverThread::Run() {
// Receive the connect message (with empty body).
i::SmartArrayPointer<char> message =
i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
ASSERT(message.get() == NULL);
while (true) {
// Receive a message.
i::SmartArrayPointer<char> message =
i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn());
if (message.get() == 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::SmartArrayPointer<char>(i::StrDup(command)));
}
}
} // namespace v8

View File

@ -8,125 +8,12 @@
#include "d8.h"
#include "debug.h"
#include "platform/socket.h"
namespace v8 {
void HandleDebugEvent(const Debug::EventDetails& event_details);
// Start the remove debugger connecting to a V8 debugger agent on the specified
// port.
void RunRemoteDebugger(Isolate* isolate, int port);
// Forward declerations.
class RemoteDebuggerEvent;
class ReceiverThread;
// Remote debugging class.
class RemoteDebugger {
public:
explicit RemoteDebugger(Isolate* isolate, int port)
: isolate_(isolate),
port_(port),
event_available_(0),
head_(NULL), tail_(NULL) {}
void Run();
// Handle events from the subordinate threads.
void MessageReceived(i::SmartArrayPointer<char> message);
void KeyboardCommand(i::SmartArrayPointer<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_; }
Isolate* isolate_;
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)
: Thread("d8:ReceiverThrd"),
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)
: Thread("d8:KeyboardThrd"),
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::SmartArrayPointer<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_.get(); }
private:
void set_next(RemoteDebuggerEvent* event) { next_ = event; }
RemoteDebuggerEvent* next() { return next_; }
int type_;
i::SmartArrayPointer<char> data_;
RemoteDebuggerEvent* next_;
friend class RemoteDebugger;
};
} // namespace v8

View File

@ -83,7 +83,7 @@ bool ReadLineEditor::Close() {
Handle<String> ReadLineEditor::Prompt(const char* prompt) {
char* result = NULL;
{ // Release lock for blocking input.
Unlocker unlock(Isolate::GetCurrent());
Unlocker unlock(isolate_);
result = readline(prompt);
}
if (result == NULL) return Handle<String>();

View File

@ -638,16 +638,6 @@ Local<Value> Shell::DebugCommandToJSONRequest(Isolate* isolate,
}
void Shell::DispatchDebugMessages() {
Isolate* isolate = v8::Isolate::GetCurrent();
HandleScope handle_scope(isolate);
v8::Local<v8::Context> context =
v8::Local<v8::Context>::New(isolate, Shell::evaluation_context_);
v8::Context::Scope context_scope(context);
v8::Debug::ProcessDebugMessages();
}
int32_t* Counter::Bind(const char* name, bool is_histogram) {
int i;
for (i = 0; i < kMaxNameSize - 1 && name[i]; i++)
@ -796,9 +786,7 @@ void Shell::InstallUtilityScript(Isolate* isolate) {
script_object->set_type(i::Smi::FromInt(i::Script::TYPE_NATIVE));
// Start the in-process debugger if requested.
if (i::FLAG_debugger && !i::FLAG_debugger_agent) {
v8::Debug::SetDebugEventListener(HandleDebugEvent);
}
if (i::FLAG_debugger) v8::Debug::SetDebugEventListener(HandleDebugEvent);
}
#endif // !V8_SHARED
@ -920,12 +908,6 @@ void Shell::InitializeDebugger(Isolate* isolate) {
Handle<ObjectTemplate> global_template = CreateGlobalTemplate(isolate);
utility_context_.Reset(isolate,
Context::New(isolate, NULL, global_template));
// Start the debugger agent if requested.
if (i::FLAG_debugger_agent) {
v8::Debug::EnableAgent("d8 shell", i::FLAG_debugger_port, true);
v8::Debug::SetDebugMessageDispatchHandler(DispatchDebugMessages, true);
}
#endif // !V8_SHARED
}
@ -1552,19 +1534,8 @@ int Shell::Main(int argc, char* argv[]) {
result = RunMain(isolate, argc, argv);
}
#ifndef V8_SHARED
// Run remote debugger if requested, but never on --test
if (i::FLAG_remote_debugger && !options.test_shell) {
InstallUtilityScript(isolate);
RunRemoteDebugger(isolate, i::FLAG_debugger_port);
return 0;
}
#endif // !V8_SHARED
// Run interactive shell if explicitly requested or if no script has been
// executed, but never on --test
if (( options.interactive_shell || !options.script_executed )
&& !options.test_shell ) {
#ifndef V8_SHARED

View File

@ -265,7 +265,6 @@ class Shell : public i::AllStatic {
Handle<String> message);
static Local<Value> DebugCommandToJSONRequest(Isolate* isolate,
Handle<String> command);
static void DispatchDebugMessages();
static void PerformanceNow(const v8::FunctionCallbackInfo<v8::Value>& args);
#endif // !V8_SHARED

View File

@ -1,481 +0,0 @@
// Copyright 2012 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#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()));
}
}
DebuggerAgentSession::~DebuggerAgentSession() {
delete client_;
}
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_.get());
if (!ok) return;
while (true) {
// Read data from the debugger front end.
SmartArrayPointer<char> message =
DebuggerAgentUtil::ReceiveMessage(client_);
const char* msg = message.get();
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(reinterpret_cast<v8::Isolate*>(agent_->isolate()),
temp.start(),
utf16_length,
NULL);
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

View File

@ -1,93 +0,0 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_DEBUG_AGENT_H_
#define V8_DEBUG_AGENT_H_
#include "../include/v8-debug.h"
#include "platform.h"
namespace v8 {
namespace internal {
// Forward decelrations.
class DebuggerAgentSession;
class Socket;
// Debugger agent which starts a socket listener on the debugger port and
// handles connection from a remote debugger.
class DebuggerAgent: public Thread {
public:
DebuggerAgent(Isolate* isolate, const char* name, int port);
~DebuggerAgent();
void Shutdown();
void WaitUntilListening();
Isolate* isolate() { return isolate_; }
private:
void Run();
void CreateSession(Socket* socket);
void DebuggerMessage(const v8::Debug::Message& message);
void CloseSession();
void OnSessionClosed(DebuggerAgentSession* session);
Isolate* isolate_;
SmartArrayPointer<const char> name_; // Name of the embedding application.
int port_; // Port to use for the agent.
Socket* server_; // Server socket for listen/accept.
bool terminate_; // Termination flag.
RecursiveMutex session_access_; // Mutex guarding access to session_.
DebuggerAgentSession* session_; // Current active session if any.
Semaphore terminate_now_; // Semaphore to signal termination.
Semaphore listening_;
friend class DebuggerAgentSession;
friend void DebuggerAgentMessageHandler(const v8::Debug::Message& message);
DISALLOW_COPY_AND_ASSIGN(DebuggerAgent);
};
// Debugger agent session. The session receives requests from the remote
// debugger and sends debugger events/responses to the remote debugger.
class DebuggerAgentSession: public Thread {
public:
DebuggerAgentSession(DebuggerAgent* agent, Socket* client)
: Thread("v8:DbgAgntSessn"),
agent_(agent), client_(client) {}
~DebuggerAgentSession();
void DebuggerMessage(Vector<uint16_t> message);
void Shutdown();
private:
void Run();
void DebuggerMessage(Vector<char> message);
DebuggerAgent* agent_;
Socket* client_;
DISALLOW_COPY_AND_ASSIGN(DebuggerAgentSession);
};
// Utility methods factored out to be used by the D8 shell as well.
class DebuggerAgentUtil {
public:
static const char* const kContentLength;
static SmartArrayPointer<char> ReceiveMessage(Socket* conn);
static bool SendConnectMessage(Socket* conn, const char* embedding_host);
static bool SendMessage(Socket* conn, const Vector<uint16_t> message);
static bool SendMessage(Socket* conn, const v8::Handle<v8::String> message);
static int ReceiveAll(Socket* conn, char* data, int len);
};
} } // namespace v8::internal
#endif // V8_DEBUG_AGENT_H_

View File

@ -2632,9 +2632,6 @@ Debugger::Debugger(Isolate* isolate)
never_unload_debugger_(false),
message_handler_(NULL),
debugger_unload_pending_(false),
debug_message_dispatch_handler_(NULL),
message_dispatch_helper_thread_(NULL),
agent_(NULL),
command_queue_(isolate->logger(), kQueueInitialSize),
command_received_(0),
event_command_queue_(isolate->logger(), kQueueInitialSize),
@ -3189,7 +3186,7 @@ void Debugger::SetMessageHandler(v8::Debug::MessageHandler handler) {
// Send an empty command to the debugger if in a break to make JavaScript
// run again if the debugger is closed.
if (isolate_->debug()->InDebugger()) {
ProcessCommand(Vector<const uint16_t>::empty());
EnqueueCommandMessage(Vector<const uint16_t>::empty());
}
}
}
@ -3211,18 +3208,6 @@ void Debugger::ListenersChanged() {
}
void Debugger::SetDebugMessageDispatchHandler(
v8::Debug::DebugMessageDispatchHandler handler, bool provide_locker) {
LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
debug_message_dispatch_handler_ = handler;
if (provide_locker && message_dispatch_helper_thread_ == NULL) {
message_dispatch_helper_thread_ = new MessageDispatchHelperThread(isolate_);
message_dispatch_helper_thread_->Start();
}
}
// Calls the registered debug message handler. This callback is part of the
// public API.
void Debugger::InvokeMessageHandler(MessageImpl message) {
@ -3238,8 +3223,8 @@ void Debugger::InvokeMessageHandler(MessageImpl message) {
// a copy of the command string managed by the debugger. Up to this
// point, the command data was managed by the API client. Called
// by the API client thread.
void Debugger::ProcessCommand(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data) {
void Debugger::EnqueueCommandMessage(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data) {
// Need to cast away const.
CommandMessage message = CommandMessage::New(
Vector<uint16_t>(const_cast<uint16_t*>(command.start()),
@ -3253,18 +3238,6 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command,
if (!isolate_->debug()->InDebugger()) {
isolate_->stack_guard()->RequestDebugCommand();
}
MessageDispatchHelperThread* dispatch_thread;
{
LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
dispatch_thread = message_dispatch_helper_thread_;
}
if (dispatch_thread == NULL) {
CallMessageDispatchHandler();
} else {
dispatch_thread->Schedule();
}
}
@ -3312,60 +3285,6 @@ MaybeHandle<Object> Debugger::Call(Handle<JSFunction> fun,
}
static void StubMessageHandler2(const v8::Debug::Message& message) {
// Simply ignore message.
}
bool Debugger::StartAgent(const char* name, int port,
bool wait_for_connection) {
if (wait_for_connection) {
// Suspend V8 if it is already running or set V8 to suspend whenever
// it starts.
// Provide stub message handler; V8 auto-continues each suspend
// when there is no message handler; we doesn't need it.
// Once become suspended, V8 will stay so indefinitely long, until remote
// debugger connects and issues "continue" command.
Debugger::message_handler_ = StubMessageHandler2;
v8::Debug::DebugBreak(reinterpret_cast<v8::Isolate*>(isolate_));
}
if (agent_ == NULL) {
agent_ = new DebuggerAgent(isolate_, name, port);
agent_->Start();
}
return true;
}
void Debugger::StopAgent() {
if (agent_ != NULL) {
agent_->Shutdown();
agent_->Join();
delete agent_;
agent_ = NULL;
}
}
void Debugger::WaitForAgent() {
if (agent_ != NULL)
agent_->WaitUntilListening();
}
void Debugger::CallMessageDispatchHandler() {
v8::Debug::DebugMessageDispatchHandler handler;
{
LockGuard<Mutex> lock_guard(&dispatch_handler_access_);
handler = Debugger::debug_message_dispatch_handler_;
}
if (handler != NULL) {
handler();
}
}
EnterDebugger::EnterDebugger(Isolate* isolate)
: isolate_(isolate),
prev_(isolate_->debug()->debugger_entry()),
@ -3703,38 +3622,4 @@ void LockingCommandMessageQueue::Clear() {
queue_.Clear();
}
MessageDispatchHelperThread::MessageDispatchHelperThread(Isolate* isolate)
: Thread("v8:MsgDispHelpr"),
isolate_(isolate), sem_(0),
already_signalled_(false) {
}
void MessageDispatchHelperThread::Schedule() {
{
LockGuard<Mutex> lock_guard(&mutex_);
if (already_signalled_) {
return;
}
already_signalled_ = true;
}
sem_.Signal();
}
void MessageDispatchHelperThread::Run() {
while (true) {
sem_.Wait();
{
LockGuard<Mutex> lock_guard(&mutex_);
already_signalled_ = false;
}
{
Locker locker(reinterpret_cast<v8::Isolate*>(isolate_));
isolate_->debugger()->CallMessageDispatchHandler();
}
}
}
} } // namespace v8::internal

View File

@ -8,7 +8,6 @@
#include "allocation.h"
#include "arguments.h"
#include "assembler.h"
#include "debug-agent.h"
#include "execution.h"
#include "factory.h"
#include "flags.h"
@ -783,16 +782,10 @@ class Debugger {
bool auto_continue);
void SetEventListener(Handle<Object> callback, Handle<Object> data);
void SetMessageHandler(v8::Debug::MessageHandler handler);
void SetDebugMessageDispatchHandler(
v8::Debug::DebugMessageDispatchHandler handler,
bool provide_locker);
// Invoke the message handler function.
void InvokeMessageHandler(MessageImpl message);
// Add a debugger command to the command queue.
void ProcessCommand(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data = NULL);
void EnqueueCommandMessage(Vector<const uint16_t> command,
v8::Debug::ClientData* client_data = NULL);
// Check whether there are commands in the command queue.
bool HasCommands();
@ -803,18 +796,6 @@ class Debugger {
MUST_USE_RESULT MaybeHandle<Object> Call(Handle<JSFunction> fun,
Handle<Object> data);
// Start the debugger agent listening on the provided port.
bool StartAgent(const char* name, int port,
bool wait_for_connection = false);
// Stop the debugger agent.
void StopAgent();
// Blocks until the agent has started listening for connections
void WaitForAgent();
void CallMessageDispatchHandler();
Handle<Context> GetDebugContext();
// Unload the debugger if possible. Only called when no debugger is currently
@ -882,6 +863,9 @@ class Debugger {
Handle<Object> event_data);
void ListenersChanged();
// Invoke the message handler function.
void InvokeMessageHandler(MessageImpl message);
RecursiveMutex debugger_access_; // Mutex guarding debugger variables.
Handle<Object> event_listener_; // Global handle to listener.
Handle<Object> event_listener_data_;
@ -892,12 +876,6 @@ class Debugger {
v8::Debug::MessageHandler message_handler_;
bool debugger_unload_pending_; // Was message handler cleared?
Mutex dispatch_handler_access_; // Mutex guarding dispatch handler.
v8::Debug::DebugMessageDispatchHandler debug_message_dispatch_handler_;
MessageDispatchHelperThread* message_dispatch_helper_thread_;
DebuggerAgent* agent_;
static const int kQueueInitialSize = 4;
LockingCommandMessageQueue command_queue_;
Semaphore command_received_; // Signaled for each command received.
@ -994,29 +972,6 @@ class Debug_Address {
Debug::AddressId id_;
};
// The optional thread that Debug Agent may use to temporary call V8 to process
// pending debug requests if debuggee is not running V8 at the moment.
// Techincally it does not call V8 itself, rather it asks embedding program
// to do this via v8::Debug::HostDispatchHandler
class MessageDispatchHelperThread: public Thread {
public:
explicit MessageDispatchHelperThread(Isolate* isolate);
~MessageDispatchHelperThread() {}
void Schedule();
private:
void Run();
Isolate* isolate_;
Semaphore sem_;
Mutex mutex_;
bool already_signalled_;
DISALLOW_COPY_AND_ASSIGN(MessageDispatchHelperThread);
};
} } // namespace v8::internal
#endif // V8_DEBUG_H_

View File

@ -714,6 +714,9 @@ void Execution::DebugBreakHelper(Isolate* isolate) {
void Execution::ProcessDebugMessages(Isolate* isolate,
bool debug_command_only) {
// Assert that we are on the main thread of the isolate.
ASSERT(ThreadId::Current().Equals(isolate->thread_id()));
isolate->stack_guard()->ClearDebugCommand();
StackLimitCheck check(isolate);

View File

@ -660,10 +660,6 @@ DEFINE_bool(help, false, "Print usage message, including flags, on console")
DEFINE_bool(dump_counters, false, "Dump counters on exit")
DEFINE_bool(debugger, false, "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, "", "Map counters to a file")
DEFINE_args(js_arguments,

View File

@ -75,7 +75,6 @@ typedef void* ExternalReferenceRedirectorPointer();
class Debug;
class Debugger;
class DebuggerAgent;
#if !defined(__arm__) && V8_TARGET_ARCH_ARM || \
!defined(__aarch64__) && V8_TARGET_ARCH_ARM64 || \
@ -358,7 +357,6 @@ typedef List<HeapObject*> DebugObjectCache;
V(bool, fp_stubs_generated, false) \
V(int, max_available_threads, 0) \
V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \
V(DebuggerAgent*, debugger_agent_instance, NULL) \
V(InterruptCallback, api_interrupt_callback, NULL) \
V(void*, api_interrupt_callback_data, NULL) \
ISOLATE_INIT_SIMULATOR_LIST(V)

View File

@ -5788,242 +5788,6 @@ TEST(DebuggerClearMessageHandlerWhileActive) {
}
/* Test DebugMessageDispatch */
/* In this test, the V8 thread waits for a message from the debug thread.
* The DebugMessageDispatchHandler is executed from the debugger thread
* which signals the V8 thread to wake up.
*/
class DebugMessageDispatchV8Thread : public v8::internal::Thread {
public:
DebugMessageDispatchV8Thread() : Thread("DebugMessageDispatchV8Thread") { }
void Run();
};
class DebugMessageDispatchDebuggerThread : public v8::internal::Thread {
public:
DebugMessageDispatchDebuggerThread()
: Thread("DebugMessageDispatchDebuggerThread") { }
void Run();
};
Barriers* debug_message_dispatch_barriers;
static void DebugMessageHandler() {
debug_message_dispatch_barriers->semaphore_1.Signal();
}
void DebugMessageDispatchV8Thread::Run() {
v8::Isolate::Scope isolate_scope(CcTest::isolate());
DebugLocalContext env;
v8::HandleScope scope(env->GetIsolate());
// Set up debug message dispatch handler.
v8::Debug::SetDebugMessageDispatchHandler(DebugMessageHandler);
CompileRun("var y = 1 + 2;\n");
debug_message_dispatch_barriers->barrier_1.Wait();
debug_message_dispatch_barriers->semaphore_1.Wait();
debug_message_dispatch_barriers->barrier_2.Wait();
}
void DebugMessageDispatchDebuggerThread::Run() {
debug_message_dispatch_barriers->barrier_1.Wait();
SendContinueCommand();
debug_message_dispatch_barriers->barrier_2.Wait();
}
TEST(DebuggerDebugMessageDispatch) {
DebugMessageDispatchDebuggerThread debug_message_dispatch_debugger_thread;
DebugMessageDispatchV8Thread debug_message_dispatch_v8_thread;
// Create a V8 environment
Barriers stack_allocated_debug_message_dispatch_barriers;
debug_message_dispatch_barriers =
&stack_allocated_debug_message_dispatch_barriers;
debug_message_dispatch_v8_thread.Start();
debug_message_dispatch_debugger_thread.Start();
debug_message_dispatch_v8_thread.Join();
debug_message_dispatch_debugger_thread.Join();
}
TEST(DebuggerAgent) {
v8::V8::Initialize();
i::Debugger* debugger = CcTest::i_isolate()->debugger();
// Make sure these ports is not used by other tests to allow tests to run in
// parallel.
const int kPort1 = 5858 + FlagDependentPortOffset();
const int kPort2 = 5857 + FlagDependentPortOffset();
const int kPort3 = 5856 + FlagDependentPortOffset();
// Make a string with the port2 number.
const int kPortBufferLen = 6;
char port2_str[kPortBufferLen];
OS::SNPrintF(i::Vector<char>(port2_str, kPortBufferLen), "%d", kPort2);
bool ok;
// Test starting and stopping the agent without any client connection.
debugger->StartAgent("test", kPort1);
debugger->StopAgent();
// Test starting the agent, connecting a client and shutting down the agent
// with the client connected.
ok = debugger->StartAgent("test", kPort2);
CHECK(ok);
debugger->WaitForAgent();
i::Socket* client = new i::Socket;
ok = client->Connect("localhost", port2_str);
CHECK(ok);
// It is important to wait for a message from the agent. Otherwise,
// we can close the server socket during "accept" syscall, making it failing
// (at least on Linux), and the test will work incorrectly.
char buf;
ok = client->Receive(&buf, 1) == 1;
CHECK(ok);
debugger->StopAgent();
delete client;
// Test starting and stopping the agent with the required port already
// occoupied.
i::Socket* server = new i::Socket;
ok = server->Bind(kPort3);
CHECK(ok);
debugger->StartAgent("test", kPort3);
debugger->StopAgent();
delete server;
}
class DebuggerAgentProtocolServerThread : public i::Thread {
public:
explicit DebuggerAgentProtocolServerThread(int port)
: Thread("DebuggerAgentProtocolServerThread"),
port_(port),
server_(NULL),
client_(NULL),
listening_(0) {
}
~DebuggerAgentProtocolServerThread() {
// Close both sockets.
delete client_;
delete server_;
}
void Run();
void WaitForListening() { listening_.Wait(); }
char* body() { return body_.get(); }
private:
int port_;
i::SmartArrayPointer<char> body_;
i::Socket* server_; // Server socket used for bind/accept.
i::Socket* client_; // Single client connection used by the test.
i::Semaphore listening_; // Signalled when the server is in listen mode.
};
void DebuggerAgentProtocolServerThread::Run() {
bool ok;
// Create the server socket and bind it to the requested port.
server_ = new i::Socket;
CHECK(server_ != NULL);
ok = server_->Bind(port_);
CHECK(ok);
// Listen for new connections.
ok = server_->Listen(1);
CHECK(ok);
listening_.Signal();
// Accept a connection.
client_ = server_->Accept();
CHECK(client_ != NULL);
// Receive a debugger agent protocol message.
i::DebuggerAgentUtil::ReceiveMessage(client_);
}
TEST(DebuggerAgentProtocolOverflowHeader) {
// Make sure this port is not used by other tests to allow tests to run in
// parallel.
const int kPort = 5860 + FlagDependentPortOffset();
static const char* kLocalhost = "localhost";
// Make a string with the port number.
const int kPortBufferLen = 6;
char port_str[kPortBufferLen];
OS::SNPrintF(i::Vector<char>(port_str, kPortBufferLen), "%d", kPort);
// Create a socket server to receive a debugger agent message.
DebuggerAgentProtocolServerThread* server =
new DebuggerAgentProtocolServerThread(kPort);
server->Start();
server->WaitForListening();
// Connect.
i::Socket* client = new i::Socket;
CHECK(client != NULL);
bool ok = client->Connect(kLocalhost, port_str);
CHECK(ok);
// Send headers which overflow the receive buffer.
static const int kBufferSize = 1000;
char buffer[kBufferSize];
// Long key and short value: XXXX....XXXX:0\r\n.
for (int i = 0; i < kBufferSize - 4; i++) {
buffer[i] = 'X';
}
buffer[kBufferSize - 4] = ':';
buffer[kBufferSize - 3] = '0';
buffer[kBufferSize - 2] = '\r';
buffer[kBufferSize - 1] = '\n';
int result = client->Send(buffer, kBufferSize);
CHECK_EQ(kBufferSize, result);
// Short key and long value: X:XXXX....XXXX\r\n.
buffer[0] = 'X';
buffer[1] = ':';
for (int i = 2; i < kBufferSize - 2; i++) {
buffer[i] = 'X';
}
buffer[kBufferSize - 2] = '\r';
buffer[kBufferSize - 1] = '\n';
result = client->Send(buffer, kBufferSize);
CHECK_EQ(kBufferSize, result);
// Add empty body to request.
const char* content_length_zero_header = "Content-Length:0\r\n";
int length = StrLength(content_length_zero_header);
result = client->Send(content_length_zero_header, length);
CHECK_EQ(length, result);
result = client->Send("\r\n", 2);
CHECK_EQ(2, result);
// Wait until data is received.
server->Join();
// Check for empty body.
CHECK(server->body() == NULL);
// Close the client before the server to avoid TIME_WAIT issues.
client->Shutdown();
delete client;
delete server;
}
// Test for issue http://code.google.com/p/v8/issues/detail?id=289.
// Make sure that DebugGetLoadedScripts doesn't return scripts
// with disposed external source.
@ -6783,7 +6547,7 @@ TEST(NoDebugBreakInAfterCompileMessageHandler) {
static int counting_message_handler_counter;
static void CountingMessageHandler(const v8::Debug::Message& message) {
counting_message_handler_counter++;
if (message.IsResponse()) counting_message_handler_counter++;
}
@ -6830,6 +6594,83 @@ TEST(ProcessDebugMessages) {
}
class SendCommandThread : public v8::internal::Thread {
public:
explicit SendCommandThread(v8::Isolate* isolate)
: Thread("SendCommandThread"),
semaphore_(0),
isolate_(isolate) { }
static void ProcessDebugMessages(v8::Isolate* isolate, void* data) {
v8::Debug::ProcessDebugMessages();
reinterpret_cast<v8::internal::Semaphore*>(data)->Signal();
}
virtual void Run() {
semaphore_.Wait();
const int kBufferSize = 1000;
uint16_t buffer[kBufferSize];
const char* scripts_command =
"{\"seq\":0,"
"\"type\":\"request\","
"\"command\":\"scripts\"}";
int length = AsciiToUtf16(scripts_command, buffer);
// Send scripts command.
for (int i = 0; i < 100; i++) {
CHECK_EQ(i, counting_message_handler_counter);
// Queue debug message.
v8::Debug::SendCommand(isolate_, buffer, length);
// Synchronize with the main thread to force message processing.
isolate_->RequestInterrupt(ProcessDebugMessages, &semaphore_);
semaphore_.Wait();
}
v8::V8::TerminateExecution(isolate_);
}
void StartSending() {
semaphore_.Signal();
}
private:
v8::internal::Semaphore semaphore_;
v8::Isolate* isolate_;
};
static SendCommandThread* send_command_thread_ = NULL;
static void StartSendingCommands(
const v8::FunctionCallbackInfo<v8::Value>& info) {
send_command_thread_->StartSending();
}
TEST(ProcessDebugMessagesThreaded) {
DebugLocalContext env;
v8::Isolate* isolate = env->GetIsolate();
v8::HandleScope scope(isolate);
counting_message_handler_counter = 0;
v8::Debug::SetMessageHandler2(CountingMessageHandler);
send_command_thread_ = new SendCommandThread(isolate);
send_command_thread_->Start();
v8::Handle<v8::FunctionTemplate> start =
v8::FunctionTemplate::New(isolate, StartSendingCommands);
env->Global()->Set(v8_str("start"), start->GetFunction());
CompileRun("start(); while (true) { }");
CHECK_EQ(100, counting_message_handler_counter);
v8::Debug::SetMessageHandler2(NULL);
CheckDebuggerUnloaded();
}
struct BacktraceData {
static int frame_counter;
static void MessageHandler(const v8::Debug::Message& message) {

View File

@ -313,8 +313,6 @@
'../../src/dateparser-inl.h',
'../../src/dateparser.cc',
'../../src/dateparser.h',
'../../src/debug-agent.cc',
'../../src/debug-agent.h',
'../../src/debug.cc',
'../../src/debug.h',
'../../src/deoptimizer.cc',