Unreviewed, rolling out r190520, some tests assert / crash.
[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 "JSGlobalObject.h"
40 #include "JSGlobalObjectConsoleAgent.h"
41 #include "JSGlobalObjectConsoleClient.h"
42 #include "JSGlobalObjectDebuggerAgent.h"
43 #include "JSGlobalObjectRuntimeAgent.h"
44 #include "ScriptArguments.h"
45 #include "ScriptCallStack.h"
46 #include "ScriptCallStackFactory.h"
47 #include <wtf/Stopwatch.h>
48
49 #include <cxxabi.h>
50 #if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK))
51 #include <dlfcn.h>
52 #include <execinfo.h>
53 #endif
54
55 #if ENABLE(REMOTE_INSPECTOR)
56 #include "JSGlobalObjectDebuggable.h"
57 #include "RemoteInspector.h"
58 #endif
59
60 using namespace JSC;
61
62 namespace Inspector {
63
64 JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObject& globalObject)
65     : m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create()))
66     , m_executionStopwatch(Stopwatch::create())
67     , m_frontendRouter(FrontendRouter::create())
68     , m_backendDispatcher(BackendDispatcher::create(m_frontendRouter.copyRef()))
69 #if ENABLE(REMOTE_INSPECTOR)
70     , m_globalObject(globalObject)
71 #endif
72 {
73     AgentContext baseContext = {
74         *this,
75         *m_injectedScriptManager,
76         m_frontendRouter.get(),
77         m_backendDispatcher.get()
78     };
79
80     JSAgentContext context = {
81         baseContext,
82         globalObject
83     };
84
85     auto inspectorAgent = std::make_unique<InspectorAgent>(context);
86     auto runtimeAgent = std::make_unique<JSGlobalObjectRuntimeAgent>(context);
87     auto consoleAgent = std::make_unique<JSGlobalObjectConsoleAgent>(context);
88     auto debuggerAgent = std::make_unique<JSGlobalObjectDebuggerAgent>(context, consoleAgent.get());
89
90     m_inspectorAgent = inspectorAgent.get();
91     m_debuggerAgent = debuggerAgent.get();
92     m_consoleAgent = consoleAgent.get();
93     m_consoleClient = std::make_unique<JSGlobalObjectConsoleClient>(m_consoleAgent);
94
95     runtimeAgent->setScriptDebugServer(&debuggerAgent->scriptDebugServer());
96
97     m_agents.append(WTF::move(inspectorAgent));
98     m_agents.append(WTF::move(runtimeAgent));
99     m_agents.append(WTF::move(consoleAgent));
100     m_agents.append(WTF::move(debuggerAgent));
101
102     m_executionStopwatch->start();
103 }
104
105 JSGlobalObjectInspectorController::~JSGlobalObjectInspectorController()
106 {
107 }
108
109 void JSGlobalObjectInspectorController::globalObjectDestroyed()
110 {
111     disconnectAllFrontends();
112
113     m_injectedScriptManager->disconnect();
114 }
115
116 void JSGlobalObjectInspectorController::connectFrontend(FrontendChannel* frontendChannel, bool isAutomaticInspection)
117 {
118     ASSERT_ARG(frontendChannel, frontendChannel);
119
120     m_isAutomaticInspection = isAutomaticInspection;
121
122     bool connectedFirstFrontend = !m_frontendRouter->hasFrontends();
123     m_frontendRouter->connectFrontend(frontendChannel);
124
125     if (!connectedFirstFrontend)
126         return;
127
128     // FIXME: change this to notify agents which frontend has connected (by id).
129     m_agents.didCreateFrontendAndBackend(nullptr, nullptr);
130
131 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
132     m_inspectorAgent->activateExtraDomains(m_agents.extraDomains());
133
134     if (m_augmentingClient)
135         m_augmentingClient->inspectorConnected();
136 #endif
137 }
138
139 void JSGlobalObjectInspectorController::disconnectFrontend(FrontendChannel* frontendChannel)
140 {
141     ASSERT_ARG(frontendChannel, frontendChannel);
142
143     // FIXME: change this to notify agents which frontend has disconnected (by id).
144     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectorDestroyed);
145
146     m_frontendRouter->disconnectFrontend(frontendChannel);
147
148     m_isAutomaticInspection = false;
149
150     bool disconnectedLastFrontend = !m_frontendRouter->hasFrontends();
151     if (!disconnectedLastFrontend)
152         return;
153
154 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
155     if (m_augmentingClient)
156         m_augmentingClient->inspectorDisconnected();
157 #endif
158 }
159
160 void JSGlobalObjectInspectorController::disconnectAllFrontends()
161 {
162     // FIXME: change this to notify agents which frontend has disconnected (by id).
163     m_agents.willDestroyFrontendAndBackend(DisconnectReason::InspectedTargetDestroyed);
164
165     m_frontendRouter->disconnectAllFrontends();
166
167     m_isAutomaticInspection = false;
168
169 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
170     if (m_augmentingClient)
171         m_augmentingClient->inspectorDisconnected();
172 #endif
173 }
174
175 void JSGlobalObjectInspectorController::dispatchMessageFromFrontend(const String& message)
176 {
177     m_backendDispatcher->dispatch(message);
178 }
179
180 void JSGlobalObjectInspectorController::pause()
181 {
182     ErrorString dummyError;
183     m_debuggerAgent->enable(dummyError);
184     m_debuggerAgent->pause(dummyError);
185 }
186
187 void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack* callStack)
188 {
189 #if OS(DARWIN) || (OS(LINUX) && !PLATFORM(GTK))
190     static const int framesToShow = 31;
191     static const int framesToSkip = 3; // WTFGetBacktrace, appendAPIBacktrace, reportAPIException.
192
193     void* samples[framesToShow + framesToSkip];
194     int frames = framesToShow + framesToSkip;
195     WTFGetBacktrace(samples, &frames);
196
197     void** stack = samples + framesToSkip;
198     int size = frames - framesToSkip;
199     for (int i = 0; i < size; ++i) {
200         const char* mangledName = nullptr;
201         char* cxaDemangled = nullptr;
202         Dl_info info;
203         if (dladdr(stack[i], &info) && info.dli_sname)
204             mangledName = info.dli_sname;
205         if (mangledName)
206             cxaDemangled = abi::__cxa_demangle(mangledName, nullptr, nullptr, nullptr);
207         if (mangledName || cxaDemangled)
208             callStack->append(ScriptCallFrame(cxaDemangled ? cxaDemangled : mangledName, ASCIILiteral("[native code]"), 0, 0));
209         else
210             callStack->append(ScriptCallFrame(ASCIILiteral("?"), ASCIILiteral("[native code]"), 0, 0));
211         free(cxaDemangled);
212     }
213 #else
214     UNUSED_PARAM(callStack);
215 #endif
216 }
217
218 void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, Exception* exception)
219 {
220     if (isTerminatedExecutionException(exception))
221         return;
222
223     ErrorHandlingScope errorScope(exec->vm());
224
225     RefPtr<ScriptCallStack> callStack = createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture);
226     if (includesNativeCallStackWhenReportingExceptions())
227         appendAPIBacktrace(callStack.get());
228
229     // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not evaluate JavaScript handling exceptions
230     // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
231     String errorMessage = exception->value().toString(exec)->value(exec);
232     exec->clearException();
233
234     if (JSGlobalObjectConsoleClient::logToSystemConsole()) {
235         if (callStack->size()) {
236             const ScriptCallFrame& callFrame = callStack->at(0);
237             ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callFrame.sourceURL(), callFrame.lineNumber(), callFrame.columnNumber());
238         } else
239             ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, String(), 0, 0);
240     }
241
242     m_consoleAgent->addMessageToConsole(std::make_unique<ConsoleMessage>(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callStack));
243 }
244
245 ConsoleClient* JSGlobalObjectInspectorController::consoleClient() const
246 {
247     return m_consoleClient.get();
248 }
249
250 bool JSGlobalObjectInspectorController::developerExtrasEnabled() const
251 {
252 #if ENABLE(REMOTE_INSPECTOR)
253     if (!RemoteInspector::singleton().enabled())
254         return false;
255
256     if (!m_globalObject.inspectorDebuggable().remoteDebuggingAllowed())
257         return false;
258 #endif
259
260     return true;
261 }
262
263 InspectorFunctionCallHandler JSGlobalObjectInspectorController::functionCallHandler() const
264 {
265     return JSC::call;
266 }
267
268 InspectorEvaluateHandler JSGlobalObjectInspectorController::evaluateHandler() const
269 {
270     return JSC::evaluate;
271 }
272
273 void JSGlobalObjectInspectorController::frontendInitialized()
274 {
275 #if ENABLE(REMOTE_INSPECTOR)
276     if (m_isAutomaticInspection)
277         m_globalObject.inspectorDebuggable().unpauseForInitializedInspector();
278 #endif
279 }
280
281 Ref<Stopwatch> JSGlobalObjectInspectorController::executionStopwatch()
282 {
283     return m_executionStopwatch.copyRef();
284 }
285
286 #if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS)
287 void JSGlobalObjectInspectorController::appendExtraAgent(std::unique_ptr<InspectorAgentBase> agent)
288 {
289     String domainName = agent->domainName();
290
291     // FIXME: change this to notify agents which frontend has connected (by id).
292     agent->didCreateFrontendAndBackend(nullptr, nullptr);
293
294     m_agents.appendExtraAgent(WTF::move(agent));
295
296     m_inspectorAgent->activateExtraDomain(domainName);
297 }
298 #endif
299
300 } // namespace Inspector
301