1 /* 2 * Copyright (C) 2010 Google Inc. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without 5 * modification, are permitted provided that the following conditions are 6 * met: 7 * 8 * * Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * * Redistributions in binary form must reproduce the above 11 * copyright notice, this list of conditions and the following disclaimer 12 * in the documentation and/or other materials provided with the 13 * distribution. 14 * * Neither the name of Google Inc. nor the names of its 15 * contributors may be used to endorse or promote products derived from 16 * this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #include "config.h" 32 #include "DebuggerAgentImpl.h" 33 34 #include "DebuggerAgentManager.h" 35 #include "Document.h" 36 #include "Frame.h" 37 #include "Page.h" 38 #include "V8Binding.h" 39 #include "V8DOMWindow.h" 40 #include "V8Index.h" 41 #include "V8Proxy.h" 42 #include "WebDevToolsAgentImpl.h" 43 #include "WebViewImpl.h" 44 #include <wtf/HashSet.h> 45 #include <wtf/RefPtr.h> 46 #include <wtf/Vector.h> 47 48 using WebCore::DOMWindow; 49 using WebCore::Document; 50 using WebCore::Frame; 51 using WebCore::Page; 52 using WebCore::String; 53 using WebCore::V8ClassIndex; 54 using WebCore::V8DOMWindow; 55 using WebCore::V8DOMWrapper; 56 using WebCore::V8Proxy; 57 58 namespace WebKit { 59 60 DebuggerAgentImpl::DebuggerAgentImpl( 61 WebViewImpl* webViewImpl, 62 DebuggerAgentDelegate* delegate, 63 WebDevToolsAgentImpl* webdevtoolsAgent) 64 : m_webViewImpl(webViewImpl) 65 , m_delegate(delegate) 66 , m_webdevtoolsAgent(webdevtoolsAgent) 67 , m_autoContinueOnException(false) 68 { 69 DebuggerAgentManager::debugAttach(this); 70 } 71 72 DebuggerAgentImpl::~DebuggerAgentImpl() 73 { 74 DebuggerAgentManager::debugDetach(this); 75 } 76 77 void DebuggerAgentImpl::getContextId() 78 { 79 m_delegate->setContextId(m_webdevtoolsAgent->hostId()); 80 } 81 82 void DebuggerAgentImpl::processDebugCommands() 83 { 84 DebuggerAgentManager::UtilityContextScope utilityScope; 85 v8::Debug::ProcessDebugMessages(); 86 } 87 88 void DebuggerAgentImpl::debuggerOutput(const String& command) 89 { 90 m_delegate->debuggerOutput(command); 91 m_webdevtoolsAgent->forceRepaint(); 92 } 93 94 // static 95 void DebuggerAgentImpl::createUtilityContext(Frame* frame, v8::Persistent<v8::Context>* context) 96 { 97 v8::HandleScope scope; 98 bool canExecuteScripts = frame->script()->canExecuteScripts(); 99 100 // Set up the DOM window as the prototype of the new global object. 101 v8::Handle<v8::Context> windowContext = V8Proxy::context(frame); 102 v8::Handle<v8::Object> windowGlobal; 103 v8::Handle<v8::Object> windowWrapper; 104 if (canExecuteScripts) { 105 // FIXME: This check prevents renderer from crashing, while providing limited capabilities for 106 // DOM inspection, Resources tracking, no scripts support, some timeline profiling. Console will 107 // result in exceptions for each evaluation. There is still some work that needs to be done in 108 // order to polish the script-less experience. 109 windowGlobal = windowContext->Global(); 110 windowWrapper = V8DOMWrapper::lookupDOMWrapper(V8DOMWindow::GetTemplate(), windowGlobal); 111 ASSERT(V8DOMWindow::toNative(windowWrapper) == frame->domWindow()); 112 } 113 114 v8::Handle<v8::ObjectTemplate> globalTemplate = v8::ObjectTemplate::New(); 115 116 // TODO(yurys): provide a function in v8 bindings that would make the 117 // utility context more like main world context of the inspected frame, 118 // otherwise we need to manually make it satisfy various invariants 119 // that V8Proxy::getEntered and some other V8Proxy methods expect to find 120 // on v8 contexts on the contexts stack. 121 // See V8Proxy::createNewContext. 122 // 123 // Install a security handler with V8. 124 globalTemplate->SetAccessCheckCallbacks( 125 V8DOMWindow::namedSecurityCheck, 126 V8DOMWindow::indexedSecurityCheck, 127 v8::Integer::New(V8ClassIndex::DOMWINDOW)); 128 // We set number of internal fields to match that in V8DOMWindow wrapper. 129 // See http://crbug.com/28961 130 globalTemplate->SetInternalFieldCount(V8DOMWindow::internalFieldCount); 131 132 *context = v8::Context::New(0 /* no extensions */, globalTemplate, v8::Handle<v8::Object>()); 133 v8::Context::Scope contextScope(*context); 134 v8::Handle<v8::Object> global = (*context)->Global(); 135 136 v8::Handle<v8::String> implicitProtoString = v8::String::New("__proto__"); 137 if (canExecuteScripts) 138 global->Set(implicitProtoString, windowWrapper); 139 140 // Give the code running in the new context a way to get access to the 141 // original context. 142 if (canExecuteScripts) 143 global->Set(v8::String::New("contentWindow"), windowGlobal); 144 } 145 146 String DebuggerAgentImpl::executeUtilityFunction( 147 v8::Handle<v8::Context> context, 148 int callId, 149 const char* object, 150 const String &functionName, 151 const String& jsonArgs, 152 bool async, 153 String* exception) 154 { 155 v8::HandleScope scope; 156 ASSERT(!context.IsEmpty()); 157 if (context.IsEmpty()) { 158 *exception = "No window context."; 159 return ""; 160 } 161 v8::Context::Scope contextScope(context); 162 163 DebuggerAgentManager::UtilityContextScope utilityScope; 164 165 v8::Handle<v8::Object> dispatchObject = v8::Handle<v8::Object>::Cast( 166 context->Global()->Get(v8::String::New(object))); 167 168 v8::Handle<v8::Value> dispatchFunction = dispatchObject->Get(v8::String::New("dispatch")); 169 ASSERT(dispatchFunction->IsFunction()); 170 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(dispatchFunction); 171 172 v8::Handle<v8::String> functionNameWrapper = v8::Handle<v8::String>( 173 v8::String::New(functionName.utf8().data())); 174 v8::Handle<v8::String> jsonArgsWrapper = v8::Handle<v8::String>( 175 v8::String::New(jsonArgs.utf8().data())); 176 v8::Handle<v8::Number> callIdWrapper = v8::Handle<v8::Number>( 177 v8::Number::New(async ? callId : 0)); 178 179 v8::Handle<v8::Value> args[] = { 180 functionNameWrapper, 181 jsonArgsWrapper, 182 callIdWrapper 183 }; 184 185 v8::TryCatch tryCatch; 186 v8::Handle<v8::Value> resObj = function->Call(context->Global(), 3, args); 187 if (tryCatch.HasCaught()) { 188 v8::Local<v8::Message> message = tryCatch.Message(); 189 if (message.IsEmpty()) 190 *exception = "Unknown exception"; 191 else 192 *exception = WebCore::toWebCoreString(message->Get()); 193 return ""; 194 } 195 return WebCore::toWebCoreStringWithNullCheck(resObj); 196 } 197 198 WebCore::Page* DebuggerAgentImpl::page() 199 { 200 return m_webViewImpl->page(); 201 } 202 203 } // namespace WebKit 204