2 * Copyright (C) 2010 Apple Inc. All rights reserved.
3 * Copyright (C) 2013 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 Computer, 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 "core/inspector/InspectorDebuggerAgent.h"
33 #include "bindings/core/v8/ScriptDebugServer.h"
34 #include "bindings/core/v8/ScriptRegexp.h"
35 #include "bindings/core/v8/ScriptSourceCode.h"
36 #include "bindings/core/v8/ScriptValue.h"
37 #include "core/dom/Document.h"
38 #include "core/dom/ExecutionContextTask.h"
39 #include "core/fetch/Resource.h"
40 #include "core/inspector/ConsoleMessage.h"
41 #include "core/inspector/ContentSearchUtils.h"
42 #include "core/inspector/InjectedScriptManager.h"
43 #include "core/inspector/InspectorPageAgent.h"
44 #include "core/inspector/InspectorState.h"
45 #include "core/inspector/InstrumentingAgents.h"
46 #include "core/inspector/JavaScriptCallFrame.h"
47 #include "core/inspector/ScriptArguments.h"
48 #include "core/inspector/ScriptAsyncCallStack.h"
49 #include "core/inspector/ScriptCallFrame.h"
50 #include "core/inspector/ScriptCallStack.h"
51 #include "platform/JSONValues.h"
52 #include "wtf/text/StringBuilder.h"
53 #include "wtf/text/WTFString.h"
55 using blink::TypeBuilder::Array;
56 using blink::TypeBuilder::Debugger::BreakpointId;
57 using blink::TypeBuilder::Debugger::CallFrame;
58 using blink::TypeBuilder::Debugger::CollectionEntry;
59 using blink::TypeBuilder::Debugger::ExceptionDetails;
60 using blink::TypeBuilder::Debugger::FunctionDetails;
61 using blink::TypeBuilder::Debugger::PromiseDetails;
62 using blink::TypeBuilder::Debugger::ScriptId;
63 using blink::TypeBuilder::Debugger::StackTrace;
64 using blink::TypeBuilder::Runtime::RemoteObject;
68 static const char v8AsyncTaskEventEnqueue[] = "enqueue";
69 static const char v8AsyncTaskEventWillHandle[] = "willHandle";
70 static const char v8AsyncTaskEventDidHandle[] = "didHandle";
76 namespace DebuggerAgentState {
77 static const char debuggerEnabled[] = "debuggerEnabled";
78 static const char javaScriptBreakpoints[] = "javaScriptBreakopints";
79 static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
80 static const char asyncCallStackDepth[] = "asyncCallStackDepth";
81 static const char promiseTrackerEnabled[] = "promiseTrackerEnabled";
83 // Breakpoint properties.
84 static const char url[] = "url";
85 static const char isRegex[] = "isRegex";
86 static const char lineNumber[] = "lineNumber";
87 static const char columnNumber[] = "columnNumber";
88 static const char condition[] = "condition";
89 static const char isAnti[] = "isAnti";
90 static const char skipStackPattern[] = "skipStackPattern";
91 static const char skipContentScripts[] = "skipContentScripts";
92 static const char skipAllPauses[] = "skipAllPauses";
93 static const char skipAllPausesExpiresOnReload[] = "skipAllPausesExpiresOnReload";
97 static const int maxSkipStepInCount = 20;
99 const char InspectorDebuggerAgent::backtraceObjectGroup[] = "backtrace";
101 static String breakpointIdSuffix(InspectorDebuggerAgent::BreakpointSource source)
104 case InspectorDebuggerAgent::UserBreakpointSource:
106 case InspectorDebuggerAgent::DebugCommandBreakpointSource:
108 case InspectorDebuggerAgent::MonitorCommandBreakpointSource:
114 static String generateBreakpointId(const String& scriptId, int lineNumber, int columnNumber, InspectorDebuggerAgent::BreakpointSource source)
116 return scriptId + ':' + String::number(lineNumber) + ':' + String::number(columnNumber) + breakpointIdSuffix(source);
119 InspectorDebuggerAgent::InspectorDebuggerAgent(InjectedScriptManager* injectedScriptManager)
120 : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger")
121 , m_injectedScriptManager(injectedScriptManager)
123 , m_pausedScriptState(nullptr)
124 , m_javaScriptPauseScheduled(false)
125 , m_debuggerStepScheduled(false)
126 , m_steppingFromFramework(false)
127 , m_pausingOnNativeEvent(false)
128 , m_listener(nullptr)
129 , m_skippedStepInCount(0)
130 , m_skipAllPauses(false)
131 , m_skipContentScripts(false)
132 , m_asyncCallStackTracker(adoptPtrWillBeNoop(new AsyncCallStackTracker()))
133 , m_promiseTracker(PromiseTracker::create())
137 InspectorDebuggerAgent::~InspectorDebuggerAgent()
140 ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent());
144 void InspectorDebuggerAgent::init()
146 // FIXME: make breakReason optional so that there was no need to init it with "other".
148 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions);
151 void InspectorDebuggerAgent::enable()
153 m_instrumentingAgents->setInspectorDebuggerAgent(this);
155 startListeningScriptDebugServer();
156 // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends
157 scriptDebugServer().setBreakpointsActivated(true);
160 m_listener->debuggerWasEnabled();
163 void InspectorDebuggerAgent::disable()
165 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, JSONObject::create());
166 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions);
167 m_state->setString(DebuggerAgentState::skipStackPattern, "");
168 m_state->setBoolean(DebuggerAgentState::skipContentScripts, false);
169 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, 0);
170 m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, false);
171 m_instrumentingAgents->setInspectorDebuggerAgent(0);
173 scriptDebugServer().clearBreakpoints();
174 scriptDebugServer().clearCompiledScripts();
175 scriptDebugServer().clearPreprocessor();
176 stopListeningScriptDebugServer();
180 m_listener->debuggerWasDisabled();
182 m_skipAllPauses = false;
185 bool InspectorDebuggerAgent::enabled()
187 return m_state->getBoolean(DebuggerAgentState::debuggerEnabled);
190 void InspectorDebuggerAgent::enable(ErrorString*)
196 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
201 void InspectorDebuggerAgent::disable(ErrorString*)
207 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
210 static PassOwnPtr<ScriptRegexp> compileSkipCallFramePattern(String patternText)
212 if (patternText.isEmpty())
214 OwnPtr<ScriptRegexp> result = adoptPtr(new ScriptRegexp(patternText, TextCaseSensitive));
215 if (!result->isValid())
217 return result.release();
220 void InspectorDebuggerAgent::restore()
223 m_frontend->globalObjectCleared();
225 long pauseState = m_state->getLong(DebuggerAgentState::pauseOnExceptionsState);
227 setPauseOnExceptionsImpl(&error, pauseState);
228 m_cachedSkipStackRegExp = compileSkipCallFramePattern(m_state->getString(DebuggerAgentState::skipStackPattern));
229 m_skipContentScripts = m_state->getBoolean(DebuggerAgentState::skipContentScripts);
230 m_skipAllPauses = m_state->getBoolean(DebuggerAgentState::skipAllPauses);
231 if (m_skipAllPauses && m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) {
232 m_skipAllPauses = false;
233 m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
235 asyncCallStackTracker().setAsyncCallStackDepth(m_state->getLong(DebuggerAgentState::asyncCallStackDepth));
236 promiseTracker().setEnabled(m_state->getBoolean(DebuggerAgentState::promiseTrackerEnabled));
240 void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend)
242 m_frontend = frontend->debugger();
245 void InspectorDebuggerAgent::clearFrontend()
254 // FIXME: due to m_state->mute() hack in InspectorController, debuggerEnabled is actually set to false only
255 // in InspectorState, but not in cookie. That's why after navigation debuggerEnabled will be true,
256 // but after front-end re-open it will still be false.
257 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
260 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active)
262 scriptDebugServer().setBreakpointsActivated(active);
265 void InspectorDebuggerAgent::setSkipAllPauses(ErrorString*, bool skipped, const bool* untilReload)
267 m_skipAllPauses = skipped;
268 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses);
269 m_state->setBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload, asBool(untilReload));
272 void InspectorDebuggerAgent::pageDidCommitLoad()
274 if (m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) {
275 m_skipAllPauses = false;
276 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses);
280 bool InspectorDebuggerAgent::isPaused()
282 return scriptDebugServer().isPaused();
285 bool InspectorDebuggerAgent::runningNestedMessageLoop()
287 return scriptDebugServer().runningNestedMessageLoop();
290 void InspectorDebuggerAgent::addMessageToConsole(ConsoleMessage* consoleMessage)
292 if (consoleMessage->type() == AssertMessageType && scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions)
293 breakProgram(InspectorFrontend::Debugger::Reason::Assert, nullptr);
296 String InspectorDebuggerAgent::preprocessEventListener(LocalFrame* frame, const String& source, const String& url, const String& functionName)
298 return scriptDebugServer().preprocessEventListener(frame, source, url, functionName);
301 PassOwnPtr<ScriptSourceCode> InspectorDebuggerAgent::preprocess(LocalFrame* frame, const ScriptSourceCode& sourceCode)
303 return scriptDebugServer().preprocess(frame, sourceCode);
306 static PassRefPtr<JSONObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex, bool isAnti)
308 RefPtr<JSONObject> breakpointObject = JSONObject::create();
309 breakpointObject->setString(DebuggerAgentState::url, url);
310 breakpointObject->setNumber(DebuggerAgentState::lineNumber, lineNumber);
311 breakpointObject->setNumber(DebuggerAgentState::columnNumber, columnNumber);
312 breakpointObject->setString(DebuggerAgentState::condition, condition);
313 breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex);
314 breakpointObject->setBoolean(DebuggerAgentState::isAnti, isAnti);
315 return breakpointObject;
318 static String scriptSourceURL(const ScriptDebugListener::Script& script)
320 bool hasSourceURL = !script.sourceURL.isEmpty();
321 return hasSourceURL ? script.sourceURL : script.url;
324 static bool matches(const String& url, const String& pattern, bool isRegex)
327 ScriptRegexp regex(pattern, TextCaseSensitive);
328 return regex.match(url) != -1;
330 return url == pattern;
333 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const String* const optionalCondition, const bool* isAntiBreakpoint, BreakpointId* outBreakpointId, RefPtr<Array<TypeBuilder::Debugger::Location> >& locations)
335 locations = Array<TypeBuilder::Debugger::Location>::create();
336 if (!optionalURL == !optionalURLRegex) {
337 *errorString = "Either url or urlRegex must be specified.";
341 bool isAntiBreakpointValue = asBool(isAntiBreakpoint);
343 String url = optionalURL ? *optionalURL : *optionalURLRegex;
345 if (optionalColumnNumber) {
346 columnNumber = *optionalColumnNumber;
347 if (columnNumber < 0) {
348 *errorString = "Incorrect column number";
352 columnNumber = isAntiBreakpointValue ? -1 : 0;
354 String condition = optionalCondition ? *optionalCondition : "";
355 bool isRegex = optionalURLRegex;
357 String breakpointId = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber);
358 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
359 if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) {
360 *errorString = "Breakpoint at specified location already exists.";
364 breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, isRegex, isAntiBreakpointValue));
365 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
367 if (!isAntiBreakpointValue) {
368 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
369 for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) {
370 if (!matches(scriptSourceURL(it->value), url, isRegex))
372 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(breakpointId, it->key, breakpoint, UserBreakpointSource);
374 locations->addItem(location);
377 *outBreakpointId = breakpointId;
380 static bool parseLocation(ErrorString* errorString, PassRefPtr<JSONObject> location, String* scriptId, int* lineNumber, int* columnNumber)
382 if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) {
383 // FIXME: replace with input validation.
384 *errorString = "scriptId and lineNumber are required.";
388 location->getNumber("columnNumber", columnNumber);
392 void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr<JSONObject>& location, const String* const optionalCondition, BreakpointId* outBreakpointId, RefPtr<TypeBuilder::Debugger::Location>& actualLocation)
398 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
401 String condition = optionalCondition ? *optionalCondition : emptyString();
403 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumber, UserBreakpointSource);
404 if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end()) {
405 *errorString = "Breakpoint at specified location already exists.";
408 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
409 actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, UserBreakpointSource);
411 *outBreakpointId = breakpointId;
413 *errorString = "Could not resolve breakpoint";
416 void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointId)
418 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
419 JSONObject::iterator it = breakpointsCookie->find(breakpointId);
420 bool isAntibreakpoint = false;
421 if (it != breakpointsCookie->end()) {
422 RefPtr<JSONObject> breakpointObject = it->value->asObject();
423 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint);
424 breakpointsCookie->remove(breakpointId);
425 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
428 if (!isAntibreakpoint)
429 removeBreakpoint(breakpointId);
432 void InspectorDebuggerAgent::removeBreakpoint(const String& breakpointId)
434 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
435 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
437 for (size_t i = 0; i < debugServerBreakpointIdsIterator->value.size(); ++i) {
438 const String& debugServerBreakpointId = debugServerBreakpointIdsIterator->value[i];
439 scriptDebugServer().removeBreakpoint(debugServerBreakpointId);
440 m_serverBreakpoints.remove(debugServerBreakpointId);
442 m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator);
445 void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const RefPtr<JSONObject>& location, const bool* interstateLocationOpt)
447 if (!m_continueToLocationBreakpointId.isEmpty()) {
448 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
449 m_continueToLocationBreakpointId = "";
456 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
459 ScriptBreakpoint breakpoint(lineNumber, columnNumber, "");
460 m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber, asBool(interstateLocationOpt));
464 void InspectorDebuggerAgent::getStepInPositions(ErrorString* errorString, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::Location> >& positions)
466 if (!isPaused() || m_currentCallStack.isEmpty()) {
467 *errorString = "Attempt to access callframe when debugger is not on pause";
470 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
471 if (injectedScript.isEmpty()) {
472 *errorString = "Inspected frame has gone";
476 injectedScript.getStepInPositions(errorString, m_currentCallStack, callFrameId, positions);
479 void InspectorDebuggerAgent::getBacktrace(ErrorString* errorString, RefPtr<Array<CallFrame> >& callFrames, RefPtr<StackTrace>& asyncStackTrace)
481 if (!assertPaused(errorString))
483 m_currentCallStack = scriptDebugServer().currentCallFrames();
484 callFrames = currentCallFrames();
485 asyncStackTrace = currentAsyncStackTrace();
488 PassRefPtrWillBeRawPtr<JavaScriptCallFrame> InspectorDebuggerAgent::topCallFrameSkipUnknownSources(String* scriptURL, bool* isBlackboxed)
490 for (int index = 0; ; ++index) {
491 RefPtrWillBeRawPtr<JavaScriptCallFrame> frame = scriptDebugServer().callFrameNoScopes(index);
494 ScriptsMap::iterator it = m_scripts.find(String::number(frame->sourceID()));
495 if (it == m_scripts.end())
497 *scriptURL = scriptSourceURL(it->value);
498 *isBlackboxed = (m_skipContentScripts && it->value.isContentScript)
499 || (m_cachedSkipStackRegExp && !scriptURL->isEmpty() && m_cachedSkipStackRegExp->match(*scriptURL) != -1);
500 return frame.release();
504 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipExceptionPause()
506 if (m_steppingFromFramework)
507 return ScriptDebugListener::NoSkip;
509 // FIXME: Fast return: if (!m_skipContentScripts && !m_cachedSkipStackRegExp && !has_any_anti_breakpoint) return ScriptDebugListener::NoSkip;
511 String topFrameScriptUrl;
512 bool isBlackboxed = false;
513 RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&topFrameScriptUrl, &isBlackboxed);
515 return ScriptDebugListener::NoSkip;
517 return ScriptDebugListener::Continue;
519 // Match against breakpoints.
520 if (topFrameScriptUrl.isEmpty())
521 return ScriptDebugListener::NoSkip;
523 // Prepare top frame parameters.
524 int topFrameLineNumber = topFrame->line();
525 int topFrameColumnNumber = topFrame->column();
527 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
528 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
529 RefPtr<JSONObject> breakpointObject = it->value->asObject();
530 bool isAntibreakpoint;
531 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint);
532 if (!isAntibreakpoint)
536 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakLineNumber);
537 int breakColumnNumber;
538 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakColumnNumber);
540 if (breakLineNumber != topFrameLineNumber)
543 if (breakColumnNumber != -1 && breakColumnNumber != topFrameColumnNumber)
547 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
549 breakpointObject->getString(DebuggerAgentState::url, &url);
550 if (!matches(topFrameScriptUrl, url, isRegex))
553 return ScriptDebugListener::Continue;
556 return ScriptDebugListener::NoSkip;
559 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipStepPause()
561 if (m_steppingFromFramework)
562 return ScriptDebugListener::NoSkip;
564 if (!m_skipContentScripts && !m_cachedSkipStackRegExp)
565 return ScriptDebugListener::NoSkip;
568 bool isBlackboxed = false;
569 RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&scriptUrl, &isBlackboxed);
570 if (!topFrame || !isBlackboxed)
571 return ScriptDebugListener::NoSkip;
573 if (m_skippedStepInCount == 0) {
574 m_minFrameCountForSkip = scriptDebugServer().frameCount();
575 m_skippedStepInCount = 1;
576 return ScriptDebugListener::StepInto;
579 if (m_skippedStepInCount < maxSkipStepInCount && topFrame->isAtReturn() && scriptDebugServer().frameCount() <= m_minFrameCountForSkip)
580 m_skippedStepInCount = maxSkipStepInCount;
582 if (m_skippedStepInCount >= maxSkipStepInCount) {
583 if (m_pausingOnNativeEvent) {
584 m_pausingOnNativeEvent = false;
585 m_skippedStepInCount = 0;
586 return ScriptDebugListener::Continue;
588 return ScriptDebugListener::StepOut;
591 ++m_skippedStepInCount;
592 return ScriptDebugListener::StepInto;
595 bool InspectorDebuggerAgent::isTopCallFrameInFramework()
597 if (!m_skipContentScripts && !m_cachedSkipStackRegExp)
601 bool isBlackboxed = false;
602 RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&scriptUrl, &isBlackboxed);
603 return topFrame && isBlackboxed;
606 PassRefPtr<TypeBuilder::Debugger::Location> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint& breakpoint, BreakpointSource source)
608 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
609 if (scriptIterator == m_scripts.end())
611 Script& script = scriptIterator->value;
612 if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint.lineNumber)
615 int actualLineNumber;
616 int actualColumnNumber;
617 String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false);
618 if (debugServerBreakpointId.isEmpty())
621 m_serverBreakpoints.set(debugServerBreakpointId, std::make_pair(breakpointId, source));
623 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
624 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
625 m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String>()).storedValue->value.append(debugServerBreakpointId);
627 debugServerBreakpointIdsIterator->value.append(debugServerBreakpointId);
629 RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
630 .setScriptId(scriptId)
631 .setLineNumber(actualLineNumber);
632 location->setColumnNumber(actualColumnNumber);
636 void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& scriptId, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Array<blink::TypeBuilder::Page::SearchMatch> >& results)
638 ScriptsMap::iterator it = m_scripts.find(scriptId);
639 if (it != m_scripts.end())
640 results = ContentSearchUtils::searchInTextByLines(it->value.source, query, asBool(optionalCaseSensitive), asBool(optionalIsRegex));
642 *error = "No script for id: " + scriptId;
645 void InspectorDebuggerAgent::setScriptSource(ErrorString* error, RefPtr<TypeBuilder::Debugger::SetScriptSourceError>& errorData, const String& scriptId, const String& newContent, const bool* const preview, RefPtr<Array<CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<StackTrace>& asyncStackTrace)
647 if (!scriptDebugServer().setScriptSource(scriptId, newContent, asBool(preview), error, errorData, &m_currentCallStack, &result))
650 newCallFrames = currentCallFrames();
651 asyncStackTrace = currentAsyncStackTrace();
653 ScriptsMap::iterator it = m_scripts.find(scriptId);
654 if (it == m_scripts.end())
656 String url = it->value.url;
659 if (InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent())
660 pageAgent->addEditedResourceContent(url, newContent);
663 void InspectorDebuggerAgent::restartFrame(ErrorString* errorString, const String& callFrameId, RefPtr<Array<CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<StackTrace>& asyncStackTrace)
665 if (!isPaused() || m_currentCallStack.isEmpty()) {
666 *errorString = "Attempt to access callframe when debugger is not on pause";
669 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
670 if (injectedScript.isEmpty()) {
671 *errorString = "Inspected frame has gone";
675 injectedScript.restartFrame(errorString, m_currentCallStack, callFrameId, &result);
676 m_currentCallStack = scriptDebugServer().currentCallFrames();
677 newCallFrames = currentCallFrames();
678 asyncStackTrace = currentAsyncStackTrace();
681 void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptId, String* scriptSource)
683 ScriptsMap::iterator it = m_scripts.find(scriptId);
684 if (it == m_scripts.end()) {
685 *error = "No script for id: " + scriptId;
689 String url = it->value.url;
690 if (!url.isEmpty()) {
691 if (InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent()) {
692 bool success = pageAgent->getEditedResourceContent(url, scriptSource);
697 *scriptSource = it->value.source;
700 void InspectorDebuggerAgent::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>& details)
702 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId);
703 if (injectedScript.isEmpty()) {
704 *errorString = "Function object id is obsolete";
707 injectedScript.getFunctionDetails(errorString, functionId, &details);
710 void InspectorDebuggerAgent::getCollectionEntries(ErrorString* errorString, const String& objectId, RefPtr<TypeBuilder::Array<CollectionEntry> >& entries)
712 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
713 if (injectedScript.isEmpty()) {
714 *errorString = "Inspected frame has gone";
717 injectedScript.getCollectionEntries(errorString, objectId, &entries);
720 void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data)
722 if (m_javaScriptPauseScheduled || isPaused())
724 m_breakReason = breakReason;
725 m_breakAuxData = data;
726 m_pausingOnNativeEvent = true;
727 scriptDebugServer().setPauseOnNextStatement(true);
730 void InspectorDebuggerAgent::cancelPauseOnNextStatement()
732 if (m_javaScriptPauseScheduled || isPaused())
735 m_pausingOnNativeEvent = false;
736 scriptDebugServer().setPauseOnNextStatement(false);
739 void InspectorDebuggerAgent::didInstallTimer(ExecutionContext* context, int timerId, int timeout, bool singleShot)
741 if (asyncCallStackTracker().isEnabled())
742 asyncCallStackTracker().didInstallTimer(context, timerId, singleShot, scriptDebugServer().currentCallFramesForAsyncStack());
745 void InspectorDebuggerAgent::didRemoveTimer(ExecutionContext* context, int timerId)
747 if (asyncCallStackTracker().isEnabled())
748 asyncCallStackTracker().didRemoveTimer(context, timerId);
751 bool InspectorDebuggerAgent::willFireTimer(ExecutionContext* context, int timerId)
753 if (asyncCallStackTracker().isEnabled())
754 asyncCallStackTracker().willFireTimer(context, timerId);
758 void InspectorDebuggerAgent::didFireTimer()
760 if (asyncCallStackTracker().isEnabled())
761 asyncCallStackTracker().didFireAsyncCall();
762 cancelPauseOnNextStatement();
765 void InspectorDebuggerAgent::didRequestAnimationFrame(Document* document, int callbackId)
767 if (asyncCallStackTracker().isEnabled())
768 asyncCallStackTracker().didRequestAnimationFrame(document, callbackId, scriptDebugServer().currentCallFramesForAsyncStack());
771 void InspectorDebuggerAgent::didCancelAnimationFrame(Document* document, int callbackId)
773 if (asyncCallStackTracker().isEnabled())
774 asyncCallStackTracker().didCancelAnimationFrame(document, callbackId);
777 bool InspectorDebuggerAgent::willFireAnimationFrame(Document* document, int callbackId)
779 if (asyncCallStackTracker().isEnabled())
780 asyncCallStackTracker().willFireAnimationFrame(document, callbackId);
784 void InspectorDebuggerAgent::didFireAnimationFrame()
786 if (asyncCallStackTracker().isEnabled())
787 asyncCallStackTracker().didFireAsyncCall();
790 void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* event)
792 if (asyncCallStackTracker().isEnabled())
793 asyncCallStackTracker().didEnqueueEvent(eventTarget, event, scriptDebugServer().currentCallFramesForAsyncStack());
796 void InspectorDebuggerAgent::didRemoveEvent(EventTarget* eventTarget, Event* event)
798 if (asyncCallStackTracker().isEnabled())
799 asyncCallStackTracker().didRemoveEvent(eventTarget, event);
802 void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture)
804 if (asyncCallStackTracker().isEnabled())
805 asyncCallStackTracker().willHandleEvent(eventTarget, event, listener, useCapture);
808 void InspectorDebuggerAgent::didHandleEvent()
810 if (asyncCallStackTracker().isEnabled())
811 asyncCallStackTracker().didFireAsyncCall();
812 cancelPauseOnNextStatement();
815 void InspectorDebuggerAgent::willLoadXHR(XMLHttpRequest* xhr, ThreadableLoaderClient*, const AtomicString&, const KURL&, bool async, PassRefPtr<FormData>, const HTTPHeaderMap&, bool)
817 if (asyncCallStackTracker().isEnabled() && async)
818 asyncCallStackTracker().willLoadXHR(xhr, scriptDebugServer().currentCallFramesForAsyncStack());
821 void InspectorDebuggerAgent::didDispatchXHRLoadendEvent(XMLHttpRequest* xhr)
823 if (asyncCallStackTracker().isEnabled())
824 asyncCallStackTracker().didLoadXHR(xhr);
827 void InspectorDebuggerAgent::didEnqueueMutationRecord(ExecutionContext* context, MutationObserver* observer)
829 if (asyncCallStackTracker().isEnabled() && !asyncCallStackTracker().hasEnqueuedMutationRecord(context, observer))
830 asyncCallStackTracker().didEnqueueMutationRecord(context, observer, scriptDebugServer().currentCallFramesForAsyncStack());
833 void InspectorDebuggerAgent::didClearAllMutationRecords(ExecutionContext* context, MutationObserver* observer)
835 if (asyncCallStackTracker().isEnabled())
836 asyncCallStackTracker().didClearAllMutationRecords(context, observer);
839 void InspectorDebuggerAgent::willDeliverMutationRecords(ExecutionContext* context, MutationObserver* observer)
841 if (asyncCallStackTracker().isEnabled())
842 asyncCallStackTracker().willDeliverMutationRecords(context, observer);
845 void InspectorDebuggerAgent::didDeliverMutationRecords()
847 if (asyncCallStackTracker().isEnabled())
848 asyncCallStackTracker().didFireAsyncCall();
851 void InspectorDebuggerAgent::didPostExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task)
853 if (asyncCallStackTracker().isEnabled() && !task->taskNameForInstrumentation().isEmpty())
854 asyncCallStackTracker().didPostExecutionContextTask(context, task, scriptDebugServer().currentCallFramesForAsyncStack());
857 void InspectorDebuggerAgent::didKillAllExecutionContextTasks(ExecutionContext* context)
859 if (asyncCallStackTracker().isEnabled())
860 asyncCallStackTracker().didKillAllExecutionContextTasks(context);
863 void InspectorDebuggerAgent::willPerformExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task)
865 if (asyncCallStackTracker().isEnabled())
866 asyncCallStackTracker().willPerformExecutionContextTask(context, task);
869 void InspectorDebuggerAgent::didPerformExecutionContextTask()
871 if (asyncCallStackTracker().isEnabled())
872 asyncCallStackTracker().didFireAsyncCall();
875 int InspectorDebuggerAgent::traceAsyncOperationStarting(ExecutionContext* context, const String& operationName, int prevOperationId)
877 if (!asyncCallStackTracker().isEnabled())
880 asyncCallStackTracker().traceAsyncOperationCompleted(context, prevOperationId);
881 return asyncCallStackTracker().traceAsyncOperationStarting(context, operationName, scriptDebugServer().currentCallFramesForAsyncStack());
884 void InspectorDebuggerAgent::traceAsyncOperationCompleted(ExecutionContext* context, int operationId)
886 if (asyncCallStackTracker().isEnabled())
887 asyncCallStackTracker().traceAsyncOperationCompleted(context, operationId);
890 void InspectorDebuggerAgent::traceAsyncOperationCompletedCallbackStarting(ExecutionContext* context, int operationId)
892 if (!asyncCallStackTracker().isEnabled())
894 asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId);
895 asyncCallStackTracker().traceAsyncOperationCompleted(context, operationId);
898 void InspectorDebuggerAgent::traceAsyncCallbackStarting(ExecutionContext* context, int operationId)
900 if (asyncCallStackTracker().isEnabled())
901 asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId);
904 void InspectorDebuggerAgent::traceAsyncCallbackCompleted()
906 if (asyncCallStackTracker().isEnabled())
907 asyncCallStackTracker().didFireAsyncCall();
910 bool InspectorDebuggerAgent::v8AsyncTaskEventsEnabled() const
912 return asyncCallStackTracker().isEnabled();
915 void InspectorDebuggerAgent::didReceiveV8AsyncTaskEvent(ExecutionContext* context, const String& eventType, const String& eventName, int id)
917 ASSERT(asyncCallStackTracker().isEnabled());
918 if (eventType == v8AsyncTaskEventEnqueue)
919 asyncCallStackTracker().didEnqueueV8AsyncTask(context, eventName, id, scriptDebugServer().currentCallFramesForAsyncStack());
920 else if (eventType == v8AsyncTaskEventWillHandle)
921 asyncCallStackTracker().willHandleV8AsyncTask(context, eventName, id);
922 else if (eventType == v8AsyncTaskEventDidHandle)
923 asyncCallStackTracker().didFireAsyncCall();
925 ASSERT_NOT_REACHED();
928 bool InspectorDebuggerAgent::v8PromiseEventsEnabled() const
930 return promiseTracker().isEnabled() || (m_listener && m_listener->canPauseOnPromiseEvent());
933 void InspectorDebuggerAgent::didReceiveV8PromiseEvent(ScriptState* scriptState, v8::Handle<v8::Object> promise, v8::Handle<v8::Value> parentPromise, int status)
935 if (promiseTracker().isEnabled())
936 promiseTracker().didReceiveV8PromiseEvent(scriptState, promise, parentPromise, status);
939 if (!parentPromise.IsEmpty() && parentPromise->IsObject())
942 m_listener->didRejectPromise();
944 m_listener->didResolvePromise();
946 m_listener->didCreatePromise();
949 void InspectorDebuggerAgent::pause(ErrorString*)
951 if (m_javaScriptPauseScheduled || isPaused())
954 m_javaScriptPauseScheduled = true;
955 scriptDebugServer().setPauseOnNextStatement(true);
958 void InspectorDebuggerAgent::resume(ErrorString* errorString)
960 if (!assertPaused(errorString))
962 m_debuggerStepScheduled = false;
963 m_steppingFromFramework = false;
964 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
965 scriptDebugServer().continueProgram();
968 void InspectorDebuggerAgent::stepOver(ErrorString* errorString)
970 if (!assertPaused(errorString))
972 m_debuggerStepScheduled = true;
973 m_steppingFromFramework = isTopCallFrameInFramework();
974 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
975 scriptDebugServer().stepOverStatement();
978 void InspectorDebuggerAgent::stepInto(ErrorString* errorString)
980 if (!assertPaused(errorString))
982 m_debuggerStepScheduled = true;
983 m_steppingFromFramework = isTopCallFrameInFramework();
984 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
985 scriptDebugServer().stepIntoStatement();
987 m_listener->stepInto();
990 void InspectorDebuggerAgent::stepOut(ErrorString* errorString)
992 if (!assertPaused(errorString))
994 m_debuggerStepScheduled = true;
995 m_steppingFromFramework = isTopCallFrameInFramework();
996 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
997 scriptDebugServer().stepOutOfFunction();
1000 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState)
1002 ScriptDebugServer::PauseOnExceptionsState pauseState;
1003 if (stringPauseState == "none")
1004 pauseState = ScriptDebugServer::DontPauseOnExceptions;
1005 else if (stringPauseState == "all")
1006 pauseState = ScriptDebugServer::PauseOnAllExceptions;
1007 else if (stringPauseState == "uncaught")
1008 pauseState = ScriptDebugServer::PauseOnUncaughtExceptions;
1010 *errorString = "Unknown pause on exceptions mode: " + stringPauseState;
1013 setPauseOnExceptionsImpl(errorString, pauseState);
1016 void InspectorDebuggerAgent::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState)
1018 scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState));
1019 if (scriptDebugServer().pauseOnExceptionsState() != pauseState)
1020 *errorString = "Internal error. Could not change pause on exceptions state";
1022 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, pauseState);
1025 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<RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>& exceptionDetails)
1027 if (!isPaused() || m_currentCallStack.isEmpty()) {
1028 *errorString = "Attempt to access callframe when debugger is not on pause";
1031 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
1032 if (injectedScript.isEmpty()) {
1033 *errorString = "Inspected frame has gone";
1037 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState();
1038 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
1039 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions)
1040 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions);
1044 Vector<ScriptValue> asyncCallStacks;
1045 const AsyncCallStackTracker::AsyncCallChain* asyncChain = asyncCallStackTracker().isEnabled() ? asyncCallStackTracker().currentAsyncCallChain() : 0;
1047 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = asyncChain->callStacks();
1048 asyncCallStacks.resize(callStacks.size());
1049 AsyncCallStackTracker::AsyncCallStackVector::const_iterator it = callStacks.begin();
1050 for (size_t i = 0; it != callStacks.end(); ++it, ++i)
1051 asyncCallStacks[i] = (*it)->callFrames();
1054 injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, asyncCallStacks, callFrameId, expression, objectGroup ? *objectGroup : "", asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), &result, wasThrown, &exceptionDetails);
1055 // V8 doesn't generate afterCompile event when it's in debugger therefore there is no content of evaluated scripts on frontend
1056 // therefore contents of the stack does not provide necessary information
1057 if (exceptionDetails)
1058 exceptionDetails->setStackTrace(TypeBuilder::Array<TypeBuilder::Console::CallFrame>::create());
1059 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
1061 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState)
1062 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState);
1066 void InspectorDebuggerAgent::compileScript(ErrorString* errorString, const String& expression, const String& sourceURL, const int* executionContextId, TypeBuilder::OptOutput<ScriptId>* scriptId, RefPtr<ExceptionDetails>& exceptionDetails)
1068 InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
1069 if (injectedScript.isEmpty()) {
1070 *errorString = "Inspected frame has gone";
1074 String scriptIdValue;
1075 String exceptionDetailsText;
1076 int lineNumberValue = 0;
1077 int columnNumberValue = 0;
1078 RefPtrWillBeRawPtr<ScriptCallStack> stackTraceValue;
1079 scriptDebugServer().compileScript(injectedScript.scriptState(), expression, sourceURL, &scriptIdValue, &exceptionDetailsText, &lineNumberValue, &columnNumberValue, &stackTraceValue);
1080 if (!scriptIdValue && !exceptionDetailsText) {
1081 *errorString = "Script compilation failed";
1084 *scriptId = scriptIdValue;
1085 if (!scriptIdValue.isEmpty())
1088 exceptionDetails = ExceptionDetails::create().setText(exceptionDetailsText);
1089 exceptionDetails->setLine(lineNumberValue);
1090 exceptionDetails->setColumn(columnNumberValue);
1091 if (stackTraceValue && stackTraceValue->size() > 0)
1092 exceptionDetails->setStackTrace(stackTraceValue->buildInspectorArray());
1095 void InspectorDebuggerAgent::runScript(ErrorString* errorString, const ScriptId& scriptId, const int* executionContextId, const String* const objectGroup, const bool* const doNotPauseOnExceptionsAndMuteConsole, RefPtr<RemoteObject>& result, RefPtr<ExceptionDetails>& exceptionDetails)
1097 InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
1098 if (injectedScript.isEmpty()) {
1099 *errorString = "Inspected frame has gone";
1103 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState();
1104 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
1105 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions)
1106 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions);
1111 bool wasThrownValue;
1112 String exceptionDetailsText;
1113 int lineNumberValue = 0;
1114 int columnNumberValue = 0;
1115 RefPtrWillBeRawPtr<ScriptCallStack> stackTraceValue;
1116 scriptDebugServer().runScript(injectedScript.scriptState(), scriptId, &value, &wasThrownValue, &exceptionDetailsText, &lineNumberValue, &columnNumberValue, &stackTraceValue);
1117 if (value.isEmpty()) {
1118 *errorString = "Script execution failed";
1121 result = injectedScript.wrapObject(value, objectGroup ? *objectGroup : "");
1122 if (wasThrownValue) {
1123 exceptionDetails = ExceptionDetails::create().setText(exceptionDetailsText);
1124 exceptionDetails->setLine(lineNumberValue);
1125 exceptionDetails->setColumn(columnNumberValue);
1126 if (stackTraceValue && stackTraceValue->size() > 0)
1127 exceptionDetails->setStackTrace(stackTraceValue->buildInspectorArray());
1130 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
1132 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState)
1133 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState);
1137 void InspectorDebuggerAgent::setOverlayMessage(ErrorString*, const String*)
1141 void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, int scopeNumber, const String& variableName, const RefPtr<JSONObject>& newValue, const String* callFrameId, const String* functionObjectId)
1143 InjectedScript injectedScript;
1145 if (!isPaused() || m_currentCallStack.isEmpty()) {
1146 *errorString = "Attempt to access callframe when debugger is not on pause";
1149 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*callFrameId);
1150 if (injectedScript.isEmpty()) {
1151 *errorString = "Inspected frame has gone";
1154 } else if (functionObjectId) {
1155 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*functionObjectId);
1156 if (injectedScript.isEmpty()) {
1157 *errorString = "Function object id cannot be resolved";
1161 *errorString = "Either call frame or function object must be specified";
1164 String newValueString = newValue->toJSONString();
1166 injectedScript.setVariableValue(errorString, m_currentCallStack, callFrameId, functionObjectId, scopeNumber, variableName, newValueString);
1169 void InspectorDebuggerAgent::skipStackFrames(ErrorString* errorString, const String* pattern, const bool* skipContentScripts)
1171 OwnPtr<ScriptRegexp> compiled;
1172 String patternValue = pattern ? *pattern : "";
1173 if (!patternValue.isEmpty()) {
1174 compiled = compileSkipCallFramePattern(patternValue);
1176 *errorString = "Invalid regular expression";
1180 m_state->setString(DebuggerAgentState::skipStackPattern, patternValue);
1181 m_cachedSkipStackRegExp = compiled.release();
1182 m_skipContentScripts = asBool(skipContentScripts);
1183 m_state->setBoolean(DebuggerAgentState::skipContentScripts, m_skipContentScripts);
1186 void InspectorDebuggerAgent::setAsyncCallStackDepth(ErrorString*, int depth)
1188 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, depth);
1189 asyncCallStackTracker().setAsyncCallStackDepth(depth);
1192 void InspectorDebuggerAgent::enablePromiseTracker(ErrorString*)
1194 m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, true);
1195 promiseTracker().setEnabled(true);
1198 void InspectorDebuggerAgent::disablePromiseTracker(ErrorString*)
1200 m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, false);
1201 promiseTracker().setEnabled(false);
1204 void InspectorDebuggerAgent::getPromises(ErrorString* errorString, RefPtr<Array<PromiseDetails> >& promises)
1206 if (!promiseTracker().isEnabled()) {
1207 *errorString = "Promise tracking is disabled";
1210 promises = promiseTracker().promises();
1213 void InspectorDebuggerAgent::getPromiseById(ErrorString* errorString, int promiseId, const String* objectGroup, RefPtr<RemoteObject>& promise)
1215 if (!promiseTracker().isEnabled()) {
1216 *errorString = "Promise tracking is disabled";
1219 ScriptValue value = promiseTracker().promiseById(promiseId);
1220 if (value.isEmpty()) {
1221 *errorString = "Promise with specified ID not found.";
1224 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(value.scriptState());
1225 promise = injectedScript.wrapObject(value, objectGroup ? *objectGroup : "");
1228 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
1230 if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) {
1231 RefPtr<JSONObject> directive = JSONObject::create();
1232 directive->setString("directiveText", directiveText);
1233 breakProgram(InspectorFrontend::Debugger::Reason::CSPViolation, directive.release());
1237 PassRefPtr<Array<CallFrame> > InspectorDebuggerAgent::currentCallFrames()
1239 if (!m_pausedScriptState || m_currentCallStack.isEmpty())
1240 return Array<CallFrame>::create();
1241 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState.get());
1242 if (injectedScript.isEmpty()) {
1243 ASSERT_NOT_REACHED();
1244 return Array<CallFrame>::create();
1246 return injectedScript.wrapCallFrames(m_currentCallStack, 0);
1249 PassRefPtr<StackTrace> InspectorDebuggerAgent::currentAsyncStackTrace()
1251 if (!m_pausedScriptState || !asyncCallStackTracker().isEnabled())
1253 const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker().currentAsyncCallChain();
1256 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callStacks();
1257 if (callStacks.isEmpty())
1259 RefPtr<StackTrace> result;
1260 int asyncOrdinal = callStacks.size();
1261 for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it, --asyncOrdinal) {
1262 ScriptValue callFrames = (*it)->callFrames();
1263 ScriptState* scriptState = callFrames.scriptState();
1264 InjectedScript injectedScript = scriptState ? m_injectedScriptManager->injectedScriptFor(scriptState) : InjectedScript();
1265 if (injectedScript.isEmpty()) {
1269 RefPtr<StackTrace> next = StackTrace::create()
1270 .setCallFrames(injectedScript.wrapCallFrames(callFrames, asyncOrdinal))
1272 next->setDescription((*it)->description());
1274 next->setAsyncStackTrace(result.release());
1277 return result.release();
1280 static PassRefPtrWillBeRawPtr<ScriptCallStack> toScriptCallStack(JavaScriptCallFrame* callFrame)
1282 Vector<ScriptCallFrame> frames;
1283 for (; callFrame; callFrame = callFrame->caller()) {
1284 StringBuilder stringBuilder;
1285 stringBuilder.appendNumber(callFrame->sourceID());
1286 String scriptId = stringBuilder.toString();
1287 // FIXME(WK62725): Debugger line/column are 0-based, while console ones are 1-based.
1288 int line = callFrame->line() + 1;
1289 int column = callFrame->column() + 1;
1290 frames.append(ScriptCallFrame(callFrame->functionName(), scriptId, callFrame->scriptName(), line, column));
1292 return ScriptCallStack::create(frames);
1295 PassRefPtrWillBeRawPtr<ScriptAsyncCallStack> InspectorDebuggerAgent::currentAsyncStackTraceForConsole()
1297 if (!asyncCallStackTracker().isEnabled())
1299 const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker().currentAsyncCallChain();
1302 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callStacks();
1303 if (callStacks.isEmpty())
1305 RefPtrWillBeRawPtr<ScriptAsyncCallStack> result = nullptr;
1306 for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it) {
1307 RefPtrWillBeRawPtr<JavaScriptCallFrame> callFrame = ScriptDebugServer::toJavaScriptCallFrameUnsafe((*it)->callFrames());
1310 result = ScriptAsyncCallStack::create((*it)->description(), toScriptCallStack(callFrame.get()), result.release());
1312 return result.release();
1315 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script, CompileResult compileResult)
1317 bool hasSyntaxError = compileResult != CompileSuccess;
1318 if (hasSyntaxError) {
1320 String sourceMapURL = ContentSearchUtils::findSourceMapURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated);
1321 if (!sourceMapURL.isEmpty())
1322 return sourceMapURL;
1325 if (!script.sourceMappingURL.isEmpty())
1326 return script.sourceMappingURL;
1328 if (script.url.isEmpty())
1331 InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent();
1334 return pageAgent->resourceSourceMapURL(script.url);
1337 // ScriptDebugListener functions
1339 void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& parsedScript, CompileResult compileResult)
1341 Script script = parsedScript;
1342 const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0;
1344 bool hasSyntaxError = compileResult != CompileSuccess;
1345 if (hasSyntaxError) {
1347 script.sourceURL = ContentSearchUtils::findSourceURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated);
1350 bool hasSourceURL = !script.sourceURL.isEmpty();
1351 String scriptURL = hasSourceURL ? script.sourceURL : script.url;
1353 String sourceMapURL = sourceMapURLForScript(script, compileResult);
1354 String* sourceMapURLParam = sourceMapURL.isNull() ? 0 : &sourceMapURL;
1356 bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : 0;
1357 if (!hasSyntaxError)
1358 m_frontend->scriptParsed(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam);
1360 m_frontend->scriptFailedToParse(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam);
1362 m_scripts.set(scriptId, script);
1364 if (scriptURL.isEmpty() || hasSyntaxError)
1367 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
1368 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) {
1369 RefPtr<JSONObject> breakpointObject = it->value->asObject();
1370 bool isAntibreakpoint;
1371 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint);
1372 if (isAntibreakpoint)
1375 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
1377 breakpointObject->getString(DebuggerAgentState::url, &url);
1378 if (!matches(scriptURL, url, isRegex))
1380 ScriptBreakpoint breakpoint;
1381 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakpoint.lineNumber);
1382 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakpoint.columnNumber);
1383 breakpointObject->getString(DebuggerAgentState::condition, &breakpoint.condition);
1384 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(it->key, scriptId, breakpoint, UserBreakpointSource);
1386 m_frontend->breakpointResolved(it->key, location);
1390 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& callFrames, const ScriptValue& exception, const Vector<String>& hitBreakpoints, bool isPromiseRejection)
1392 ScriptDebugListener::SkipPauseRequest result;
1393 if (callFrames.isEmpty())
1394 result = ScriptDebugListener::Continue; // Skip pauses inside V8 internal scripts and on syntax errors.
1395 else if (m_javaScriptPauseScheduled)
1396 result = ScriptDebugListener::NoSkip; // Don't skip explicit pause requests from front-end.
1397 else if (m_skipAllPauses)
1398 result = ScriptDebugListener::Continue;
1399 else if (!hitBreakpoints.isEmpty())
1400 result = ScriptDebugListener::NoSkip; // Don't skip explicit breakpoints even if set in frameworks.
1401 else if (!exception.isEmpty())
1402 result = shouldSkipExceptionPause();
1403 else if (m_debuggerStepScheduled || m_pausingOnNativeEvent)
1404 result = shouldSkipStepPause();
1406 result = ScriptDebugListener::NoSkip;
1408 if (result != ScriptDebugListener::NoSkip)
1411 ASSERT(scriptState && !m_pausedScriptState);
1412 m_pausedScriptState = scriptState;
1413 m_currentCallStack = callFrames;
1415 if (!exception.isEmpty()) {
1416 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
1417 if (!injectedScript.isEmpty()) {
1418 m_breakReason = isPromiseRejection ? InspectorFrontend::Debugger::Reason::PromiseRejection : InspectorFrontend::Debugger::Reason::Exception;
1419 m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors();
1420 // m_breakAuxData might be null after this.
1424 RefPtr<Array<String> > hitBreakpointIds = Array<String>::create();
1426 for (Vector<String>::const_iterator i = hitBreakpoints.begin(); i != hitBreakpoints.end(); ++i) {
1427 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator breakpointIterator = m_serverBreakpoints.find(*i);
1428 if (breakpointIterator != m_serverBreakpoints.end()) {
1429 const String& localId = breakpointIterator->value.first;
1430 hitBreakpointIds->addItem(localId);
1432 BreakpointSource source = breakpointIterator->value.second;
1433 if (m_breakReason == InspectorFrontend::Debugger::Reason::Other && source == DebugCommandBreakpointSource)
1434 m_breakReason = InspectorFrontend::Debugger::Reason::DebugCommand;
1438 m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData, hitBreakpointIds, currentAsyncStackTrace());
1439 m_javaScriptPauseScheduled = false;
1440 m_debuggerStepScheduled = false;
1441 m_steppingFromFramework = false;
1442 m_pausingOnNativeEvent = false;
1443 m_skippedStepInCount = 0;
1445 if (!m_continueToLocationBreakpointId.isEmpty()) {
1446 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
1447 m_continueToLocationBreakpointId = "";
1450 m_listener->didPause();
1454 void InspectorDebuggerAgent::didContinue()
1456 m_pausedScriptState = nullptr;
1457 m_currentCallStack = ScriptValue();
1458 clearBreakDetails();
1459 m_frontend->resumed();
1462 bool InspectorDebuggerAgent::canBreakProgram()
1464 return scriptDebugServer().canBreakProgram();
1467 void InspectorDebuggerAgent::breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data)
1469 if (m_skipAllPauses)
1471 m_breakReason = breakReason;
1472 m_breakAuxData = data;
1473 m_debuggerStepScheduled = false;
1474 m_steppingFromFramework = false;
1475 m_pausingOnNativeEvent = false;
1476 scriptDebugServer().breakProgram();
1479 void InspectorDebuggerAgent::clear()
1481 m_pausedScriptState = nullptr;
1482 m_currentCallStack = ScriptValue();
1484 m_breakpointIdToDebugServerBreakpointIds.clear();
1485 asyncCallStackTracker().clear();
1486 promiseTracker().clear();
1487 m_continueToLocationBreakpointId = String();
1488 clearBreakDetails();
1489 m_javaScriptPauseScheduled = false;
1490 m_debuggerStepScheduled = false;
1491 m_steppingFromFramework = false;
1492 m_pausingOnNativeEvent = false;
1494 setOverlayMessage(&error, 0);
1497 bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString)
1499 if (!m_pausedScriptState) {
1500 *errorString = "Can only perform operation while paused.";
1506 void InspectorDebuggerAgent::clearBreakDetails()
1508 m_breakReason = InspectorFrontend::Debugger::Reason::Other;
1509 m_breakAuxData = nullptr;
1512 void InspectorDebuggerAgent::setBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source, const String& condition)
1514 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumber, source);
1515 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
1516 resolveBreakpoint(breakpointId, scriptId, breakpoint, source);
1519 void InspectorDebuggerAgent::removeBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source)
1521 removeBreakpoint(generateBreakpointId(scriptId, lineNumber, columnNumber, source));
1524 void InspectorDebuggerAgent::reset()
1527 m_breakpointIdToDebugServerBreakpointIds.clear();
1528 asyncCallStackTracker().clear();
1529 promiseTracker().clear();
1531 m_frontend->globalObjectCleared();
1534 void InspectorDebuggerAgent::trace(Visitor* visitor)
1536 visitor->trace(m_injectedScriptManager);
1537 visitor->trace(m_listener);
1538 visitor->trace(m_asyncCallStackTracker);
1540 visitor->trace(m_promiseTracker);
1542 InspectorBaseAgent::trace(visitor);
1545 } // namespace blink