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