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