Web Inspector: Should be able to attach a debugger to a JSContext before anything...
[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 #if ENABLE(INSPECTOR)
30
31 #include "Completion.h"
32 #include "ErrorHandlingScope.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 <cxxabi.h>
47 #include <dlfcn.h>
48 #include <execinfo.h>
49
50 using namespace JSC;
51
52 namespace Inspector {
53
54 JSGlobalObjectInspectorController::JSGlobalObjectInspectorController(JSGlobalObject& globalObject)
55     : m_globalObject(globalObject)
56     , m_injectedScriptManager(std::make_unique<InjectedScriptManager>(*this, InjectedScriptHost::create()))
57     , m_inspectorFrontendChannel(nullptr)
58     , m_includeNativeCallStackWithExceptions(true)
59 {
60     auto runtimeAgent = std::make_unique<JSGlobalObjectRuntimeAgent>(m_injectedScriptManager.get(), m_globalObject);
61     auto consoleAgent = std::make_unique<JSGlobalObjectConsoleAgent>(m_injectedScriptManager.get());
62     auto debuggerAgent = std::make_unique<JSGlobalObjectDebuggerAgent>(m_injectedScriptManager.get(), m_globalObject, consoleAgent.get());
63
64     m_debuggerAgent = debuggerAgent.get();
65     m_consoleAgent = consoleAgent.get();
66     m_consoleClient = std::make_unique<JSGlobalObjectConsoleClient>(m_consoleAgent);
67
68     runtimeAgent->setScriptDebugServer(&debuggerAgent->scriptDebugServer());
69
70     m_agents.append(std::make_unique<InspectorAgent>());
71     m_agents.append(WTF::move(runtimeAgent));
72     m_agents.append(WTF::move(consoleAgent));
73     m_agents.append(WTF::move(debuggerAgent));
74 }
75
76 JSGlobalObjectInspectorController::~JSGlobalObjectInspectorController()
77 {
78     m_agents.discardAgents();
79 }
80
81 void JSGlobalObjectInspectorController::globalObjectDestroyed()
82 {
83     disconnectFrontend(InspectorDisconnectReason::InspectedTargetDestroyed);
84
85     m_injectedScriptManager->disconnect();
86 }
87
88 void JSGlobalObjectInspectorController::connectFrontend(InspectorFrontendChannel* frontendChannel, bool isAutomaticInspection)
89 {
90     ASSERT(!m_inspectorFrontendChannel);
91     ASSERT(!m_inspectorBackendDispatcher);
92
93     m_inspectorFrontendChannel = frontendChannel;
94     m_inspectorBackendDispatcher = InspectorBackendDispatcher::create(frontendChannel);
95
96     m_agents.didCreateFrontendAndBackend(frontendChannel, m_inspectorBackendDispatcher.get());
97
98     if (isAutomaticInspection) {
99         // FIXME: We should not always pause for automatic inspection.
100         // Currently if we don't automatically pause, then we may miss a breakpoint, since breakpoints
101         // come from the frontend and might be received after some evaluateScript message. We should
102         // have the frontend signal the backend when its setup messages are complete.
103         m_debuggerAgent->enable(nullptr);
104         m_debuggerAgent->pause(nullptr);
105     }
106 }
107
108 void JSGlobalObjectInspectorController::disconnectFrontend(InspectorDisconnectReason reason)
109 {
110     if (!m_inspectorFrontendChannel)
111         return;
112
113     m_agents.willDestroyFrontendAndBackend(reason);
114
115     m_inspectorBackendDispatcher->clearFrontend();
116     m_inspectorBackendDispatcher.clear();
117     m_inspectorFrontendChannel = nullptr;
118 }
119
120 void JSGlobalObjectInspectorController::dispatchMessageFromFrontend(const String& message)
121 {
122     if (m_inspectorBackendDispatcher)
123         m_inspectorBackendDispatcher->dispatch(message);
124 }
125
126 void JSGlobalObjectInspectorController::appendAPIBacktrace(ScriptCallStack* callStack)
127 {
128     static const int framesToShow = 31;
129     static const int framesToSkip = 3; // WTFGetBacktrace, appendAPIBacktrace, reportAPIException.
130
131     void* samples[framesToShow + framesToSkip];
132     int frames = framesToShow + framesToSkip;
133     WTFGetBacktrace(samples, &frames);
134
135     void** stack = samples + framesToSkip;
136     int size = frames - framesToSkip;
137     for (int i = 0; i < size; ++i) {
138         const char* mangledName = nullptr;
139         char* cxaDemangled = nullptr;
140         Dl_info info;
141         if (dladdr(stack[i], &info) && info.dli_sname)
142             mangledName = info.dli_sname;
143         if (mangledName)
144             cxaDemangled = abi::__cxa_demangle(mangledName, nullptr, nullptr, nullptr);
145         if (mangledName || cxaDemangled)
146             callStack->append(ScriptCallFrame(cxaDemangled ? cxaDemangled : mangledName, ASCIILiteral("[native code]"), 0, 0));
147         else
148             callStack->append(ScriptCallFrame(ASCIILiteral("?"), ASCIILiteral("[native code]"), 0, 0));
149         free(cxaDemangled);
150     }
151 }
152
153 void JSGlobalObjectInspectorController::reportAPIException(ExecState* exec, JSValue exception)
154 {
155     if (isTerminatedExecutionException(exception))
156         return;
157
158     ErrorHandlingScope errorScope(exec->vm());
159
160     RefPtr<ScriptCallStack> callStack = createScriptCallStackFromException(exec, exception, ScriptCallStack::maxCallStackSizeToCapture);
161     if (includesNativeCallStackWhenReportingExceptions())
162         appendAPIBacktrace(callStack.get());
163
164     // FIXME: <http://webkit.org/b/115087> Web Inspector: Should not evaluate JavaScript handling exceptions
165     // If this is a custom exception object, call toString on it to try and get a nice string representation for the exception.
166     String errorMessage = exception.toString(exec)->value(exec);
167     exec->clearException();
168
169     if (JSGlobalObjectConsoleClient::logToSystemConsole()) {
170         if (callStack->size()) {
171             const ScriptCallFrame& callFrame = callStack->at(0);
172             ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callFrame.sourceURL(), callFrame.lineNumber(), callFrame.columnNumber());
173         } else
174             ConsoleClient::printConsoleMessage(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, String(), 0, 0);
175     }
176
177     m_consoleAgent->addMessageToConsole(MessageSource::JS, MessageType::Log, MessageLevel::Error, errorMessage, callStack);
178 }
179
180 ConsoleClient* JSGlobalObjectInspectorController::consoleClient() const
181 {
182     return m_consoleClient.get();
183 }
184
185 InspectorFunctionCallHandler JSGlobalObjectInspectorController::functionCallHandler() const
186 {
187     return JSC::call;
188 }
189
190 InspectorEvaluateHandler JSGlobalObjectInspectorController::evaluateHandler() const
191 {
192     return JSC::evaluate;
193 }
194
195 } // namespace Inspector
196
197 #endif // ENABLE(INSPECTOR)