diff options
Diffstat (limited to 'src/3rdparty/v8/src/d8-debug.cc')
-rw-r--r-- | src/3rdparty/v8/src/d8-debug.cc | 367 |
1 files changed, 367 insertions, 0 deletions
diff --git a/src/3rdparty/v8/src/d8-debug.cc b/src/3rdparty/v8/src/d8-debug.cc new file mode 100644 index 0000000..3df8693 --- /dev/null +++ b/src/3rdparty/v8/src/d8-debug.cc @@ -0,0 +1,367 @@ +// Copyright 2008 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. + + +#include "d8.h" +#include "d8-debug.h" +#include "platform.h" +#include "debug-agent.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(DebugEvent event, + Handle<Object> exec_state, + Handle<Object> event_data, + Handle<Value> data) { + HandleScope scope; + + // Check for handled event. + if (event != Break && event != Exception && event != AfterCompile) { + return; + } + + TryCatch try_catch; + + // Get the toJSONProtocol function on the event and get the JSON format. + Local<String> to_json_fun_name = String::New("toJSONProtocol"); + Local<Function> to_json_fun = + Function::Cast(*event_data->Get(to_json_fun_name)); + Local<Value> event_json = to_json_fun->Call(event_data, 0, NULL); + if (try_catch.HasCaught()) { + Shell::ReportException(&try_catch); + return; + } + + // Print the event details. + Handle<Object> details = + Shell::DebugMessageDetails(Handle<String>::Cast(event_json)); + 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; + } + printf("%s\n", *str); + + // Get the debug command processor. + Local<String> fun_name = String::New("debugCommandProcessor"); + Local<Function> fun = Function::Cast(*exec_state->Get(fun_name)); + Local<Object> cmd_processor = + Object::Cast(*fun->Call(exec_state, 0, NULL)); + if (try_catch.HasCaught()) { + Shell::ReportException(&try_catch); + return; + } + + static const int kBufferSize = 256; + bool running = false; + while (!running) { + char command[kBufferSize]; + PrintPrompt(running); + char* str = fgets(command, kBufferSize, stdin); + if (str == NULL) break; + + // Ignore empty commands. + if (strlen(command) == 0) continue; + + TryCatch try_catch; + + // Convert the debugger command to a JSON debugger request. + Handle<Value> request = + Shell::DebugCommandToJSONRequest(String::New(command)); + if (try_catch.HasCaught()) { + Shell::ReportException(&try_catch); + continue; + } + + // If undefined is returned the command was handled internally and there is + // no JSON to send. + if (request->IsUndefined()) { + continue; + } + + Handle<String> fun_name; + Handle<Function> fun; + // All the functions used below take one argument. + static const int kArgc = 1; + Handle<Value> args[kArgc]; + + // Invoke the JavaScript to convert the debug command line to a JSON + // request, invoke the JSON request and convert the JSON respose to a text + // representation. + fun_name = String::New("processDebugRequest"); + fun = Handle<Function>::Cast(cmd_processor->Get(fun_name)); + args[0] = request; + Handle<Value> response_val = fun->Call(cmd_processor, kArgc, args); + if (try_catch.HasCaught()) { + Shell::ReportException(&try_catch); + continue; + } + Handle<String> response = Handle<String>::Cast(response_val); + + // Convert the debugger response into text details and the running state. + Handle<Object> response_details = Shell::DebugMessageDetails(response); + if (try_catch.HasCaught()) { + Shell::ReportException(&try_catch); + continue; + } + String::Utf8Value text_str(response_details->Get(String::New("text"))); + if (text_str.length() > 0) { + printf("%s\n", *text_str); + } + running = + response_details->Get(String::New("running"))->ToBoolean()->Value(); + } +} + + +void RunRemoteDebugger(int port) { + RemoteDebugger debugger(i::Isolate::Current(), 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(isolate_, this); + receiver.Start(); + + // Start the keyboard thread. + KeyboardThread keyboard(isolate_, 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; + } + + // 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); + PrintPrompt(); + 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"); + } + + bool is_running = details->Get(String::New("running"))->ToBoolean()->Value(); + PrintPrompt(is_running); +} + + +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()) { + v8::String::Utf8Value exception(try_catch.Exception()); + const char* exception_string = Shell::ToCString(exception); + printf("%s\n", exception_string); + 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::SmartPointer<char> message = + i::DebuggerAgentUtil::ReceiveMessage(remote_debugger_->conn()); + ASSERT(*message == NULL); + + 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::StrDup(command))); + } +} + + +} // namespace v8 |