summaryrefslogtreecommitdiffstats
path: root/chrome/browser/debugger/debugger_shell.cc
diff options
context:
space:
mode:
authorinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
committerinitial.commit <initial.commit@0039d316-1c4b-4281-b951-d872f2087c98>2008-07-26 23:55:29 +0000
commit09911bf300f1a419907a9412154760efd0b7abc3 (patch)
treef131325fb4e2ad12c6d3504ab75b16dd92facfed /chrome/browser/debugger/debugger_shell.cc
parent586acc5fe142f498261f52c66862fa417c3d52d2 (diff)
downloadchromium_src-09911bf300f1a419907a9412154760efd0b7abc3.zip
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.gz
chromium_src-09911bf300f1a419907a9412154760efd0b7abc3.tar.bz2
Add chrome to the repository.
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@15 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/debugger/debugger_shell.cc')
-rw-r--r--chrome/browser/debugger/debugger_shell.cc419
1 files changed, 419 insertions, 0 deletions
diff --git a/chrome/browser/debugger/debugger_shell.cc b/chrome/browser/debugger/debugger_shell.cc
new file mode 100644
index 0000000..0679292
--- /dev/null
+++ b/chrome/browser/debugger/debugger_shell.cc
@@ -0,0 +1,419 @@
+// Copyright 2008, Google Inc.
+// 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 "chrome/browser/debugger/debugger_shell.h"
+
+#include "base/file_util.h"
+#include "base/path_service.h"
+#include "base/string_util.h"
+#include "base/thread.h"
+#include "chrome/browser/browser.h"
+#include "chrome/browser/browser_list.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/browser_resources.h"
+#include "chrome/browser/render_process_host.h"
+#include "chrome/browser/tab_contents.h"
+#include "chrome/browser/debugger/debugger_io.h"
+#include "chrome/browser/debugger/debugger_node.h"
+#include "chrome/common/chrome_paths.h"
+#include "chrome/common/resource_bundle.h"
+#include "v8/public/v8.h"
+
+DebuggerShell::DebuggerShell(DebuggerInputOutput* io) : io_(io),
+ debugger_ready_(true) {
+}
+
+DebuggerShell::~DebuggerShell() {
+ io_->Stop();
+ io_ = NULL;
+
+ v8::HandleScope scope;
+ SubshellFunction("exit", 0, NULL);
+ v8::V8::RemoveMessageListeners(&DelegateMessageListener);
+ v8_this_.Dispose();
+ v8_context_.Dispose();
+ shell_.Dispose();
+}
+
+void DebuggerShell::Start() {
+ io_->Start(this);
+
+ v8::HandleScope scope;
+
+ v8_this_ = v8::Persistent<v8::External>::New(v8::External::New(this));
+
+ v8::V8::AddMessageListener(&DelegateMessageListener, v8_this_);
+
+ v8::Local<v8::ObjectTemplate> global_template = v8::ObjectTemplate::New();
+
+ // shell function
+ v8::Local<v8::FunctionTemplate> shell_template =
+ v8::FunctionTemplate::New(&DelegateSubshell, v8_this_);
+ global_template->Set(v8::String::New("shell"), shell_template);
+
+ // print function
+ v8::Local<v8::FunctionTemplate> print_template =
+ v8::FunctionTemplate::New(&DelegatePrint, v8_this_);
+ global_template->Set(v8::String::New("print"), print_template);
+
+ // source function
+ v8::Local<v8::FunctionTemplate> source_template =
+ v8::FunctionTemplate::New(&DelegateSource, v8_this_);
+ global_template->Set(v8::String::New("source"), source_template);
+
+ v8_context_ = v8::Context::New(NULL, global_template);
+ v8::Context::Scope ctx(v8_context_);
+
+ // This doesn't really leak. It's wrapped by the NewInstance() return value.
+ ChromeNode* chrome = new ChromeNode(this);
+ v8_context_->Global()->Set(v8::String::New("chrome"),
+ chrome->NewInstance());
+
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ const std::string& debugger_shell_js =
+ rb.GetDataResource(IDR_DEBUGGER_SHELL_JS);
+ CompileAndRun(debugger_shell_js, "chrome.dll/debugger_shell.js");
+}
+
+void DebuggerShell::HandleWeakReference(v8::Persistent<v8::Object> obj, void* data) {
+ DebuggerNodeWrapper* node = static_cast<DebuggerNodeWrapper*>(data);
+ node->Release();
+}
+
+v8::Handle<v8::Value> DebuggerShell::SetDebuggerReady(const v8::Arguments& args,
+ DebuggerShell* debugger) {
+ if (args[0]->IsBoolean()) {
+ bool flag = args[0]->BooleanValue();
+ debugger->debugger_ready_ = flag;
+ debugger->GetIo()->SetDebuggerReady(flag);
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> DebuggerShell::SetDebuggerBreak(const v8::Arguments& args,
+ DebuggerShell* debugger) {
+ if (args[0]->IsBoolean()) {
+ bool flag = args[0]->BooleanValue();
+ debugger->GetIo()->SetDebuggerBreak(flag);
+ }
+ return v8::Undefined();
+}
+
+DebuggerInputOutput* DebuggerShell::GetIo() {
+ return io_.get();
+}
+
+v8::Handle<v8::Value> DebuggerShell::DelegateSubshell(const v8::Arguments& args) {
+ DebuggerShell* debugger =
+ static_cast<DebuggerShell*>(v8::External::Cast(*args.Data())->Value());
+ return debugger->Subshell(args);
+}
+
+v8::Handle<v8::Value> DebuggerShell::Subshell(const v8::Arguments& args) {
+ if (args.Length() != 1) {
+ return v8::Undefined();
+ }
+ if (!shell_.IsEmpty()) {
+ shell_.Dispose();
+ shell_.Clear();
+ v8_context_->Global()->Delete(v8::String::New("shell_"));
+ }
+ if (args[0]->IsFunction()) {
+ v8::Handle<v8::Function> func = v8::Handle<v8::Function>::Cast(args[0]);
+ v8::Local<v8::Object> obj = func->NewInstance();
+ if (!obj->IsUndefined()) {
+ shell_= v8::Persistent<v8::Object>::New(obj);
+ v8_context_->Global()->Set(v8::String::New("shell_"), shell_);
+ }
+ } else if (args[0]->IsObject()) {
+ shell_= v8::Persistent<v8::Object>::New(v8::Local<v8::Object>::Cast(args[0]));
+ v8_context_->Global()->Set(v8::String::New("shell_"), shell_);
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> DebuggerShell::SubshellFunction(const char* func,
+ int argc,
+ v8::Handle<v8::Value>* argv) {
+ if (!shell_.IsEmpty()) {
+ v8::Context::Scope scope(v8_context_);
+ v8::Local<v8::Value> function = shell_->Get(v8::String::New(func));
+ if (function->IsFunction()) {
+ v8::Local<v8::Value> ret =
+ v8::Function::Cast(*function)->Call(shell_, argc, argv);
+ return ret;
+ }
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> DebuggerShell::DelegatePrint(const v8::Arguments& args) {
+ DebuggerShell* debugger =
+ static_cast<DebuggerShell*>(v8::External::Cast(*args.Data())->Value());
+ return debugger->Print(args);
+}
+
+v8::Handle<v8::Value> DebuggerShell::Print(const v8::Arguments& args) {
+ int len = args.Length();
+ for (int i = 0; i < len; i++) {
+ PrintObject(args[i]);
+ }
+ return v8::Undefined();
+}
+
+v8::Handle<v8::Value> DebuggerShell::DelegateSource(const v8::Arguments& args) {
+ DebuggerShell* debugger =
+ static_cast<DebuggerShell*>(v8::External::Cast(*args.Data())->Value());
+ std::wstring path;
+ if (args.Length() == 0) {
+ debugger->LoadUserConfig();
+ } else {
+ ObjectToString(args[0], &path);
+ bool ret = debugger->LoadFile(path);
+ if (!ret) {
+ return v8::String::New("failed to load");
+ }
+ }
+ return v8::Undefined();
+}
+
+void DebuggerShell::DelegateMessageListener(v8::Handle<v8::Message> message,
+ v8::Handle<v8::Value> data) {
+ DCHECK(!data.IsEmpty());
+ DebuggerShell* debugger =
+ static_cast<DebuggerShell*>(v8::External::Cast(*data)->Value());
+ debugger->MessageListener(message);
+}
+
+void DebuggerShell::MessageListener(v8::Handle<v8::Message> message) {
+ v8::HandleScope scope;
+ v8::Local<v8::String> msg_str = message->Get();
+ PrintObject(msg_str);
+
+ v8::Handle<v8::Value> data = message->GetScriptResourceName();
+ if (!data.IsEmpty() && !data->IsUndefined()) {
+ std::wstring out;
+ ObjectToString(data, &out);
+ int line_number = message->GetLineNumber();
+ if (line_number >= 0)
+ out += StringPrintf(L":%d", line_number);
+ PrintLine(out);
+ data = message->GetSourceLine();
+ if (!data->IsUndefined()) {
+ ObjectToString(data, &out);
+ PrintLine(out);
+ }
+ }
+}
+
+void DebuggerShell::Debug(TabContents* tab) {
+ v8::HandleScope outer;
+ v8::Context::Scope scope(v8_context_);
+
+ v8::Local<v8::Object> global = v8_context_->Global();
+ v8::Local<v8::Value> function = global->Get(v8::String::New("debug"));
+ if (function->IsFunction()) {
+ TabNode* node = new TabNode(tab);
+ v8::Handle<v8::Value> argv[] = {node->NewInstance()};
+ PrintObject(v8::Function::Cast(*function)->Call(global, 1, argv));
+ }
+}
+
+void DebuggerShell::DebugMessage(const std::wstring& msg) {
+ v8::HandleScope scope;
+
+ if (msg.length()) {
+ if ((msg[0] == L'{' || msg[0] == L'[' || msg[0] == L'(') && (!shell_.IsEmpty())) {
+ // v8's wide String constructor requires uint16 rather than wchar
+ const uint16* data = reinterpret_cast<const uint16* >(msg.c_str());
+ v8::Handle<v8::Value> argv[] = {v8::String::New(data)};
+ PrintObject(SubshellFunction("response", 1, argv));
+ PrintPrompt();
+ } else {
+ if (msg[msg.length() - 1] == L'\n')
+ PrintString(msg);
+ else
+ PrintLine(msg);
+ }
+ }
+}
+
+void DebuggerShell::OnDebugDisconnect() {
+ v8::HandleScope scope;
+ SubshellFunction("on_disconnect", 0, NULL);
+}
+
+void DebuggerShell::ObjectToString(v8::Handle<v8::Value> result, std::wstring* str) {
+ v8::HandleScope scope;
+ if (!result.IsEmpty() && !result->IsUndefined()) {
+ v8::Local<v8::String> str_obj = result->ToString();
+ if (!str_obj.IsEmpty()) {
+ int length = str_obj->Length();
+ wchar_t* buf = new wchar_t[length + 1];
+ int size = str_obj->Write(reinterpret_cast<uint16_t*>(buf));
+ str->clear();
+ str->append(buf, size);
+ delete[] buf;
+ }
+ }
+}
+
+void DebuggerShell::ObjectToString(v8::Handle<v8::Value> result, std::string* str) {
+ v8::HandleScope scope;
+ if (!result.IsEmpty() && !result->IsUndefined()) {
+ v8::Local<v8::String> str_obj = result->ToString();
+ if (!str_obj.IsEmpty()) {
+ int length = str_obj->Length();
+ char* buf = new char[length + 1];
+ str_obj->WriteAscii(buf);
+ str->clear();
+ str->append(buf);
+ delete[] buf;
+ }
+ }
+}
+
+void DebuggerShell::PrintObject(v8::Handle<v8::Value> result, bool crlf) {
+ if (!result.IsEmpty() && !result->IsUndefined()) {
+ std::wstring out;
+ ObjectToString(result, &out);
+ if (crlf) {
+ PrintLine(out);
+ } else if (out.length()) {
+ PrintString(out);
+ }
+ }
+}
+
+void DebuggerShell::PrintString(const std::wstring& out) {
+ if (io_)
+ io_->Output(out);
+}
+
+void DebuggerShell::PrintLine(const std::wstring& out) {
+ if (io_)
+ io_->OutputLine(out);
+}
+
+void DebuggerShell::PrintString(const std::string& out) {
+ if (io_)
+ io_->Output(out);
+}
+
+void DebuggerShell::PrintLine(const std::string& out) {
+ if (io_)
+ io_->OutputLine(out);
+}
+
+void DebuggerShell::PrintPrompt() {
+ std::wstring out = L"Chrome> ";
+ if (!shell_.IsEmpty()) {
+ if (!debugger_ready_)
+ return;
+ v8::HandleScope outer;
+ v8::Handle<v8::Value> result = CompileAndRun("shell_.prompt()");
+ if (!result.IsEmpty() && !result->IsUndefined()) {
+ ObjectToString(result, &out);
+ }
+ }
+ if (io_)
+ io_->OutputPrompt(out);
+}
+
+void DebuggerShell::ProcessCommand(const std::string& data) {
+ v8::HandleScope outer;
+ v8::Context::Scope scope(v8_context_);
+ if (!shell_.IsEmpty() && data.substr(0, 7) != "source(") {
+ if (data == "exit") {
+ PrintObject(SubshellFunction("exit", 0, NULL));
+ v8_context_->Global()->Delete(v8::String::New("shell_"));
+ shell_.Dispose();
+ shell_.Clear();
+ } else {
+ v8::Handle<v8::Value> argv[] = {v8::String::New(data.c_str())};
+ PrintObject(SubshellFunction("command", 1, argv));
+ }
+ } else if (data.length()) {
+ v8::Handle<v8::Value> result = CompileAndRun(data);
+ PrintObject(result);
+ }
+ PrintPrompt();
+}
+
+bool DebuggerShell::LoadFile(const std::wstring& file) {
+ if (file_util::PathExists(file)) {
+ std::string contents;
+ if (file_util::ReadFileToString(file, &contents)) {
+ std::string afile = WideToUTF8(file);
+ CompileAndRun(contents, afile);
+ return true;
+ }
+ }
+ return false;
+}
+
+void DebuggerShell::LoadUserConfig() {
+ std::wstring path;
+ PathService::Get(chrome::DIR_USER_DATA, &path);
+ file_util::AppendToPath(&path, L"debugger_custom.js");
+ LoadFile(path);
+}
+
+void DebuggerShell::DidConnect() {
+ v8::HandleScope outer;
+ v8::Context::Scope scope(v8_context_);
+
+ LoadUserConfig();
+
+ PrintPrompt();
+}
+
+v8::Handle<v8::Value> DebuggerShell::CompileAndRun(const std::string& str,
+ const std::string& filename) {
+ v8::Context::Scope scope(v8_context_);
+ v8::Handle<v8::String> scriptname;
+ if (filename.length() > 0) {
+ scriptname = v8::String::New(filename.c_str());
+ } else {
+ scriptname = v8::String::New("");
+ }
+ v8::ScriptOrigin origin =
+ v8::ScriptOrigin(scriptname);
+ v8::Local<v8::Script> code =
+ v8::Script::Compile(v8::String::New(str.c_str()), &origin);
+ if (!code.IsEmpty()) {
+ v8::Local<v8::Value> result = code->Run();
+ if (!result.IsEmpty()) {
+ return result;
+ }
+ }
+ return v8::Undefined();
+}
+
+