2 * Copyright (C) 2010, 2013 Apple Inc. All rights reserved.
3 * Copyright (C) 2010-2011 Google Inc. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
31 #include "InspectorDebuggerAgent.h"
35 #include "ContentSearchUtilities.h"
36 #include "InjectedScript.h"
37 #include "InjectedScriptManager.h"
38 #include "InspectorValues.h"
39 #include "RegularExpression.h"
40 #include "ScriptDebugServer.h"
41 #include "ScriptObject.h"
42 #include "ScriptValue.h"
43 #include <wtf/text/WTFString.h>
47 const char* InspectorDebuggerAgent::backtraceObjectGroup
= "backtrace";
49 // Objects created and retained by evaluating breakpoint actions are put into object groups
50 // according to the breakpoint action identifier assigned by the frontend. A breakpoint may
51 // have several object groups, and objects from several backend breakpoint action instances may
52 // create objects in the same group.
53 static String
objectGroupForBreakpointAction(const ScriptBreakpointAction
& action
)
55 DEPRECATED_DEFINE_STATIC_LOCAL(const AtomicString
, objectGroup
, ("breakpoint-action-", AtomicString::ConstructFromLiteral
));
56 return makeString(objectGroup
, String::number(action
.identifier
));
59 InspectorDebuggerAgent::InspectorDebuggerAgent(InjectedScriptManager
* injectedScriptManager
)
60 : InspectorAgentBase(ASCIILiteral("Debugger"))
61 , m_injectedScriptManager(injectedScriptManager
)
63 , m_pausedScriptState(nullptr)
64 , m_continueToLocationBreakpointID(JSC::noBreakpointID
)
66 , m_javaScriptPauseScheduled(false)
67 , m_nextProbeSampleId(1)
69 // FIXME: make breakReason optional so that there was no need to init it with "other".
73 InspectorDebuggerAgent::~InspectorDebuggerAgent()
77 void InspectorDebuggerAgent::didCreateFrontendAndBackend(InspectorFrontendChannel
* frontendChannel
, InspectorBackendDispatcher
* backendDispatcher
)
79 m_frontendDispatcher
= std::make_unique
<InspectorDebuggerFrontendDispatcher
>(frontendChannel
);
80 m_backendDispatcher
= InspectorDebuggerBackendDispatcher::create(backendDispatcher
, this);
83 void InspectorDebuggerAgent::willDestroyFrontendAndBackend(InspectorDisconnectReason reason
)
85 m_frontendDispatcher
= nullptr;
86 m_backendDispatcher
.clear();
88 bool skipRecompile
= reason
== InspectorDisconnectReason::InspectedTargetDestroyed
;
89 disable(skipRecompile
);
92 void InspectorDebuggerAgent::enable()
97 scriptDebugServer().setBreakpointsActivated(true);
98 startListeningScriptDebugServer();
101 m_listener
->debuggerWasEnabled();
106 void InspectorDebuggerAgent::disable(bool isBeingDestroyed
)
111 stopListeningScriptDebugServer(isBeingDestroyed
);
112 clearInspectorBreakpointState();
114 ASSERT(m_javaScriptBreakpoints
.isEmpty());
117 m_listener
->debuggerWasDisabled();
122 void InspectorDebuggerAgent::enable(ErrorString
*)
127 void InspectorDebuggerAgent::disable(ErrorString
*)
132 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString
*, bool active
)
135 scriptDebugServer().activateBreakpoints();
137 scriptDebugServer().deactivateBreakpoints();
140 bool InspectorDebuggerAgent::isPaused()
142 return scriptDebugServer().isPaused();
145 void InspectorDebuggerAgent::handleConsoleAssert()
147 if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions
)
148 breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Assert
, nullptr);
151 static PassRefPtr
<InspectorObject
> buildObjectForBreakpointCookie(const String
& url
, int lineNumber
, int columnNumber
, const String
& condition
, RefPtr
<InspectorArray
>& actions
, bool isRegex
, bool autoContinue
)
153 RefPtr
<InspectorObject
> breakpointObject
= InspectorObject::create();
154 breakpointObject
->setString(ASCIILiteral("url"), url
);
155 breakpointObject
->setNumber(ASCIILiteral("lineNumber"), lineNumber
);
156 breakpointObject
->setNumber(ASCIILiteral("columnNumber"), columnNumber
);
157 breakpointObject
->setString(ASCIILiteral("condition"), condition
);
158 breakpointObject
->setBoolean(ASCIILiteral("isRegex"), isRegex
);
159 breakpointObject
->setBoolean(ASCIILiteral("autoContinue"), autoContinue
);
162 breakpointObject
->setArray(ASCIILiteral("actions"), actions
);
164 return breakpointObject
;
167 static bool matches(const String
& url
, const String
& pattern
, bool isRegex
)
170 JSC::Yarr::RegularExpression
regex(pattern
, TextCaseSensitive
);
171 return regex
.match(url
) != -1;
173 return url
== pattern
;
176 static bool breakpointActionTypeForString(const String
& typeString
, ScriptBreakpointActionType
* output
)
178 if (typeString
== Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Log
)) {
179 *output
= ScriptBreakpointActionTypeLog
;
182 if (typeString
== Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Evaluate
)) {
183 *output
= ScriptBreakpointActionTypeEvaluate
;
186 if (typeString
== Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Sound
)) {
187 *output
= ScriptBreakpointActionTypeSound
;
190 if (typeString
== Inspector::TypeBuilder::getJSEnumConstantValue(Inspector::TypeBuilder::Debugger::BreakpointAction::Type::Probe
)) {
191 *output
= ScriptBreakpointActionTypeProbe
;
198 bool InspectorDebuggerAgent::breakpointActionsFromProtocol(ErrorString
* errorString
, RefPtr
<InspectorArray
>& actions
, BreakpointActions
* result
)
203 unsigned actionsLength
= actions
->length();
207 result
->reserveCapacity(actionsLength
);
208 for (unsigned i
= 0; i
< actionsLength
; ++i
) {
209 RefPtr
<InspectorValue
> value
= actions
->get(i
);
210 RefPtr
<InspectorObject
> object
;
211 if (!value
->asObject(&object
)) {
212 *errorString
= ASCIILiteral("BreakpointAction of incorrect type, expected object");
217 if (!object
->getString(ASCIILiteral("type"), &typeString
)) {
218 *errorString
= ASCIILiteral("BreakpointAction had type missing");
222 ScriptBreakpointActionType type
;
223 if (!breakpointActionTypeForString(typeString
, &type
)) {
224 *errorString
= ASCIILiteral("BreakpointAction had unknown type");
228 // Specifying an identifier is optional. They are used to correlate probe samples
229 // in the frontend across multiple backend probe actions and segregate object groups.
231 object
->getNumber(ASCIILiteral("id"), &identifier
);
234 object
->getString(ASCIILiteral("data"), &data
);
236 result
->append(ScriptBreakpointAction(type
, identifier
, data
));
242 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString
* errorString
, int lineNumber
, const String
* const optionalURL
, const String
* const optionalURLRegex
, const int* const optionalColumnNumber
, const RefPtr
<InspectorObject
>* options
, Inspector::TypeBuilder::Debugger::BreakpointId
* outBreakpointIdentifier
, RefPtr
<Inspector::TypeBuilder::Array
<Inspector::TypeBuilder::Debugger::Location
>>& locations
)
244 locations
= Inspector::TypeBuilder::Array
<Inspector::TypeBuilder::Debugger::Location
>::create();
245 if (!optionalURL
== !optionalURLRegex
) {
246 *errorString
= ASCIILiteral("Either url or urlRegex must be specified.");
250 String url
= optionalURL
? *optionalURL
: *optionalURLRegex
;
251 int columnNumber
= optionalColumnNumber
? *optionalColumnNumber
: 0;
252 bool isRegex
= optionalURLRegex
;
254 String breakpointIdentifier
= (isRegex
? "/" + url
+ "/" : url
) + ':' + String::number(lineNumber
) + ':' + String::number(columnNumber
);
255 if (m_javaScriptBreakpoints
.contains(breakpointIdentifier
)) {
256 *errorString
= ASCIILiteral("Breakpoint at specified location already exists.");
260 String condition
= emptyString();
261 bool autoContinue
= false;
262 RefPtr
<InspectorArray
> actions
;
264 (*options
)->getString(ASCIILiteral("condition"), &condition
);
265 (*options
)->getBoolean(ASCIILiteral("autoContinue"), &autoContinue
);
266 actions
= (*options
)->getArray(ASCIILiteral("actions"));
269 BreakpointActions breakpointActions
;
270 if (!breakpointActionsFromProtocol(errorString
, actions
, &breakpointActions
))
273 m_javaScriptBreakpoints
.set(breakpointIdentifier
, buildObjectForBreakpointCookie(url
, lineNumber
, columnNumber
, condition
, actions
, isRegex
, autoContinue
));
275 ScriptBreakpoint
breakpoint(lineNumber
, columnNumber
, condition
, breakpointActions
, autoContinue
);
276 for (ScriptsMap::iterator it
= m_scripts
.begin(); it
!= m_scripts
.end(); ++it
) {
277 String scriptURL
= !it
->value
.sourceURL
.isEmpty() ? it
->value
.sourceURL
: it
->value
.url
;
278 if (!matches(scriptURL
, url
, isRegex
))
281 RefPtr
<Inspector::TypeBuilder::Debugger::Location
> location
= resolveBreakpoint(breakpointIdentifier
, it
->key
, breakpoint
);
283 locations
->addItem(location
);
285 *outBreakpointIdentifier
= breakpointIdentifier
;
288 static bool parseLocation(ErrorString
* errorString
, InspectorObject
* location
, JSC::SourceID
* sourceID
, unsigned* lineNumber
, unsigned* columnNumber
)
291 if (!location
->getString(ASCIILiteral("scriptId"), &scriptIDStr
) || !location
->getNumber(ASCIILiteral("lineNumber"), lineNumber
)) {
292 *sourceID
= JSC::noSourceID
;
293 *errorString
= ASCIILiteral("scriptId and lineNumber are required.");
297 *sourceID
= scriptIDStr
.toIntPtr();
299 location
->getNumber(ASCIILiteral("columnNumber"), columnNumber
);
303 void InspectorDebuggerAgent::setBreakpoint(ErrorString
* errorString
, const RefPtr
<InspectorObject
>& location
, const RefPtr
<InspectorObject
>* options
, Inspector::TypeBuilder::Debugger::BreakpointId
* outBreakpointIdentifier
, RefPtr
<Inspector::TypeBuilder::Debugger::Location
>& actualLocation
)
305 JSC::SourceID sourceID
;
307 unsigned columnNumber
;
308 if (!parseLocation(errorString
, location
.get(), &sourceID
, &lineNumber
, &columnNumber
))
311 String condition
= emptyString();
312 bool autoContinue
= false;
313 RefPtr
<InspectorArray
> actions
;
315 (*options
)->getString(ASCIILiteral("condition"), &condition
);
316 (*options
)->getBoolean(ASCIILiteral("autoContinue"), &autoContinue
);
317 actions
= (*options
)->getArray(ASCIILiteral("actions"));
320 BreakpointActions breakpointActions
;
321 if (!breakpointActionsFromProtocol(errorString
, actions
, &breakpointActions
))
324 String breakpointIdentifier
= String::number(sourceID
) + ':' + String::number(lineNumber
) + ':' + String::number(columnNumber
);
325 if (m_breakpointIdentifierToDebugServerBreakpointIDs
.find(breakpointIdentifier
) != m_breakpointIdentifierToDebugServerBreakpointIDs
.end()) {
326 *errorString
= ASCIILiteral("Breakpoint at specified location already exists.");
330 ScriptBreakpoint
breakpoint(lineNumber
, columnNumber
, condition
, breakpointActions
, autoContinue
);
331 actualLocation
= resolveBreakpoint(breakpointIdentifier
, sourceID
, breakpoint
);
332 if (!actualLocation
) {
333 *errorString
= ASCIILiteral("Could not resolve breakpoint");
337 *outBreakpointIdentifier
= breakpointIdentifier
;
340 void InspectorDebuggerAgent::removeBreakpoint(ErrorString
*, const String
& breakpointIdentifier
)
342 m_javaScriptBreakpoints
.remove(breakpointIdentifier
);
344 for (JSC::BreakpointID breakpointID
: m_breakpointIdentifierToDebugServerBreakpointIDs
.take(breakpointIdentifier
)) {
345 const BreakpointActions
& breakpointActions
= scriptDebugServer().getActionsForBreakpoint(breakpointID
);
346 for (auto& action
: breakpointActions
)
347 m_injectedScriptManager
->releaseObjectGroup(objectGroupForBreakpointAction(action
));
349 scriptDebugServer().removeBreakpoint(breakpointID
);
353 void InspectorDebuggerAgent::continueToLocation(ErrorString
* errorString
, const RefPtr
<InspectorObject
>& location
)
355 if (m_continueToLocationBreakpointID
!= JSC::noBreakpointID
) {
356 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointID
);
357 m_continueToLocationBreakpointID
= JSC::noBreakpointID
;
360 JSC::SourceID sourceID
;
362 unsigned columnNumber
;
363 if (!parseLocation(errorString
, location
.get(), &sourceID
, &lineNumber
, &columnNumber
))
366 ScriptBreakpoint
breakpoint(lineNumber
, columnNumber
, "", false);
367 m_continueToLocationBreakpointID
= scriptDebugServer().setBreakpoint(sourceID
, breakpoint
, &lineNumber
, &columnNumber
);
371 PassRefPtr
<Inspector::TypeBuilder::Debugger::Location
> InspectorDebuggerAgent::resolveBreakpoint(const String
& breakpointIdentifier
, JSC::SourceID sourceID
, const ScriptBreakpoint
& breakpoint
)
373 ScriptsMap::iterator scriptIterator
= m_scripts
.find(sourceID
);
374 if (scriptIterator
== m_scripts
.end())
376 Script
& script
= scriptIterator
->value
;
377 if (breakpoint
.lineNumber
< script
.startLine
|| script
.endLine
< breakpoint
.lineNumber
)
380 unsigned actualLineNumber
;
381 unsigned actualColumnNumber
;
382 JSC::BreakpointID debugServerBreakpointID
= scriptDebugServer().setBreakpoint(sourceID
, breakpoint
, &actualLineNumber
, &actualColumnNumber
);
383 if (debugServerBreakpointID
== JSC::noBreakpointID
)
386 BreakpointIdentifierToDebugServerBreakpointIDsMap::iterator debugServerBreakpointIDsIterator
= m_breakpointIdentifierToDebugServerBreakpointIDs
.find(breakpointIdentifier
);
387 if (debugServerBreakpointIDsIterator
== m_breakpointIdentifierToDebugServerBreakpointIDs
.end())
388 debugServerBreakpointIDsIterator
= m_breakpointIdentifierToDebugServerBreakpointIDs
.set(breakpointIdentifier
, Vector
<JSC::BreakpointID
>()).iterator
;
389 debugServerBreakpointIDsIterator
->value
.append(debugServerBreakpointID
);
391 RefPtr
<Inspector::TypeBuilder::Debugger::Location
> location
= Inspector::TypeBuilder::Debugger::Location::create()
392 .setScriptId(String::number(sourceID
))
393 .setLineNumber(actualLineNumber
);
394 location
->setColumnNumber(actualColumnNumber
);
398 void InspectorDebuggerAgent::searchInContent(ErrorString
* error
, const String
& scriptIDStr
, const String
& query
, const bool* const optionalCaseSensitive
, const bool* const optionalIsRegex
, RefPtr
<Inspector::TypeBuilder::Array
<Inspector::TypeBuilder::GenericTypes::SearchMatch
>>& results
)
400 bool isRegex
= optionalIsRegex
? *optionalIsRegex
: false;
401 bool caseSensitive
= optionalCaseSensitive
? *optionalCaseSensitive
: false;
403 JSC::SourceID sourceID
= scriptIDStr
.toIntPtr();
404 ScriptsMap::iterator it
= m_scripts
.find(sourceID
);
405 if (it
!= m_scripts
.end())
406 results
= ContentSearchUtilities::searchInTextByLines(it
->value
.source
, query
, caseSensitive
, isRegex
);
408 *error
= "No script for id: " + scriptIDStr
;
411 void InspectorDebuggerAgent::getScriptSource(ErrorString
* error
, const String
& scriptIDStr
, String
* scriptSource
)
413 JSC::SourceID sourceID
= scriptIDStr
.toIntPtr();
414 ScriptsMap::iterator it
= m_scripts
.find(sourceID
);
415 if (it
!= m_scripts
.end())
416 *scriptSource
= it
->value
.source
;
418 *error
= "No script for id: " + scriptIDStr
;
421 void InspectorDebuggerAgent::getFunctionDetails(ErrorString
* errorString
, const String
& functionId
, RefPtr
<Inspector::TypeBuilder::Debugger::FunctionDetails
>& details
)
423 InjectedScript injectedScript
= m_injectedScriptManager
->injectedScriptForObjectId(functionId
);
424 if (injectedScript
.hasNoValue()) {
425 *errorString
= ASCIILiteral("Function object id is obsolete");
429 injectedScript
.getFunctionDetails(errorString
, functionId
, &details
);
432 void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorDebuggerFrontendDispatcher::Reason::Enum breakReason
, PassRefPtr
<InspectorObject
> data
)
434 if (m_javaScriptPauseScheduled
)
437 m_breakReason
= breakReason
;
438 m_breakAuxData
= data
;
439 scriptDebugServer().setPauseOnNextStatement(true);
442 void InspectorDebuggerAgent::cancelPauseOnNextStatement()
444 if (m_javaScriptPauseScheduled
)
448 scriptDebugServer().setPauseOnNextStatement(false);
451 void InspectorDebuggerAgent::pause(ErrorString
*)
453 if (m_javaScriptPauseScheduled
)
457 scriptDebugServer().setPauseOnNextStatement(true);
458 m_javaScriptPauseScheduled
= true;
461 void InspectorDebuggerAgent::resume(ErrorString
* errorString
)
463 if (!assertPaused(errorString
))
466 m_injectedScriptManager
->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup
);
467 scriptDebugServer().continueProgram();
470 void InspectorDebuggerAgent::stepOver(ErrorString
* errorString
)
472 if (!assertPaused(errorString
))
475 m_injectedScriptManager
->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup
);
476 scriptDebugServer().stepOverStatement();
479 void InspectorDebuggerAgent::stepInto(ErrorString
* errorString
)
481 if (!assertPaused(errorString
))
484 m_injectedScriptManager
->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup
);
485 scriptDebugServer().stepIntoStatement();
488 m_listener
->stepInto();
491 void InspectorDebuggerAgent::stepOut(ErrorString
* errorString
)
493 if (!assertPaused(errorString
))
496 m_injectedScriptManager
->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup
);
497 scriptDebugServer().stepOutOfFunction();
500 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString
* errorString
, const String
& stringPauseState
)
502 JSC::Debugger::PauseOnExceptionsState pauseState
;
503 if (stringPauseState
== "none")
504 pauseState
= JSC::Debugger::DontPauseOnExceptions
;
505 else if (stringPauseState
== "all")
506 pauseState
= JSC::Debugger::PauseOnAllExceptions
;
507 else if (stringPauseState
== "uncaught")
508 pauseState
= JSC::Debugger::PauseOnUncaughtExceptions
;
510 *errorString
= "Unknown pause on exceptions mode: " + stringPauseState
;
514 scriptDebugServer().setPauseOnExceptionsState(static_cast<JSC::Debugger::PauseOnExceptionsState
>(pauseState
));
515 if (scriptDebugServer().pauseOnExceptionsState() != pauseState
)
516 *errorString
= ASCIILiteral("Internal error. Could not change pause on exceptions state");
519 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
, RefPtr
<Inspector::TypeBuilder::Runtime::RemoteObject
>& result
, Inspector::TypeBuilder::OptOutput
<bool>* wasThrown
)
521 InjectedScript injectedScript
= m_injectedScriptManager
->injectedScriptForObjectId(callFrameId
);
522 if (injectedScript
.hasNoValue()) {
523 *errorString
= ASCIILiteral("Inspected frame has gone");
527 JSC::Debugger::PauseOnExceptionsState previousPauseOnExceptionsState
= scriptDebugServer().pauseOnExceptionsState();
528 if (doNotPauseOnExceptionsAndMuteConsole
? *doNotPauseOnExceptionsAndMuteConsole
: false) {
529 if (previousPauseOnExceptionsState
!= JSC::Debugger::DontPauseOnExceptions
)
530 scriptDebugServer().setPauseOnExceptionsState(JSC::Debugger::DontPauseOnExceptions
);
534 injectedScript
.evaluateOnCallFrame(errorString
, m_currentCallStack
, callFrameId
, expression
, objectGroup
? *objectGroup
: "", includeCommandLineAPI
? *includeCommandLineAPI
: false, returnByValue
? *returnByValue
: false, generatePreview
? *generatePreview
: false, &result
, wasThrown
);
536 if (doNotPauseOnExceptionsAndMuteConsole
? *doNotPauseOnExceptionsAndMuteConsole
: false) {
538 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState
)
539 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState
);
543 void InspectorDebuggerAgent::setOverlayMessage(ErrorString
*, const String
*)
547 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String
& directiveText
)
549 if (scriptDebugServer().pauseOnExceptionsState() != JSC::Debugger::DontPauseOnExceptions
) {
550 RefPtr
<InspectorObject
> directive
= InspectorObject::create();
551 directive
->setString(ASCIILiteral("directiveText"), directiveText
);
552 breakProgram(InspectorDebuggerFrontendDispatcher::Reason::CSPViolation
, directive
.release());
556 PassRefPtr
<Inspector::TypeBuilder::Array
<Inspector::TypeBuilder::Debugger::CallFrame
>> InspectorDebuggerAgent::currentCallFrames()
558 if (!m_pausedScriptState
)
559 return Inspector::TypeBuilder::Array
<Inspector::TypeBuilder::Debugger::CallFrame
>::create();
561 InjectedScript injectedScript
= m_injectedScriptManager
->injectedScriptFor(m_pausedScriptState
);
562 if (injectedScript
.hasNoValue()) {
563 ASSERT_NOT_REACHED();
564 return Inspector::TypeBuilder::Array
<Inspector::TypeBuilder::Debugger::CallFrame
>::create();
567 return injectedScript
.wrapCallFrames(m_currentCallStack
);
570 String
InspectorDebuggerAgent::sourceMapURLForScript(const Script
& script
)
572 return ContentSearchUtilities::findScriptSourceMapURL(script
.source
);
575 void InspectorDebuggerAgent::didParseSource(JSC::SourceID sourceID
, const Script
& inScript
)
577 Script script
= inScript
;
578 if (script
.startLine
<= 0 && !script
.startColumn
)
579 script
.sourceURL
= ContentSearchUtilities::findScriptSourceURL(script
.source
);
580 script
.sourceMappingURL
= sourceMapURLForScript(script
);
582 bool hasSourceURL
= !script
.sourceURL
.isEmpty();
583 String scriptURL
= hasSourceURL
? script
.sourceURL
: script
.url
;
584 bool* hasSourceURLParam
= hasSourceURL
? &hasSourceURL
: nullptr;
585 String
* sourceMapURLParam
= script
.sourceMappingURL
.isNull() ? nullptr : &script
.sourceMappingURL
;
586 const bool* isContentScript
= script
.isContentScript
? &script
.isContentScript
: nullptr;
587 String scriptIDStr
= String::number(sourceID
);
588 m_frontendDispatcher
->scriptParsed(scriptIDStr
, scriptURL
, script
.startLine
, script
.startColumn
, script
.endLine
, script
.endColumn
, isContentScript
, sourceMapURLParam
, hasSourceURLParam
);
590 m_scripts
.set(sourceID
, script
);
592 if (scriptURL
.isEmpty())
595 for (auto it
= m_javaScriptBreakpoints
.begin(), end
= m_javaScriptBreakpoints
.end(); it
!= end
; ++it
) {
596 RefPtr
<InspectorObject
> breakpointObject
= it
->value
->asObject();
598 breakpointObject
->getBoolean(ASCIILiteral("isRegex"), &isRegex
);
600 breakpointObject
->getString(ASCIILiteral("url"), &url
);
601 if (!matches(scriptURL
, url
, isRegex
))
603 ScriptBreakpoint breakpoint
;
604 breakpointObject
->getNumber(ASCIILiteral("lineNumber"), &breakpoint
.lineNumber
);
605 breakpointObject
->getNumber(ASCIILiteral("columnNumber"), &breakpoint
.columnNumber
);
606 breakpointObject
->getString(ASCIILiteral("condition"), &breakpoint
.condition
);
607 breakpointObject
->getBoolean(ASCIILiteral("autoContinue"), &breakpoint
.autoContinue
);
608 ErrorString errorString
;
609 RefPtr
<InspectorArray
> actions
= breakpointObject
->getArray(ASCIILiteral("actions"));
610 if (!breakpointActionsFromProtocol(&errorString
, actions
, &breakpoint
.actions
)) {
611 ASSERT_NOT_REACHED();
615 RefPtr
<Inspector::TypeBuilder::Debugger::Location
> location
= resolveBreakpoint(it
->key
, sourceID
, breakpoint
);
617 m_frontendDispatcher
->breakpointResolved(it
->key
, location
);
621 void InspectorDebuggerAgent::failedToParseSource(const String
& url
, const String
& data
, int firstLine
, int errorLine
, const String
& errorMessage
)
623 m_frontendDispatcher
->scriptFailedToParse(url
, data
, firstLine
, errorLine
, errorMessage
);
626 void InspectorDebuggerAgent::didPause(JSC::ExecState
* scriptState
, const Deprecated::ScriptValue
& callFrames
, const Deprecated::ScriptValue
& exception
)
628 ASSERT(scriptState
&& !m_pausedScriptState
);
629 m_pausedScriptState
= scriptState
;
630 m_currentCallStack
= callFrames
;
632 if (!exception
.hasNoValue()) {
633 InjectedScript injectedScript
= m_injectedScriptManager
->injectedScriptFor(scriptState
);
634 if (!injectedScript
.hasNoValue()) {
635 m_breakReason
= InspectorDebuggerFrontendDispatcher::Reason::Exception
;
636 m_breakAuxData
= injectedScript
.wrapObject(exception
, InspectorDebuggerAgent::backtraceObjectGroup
)->openAccessors();
637 // m_breakAuxData might be null after this.
641 m_frontendDispatcher
->paused(currentCallFrames(), m_breakReason
, m_breakAuxData
);
642 m_javaScriptPauseScheduled
= false;
644 if (m_continueToLocationBreakpointID
!= JSC::noBreakpointID
) {
645 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointID
);
646 m_continueToLocationBreakpointID
= JSC::noBreakpointID
;
650 m_listener
->didPause();
653 void InspectorDebuggerAgent::breakpointActionSound(int breakpointActionIdentifier
)
655 m_frontendDispatcher
->playBreakpointActionSound(breakpointActionIdentifier
);
658 void InspectorDebuggerAgent::breakpointActionProbe(JSC::ExecState
* scriptState
, const ScriptBreakpointAction
& action
, int hitCount
, const Deprecated::ScriptValue
& sample
)
660 int sampleId
= m_nextProbeSampleId
++;
662 InjectedScript injectedScript
= m_injectedScriptManager
->injectedScriptFor(scriptState
);
663 RefPtr
<TypeBuilder::Runtime::RemoteObject
> payload
= injectedScript
.wrapObject(sample
, objectGroupForBreakpointAction(action
));
664 RefPtr
<TypeBuilder::Debugger::ProbeSample
> result
= TypeBuilder::Debugger::ProbeSample::create()
665 .setProbeId(action
.identifier
)
666 .setSampleId(sampleId
)
667 .setBatchId(hitCount
)
668 .setTimestamp(monotonicallyIncreasingTime())
669 .setPayload(payload
.release());
671 m_frontendDispatcher
->didSampleProbe(result
.release());
674 void InspectorDebuggerAgent::didContinue()
676 m_pausedScriptState
= nullptr;
677 m_currentCallStack
= Deprecated::ScriptValue();
680 m_frontendDispatcher
->resumed();
683 void InspectorDebuggerAgent::breakProgram(InspectorDebuggerFrontendDispatcher::Reason::Enum breakReason
, PassRefPtr
<InspectorObject
> data
)
685 m_breakReason
= breakReason
;
686 m_breakAuxData
= data
;
687 scriptDebugServer().breakProgram();
690 void InspectorDebuggerAgent::clearInspectorBreakpointState()
692 ErrorString dummyError
;
693 Vector
<String
> breakpointIdentifiers
;
694 copyKeysToVector(m_breakpointIdentifierToDebugServerBreakpointIDs
, breakpointIdentifiers
);
695 for (const String
& identifier
: breakpointIdentifiers
)
696 removeBreakpoint(&dummyError
, identifier
);
698 m_javaScriptBreakpoints
.clear();
700 clearDebuggerBreakpointState();
703 void InspectorDebuggerAgent::clearDebuggerBreakpointState()
705 scriptDebugServer().clearBreakpoints();
707 m_pausedScriptState
= nullptr;
708 m_currentCallStack
= Deprecated::ScriptValue();
710 m_breakpointIdentifierToDebugServerBreakpointIDs
.clear();
711 m_continueToLocationBreakpointID
= JSC::noBreakpointID
;
713 m_javaScriptPauseScheduled
= false;
715 scriptDebugServer().continueProgram();
718 void InspectorDebuggerAgent::didClearGlobalObject()
720 // Clear breakpoints from the debugger, but keep the inspector's model of which
721 // pages have what breakpoints, as the mapping is only sent to DebuggerAgent once.
722 clearDebuggerBreakpointState();
724 if (m_frontendDispatcher
)
725 m_frontendDispatcher
->globalObjectCleared();
728 bool InspectorDebuggerAgent::assertPaused(ErrorString
* errorString
)
730 if (!m_pausedScriptState
) {
731 *errorString
= ASCIILiteral("Can only perform operation while paused.");
738 void InspectorDebuggerAgent::clearBreakDetails()
740 m_breakReason
= InspectorDebuggerFrontendDispatcher::Reason::Other
;
741 m_breakAuxData
= nullptr;
745 } // namespace Inspector
747 #endif // ENABLE(INSPECTOR)