617efb9ac39b2aaff0f7266845b577bc9ddf8e82
[WebKit-https.git] / Source / JavaScriptCore / inspector / agents / InspectorDebuggerAgent.cpp
1 /*
2  * Copyright (C) 2010, 2013, 2015 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 #include "config.h"
31 #include "InspectorDebuggerAgent.h"
32
33 #include "AsyncStackTrace.h"
34 #include "ContentSearchUtilities.h"
35 #include "InjectedScript.h"
36 #include "InjectedScriptManager.h"
37 #include "InspectorFrontendRouter.h"
38 #include "InspectorValues.h"
39 #include "JSCInlines.h"
40 #include "RegularExpression.h"
41 #include "ScriptCallStackFactory.h"
42 #include "ScriptDebugServer.h"
43 #include "ScriptObject.h"
44 #include "ScriptValue.h"
45 #include <wtf/NeverDestroyed.h>
46 #include <wtf/Stopwatch.h>
47 #include <wtf/text/WTFString.h>
48
49 namespace Inspector {
50
51 const char* InspectorDebuggerAgent::backtraceObjectGroup = "backtrace";
52
53 // Objects created and retained by evaluating breakpoint actions are put into object groups
54 // according to the breakpoint action identifier assigned by the frontend. A breakpoint may
55 // have several object groups, and objects from several backend breakpoint action instances may
56 // create objects in the same group.
57 static String objectGroupForBreakpointAction(const ScriptBreakpointAction& action)
58 {
59     static NeverDestroyed<String> objectGroup(ASCIILiteral("breakpoint-action-"));
60     return makeString(objectGroup.get(), String::number(action.identifier));
61 }
62
63 InspectorDebuggerAgent::InspectorDebuggerAgent(AgentContext& context)
64     : InspectorAgentBase(ASCIILiteral("Debugger"))
65     , m_injectedScriptManager(context.injectedScriptManager)
66     , m_frontendDispatcher(std::make_unique<DebuggerFrontendDispatcher>(context.frontendRouter))
67     , m_backendDispatcher(DebuggerBackendDispatcher::create(context.backendDispatcher, this))
68     , m_scriptDebugServer(context.environment.scriptDebugServer())
69     , m_continueToLocationBreakpointID(JSC::noBreakpointID)
70 {
71     // FIXME: make breakReason optional so that there was no need to init it with "other".
72     clearBreakDetails();
73 }
74
75 InspectorDebuggerAgent::~InspectorDebuggerAgent()
76 {
77 }
78
79 void InspectorDebuggerAgent::didCreateFrontendAndBackend(FrontendRouter*, BackendDispatcher*)
80 {
81 }
82
83 void InspectorDebuggerAgent::willDestroyFrontendAndBackend(DisconnectReason reason)
84 {
85     bool skipRecompile = reason == DisconnectReason::InspectedTargetDestroyed;
86     disable(skipRecompile);
87 }
88
89 void InspectorDebuggerAgent::enable()
90 {
91     if (m_enabled)
92         return;
93
94     m_scriptDebugServer.addListener(this);
95
96     if (m_listener)
97         m_listener->debuggerWasEnabled();
98
99     m_enabled = true;
100 }
101
102 void InspectorDebuggerAgent::disable(bool isBeingDestroyed)
103 {
104     if (!m_enabled)
105         return;
106
107     m_scriptDebugServer.removeListener(this, isBeingDestroyed);
108     clearInspectorBreakpointState();
109
110     if (!isBeingDestroyed)
111         m_scriptDebugServer.deactivateBreakpoints();
112
113     ASSERT(m_javaScriptBreakpoints.isEmpty());
114
115     if (m_listener)
116         m_listener->debuggerWasDisabled();
117
118     clearAsyncStackTraceData();
119
120     m_pauseOnAssertionFailures = false;
121
122     m_enabled = false;
123 }
124
125 void InspectorDebuggerAgent::enable(ErrorString&)
126 {
127     enable();
128 }
129
130 void InspectorDebuggerAgent::disable(ErrorString&)
131 {
132     disable(false);
133 }
134
135 bool InspectorDebuggerAgent::breakpointsActive() const
136 {
137     return m_scriptDebugServer.breakpointsActive();
138 }
139
140 void InspectorDebuggerAgent::setAsyncStackTraceDepth(ErrorString& errorString, int depth)
141 {
142     if (m_asyncStackTraceDepth == depth)
143         return;
144
145     if (depth < 0) {
146         errorString = ASCIILiteral("depth must be a positive number.");
147         return;
148     }
149
150     m_asyncStackTraceDepth = depth;
151
152     if (!m_asyncStackTraceDepth)
153         clearAsyncStackTraceData();
154 }
155
156 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString&, bool active)
157 {
158     if (active)
159         m_scriptDebugServer.activateBreakpoints();
160     else
161         m_scriptDebugServer.deactivateBreakpoints();
162 }
163
164 bool InspectorDebuggerAgent::isPaused() const
165 {
166     return m_scriptDebugServer.isPaused();
167 }
168
169 void InspectorDebuggerAgent::setSuppressAllPauses(bool suppress)
170 {
171     m_scriptDebugServer.setSuppressAllPauses(suppress);
172 }
173
174 static RefPtr<InspectorObject> buildAssertPauseReason(const String& message)
175 {
176     auto reason = Inspector::Protocol::Debugger::AssertPauseReason::create().release();
177     if (!message.isNull())
178         reason->setMessage(message);
179     return reason->openAccessors();
180 }
181
182 static RefPtr<InspectorObject> buildCSPViolationPauseReason(const String& directiveText)
183 {
184     auto reason = Inspector::Protocol::Debugger::CSPViolationPauseReason::create()
185         .setDirective(directiveText)
186         .release();
187     return reason->openAccessors();
188 }
189
190 RefPtr<InspectorObject> InspectorDebuggerAgent::buildBreakpointPauseReason(JSC::BreakpointID debuggerBreakpointIdentifier)
191 {
192     ASSERT(debuggerBreakpointIdentifier != JSC::noBreakpointID);
193     auto it = m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.find(debuggerBreakpointIdentifier);
194     if (it == m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.end())
195         return nullptr;
196
197     auto reason = Inspector::Protocol::Debugger::BreakpointPauseReason::create()
198         .setBreakpointId(it->value)
199         .release();
200     return reason->openAccessors();
201 }
202
203 RefPtr<InspectorObject> InspectorDebuggerAgent::buildExceptionPauseReason(JSC::JSValue exception, const InjectedScript& injectedScript)
204 {
205     ASSERT(exception);
206     if (!exception)
207         return nullptr;
208
209     ASSERT(!injectedScript.hasNoValue());
210     if (injectedScript.hasNoValue())
211         return nullptr;
212
213     return injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors();
214 }
215
216 void InspectorDebuggerAgent::handleConsoleAssert(const String& message)
217 {
218     if (!m_scriptDebugServer.breakpointsActive())
219         return;
220
221     if (m_pauseOnAssertionFailures)
222         breakProgram(DebuggerFrontendDispatcher::Reason::Assert, buildAssertPauseReason(message));
223 }
224
225 void InspectorDebuggerAgent::didScheduleAsyncCall(JSC::ExecState* exec, int asyncCallType, int callbackIdentifier, bool singleShot)
226 {
227     if (!m_asyncStackTraceDepth)
228         return;
229
230     if (!m_scriptDebugServer.breakpointsActive())
231         return;
232
233     Ref<ScriptCallStack> callStack = createScriptCallStack(exec, m_asyncStackTraceDepth);
234     ASSERT(callStack->size());
235     if (!callStack->size())
236         return;
237
238     RefPtr<AsyncStackTrace> parentStackTrace;
239     if (m_currentAsyncCallIdentifier) {
240         auto it = m_pendingAsyncCalls.find(m_currentAsyncCallIdentifier.value());
241         ASSERT(it != m_pendingAsyncCalls.end());
242         parentStackTrace = it->value;
243     }
244
245     auto identifier = std::make_pair(asyncCallType, callbackIdentifier);
246     auto asyncStackTrace = AsyncStackTrace::create(WTFMove(callStack), singleShot, WTFMove(parentStackTrace));
247
248     m_pendingAsyncCalls.set(identifier, WTFMove(asyncStackTrace));
249 }
250
251 void InspectorDebuggerAgent::didCancelAsyncCall(int asyncCallType, int callbackIdentifier)
252 {
253     if (!m_asyncStackTraceDepth)
254         return;
255
256     auto identifier = std::make_pair(asyncCallType, callbackIdentifier);
257     auto it = m_pendingAsyncCalls.find(identifier);
258     if (it == m_pendingAsyncCalls.end())
259         return;
260
261     auto& asyncStackTrace = it->value;
262     asyncStackTrace->didCancelAsyncCall();
263
264     if (m_currentAsyncCallIdentifier && m_currentAsyncCallIdentifier.value() == identifier)
265         return;
266
267     m_pendingAsyncCalls.remove(identifier);
268 }
269
270 void InspectorDebuggerAgent::willDispatchAsyncCall(int asyncCallType, int callbackIdentifier)
271 {
272     if (!m_asyncStackTraceDepth)
273         return;
274
275     if (m_currentAsyncCallIdentifier)
276         return;
277
278     // A call can be scheduled before the Inspector is opened, or while async stack
279     // traces are disabled. If no call data exists, do nothing.
280     auto identifier = std::make_pair(asyncCallType, callbackIdentifier);
281     auto it = m_pendingAsyncCalls.find(identifier);
282     if (it == m_pendingAsyncCalls.end())
283         return;
284
285     auto& asyncStackTrace = it->value;
286     asyncStackTrace->willDispatchAsyncCall(m_asyncStackTraceDepth);
287
288     m_currentAsyncCallIdentifier = identifier;
289 }
290
291 void InspectorDebuggerAgent::didDispatchAsyncCall()
292 {
293     if (!m_asyncStackTraceDepth)
294         return;
295
296     if (!m_currentAsyncCallIdentifier)
297         return;
298
299     auto identifier = m_currentAsyncCallIdentifier.value();
300     auto it = m_pendingAsyncCalls.find(identifier);
301     ASSERT(it != m_pendingAsyncCalls.end());
302
303     auto& asyncStackTrace = it->value;
304     asyncStackTrace->didDispatchAsyncCall();
305
306     m_currentAsyncCallIdentifier = std::nullopt;
307
308     if (!asyncStackTrace->isPending())
309         m_pendingAsyncCalls.remove(identifier);
310 }
311
312 static Ref<InspectorObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, RefPtr<InspectorArray>& actions, bool isRegex, bool autoContinue, unsigned ignoreCount)
313 {
314     Ref<InspectorObject> breakpointObject = InspectorObject::create();
315     breakpointObject->setString(ASCIILiteral("url"), url);
316     breakpointObject->setInteger(ASCIILiteral("lineNumber"), lineNumber);
317     breakpointObject->setInteger(ASCIILiteral("columnNumber"), columnNumber);
318     breakpointObject->setString(ASCIILiteral("condition"), condition);
319     breakpointObject->setBoolean(ASCIILiteral("isRegex"), isRegex);
320     breakpointObject->setBoolean(ASCIILiteral("autoContinue"), autoContinue);
321     breakpointObject->setInteger(ASCIILiteral("ignoreCount"), ignoreCount);
322
323     if (actions)
324         breakpointObject->setArray(ASCIILiteral("actions"), actions);
325
326     return breakpointObject;
327 }
328
329 static bool matches(const String& url, const String& pattern, bool isRegex)
330 {
331     if (isRegex) {
332         JSC::Yarr::RegularExpression regex(pattern, TextCaseSensitive);
333         return regex.match(url) != -1;
334     }
335     return url == pattern;
336 }
337
338 static bool breakpointActionTypeForString(const String& typeString, ScriptBreakpointActionType* output)
339 {
340     if (typeString == Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Log)) {
341         *output = ScriptBreakpointActionTypeLog;
342         return true;
343     }
344     if (typeString == Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Evaluate)) {
345         *output = ScriptBreakpointActionTypeEvaluate;
346         return true;
347     }
348     if (typeString == Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Sound)) {
349         *output = ScriptBreakpointActionTypeSound;
350         return true;
351     }
352     if (typeString == Inspector::Protocol::InspectorHelpers::getEnumConstantValue(Inspector::Protocol::Debugger::BreakpointAction::Type::Probe)) {
353         *output = ScriptBreakpointActionTypeProbe;
354         return true;
355     }
356
357     return false;
358 }
359
360 bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString& errorString, RefPtr<InspectorArray>& actions, BreakpointActions* result)
361 {
362     if (!actions)
363         return true;
364
365     unsigned actionsLength = actions->length();
366     if (!actionsLength)
367         return true;
368
369     result->reserveCapacity(actionsLength);
370     for (unsigned i = 0; i < actionsLength; ++i) {
371         RefPtr<InspectorValue> value = actions->get(i);
372         RefPtr<InspectorObject> object;
373         if (!value->asObject(object)) {
374             errorString = ASCIILiteral("BreakpointAction of incorrect type, expected object");
375             return false;
376         }
377
378         String typeString;
379         if (!object->getString(ASCIILiteral("type"), typeString)) {
380             errorString = ASCIILiteral("BreakpointAction had type missing");
381             return false;
382         }
383
384         ScriptBreakpointActionType type;
385         if (!breakpointActionTypeForString(typeString, &type)) {
386             errorString = ASCIILiteral("BreakpointAction had unknown type");
387             return false;
388         }
389
390         // Specifying an identifier is optional. They are used to correlate probe samples
391         // in the frontend across multiple backend probe actions and segregate object groups.
392         int identifier = 0;
393         object->getInteger(ASCIILiteral("id"), identifier);
394
395         String data;
396         object->getString(ASCIILiteral("data"), data);
397
398         result->append(ScriptBreakpointAction(type, identifier, data));
399     }
400
401     return true;
402 }
403
404 static RefPtr<Inspector::Protocol::Debugger::Location> buildDebuggerLocation(const JSC::Breakpoint& breakpoint)
405 {
406     ASSERT(breakpoint.resolved);
407
408     auto location = Inspector::Protocol::Debugger::Location::create()
409         .setScriptId(String::number(breakpoint.sourceID))
410         .setLineNumber(breakpoint.line)
411         .release();
412     location->setColumnNumber(breakpoint.column);
413
414     return WTFMove(location);
415 }
416
417 static bool parseLocation(ErrorString& errorString, const InspectorObject& location, JSC::SourceID& sourceID, unsigned& lineNumber, unsigned& columnNumber)
418 {
419     String scriptIDStr;
420     if (!location.getString(ASCIILiteral("scriptId"), scriptIDStr) || !location.getInteger(ASCIILiteral("lineNumber"), lineNumber)) {
421         sourceID = JSC::noSourceID;
422         errorString = ASCIILiteral("scriptId and lineNumber are required.");
423         return false;
424     }
425
426     sourceID = scriptIDStr.toIntPtr();
427     columnNumber = 0;
428     location.getInteger(ASCIILiteral("columnNumber"), columnNumber);
429     return true;
430 }
431
432 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString& errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const InspectorObject* options, Inspector::Protocol::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::Debugger::Location>>& locations)
433 {
434     locations = Inspector::Protocol::Array<Inspector::Protocol::Debugger::Location>::create();
435     if (!optionalURL == !optionalURLRegex) {
436         errorString = ASCIILiteral("Either url or urlRegex must be specified.");
437         return;
438     }
439
440     String url = optionalURL ? *optionalURL : *optionalURLRegex;
441     int columnNumber = optionalColumnNumber ? *optionalColumnNumber : 0;
442     bool isRegex = optionalURLRegex;
443
444     String breakpointIdentifier = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
445     if (m_javaScriptBreakpoints.contains(breakpointIdentifier)) {
446         errorString = ASCIILiteral("Breakpoint at specified location already exists.");
447         return;
448     }
449
450     String condition = emptyString();
451     bool autoContinue = false;
452     unsigned ignoreCount = 0;
453     RefPtr<InspectorArray> actions;
454     if (options) {
455         options->getString(ASCIILiteral("condition"), condition);
456         options->getBoolean(ASCIILiteral("autoContinue"), autoContinue);
457         options->getArray(ASCIILiteral("actions"), actions);
458         options->getInteger(ASCIILiteral("ignoreCount"), ignoreCount);
459     }
460
461     BreakpointActions breakpointActions;
462     if (!breakpointActionsFromProtocol(errorString, actions, &breakpointActions))
463         return;
464
465     m_javaScriptBreakpoints.set(breakpointIdentifier, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, actions, isRegex, autoContinue, ignoreCount));
466
467     for (auto& entry : m_scripts) {
468         Script& script = entry.value;
469         String scriptURLForBreakpoints = !script.sourceURL.isEmpty() ? script.sourceURL : script.url;
470         if (!matches(scriptURLForBreakpoints, url, isRegex))
471             continue;
472
473         JSC::SourceID sourceID = entry.key;
474         JSC::Breakpoint breakpoint(sourceID, lineNumber, columnNumber, condition, autoContinue, ignoreCount);
475         resolveBreakpoint(script, breakpoint);
476         if (!breakpoint.resolved)
477             continue;
478
479         bool existing;
480         setBreakpoint(breakpoint, existing);
481         if (existing)
482             continue;
483
484         ScriptBreakpoint scriptBreakpoint(breakpoint.line, breakpoint.column, condition, breakpointActions, autoContinue, ignoreCount);
485         didSetBreakpoint(breakpoint, breakpointIdentifier, scriptBreakpoint);
486
487         locations->addItem(buildDebuggerLocation(breakpoint));
488     }
489
490     *outBreakpointIdentifier = breakpointIdentifier;
491 }
492
493 void InspectorDebuggerAgent::setBreakpoint(ErrorString& errorString, const InspectorObject& location, const InspectorObject* options, Inspector::Protocol::Debugger::BreakpointId* outBreakpointIdentifier, RefPtr<Inspector::Protocol::Debugger::Location>& actualLocation)
494 {
495     JSC::SourceID sourceID;
496     unsigned lineNumber;
497     unsigned columnNumber;
498     if (!parseLocation(errorString, location, sourceID, lineNumber, columnNumber))
499         return;
500
501     String condition = emptyString();
502     bool autoContinue = false;
503     unsigned ignoreCount = 0;
504     RefPtr<InspectorArray> actions;
505     if (options) {
506         options->getString(ASCIILiteral("condition"), condition);
507         options->getBoolean(ASCIILiteral("autoContinue"), autoContinue);
508         options->getArray(ASCIILiteral("actions"), actions);
509         options->getInteger(ASCIILiteral("ignoreCount"), ignoreCount);
510     }
511
512     BreakpointActions breakpointActions;
513     if (!breakpointActionsFromProtocol(errorString, actions, &breakpointActions))
514         return;
515
516     auto scriptIterator = m_scripts.find(sourceID);
517     if (scriptIterator == m_scripts.end()) {
518         errorString = ASCIILiteral("No script for id: ") + String::number(sourceID);
519         return;
520     }
521
522     Script& script = scriptIterator->value;
523     JSC::Breakpoint breakpoint(sourceID, lineNumber, columnNumber, condition, autoContinue, ignoreCount);
524     resolveBreakpoint(script, breakpoint);
525     if (!breakpoint.resolved) {
526         errorString = ASCIILiteral("Could not resolve breakpoint");
527         return;
528     }
529
530     bool existing;
531     setBreakpoint(breakpoint, existing);
532     if (existing) {
533         errorString = ASCIILiteral("Breakpoint at specified location already exists");
534         return;
535     }
536
537     String breakpointIdentifier = String::number(sourceID) + ':' + String::number(breakpoint.line) + ':' + String::number(breakpoint.column);
538     ScriptBreakpoint scriptBreakpoint(breakpoint.line, breakpoint.column, condition, breakpointActions, autoContinue, ignoreCount);
539     didSetBreakpoint(breakpoint, breakpointIdentifier, scriptBreakpoint);
540
541     actualLocation = buildDebuggerLocation(breakpoint);
542     *outBreakpointIdentifier = breakpointIdentifier;
543 }
544
545 void InspectorDebuggerAgent::didSetBreakpoint(const JSC::Breakpoint& breakpoint, const String& breakpointIdentifier, const ScriptBreakpoint& scriptBreakpoint)
546 {
547     JSC::BreakpointID id = breakpoint.id;
548     m_scriptDebugServer.setBreakpointActions(id, scriptBreakpoint);
549
550     auto debugServerBreakpointIDsIterator = m_breakpointIdentifierToDebugServerBreakpointIDs.find(breakpointIdentifier);
551     if (debugServerBreakpointIDsIterator == m_breakpointIdentifierToDebugServerBreakpointIDs.end())
552         debugServerBreakpointIDsIterator = m_breakpointIdentifierToDebugServerBreakpointIDs.set(breakpointIdentifier, Vector<JSC::BreakpointID>()).iterator;
553     debugServerBreakpointIDsIterator->value.append(id);
554
555     m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.set(id, breakpointIdentifier);
556 }
557
558 void InspectorDebuggerAgent::resolveBreakpoint(const Script& script, JSC::Breakpoint& breakpoint)
559 {
560     if (breakpoint.line < static_cast<unsigned>(script.startLine) || static_cast<unsigned>(script.endLine) < breakpoint.line)
561         return;
562
563     m_scriptDebugServer.resolveBreakpoint(breakpoint, script.sourceProvider.get());
564 }
565
566 void InspectorDebuggerAgent::setBreakpoint(JSC::Breakpoint& breakpoint, bool& existing)
567 {
568     JSC::JSLockHolder locker(m_scriptDebugServer.vm());
569     m_scriptDebugServer.setBreakpoint(breakpoint, existing);
570 }
571
572 void InspectorDebuggerAgent::removeBreakpoint(ErrorString&, const String& breakpointIdentifier)
573 {
574     m_javaScriptBreakpoints.remove(breakpointIdentifier);
575
576     for (JSC::BreakpointID breakpointID : m_breakpointIdentifierToDebugServerBreakpointIDs.take(breakpointIdentifier)) {
577         m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.remove(breakpointID);
578
579         const BreakpointActions& breakpointActions = m_scriptDebugServer.getActionsForBreakpoint(breakpointID);
580         for (auto& action : breakpointActions)
581             m_injectedScriptManager.releaseObjectGroup(objectGroupForBreakpointAction(action));
582
583         JSC::JSLockHolder locker(m_scriptDebugServer.vm());
584         m_scriptDebugServer.removeBreakpointActions(breakpointID);
585         m_scriptDebugServer.removeBreakpoint(breakpointID);
586     }
587 }
588
589 void InspectorDebuggerAgent::continueUntilNextRunLoop(ErrorString& errorString)
590 {
591     if (!assertPaused(errorString))
592         return;
593
594     resume(errorString);
595
596     m_enablePauseWhenIdle = true;
597
598     registerIdleHandler();
599 }
600
601 void InspectorDebuggerAgent::continueToLocation(ErrorString& errorString, const InspectorObject& location)
602 {
603     if (!assertPaused(errorString))
604         return;
605
606     if (m_continueToLocationBreakpointID != JSC::noBreakpointID) {
607         m_scriptDebugServer.removeBreakpoint(m_continueToLocationBreakpointID);
608         m_continueToLocationBreakpointID = JSC::noBreakpointID;
609     }
610
611     JSC::SourceID sourceID;
612     unsigned lineNumber;
613     unsigned columnNumber;
614     if (!parseLocation(errorString, location, sourceID, lineNumber, columnNumber))
615         return;
616
617     auto scriptIterator = m_scripts.find(sourceID);
618     if (scriptIterator == m_scripts.end()) {
619         m_scriptDebugServer.continueProgram();
620         m_frontendDispatcher->resumed();
621         errorString = ASCIILiteral("No script for id: ") + String::number(sourceID);
622         return;
623     }
624
625     String condition;
626     bool autoContinue = false;
627     unsigned ignoreCount = 0;
628     JSC::Breakpoint breakpoint(sourceID, lineNumber, columnNumber, condition, autoContinue, ignoreCount);
629     Script& script = scriptIterator->value;
630     resolveBreakpoint(script, breakpoint);
631     if (!breakpoint.resolved) {
632         m_scriptDebugServer.continueProgram();
633         m_frontendDispatcher->resumed();
634         errorString = ASCIILiteral("Could not resolve breakpoint");
635         return;
636     }
637
638     bool existing;
639     setBreakpoint(breakpoint, existing);
640     if (existing) {
641         // There is an existing breakpoint at this location. Instead of
642         // acting like a series of steps, just resume and we will either
643         // hit this new breakpoint or not.
644         m_scriptDebugServer.continueProgram();
645         m_frontendDispatcher->resumed();
646         return;
647     }
648
649     m_continueToLocationBreakpointID = breakpoint.id;
650
651     // Treat this as a series of steps until reaching the new breakpoint.
652     // So don't issue a resumed event unless we exit the VM without pausing.
653     willStepAndMayBecomeIdle();
654     m_scriptDebugServer.continueProgram();
655 }
656
657 void InspectorDebuggerAgent::searchInContent(ErrorString& error, const String& scriptIDStr, const String& query, const bool* optionalCaseSensitive, const bool* optionalIsRegex, RefPtr<Inspector::Protocol::Array<Inspector::Protocol::GenericTypes::SearchMatch>>& results)
658 {
659     JSC::SourceID sourceID = scriptIDStr.toIntPtr();
660     auto it = m_scripts.find(sourceID);
661     if (it == m_scripts.end()) {
662         error = ASCIILiteral("No script for id: ") + scriptIDStr;
663         return;
664     }
665
666     bool isRegex = optionalIsRegex ? *optionalIsRegex : false;
667     bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false;
668     results = ContentSearchUtilities::searchInTextByLines(it->value.source, query, caseSensitive, isRegex);
669 }
670
671 void InspectorDebuggerAgent::getScriptSource(ErrorString& error, const String& scriptIDStr, String* scriptSource)
672 {
673     JSC::SourceID sourceID = scriptIDStr.toIntPtr();
674     ScriptsMap::iterator it = m_scripts.find(sourceID);
675     if (it != m_scripts.end())
676         *scriptSource = it->value.source;
677     else
678         error = ASCIILiteral("No script for id: ") + scriptIDStr;
679 }
680
681 void InspectorDebuggerAgent::getFunctionDetails(ErrorString& errorString, const String& functionId, RefPtr<Inspector::Protocol::Debugger::FunctionDetails>& details)
682 {
683     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(functionId);
684     if (injectedScript.hasNoValue()) {
685         errorString = ASCIILiteral("Function object id is obsolete");
686         return;
687     }
688
689     injectedScript.getFunctionDetails(errorString, functionId, &details);
690 }
691
692 void InspectorDebuggerAgent::schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data)
693 {
694     if (m_javaScriptPauseScheduled)
695         return;
696
697     m_javaScriptPauseScheduled = true;
698
699     m_breakReason = breakReason;
700     m_breakAuxData = WTFMove(data);
701
702     JSC::JSLockHolder locker(m_scriptDebugServer.vm());
703     m_scriptDebugServer.setPauseOnNextStatement(true);
704 }
705
706 void InspectorDebuggerAgent::cancelPauseOnNextStatement()
707 {
708     if (!m_javaScriptPauseScheduled)
709         return;
710
711     m_javaScriptPauseScheduled = false;
712
713     clearBreakDetails();
714     m_scriptDebugServer.setPauseOnNextStatement(false);
715     m_enablePauseWhenIdle = false;
716 }
717
718 void InspectorDebuggerAgent::pause(ErrorString&)
719 {
720     schedulePauseOnNextStatement(DebuggerFrontendDispatcher::Reason::PauseOnNextStatement, nullptr);
721 }
722
723 void InspectorDebuggerAgent::resume(ErrorString& errorString)
724 {
725     if (!m_pausedScriptState && !m_javaScriptPauseScheduled) {
726         errorString = ASCIILiteral("Was not paused or waiting to pause");
727         return;
728     }
729
730     cancelPauseOnNextStatement();
731     m_scriptDebugServer.continueProgram();
732     m_conditionToDispatchResumed = ShouldDispatchResumed::WhenContinued;
733 }
734
735 void InspectorDebuggerAgent::stepOver(ErrorString& errorString)
736 {
737     if (!assertPaused(errorString))
738         return;
739
740     willStepAndMayBecomeIdle();
741     m_scriptDebugServer.stepOverStatement();
742 }
743
744 void InspectorDebuggerAgent::stepInto(ErrorString& errorString)
745 {
746     if (!assertPaused(errorString))
747         return;
748
749     willStepAndMayBecomeIdle();
750     m_scriptDebugServer.stepIntoStatement();
751 }
752
753 void InspectorDebuggerAgent::stepOut(ErrorString& errorString)
754 {
755     if (!assertPaused(errorString))
756         return;
757
758     willStepAndMayBecomeIdle();
759     m_scriptDebugServer.stepOutOfFunction();
760 }
761
762 void InspectorDebuggerAgent::registerIdleHandler()
763 {
764     if (!m_registeredIdleCallback) {
765         m_registeredIdleCallback = true;
766         JSC::VM& vm = m_scriptDebugServer.vm();
767         vm.whenIdle([this]() {
768             didBecomeIdle();
769         });
770     }
771 }
772
773 void InspectorDebuggerAgent::willStepAndMayBecomeIdle()
774 {
775     // When stepping the backend must eventually trigger a "paused" or "resumed" event.
776     // If the step causes us to exit the VM, then we should issue "resumed".
777     m_conditionToDispatchResumed = ShouldDispatchResumed::WhenIdle;
778
779     registerIdleHandler();
780 }
781
782 void InspectorDebuggerAgent::didBecomeIdle()
783 {
784     m_registeredIdleCallback = false;
785
786     if (m_conditionToDispatchResumed == ShouldDispatchResumed::WhenIdle) {
787         cancelPauseOnNextStatement();
788         m_scriptDebugServer.continueProgram();
789         m_frontendDispatcher->resumed();
790     }
791
792     m_conditionToDispatchResumed = ShouldDispatchResumed::No;
793
794     if (m_enablePauseWhenIdle) {
795         ErrorString ignored;
796         pause(ignored);
797     }
798 }
799
800 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString& errorString, const String& stringPauseState)
801 {
802     JSC::Debugger::PauseOnExceptionsState pauseState;
803     if (stringPauseState == "none")
804         pauseState = JSC::Debugger::DontPauseOnExceptions;
805     else if (stringPauseState == "all")
806         pauseState = JSC::Debugger::PauseOnAllExceptions;
807     else if (stringPauseState == "uncaught")
808         pauseState = JSC::Debugger::PauseOnUncaughtExceptions;
809     else {
810         errorString = ASCIILiteral("Unknown pause on exceptions mode: ") + stringPauseState;
811         return;
812     }
813
814     m_scriptDebugServer.setPauseOnExceptionsState(static_cast<JSC::Debugger::PauseOnExceptionsState>(pauseState));
815     if (m_scriptDebugServer.pauseOnExceptionsState() != pauseState)
816         errorString = ASCIILiteral("Internal error. Could not change pause on exceptions state");
817 }
818
819 void InspectorDebuggerAgent::setPauseOnAssertions(ErrorString&, bool enabled)
820 {
821     m_pauseOnAssertionFailures = enabled;
822 }
823
824 void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString& errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, const bool* saveResult, RefPtr<Inspector::Protocol::Runtime::RemoteObject>& result, Inspector::Protocol::OptOutput<bool>* wasThrown, Inspector::Protocol::OptOutput<int>* savedResultIndex)
825 {
826     if (m_currentCallStack.hasNoValue()) {
827         errorString = ASCIILiteral("Not paused");
828         return;
829     }
830
831     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptForObjectId(callFrameId);
832     if (injectedScript.hasNoValue()) {
833         errorString = ASCIILiteral("Could not find InjectedScript for callFrameId");
834         return;
835     }
836
837     JSC::Debugger::PauseOnExceptionsState previousPauseOnExceptionsState = m_scriptDebugServer.pauseOnExceptionsState();
838     if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) {
839         if (previousPauseOnExceptionsState != JSC::Debugger::DontPauseOnExceptions)
840             m_scriptDebugServer.setPauseOnExceptionsState(JSC::Debugger::DontPauseOnExceptions);
841         muteConsole();
842     }
843
844     injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, saveResult ? *saveResult : false, &result, wasThrown, savedResultIndex);
845
846     if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) {
847         unmuteConsole();
848         if (m_scriptDebugServer.pauseOnExceptionsState() != previousPauseOnExceptionsState)
849             m_scriptDebugServer.setPauseOnExceptionsState(previousPauseOnExceptionsState);
850     }
851 }
852
853 void InspectorDebuggerAgent::setOverlayMessage(ErrorString&, const String*)
854 {
855 }
856
857 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
858 {
859     if (m_scriptDebugServer.pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions)
860         breakProgram(DebuggerFrontendDispatcher::Reason::CSPViolation, buildCSPViolationPauseReason(directiveText));
861 }
862
863 Ref<Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>> InspectorDebuggerAgent::currentCallFrames(const InjectedScript& injectedScript)
864 {
865     ASSERT(!injectedScript.hasNoValue());
866     if (injectedScript.hasNoValue())
867         return Inspector::Protocol::Array<Inspector::Protocol::Debugger::CallFrame>::create();
868
869     return injectedScript.wrapCallFrames(m_currentCallStack);
870 }
871
872 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script)
873 {
874     return script.sourceMappingURL;
875 }
876
877 static bool isWebKitInjectedScript(const String& sourceURL)
878 {
879     return sourceURL.startsWith("__InjectedScript_") && sourceURL.endsWith(".js");
880 }
881
882 void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID, const Script& script)
883 {
884     String scriptIDStr = String::number(sourceID);
885     bool hasSourceURL = !script.sourceURL.isEmpty();
886     String sourceURL = script.sourceURL;
887     String sourceMappingURL = sourceMapURLForScript(script);
888
889     const bool isModule = script.sourceProvider->sourceType() == JSC::SourceProviderSourceType::Module;
890     const bool* isContentScript = script.isContentScript ? &script.isContentScript : nullptr;
891     String* sourceURLParam = hasSourceURL ? &sourceURL : nullptr;
892     String* sourceMapURLParam = sourceMappingURL.isEmpty() ? nullptr : &sourceMappingURL;
893
894     m_frontendDispatcher->scriptParsed(scriptIDStr, script.url, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceURLParam, sourceMapURLParam, isModule ? &isModule : nullptr);
895
896     m_scripts.set(sourceID, script);
897
898     if (hasSourceURL && isWebKitInjectedScript(sourceURL))
899         m_scriptDebugServer.addToBlacklist(sourceID);
900
901     String scriptURLForBreakpoints = hasSourceURL ? script.sourceURL : script.url;
902     if (scriptURLForBreakpoints.isEmpty())
903         return;
904
905     for (auto& entry : m_javaScriptBreakpoints) {
906         RefPtr<InspectorObject> breakpointObject = entry.value;
907
908         bool isRegex;
909         String url;
910         breakpointObject->getBoolean(ASCIILiteral("isRegex"), isRegex);
911         breakpointObject->getString(ASCIILiteral("url"), url);
912         if (!matches(scriptURLForBreakpoints, url, isRegex))
913             continue;
914
915         ScriptBreakpoint scriptBreakpoint;
916         breakpointObject->getInteger(ASCIILiteral("lineNumber"), scriptBreakpoint.lineNumber);
917         breakpointObject->getInteger(ASCIILiteral("columnNumber"), scriptBreakpoint.columnNumber);
918         breakpointObject->getString(ASCIILiteral("condition"), scriptBreakpoint.condition);
919         breakpointObject->getBoolean(ASCIILiteral("autoContinue"), scriptBreakpoint.autoContinue);
920         breakpointObject->getInteger(ASCIILiteral("ignoreCount"), scriptBreakpoint.ignoreCount);
921         ErrorString errorString;
922         RefPtr<InspectorArray> actions;
923         breakpointObject->getArray(ASCIILiteral("actions"), actions);
924         if (!breakpointActionsFromProtocol(errorString, actions, &scriptBreakpoint.actions)) {
925             ASSERT_NOT_REACHED();
926             continue;
927         }
928
929         JSC::Breakpoint breakpoint(sourceID, scriptBreakpoint.lineNumber, scriptBreakpoint.columnNumber, scriptBreakpoint.condition, scriptBreakpoint.autoContinue, scriptBreakpoint.ignoreCount);
930         resolveBreakpoint(script, breakpoint);
931         if (!breakpoint.resolved)
932             continue;
933
934         bool existing;
935         setBreakpoint(breakpoint, existing);
936         if (existing)
937             continue;
938
939         String breakpointIdentifier = entry.key;
940         didSetBreakpoint(breakpoint, breakpointIdentifier, scriptBreakpoint);
941
942         m_frontendDispatcher->breakpointResolved(breakpointIdentifier, buildDebuggerLocation(breakpoint));
943     }
944 }
945
946 void InspectorDebuggerAgent::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage)
947 {
948     m_frontendDispatcher->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage);
949 }
950
951 void InspectorDebuggerAgent::didPause(JSC::ExecState& scriptState, JSC::JSValue callFrames, JSC::JSValue exceptionOrCaughtValue)
952 {
953     ASSERT(!m_pausedScriptState);
954     m_pausedScriptState = &scriptState;
955     m_currentCallStack = { scriptState.vm(), callFrames };
956
957     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(&scriptState);
958
959     // If a high level pause pause reason is not already set, try to infer a reason from the debugger.
960     if (m_breakReason == DebuggerFrontendDispatcher::Reason::Other) {
961         switch (m_scriptDebugServer.reasonForPause()) {
962         case JSC::Debugger::PausedForBreakpoint: {
963             JSC::BreakpointID debuggerBreakpointId = m_scriptDebugServer.pausingBreakpointID();
964             if (debuggerBreakpointId != m_continueToLocationBreakpointID) {
965                 m_breakReason = DebuggerFrontendDispatcher::Reason::Breakpoint;
966                 m_breakAuxData = buildBreakpointPauseReason(debuggerBreakpointId);
967             }
968             break;
969         }
970         case JSC::Debugger::PausedForDebuggerStatement:
971             m_breakReason = DebuggerFrontendDispatcher::Reason::DebuggerStatement;
972             m_breakAuxData = nullptr;
973             break;
974         case JSC::Debugger::PausedForException:
975             m_breakReason = DebuggerFrontendDispatcher::Reason::Exception;
976             m_breakAuxData = buildExceptionPauseReason(exceptionOrCaughtValue, injectedScript);
977             break;
978         case JSC::Debugger::PausedAtStatement:
979         case JSC::Debugger::PausedAtExpression:
980         case JSC::Debugger::PausedBeforeReturn:
981         case JSC::Debugger::PausedAtEndOfProgram:
982             // Pause was just stepping. Nothing to report.
983             break;
984         case JSC::Debugger::NotPaused:
985             ASSERT_NOT_REACHED();
986             break;
987         }
988     }
989
990     // Set $exception to the exception or caught value.
991     if (exceptionOrCaughtValue && !injectedScript.hasNoValue()) {
992         injectedScript.setExceptionValue(exceptionOrCaughtValue);
993         m_hasExceptionValue = true;
994     }
995
996     m_conditionToDispatchResumed = ShouldDispatchResumed::No;
997     m_enablePauseWhenIdle = false;
998
999     RefPtr<Inspector::Protocol::Console::StackTrace> asyncStackTrace;
1000     if (m_currentAsyncCallIdentifier) {
1001         auto it = m_pendingAsyncCalls.find(m_currentAsyncCallIdentifier.value());
1002         if (it != m_pendingAsyncCalls.end())
1003             asyncStackTrace = it->value->buildInspectorObject();
1004     }
1005
1006     m_frontendDispatcher->paused(currentCallFrames(injectedScript), m_breakReason, m_breakAuxData, asyncStackTrace);
1007
1008     m_javaScriptPauseScheduled = false;
1009
1010     if (m_continueToLocationBreakpointID != JSC::noBreakpointID) {
1011         m_scriptDebugServer.removeBreakpoint(m_continueToLocationBreakpointID);
1012         m_continueToLocationBreakpointID = JSC::noBreakpointID;
1013     }
1014
1015     RefPtr<Stopwatch> stopwatch = m_injectedScriptManager.inspectorEnvironment().executionStopwatch();
1016     if (stopwatch && stopwatch->isActive()) {
1017         stopwatch->stop();
1018         m_didPauseStopwatch = true;
1019     }
1020 }
1021
1022 void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifier)
1023 {
1024     m_frontendDispatcher->playBreakpointActionSound(breakpointActionIdentifier);
1025 }
1026
1027 void InspectorDebuggerAgent::breakpointActionProbe(JSC::ExecState& scriptState, const ScriptBreakpointAction& action, unsigned batchId, unsigned sampleId, JSC::JSValue sample)
1028 {
1029     InjectedScript injectedScript = m_injectedScriptManager.injectedScriptFor(&scriptState);
1030     auto payload = injectedScript.wrapObject(sample, objectGroupForBreakpointAction(action), true);
1031     auto result = Protocol::Debugger::ProbeSample::create()
1032         .setProbeId(action.identifier)
1033         .setBatchId(batchId)
1034         .setSampleId(sampleId)
1035         .setTimestamp(m_injectedScriptManager.inspectorEnvironment().executionStopwatch()->elapsedTime())
1036         .setPayload(WTFMove(payload))
1037         .release();
1038     m_frontendDispatcher->didSampleProbe(WTFMove(result));
1039 }
1040
1041 void InspectorDebuggerAgent::didContinue()
1042 {
1043     if (m_didPauseStopwatch) {
1044         m_didPauseStopwatch = false;
1045         m_injectedScriptManager.inspectorEnvironment().executionStopwatch()->start();
1046     }
1047
1048     m_pausedScriptState = nullptr;
1049     m_currentCallStack = { };
1050     m_injectedScriptManager.releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
1051     clearBreakDetails();
1052     clearExceptionValue();
1053
1054     if (m_conditionToDispatchResumed == ShouldDispatchResumed::WhenContinued)
1055         m_frontendDispatcher->resumed();
1056 }
1057
1058 void InspectorDebuggerAgent::breakProgram(DebuggerFrontendDispatcher::Reason breakReason, RefPtr<InspectorObject>&& data)
1059 {
1060     m_breakReason = breakReason;
1061     m_breakAuxData = WTFMove(data);
1062     m_scriptDebugServer.breakProgram();
1063 }
1064
1065 void InspectorDebuggerAgent::clearInspectorBreakpointState()
1066 {
1067     ErrorString dummyError;
1068     Vector<String> breakpointIdentifiers;
1069     copyKeysToVector(m_breakpointIdentifierToDebugServerBreakpointIDs, breakpointIdentifiers);
1070     for (const String& identifier : breakpointIdentifiers)
1071         removeBreakpoint(dummyError, identifier);
1072
1073     m_javaScriptBreakpoints.clear();
1074
1075     clearDebuggerBreakpointState();
1076 }
1077
1078 void InspectorDebuggerAgent::clearDebuggerBreakpointState()
1079 {
1080     {
1081         JSC::JSLockHolder holder(m_scriptDebugServer.vm());
1082         m_scriptDebugServer.clearBreakpointActions();
1083         m_scriptDebugServer.clearBreakpoints();
1084         m_scriptDebugServer.clearBlacklist();
1085     }
1086
1087     m_pausedScriptState = nullptr;
1088     m_currentCallStack = { };
1089     m_scripts.clear();
1090     m_breakpointIdentifierToDebugServerBreakpointIDs.clear();
1091     m_debuggerBreakpointIdentifierToInspectorBreakpointIdentifier.clear();
1092     m_continueToLocationBreakpointID = JSC::noBreakpointID;
1093     clearBreakDetails();
1094     m_javaScriptPauseScheduled = false;
1095     m_hasExceptionValue = false;
1096
1097     if (isPaused()) {
1098         m_scriptDebugServer.continueProgram();
1099         m_frontendDispatcher->resumed();
1100     }
1101 }
1102
1103 void InspectorDebuggerAgent::didClearGlobalObject()
1104 {
1105     // Clear breakpoints from the debugger, but keep the inspector's model of which
1106     // pages have what breakpoints, as the mapping is only sent to DebuggerAgent once.
1107     clearDebuggerBreakpointState();
1108
1109     clearAsyncStackTraceData();
1110
1111     m_frontendDispatcher->globalObjectCleared();
1112 }
1113
1114 bool InspectorDebuggerAgent::assertPaused(ErrorString& errorString)
1115 {
1116     if (!m_pausedScriptState) {
1117         errorString = ASCIILiteral("Can only perform operation while paused.");
1118         return false;
1119     }
1120
1121     return true;
1122 }
1123
1124 void InspectorDebuggerAgent::clearBreakDetails()
1125 {
1126     m_breakReason = DebuggerFrontendDispatcher::Reason::Other;
1127     m_breakAuxData = nullptr;
1128 }
1129
1130 void InspectorDebuggerAgent::clearExceptionValue()
1131 {
1132     if (m_hasExceptionValue) {
1133         m_injectedScriptManager.clearExceptionValue();
1134         m_hasExceptionValue = false;
1135     }
1136 }
1137
1138 void InspectorDebuggerAgent::clearAsyncStackTraceData()
1139 {
1140     m_pendingAsyncCalls.clear();
1141     m_currentAsyncCallIdentifier = std::nullopt;
1142 }
1143
1144 } // namespace Inspector