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