1/*
2 * Copyright (C) 2010, 2013, 2015-2016 Apple Inc. All rights reserved.
3 * Copyright (C) 2010, 2011 Google Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#pragma once
31
32#include "Debugger.h"
33#include "InspectorAgentBase.h"
34#include "InspectorBackendDispatchers.h"
35#include "InspectorFrontendDispatchers.h"
36#include "ScriptBreakpoint.h"
37#include "ScriptDebugListener.h"
38#include <wtf/Forward.h>
39#include <wtf/HashMap.h>
40#include <wtf/HashSet.h>
41#include <wtf/Noncopyable.h>
42#include <wtf/Vector.h>
43
44namespace Inspector {
45
46class AsyncStackTrace;
47class InjectedScript;
48class InjectedScriptManager;
49class ScriptDebugServer;
50typedef String ErrorString;
51
52class JS_EXPORT_PRIVATE InspectorDebuggerAgent : public InspectorAgentBase, public ScriptDebugListener, public DebuggerBackendDispatcherHandler {
53 WTF_MAKE_NONCOPYABLE(InspectorDebuggerAgent);
54 WTF_MAKE_FAST_ALLOCATED;
55public:
56 static const char* backtraceObjectGroup;
57
58 virtual ~InspectorDebuggerAgent();
59
60 void didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*) final;
61 void willDestroyFrontendAndBackend(DisconnectReason) final;
62
63 void enable(ErrorString&) final;
64 void disable(ErrorString&) final;
65 void setPauseForInternalScripts(ErrorString&, bool shouldPause) final;
66 void setAsyncStackTraceDepth(ErrorString&, int depth) final;
67 void setBreakpointsActive(ErrorString&, bool active) final;
68 void setBreakpointByUrl(ErrorString&, int lineNumber, const String* optionalURL, const String* optionalURLRegex, const int* optionalColumnNumber, const JSON::Object* options, Protocol::Debugger::BreakpointId*, RefPtr<JSON::ArrayOf<Protocol::Debugger::Location>>& locations) final;
69 void setBreakpoint(ErrorString&, const JSON::Object& location, const JSON::Object* options, Protocol::Debugger::BreakpointId*, RefPtr<Protocol::Debugger::Location>& actualLocation) final;
70 void removeBreakpoint(ErrorString&, const String& breakpointIdentifier) final;
71 void continueUntilNextRunLoop(ErrorString&) final;
72 void continueToLocation(ErrorString&, const JSON::Object& location) final;
73 void searchInContent(ErrorString&, const String& scriptID, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<JSON::ArrayOf<Protocol::GenericTypes::SearchMatch>>&) final;
74 void getScriptSource(ErrorString&, const String& scriptID, String* scriptSource) final;
75 void getFunctionDetails(ErrorString&, const String& functionId, RefPtr<Protocol::Debugger::FunctionDetails>&) final;
76 void pause(ErrorString&) final;
77 void resume(ErrorString&) final;
78 void stepOver(ErrorString&) final;
79 void stepInto(ErrorString&) final;
80 void stepOut(ErrorString&) final;
81 void setPauseOnExceptions(ErrorString&, const String& pauseState) final;
82 void setPauseOnAssertions(ErrorString&, bool enabled) final;
83 void evaluateOnCallFrame(ErrorString&, const String& callFrameId, const String& expression, const String* objectGroup, const bool* includeCommandLineAPI, const bool* doNotPauseOnExceptionsAndMuteConsole, const bool* returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Protocol::Runtime::RemoteObject>& result, Optional<bool>& wasThrown, Optional<int>& savedResultIndex) final;
84
85 bool isPaused() const;
86 bool breakpointsActive() const;
87
88 void setSuppressAllPauses(bool);
89
90 void handleConsoleAssert(const String& message);
91
92 enum class AsyncCallType {
93 DOMTimer,
94 EventListener,
95 PostMessage,
96 RequestAnimationFrame,
97 };
98
99 void didScheduleAsyncCall(JSC::ExecState*, AsyncCallType, int callbackId, bool singleShot);
100 void didCancelAsyncCall(AsyncCallType, int callbackId);
101 void willDispatchAsyncCall(AsyncCallType, int callbackId);
102 void didDispatchAsyncCall();
103
104 void schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<JSON::Object>&& data);
105 void cancelPauseOnNextStatement();
106 bool pauseOnNextStatementEnabled() const { return m_javaScriptPauseScheduled; }
107
108 void breakProgram(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<JSON::Object>&& data);
109 void scriptExecutionBlockedByCSP(const String& directiveText);
110
111 class Listener {
112 public:
113 virtual ~Listener() { }
114 virtual void debuggerWasEnabled() = 0;
115 virtual void debuggerWasDisabled() = 0;
116 };
117 void addListener(Listener& listener) { m_listeners.add(&listener); }
118 void removeListener(Listener& listener) { m_listeners.remove(&listener); }
119
120protected:
121 InspectorDebuggerAgent(AgentContext&);
122
123 InjectedScriptManager& injectedScriptManager() const { return m_injectedScriptManager; }
124 virtual InjectedScript injectedScriptForEval(ErrorString&, const int* executionContextId) = 0;
125
126 ScriptDebugServer& scriptDebugServer() { return m_scriptDebugServer; }
127
128 virtual void muteConsole() = 0;
129 virtual void unmuteConsole() = 0;
130
131 virtual void enable();
132 virtual void disable(bool skipRecompile);
133 void didPause(JSC::ExecState&, JSC::JSValue callFrames, JSC::JSValue exceptionOrCaughtValue) final;
134 void didContinue() final;
135
136 virtual String sourceMapURLForScript(const Script&);
137
138 void didClearGlobalObject();
139 virtual void didClearAsyncStackTraceData() { }
140
141private:
142 Ref<JSON::ArrayOf<Protocol::Debugger::CallFrame>> currentCallFrames(const InjectedScript&);
143
144 void didParseSource(JSC::SourceID, const Script&) final;
145 void failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) final;
146
147 void breakpointActionSound(int breakpointActionIdentifier) final;
148 void breakpointActionProbe(JSC::ExecState&, const ScriptBreakpointAction&, unsigned batchId, unsigned sampleId, JSC::JSValue sample) final;
149
150 void resolveBreakpoint(const Script&, JSC::Breakpoint&);
151 void setBreakpoint(JSC::Breakpoint&, bool& existing);
152 void didSetBreakpoint(const JSC::Breakpoint&, const String&, const ScriptBreakpoint&);
153
154 bool assertPaused(ErrorString&);
155 void clearDebuggerBreakpointState();
156 void clearInspectorBreakpointState();
157 void clearBreakDetails();
158 void clearExceptionValue();
159 void clearAsyncStackTraceData();
160
161 enum class ShouldDispatchResumed { No, WhenIdle, WhenContinued };
162 void registerIdleHandler();
163 void willStepAndMayBecomeIdle();
164 void didBecomeIdle();
165
166 RefPtr<JSON::Object> buildBreakpointPauseReason(JSC::BreakpointID);
167 RefPtr<JSON::Object> buildExceptionPauseReason(JSC::JSValue exception, const InjectedScript&);
168
169 bool breakpointActionsFromProtocol(ErrorString&, RefPtr<JSON::Array>& actions, BreakpointActions* result);
170
171 typedef std::pair<unsigned, int> AsyncCallIdentifier;
172 static AsyncCallIdentifier asyncCallIdentifier(AsyncCallType, int callbackId);
173
174 std::unique_ptr<DebuggerFrontendDispatcher> m_frontendDispatcher;
175 RefPtr<DebuggerBackendDispatcher> m_backendDispatcher;
176
177 ScriptDebugServer& m_scriptDebugServer;
178 InjectedScriptManager& m_injectedScriptManager;
179 HashMap<JSC::SourceID, Script> m_scripts;
180
181 HashSet<Listener*> m_listeners;
182
183 JSC::ExecState* m_pausedScriptState { nullptr };
184 JSC::Strong<JSC::Unknown> m_currentCallStack;
185
186 HashMap<String, Vector<JSC::BreakpointID>> m_breakpointIdentifierToDebugServerBreakpointIDs;
187 HashMap<String, RefPtr<JSON::Object>> m_javaScriptBreakpoints;
188 HashMap<JSC::BreakpointID, String> m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier;
189 JSC::BreakpointID m_continueToLocationBreakpointID { JSC::noBreakpointID };
190 DebuggerFrontendDispatcher::Reason m_breakReason;
191 RefPtr<JSON::Object> m_breakData;
192 ShouldDispatchResumed m_conditionToDispatchResumed { ShouldDispatchResumed::No };
193
194 HashMap<AsyncCallIdentifier, RefPtr<AsyncStackTrace>> m_pendingAsyncCalls;
195 Optional<AsyncCallIdentifier> m_currentAsyncCallIdentifier;
196 int m_asyncStackTraceDepth { 0 };
197
198 bool m_enabled { false };
199 bool m_enablePauseWhenIdle { false };
200 bool m_pauseOnAssertionFailures { false };
201 bool m_pauseForInternalScripts { false };
202 bool m_javaScriptPauseScheduled { false };
203 bool m_didPauseStopwatch { false };
204 bool m_hasExceptionValue { false };
205 bool m_registeredIdleCallback { false };
206};
207
208} // namespace Inspector
209