Replace WTF::move with WTFMove
[WebKit-https.git] / Source / JavaScriptCore / inspector / JSGlobalObjectInspectorController.cpp
1 /*
2  * Copyright (C) 2014, 2015 Apple 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
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "JSGlobalObjectInspectorController.h"
28
29 #include "Completion.h"
30 #include "ConsoleMessage.h"
31 #include "ErrorHandlingScope.h"
32 #include "Exception.h"
33 #include "InjectedScriptHost.h"
34 #include "InjectedScriptManager.h"
35 #include "InspectorAgent.h"
36 #include "InspectorBackendDispatcher.h"
37 #include "InspectorFrontendChannel.h"
38 #include "InspectorFrontendRouter.h"
39 #include "InspectorHeapAgent.h"
40 #include "InspectorScriptProfilerAgent.h"
41 #include "JSGlobalObject.h"
42 #include "JSGlobalObjectConsoleAgent.h"
43 #include "JSGlobalObjectConsoleClient.h"
44 #include "JSGlobalObjectDebuggerAgent.h"
45 #include "JSGlobalObjectRuntimeAgent.h"
46 #include "ScriptArguments.h"
47 #include "ScriptCallStack.h"
48 #include "ScriptCallStackFactory.h"
49 #include <wtf/Stopwatch.h>
50
51 #include <cxxabi.h>
52 #if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK))
53 #include <dlfcn.h>
54 #include <execinfo.h>
55 #endif
56
57 #if ENABLE(REMOTE_INSPECTOR)
58 #include "JSGlobalObjectDebuggable.h"
59 #include "RemoteInspector.h"
60 #endif
61
62 using namespace JSC;
63
64 namespace Inspector {
65
66 JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObject& globalObject)
67     : m_globalObject(globalObject)
68     , m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create()))
69     , m_executionStopwatch(Stopwatch::create())
70     , m_scriptDebugServer(globalObject)
71     , m_frontendRouter(FrontendRouter::create())
72     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
73 {
74     AgentContext baseContext = {
75         *this,
76         *m_injectedScriptManager,
77         m_frontendRouter.get(),
78         m_backendDispatcher.get()
79     };
80
81     JSAgentContext context = {
82         baseContext,
83         globalObject
84     };
85
86     auto inspectorAgent = std::make_unique<InspectorAgent>(context);
87     auto runtimeAgent = std::make_unique<JSGlobalObjectRuntimeAgent>(context);
88     auto consoleAgent = std::make_unique<JSGlobalObjectConsoleAgent>(context);
89     auto debuggerAgent = std::make_unique<JSGlobalObjectDebuggerAgent>(context, consoleAgent.get());
90
91     m_inspectorAgent = inspectorAgent.get();
92     m_debuggerAgent = debuggerAgent.get();
93     m_consoleAgent = consoleAgent.get();
94     m_consoleClient = std::make_unique<JSGlobalObjectConsoleClient>(m_consoleAgent);
95
96     m_agents.append(WTFMove(inspectorAgent));
97     m_agents.append(WTFMove(runtimeAgent));
98     m_agents.append(WTFMove(consoleAgent));
99     m_agents.append(WTFMove(debuggerAgent));
100     m_agents.append(std::make_unique<InspectorHeapAgent>(context));
101     m_agents.append(std::make_unique<InspectorScriptProfilerAgent>(context));
102
103     m_executionStopwatch->start();
104 }
105
106 JSGlobalObjectInspectorController::~JSGlobalObjectInspectorController()
107 {
108 }
109
110 void JSGlobalObjectInspectorController::globalObjectDestroyed()
111 {
112     disconnectAllFrontends();
113
114     m_injectedScriptManager->disconnect();
115 }
116
117 void JSGlobalObjectInspectorController::connectFrontend(FrontendChannel* frontendChannel, bool isAutomaticInspection)
118 {
119     ASSERT_ARG(frontendChannel, frontendChannel);
120
121     m_isAutomaticInspection = isAutomaticInspection;
122
123     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
124     m_frontendRouter->connectFrontend(frontendChannel);
125
126     if (!connectedFirstFrontend)
127         return;
128
129     // FIXME: change this to notify agents which frontend has connected (by id).
130     m_agents.didCreateFrontendAndBackend(nullptr, nullptr);
131
132 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
133     m_inspectorAgent->activateExtraDomains(m_agents.extraDomains());
134
135     if (m_augmentingClient)
136         m_augmentingClient->inspectorConnected();
137 #endif
138 }
139
140 void JSGlobalObjectInspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
141 {
142     ASSERT_ARG(frontendChannel, frontendChannel);
143
144     // FIXME: change this to notify agents which frontend has disconnected (by id).
145     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
146
147     m_frontendRouter->disconnectFrontend(frontendChannel);
148
149     m_isAutomaticInspection = false;
150
151     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
152     if (!disconnectedLastFrontend)
153         return;
154
155 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
156     if (m_augmentingClient)
157         m_augmentingClient->inspectorDisconnected();
158 #endif
159 }
160
161 void JSGlobalObjectInspectorController::disconnectAllFrontends()
162 {
163     // FIXME: change this to notify agents which frontend has disconnected (by id).
164     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
165
166     m_frontendRouter->disconnectAllFrontends();
167
168     m_isAutomaticInspection = false;
169
170 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
171     if (m_augmentingClient)
172         m_augmentingClient->inspectorDisconnected();
173 #endif
174 }
175
176 void JSGlobalObjectInspectorController::dispatchMessageFromFrontend(const String& message)
177 {
178     m_backendDispatcher->dispatch(message);
179 }
180
181 void JSGlobalObjectInspectorController::pause()
182 {
183     ErrorString dummyError;
184     m_debuggerAgent->enable(dummyError);
185     m_debuggerAgent->pause(dummyError);
186 }
187
188 void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack* callStack)
189 {
190 #if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK))
191     static const int framesToShow = 31;
192     static const int framesToSkip = 3; // WTFGetBacktrace, appendAPIBacktrace, reportAPIException.
193
194     void* samples[framesToShow + framesToSkip];
195     int frames = framesToShow + framesToSkip;
196     WTFGetBacktrace(samples, &frames);
197
198     void** stack = samples + framesToSkip;
199     int size = frames - framesToSkip;
200     for (int i = 0; i < size; ++i) {
201         const char* mangledName = nullptr;
202         char* cxaDemangled = nullptr;
203         Dl_info info;
204         if (dladdr(stack[i], &info) && info.dli_sname)
205             mangledName = info.dli_sname;
206         if (mangledName)
207             cxaDemangled = abi::__cxa_demangle(mangledName, nullptr, nullptr, nullptr);
208         if (mangledName || cxaDemangled)
209             callStack->append(ScriptCallFrame(cxaDemangled ? cxaDemangled : mangledName, ASCIILiteral("[native code]"), 0, 0));
210         else
211             callStack->append(ScriptCallFrame(ASCIILiteral("?"), ASCIILiteral("[native code]"), 0, 0));
212         free(cxaDemangled);
213     }
214 #else
215     UNUSED_PARAM(callStack);
216 #endif
217 }
218
219 void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, Exception* exception)
220 {
221     if (isTerminatedExecutionException(exception))
222         return;
223
224     ErrorHandlingScope errorScope(exec->vm());
225
226     RefPtr<ScriptCallStack> callStack = createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture);
227     if (includesNativeCallStackWhenReportingExceptions())
228         appendAPIBacktrace(callStack.get());
229
230     // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not evaluate JavaScript handling exceptions
231     // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
232     String errorMessage = exception->value().toString(exec)->value(exec);
233     exec->clearException();
234
235     if (JSGlobalObjectConsoleClient::logToSystemConsole()) {
236         if (callStack->size()) {
237             const ScriptCallFrame& callFrame = callStack->at(0);
238             ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callFrame.sourceURL(), callFrame.lineNumber(), callFrame.columnNumber());
239         } else
240             ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, String(), 0, 0);
241     }
242
243     m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callStack));
244 }
245
246 ConsoleClient* JSGlobalObjectInspectorController::consoleClient() const
247 {
248     return m_consoleClient.get();
249 }
250
251 bool JSGlobalObjectInspectorController::developerExtrasEnabled() const
252 {
253 #if ENABLE(REMOTE_INSPECTOR)
254     if (!RemoteInspector::singleton().enabled())
255         return false;
256
257     if (!m_globalObject.inspectorDebuggable().remoteDebuggingAllowed())
258         return false;
259 #endif
260
261     return true;
262 }
263
264 InspectorFunctionCallHandler JSGlobalObjectInspectorController::functionCallHandler() const
265 {
266     return JSC::call;
267 }
268
269 InspectorEvaluateHandler JSGlobalObjectInspectorController::evaluateHandler() const
270 {
271     return JSC::evaluate;
272 }
273
274 void JSGlobalObjectInspectorController::frontendInitialized()
275 {
276 #if ENABLE(REMOTE_INSPECTOR)
277     if (m_isAutomaticInspection)
278         m_globalObject.inspectorDebuggable().unpauseForInitializedInspector();
279 #endif
280 }
281
282 Ref<Stopwatch> JSGlobalObjectInspectorController::executionStopwatch()
283 {
284     return m_executionStopwatch.copyRef();
285 }
286
287 JSGlobalObjectScriptDebugServer& JSGlobalObjectInspectorController::scriptDebugServer()
288 {
289     return m_scriptDebugServer;
290 }
291
292 VM& JSGlobalObjectInspectorController::vm()
293 {
294     return m_globalObject.vm();
295 }
296
297 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
298 void JSGlobalObjectInspectorController::appendExtraAgent(std::unique_ptr<InspectorAgentBase> agent)
299 {
300     String domainName = agent->domainName();
301
302     // FIXME: change this to notify agents which frontend has connected (by id).
303     agent->didCreateFrontendAndBackend(nullptr, nullptr);
304
305     m_agents.appendExtraAgent(WTFMove(agent));
306
307     m_inspectorAgent->activateExtraDomain(domainName);
308 }
309 #endif
310
311 } // namespace Inspector
312