• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 Apple Inc. All rights reserved.
3  * Copyright (C) 2013 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 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.
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 "core/inspector/InspectorDebuggerAgent.h"
32 
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"
54 
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;
65 
66 namespace {
67 
68 static const char v8AsyncTaskEventEnqueue[] = "enqueue";
69 static const char v8AsyncTaskEventWillHandle[] = "willHandle";
70 static const char v8AsyncTaskEventDidHandle[] = "didHandle";
71 
72 }
73 
74 namespace blink {
75 
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";
82 
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";
94 
95 };
96 
97 static const int maxSkipStepInCount = 20;
98 
99 const char InspectorDebuggerAgent::backtraceObjectGroup[] = "backtrace";
100 
breakpointIdSuffix(InspectorDebuggerAgent::BreakpointSource source)101 static String breakpointIdSuffix(InspectorDebuggerAgent::BreakpointSource source)
102 {
103     switch (source) {
104     case InspectorDebuggerAgent::UserBreakpointSource:
105         break;
106     case InspectorDebuggerAgent::DebugCommandBreakpointSource:
107         return ":debug";
108     case InspectorDebuggerAgent::MonitorCommandBreakpointSource:
109         return ":monitor";
110     }
111     return String();
112 }
113 
generateBreakpointId(const String & scriptId,int lineNumber,int columnNumber,InspectorDebuggerAgent::BreakpointSource source)114 static String generateBreakpointId(const String& scriptId, int lineNumber, int columnNumber, InspectorDebuggerAgent::BreakpointSource source)
115 {
116     return scriptId + ':' + String::number(lineNumber) + ':' + String::number(columnNumber) + breakpointIdSuffix(source);
117 }
118 
InspectorDebuggerAgent(InjectedScriptManager * injectedScriptManager)119 InspectorDebuggerAgent::InspectorDebuggerAgent(InjectedScriptManager* injectedScriptManager)
120     : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger")
121     , m_injectedScriptManager(injectedScriptManager)
122     , m_frontend(0)
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())
134 {
135 }
136 
~InspectorDebuggerAgent()137 InspectorDebuggerAgent::~InspectorDebuggerAgent()
138 {
139 #if !ENABLE(OILPAN)
140     ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent());
141 #endif
142 }
143 
init()144 void InspectorDebuggerAgent::init()
145 {
146     // FIXME: make breakReason optional so that there was no need to init it with "other".
147     clearBreakDetails();
148     m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions);
149 }
150 
enable()151 void InspectorDebuggerAgent::enable()
152 {
153     m_instrumentingAgents->setInspectorDebuggerAgent(this);
154 
155     startListeningScriptDebugServer();
156     // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends
157     scriptDebugServer().setBreakpointsActivated(true);
158 
159     if (m_listener)
160         m_listener->debuggerWasEnabled();
161 }
162 
disable()163 void InspectorDebuggerAgent::disable()
164 {
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);
172 
173     scriptDebugServer().clearBreakpoints();
174     scriptDebugServer().clearCompiledScripts();
175     scriptDebugServer().clearPreprocessor();
176     stopListeningScriptDebugServer();
177     clear();
178 
179     if (m_listener)
180         m_listener->debuggerWasDisabled();
181 
182     m_skipAllPauses = false;
183 }
184 
enabled()185 bool InspectorDebuggerAgent::enabled()
186 {
187     return m_state->getBoolean(DebuggerAgentState::debuggerEnabled);
188 }
189 
enable(ErrorString *)190 void InspectorDebuggerAgent::enable(ErrorString*)
191 {
192     if (enabled())
193         return;
194 
195     enable();
196     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
197 
198     ASSERT(m_frontend);
199 }
200 
disable(ErrorString *)201 void InspectorDebuggerAgent::disable(ErrorString*)
202 {
203     if (!enabled())
204         return;
205 
206     disable();
207     m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
208 }
209 
compileSkipCallFramePattern(String patternText)210 static PassOwnPtr<ScriptRegexp> compileSkipCallFramePattern(String patternText)
211 {
212     if (patternText.isEmpty())
213         return nullptr;
214     OwnPtr<ScriptRegexp> result = adoptPtr(new ScriptRegexp(patternText, TextCaseSensitive));
215     if (!result->isValid())
216         result.clear();
217     return result.release();
218 }
219 
restore()220 void InspectorDebuggerAgent::restore()
221 {
222     if (enabled()) {
223         m_frontend->globalObjectCleared();
224         enable();
225         long pauseState = m_state->getLong(DebuggerAgentState::pauseOnExceptionsState);
226         String error;
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);
234         }
235         asyncCallStackTracker().setAsyncCallStackDepth(m_state->getLong(DebuggerAgentState::asyncCallStackDepth));
236         promiseTracker().setEnabled(m_state->getBoolean(DebuggerAgentState::promiseTrackerEnabled));
237     }
238 }
239 
setFrontend(InspectorFrontend * frontend)240 void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend)
241 {
242     m_frontend = frontend->debugger();
243 }
244 
clearFrontend()245 void InspectorDebuggerAgent::clearFrontend()
246 {
247     m_frontend = 0;
248 
249     if (!enabled())
250         return;
251 
252     disable();
253 
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);
258 }
259 
setBreakpointsActive(ErrorString *,bool active)260 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active)
261 {
262     scriptDebugServer().setBreakpointsActivated(active);
263 }
264 
setSkipAllPauses(ErrorString *,bool skipped,const bool * untilReload)265 void InspectorDebuggerAgent::setSkipAllPauses(ErrorString*, bool skipped, const bool* untilReload)
266 {
267     m_skipAllPauses = skipped;
268     m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses);
269     m_state->setBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload, asBool(untilReload));
270 }
271 
pageDidCommitLoad()272 void InspectorDebuggerAgent::pageDidCommitLoad()
273 {
274     if (m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) {
275         m_skipAllPauses = false;
276         m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses);
277     }
278 }
279 
isPaused()280 bool InspectorDebuggerAgent::isPaused()
281 {
282     return scriptDebugServer().isPaused();
283 }
284 
runningNestedMessageLoop()285 bool InspectorDebuggerAgent::runningNestedMessageLoop()
286 {
287     return scriptDebugServer().runningNestedMessageLoop();
288 }
289 
addMessageToConsole(ConsoleMessage * consoleMessage)290 void InspectorDebuggerAgent::addMessageToConsole(ConsoleMessage* consoleMessage)
291 {
292     if (consoleMessage->type() == AssertMessageType && scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions)
293         breakProgram(InspectorFrontend::Debugger::Reason::Assert, nullptr);
294 }
295 
preprocessEventListener(LocalFrame * frame,const String & source,const String & url,const String & functionName)296 String InspectorDebuggerAgent::preprocessEventListener(LocalFrame* frame, const String& source, const String& url, const String& functionName)
297 {
298     return scriptDebugServer().preprocessEventListener(frame, source, url, functionName);
299 }
300 
preprocess(LocalFrame * frame,const ScriptSourceCode & sourceCode)301 PassOwnPtr<ScriptSourceCode> InspectorDebuggerAgent::preprocess(LocalFrame* frame, const ScriptSourceCode& sourceCode)
302 {
303     return scriptDebugServer().preprocess(frame, sourceCode);
304 }
305 
buildObjectForBreakpointCookie(const String & url,int lineNumber,int columnNumber,const String & condition,bool isRegex,bool isAnti)306 static PassRefPtr<JSONObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex, bool isAnti)
307 {
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;
316 }
317 
scriptSourceURL(const ScriptDebugListener::Script & script)318 static String scriptSourceURL(const ScriptDebugListener::Script& script)
319 {
320     bool hasSourceURL = !script.sourceURL.isEmpty();
321     return hasSourceURL ? script.sourceURL : script.url;
322 }
323 
matches(const String & url,const String & pattern,bool isRegex)324 static bool matches(const String& url, const String& pattern, bool isRegex)
325 {
326     if (isRegex) {
327         ScriptRegexp regex(pattern, TextCaseSensitive);
328         return regex.match(url) != -1;
329     }
330     return url == pattern;
331 }
332 
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)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)
334 {
335     locations = Array<TypeBuilder::Debugger::Location>::create();
336     if (!optionalURL == !optionalURLRegex) {
337         *errorString = "Either url or urlRegex must be specified.";
338         return;
339     }
340 
341     bool isAntiBreakpointValue = asBool(isAntiBreakpoint);
342 
343     String url = optionalURL ? *optionalURL : *optionalURLRegex;
344     int columnNumber;
345     if (optionalColumnNumber) {
346         columnNumber = *optionalColumnNumber;
347         if (columnNumber < 0) {
348             *errorString = "Incorrect column number";
349             return;
350         }
351     } else {
352         columnNumber = isAntiBreakpointValue ? -1 : 0;
353     }
354     String condition = optionalCondition ? *optionalCondition : "";
355     bool isRegex = optionalURLRegex;
356 
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.";
361         return;
362     }
363 
364     breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, isRegex, isAntiBreakpointValue));
365     m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie);
366 
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))
371                 continue;
372             RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(breakpointId, it->key, breakpoint, UserBreakpointSource);
373             if (location)
374                 locations->addItem(location);
375         }
376     }
377     *outBreakpointId = breakpointId;
378 }
379 
parseLocation(ErrorString * errorString,PassRefPtr<JSONObject> location,String * scriptId,int * lineNumber,int * columnNumber)380 static bool parseLocation(ErrorString* errorString, PassRefPtr<JSONObject> location, String* scriptId, int* lineNumber, int* columnNumber)
381 {
382     if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) {
383         // FIXME: replace with input validation.
384         *errorString = "scriptId and lineNumber are required.";
385         return false;
386     }
387     *columnNumber = 0;
388     location->getNumber("columnNumber", columnNumber);
389     return true;
390 }
391 
setBreakpoint(ErrorString * errorString,const RefPtr<JSONObject> & location,const String * const optionalCondition,BreakpointId * outBreakpointId,RefPtr<TypeBuilder::Debugger::Location> & actualLocation)392 void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr<JSONObject>& location, const String* const optionalCondition, BreakpointId* outBreakpointId, RefPtr<TypeBuilder::Debugger::Location>& actualLocation)
393 {
394     String scriptId;
395     int lineNumber;
396     int columnNumber;
397 
398     if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
399         return;
400 
401     String condition = optionalCondition ? *optionalCondition : emptyString();
402 
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.";
406         return;
407     }
408     ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
409     actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, UserBreakpointSource);
410     if (actualLocation)
411         *outBreakpointId = breakpointId;
412     else
413         *errorString = "Could not resolve breakpoint";
414 }
415 
removeBreakpoint(ErrorString *,const String & breakpointId)416 void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointId)
417 {
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);
426     }
427 
428     if (!isAntibreakpoint)
429         removeBreakpoint(breakpointId);
430 }
431 
removeBreakpoint(const String & breakpointId)432 void InspectorDebuggerAgent::removeBreakpoint(const String& breakpointId)
433 {
434     BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId);
435     if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end())
436         return;
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);
441     }
442     m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator);
443 }
444 
continueToLocation(ErrorString * errorString,const RefPtr<JSONObject> & location,const bool * interstateLocationOpt)445 void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const RefPtr<JSONObject>& location, const bool* interstateLocationOpt)
446 {
447     if (!m_continueToLocationBreakpointId.isEmpty()) {
448         scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
449         m_continueToLocationBreakpointId = "";
450     }
451 
452     String scriptId;
453     int lineNumber;
454     int columnNumber;
455 
456     if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber))
457         return;
458 
459     ScriptBreakpoint breakpoint(lineNumber, columnNumber, "");
460     m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber, asBool(interstateLocationOpt));
461     resume(errorString);
462 }
463 
getStepInPositions(ErrorString * errorString,const String & callFrameId,RefPtr<Array<TypeBuilder::Debugger::Location>> & positions)464 void InspectorDebuggerAgent::getStepInPositions(ErrorString* errorString, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::Location> >& positions)
465 {
466     if (!isPaused() || m_currentCallStack.isEmpty()) {
467         *errorString = "Attempt to access callframe when debugger is not on pause";
468         return;
469     }
470     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
471     if (injectedScript.isEmpty()) {
472         *errorString = "Inspected frame has gone";
473         return;
474     }
475 
476     injectedScript.getStepInPositions(errorString, m_currentCallStack, callFrameId, positions);
477 }
478 
getBacktrace(ErrorString * errorString,RefPtr<Array<CallFrame>> & callFrames,RefPtr<StackTrace> & asyncStackTrace)479 void InspectorDebuggerAgent::getBacktrace(ErrorString* errorString, RefPtr<Array<CallFrame> >& callFrames, RefPtr<StackTrace>& asyncStackTrace)
480 {
481     if (!assertPaused(errorString))
482         return;
483     m_currentCallStack = scriptDebugServer().currentCallFrames();
484     callFrames = currentCallFrames();
485     asyncStackTrace = currentAsyncStackTrace();
486 }
487 
topCallFrameSkipUnknownSources(String * scriptURL,bool * isBlackboxed)488 PassRefPtrWillBeRawPtr<JavaScriptCallFrame> InspectorDebuggerAgent::topCallFrameSkipUnknownSources(String* scriptURL, bool* isBlackboxed)
489 {
490     for (int index = 0; ; ++index) {
491         RefPtrWillBeRawPtr<JavaScriptCallFrame> frame = scriptDebugServer().callFrameNoScopes(index);
492         if (!frame)
493             return nullptr;
494         ScriptsMap::iterator it = m_scripts.find(String::number(frame->sourceID()));
495         if (it == m_scripts.end())
496             continue;
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();
501     }
502 }
503 
shouldSkipExceptionPause()504 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipExceptionPause()
505 {
506     if (m_steppingFromFramework)
507         return ScriptDebugListener::NoSkip;
508 
509     // FIXME: Fast return: if (!m_skipContentScripts && !m_cachedSkipStackRegExp && !has_any_anti_breakpoint) return ScriptDebugListener::NoSkip;
510 
511     String topFrameScriptUrl;
512     bool isBlackboxed = false;
513     RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&topFrameScriptUrl, &isBlackboxed);
514     if (!topFrame)
515         return ScriptDebugListener::NoSkip;
516     if (isBlackboxed)
517         return ScriptDebugListener::Continue;
518 
519     // Match against breakpoints.
520     if (topFrameScriptUrl.isEmpty())
521         return ScriptDebugListener::NoSkip;
522 
523     // Prepare top frame parameters.
524     int topFrameLineNumber = topFrame->line();
525     int topFrameColumnNumber = topFrame->column();
526 
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)
533             continue;
534 
535         int breakLineNumber;
536         breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakLineNumber);
537         int breakColumnNumber;
538         breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakColumnNumber);
539 
540         if (breakLineNumber != topFrameLineNumber)
541             continue;
542 
543         if (breakColumnNumber != -1 && breakColumnNumber != topFrameColumnNumber)
544             continue;
545 
546         bool isRegex;
547         breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
548         String url;
549         breakpointObject->getString(DebuggerAgentState::url, &url);
550         if (!matches(topFrameScriptUrl, url, isRegex))
551             continue;
552 
553         return ScriptDebugListener::Continue;
554     }
555 
556     return ScriptDebugListener::NoSkip;
557 }
558 
shouldSkipStepPause()559 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipStepPause()
560 {
561     if (m_steppingFromFramework)
562         return ScriptDebugListener::NoSkip;
563     // Fast return.
564     if (!m_skipContentScripts && !m_cachedSkipStackRegExp)
565         return ScriptDebugListener::NoSkip;
566 
567     String scriptUrl;
568     bool isBlackboxed = false;
569     RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&scriptUrl, &isBlackboxed);
570     if (!topFrame || !isBlackboxed)
571         return ScriptDebugListener::NoSkip;
572 
573     if (m_skippedStepInCount == 0) {
574         m_minFrameCountForSkip = scriptDebugServer().frameCount();
575         m_skippedStepInCount = 1;
576         return ScriptDebugListener::StepInto;
577     }
578 
579     if (m_skippedStepInCount < maxSkipStepInCount && topFrame->isAtReturn() && scriptDebugServer().frameCount() <= m_minFrameCountForSkip)
580         m_skippedStepInCount = maxSkipStepInCount;
581 
582     if (m_skippedStepInCount >= maxSkipStepInCount) {
583         if (m_pausingOnNativeEvent) {
584             m_pausingOnNativeEvent = false;
585             m_skippedStepInCount = 0;
586             return ScriptDebugListener::Continue;
587         }
588         return ScriptDebugListener::StepOut;
589     }
590 
591     ++m_skippedStepInCount;
592     return ScriptDebugListener::StepInto;
593 }
594 
isTopCallFrameInFramework()595 bool InspectorDebuggerAgent::isTopCallFrameInFramework()
596 {
597     if (!m_skipContentScripts && !m_cachedSkipStackRegExp)
598         return false;
599 
600     String scriptUrl;
601     bool isBlackboxed = false;
602     RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&scriptUrl, &isBlackboxed);
603     return topFrame && isBlackboxed;
604 }
605 
resolveBreakpoint(const String & breakpointId,const String & scriptId,const ScriptBreakpoint & breakpoint,BreakpointSource source)606 PassRefPtr<TypeBuilder::Debugger::Location> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint& breakpoint, BreakpointSource source)
607 {
608     ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
609     if (scriptIterator == m_scripts.end())
610         return nullptr;
611     Script& script = scriptIterator->value;
612     if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint.lineNumber)
613         return nullptr;
614 
615     int actualLineNumber;
616     int actualColumnNumber;
617     String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false);
618     if (debugServerBreakpointId.isEmpty())
619         return nullptr;
620 
621     m_serverBreakpoints.set(debugServerBreakpointId, std::make_pair(breakpointId, source));
622 
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);
626     else
627         debugServerBreakpointIdsIterator->value.append(debugServerBreakpointId);
628 
629     RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create()
630         .setScriptId(scriptId)
631         .setLineNumber(actualLineNumber);
632     location->setColumnNumber(actualColumnNumber);
633     return location;
634 }
635 
searchInContent(ErrorString * error,const String & scriptId,const String & query,const bool * const optionalCaseSensitive,const bool * const optionalIsRegex,RefPtr<Array<blink::TypeBuilder::Page::SearchMatch>> & results)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)
637 {
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));
641     else
642         *error = "No script for id: " + scriptId;
643 }
644 
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)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)
646 {
647     if (!scriptDebugServer().setScriptSource(scriptId, newContent, asBool(preview), error, errorData, &m_currentCallStack, &result))
648         return;
649 
650     newCallFrames = currentCallFrames();
651     asyncStackTrace = currentAsyncStackTrace();
652 
653     ScriptsMap::iterator it = m_scripts.find(scriptId);
654     if (it == m_scripts.end())
655         return;
656     String url = it->value.url;
657     if (url.isEmpty())
658         return;
659     if (InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent())
660         pageAgent->addEditedResourceContent(url, newContent);
661 }
662 
restartFrame(ErrorString * errorString,const String & callFrameId,RefPtr<Array<CallFrame>> & newCallFrames,RefPtr<JSONObject> & result,RefPtr<StackTrace> & asyncStackTrace)663 void InspectorDebuggerAgent::restartFrame(ErrorString* errorString, const String& callFrameId, RefPtr<Array<CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<StackTrace>& asyncStackTrace)
664 {
665     if (!isPaused() || m_currentCallStack.isEmpty()) {
666         *errorString = "Attempt to access callframe when debugger is not on pause";
667         return;
668     }
669     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
670     if (injectedScript.isEmpty()) {
671         *errorString = "Inspected frame has gone";
672         return;
673     }
674 
675     injectedScript.restartFrame(errorString, m_currentCallStack, callFrameId, &result);
676     m_currentCallStack = scriptDebugServer().currentCallFrames();
677     newCallFrames = currentCallFrames();
678     asyncStackTrace = currentAsyncStackTrace();
679 }
680 
getScriptSource(ErrorString * error,const String & scriptId,String * scriptSource)681 void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptId, String* scriptSource)
682 {
683     ScriptsMap::iterator it = m_scripts.find(scriptId);
684     if (it == m_scripts.end()) {
685         *error = "No script for id: " + scriptId;
686         return;
687     }
688 
689     String url = it->value.url;
690     if (!url.isEmpty()) {
691         if (InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent()) {
692             bool success = pageAgent->getEditedResourceContent(url, scriptSource);
693             if (success)
694                 return;
695         }
696     }
697     *scriptSource = it->value.source;
698 }
699 
getFunctionDetails(ErrorString * errorString,const String & functionId,RefPtr<FunctionDetails> & details)700 void InspectorDebuggerAgent::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>& details)
701 {
702     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId);
703     if (injectedScript.isEmpty()) {
704         *errorString = "Function object id is obsolete";
705         return;
706     }
707     injectedScript.getFunctionDetails(errorString, functionId, &details);
708 }
709 
getCollectionEntries(ErrorString * errorString,const String & objectId,RefPtr<TypeBuilder::Array<CollectionEntry>> & entries)710 void InspectorDebuggerAgent::getCollectionEntries(ErrorString* errorString, const String& objectId, RefPtr<TypeBuilder::Array<CollectionEntry> >& entries)
711 {
712     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId);
713     if (injectedScript.isEmpty()) {
714         *errorString = "Inspected frame has gone";
715         return;
716     }
717     injectedScript.getCollectionEntries(errorString, objectId, &entries);
718 }
719 
schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason,PassRefPtr<JSONObject> data)720 void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data)
721 {
722     if (m_javaScriptPauseScheduled || isPaused())
723         return;
724     m_breakReason = breakReason;
725     m_breakAuxData = data;
726     m_pausingOnNativeEvent = true;
727     scriptDebugServer().setPauseOnNextStatement(true);
728 }
729 
cancelPauseOnNextStatement()730 void InspectorDebuggerAgent::cancelPauseOnNextStatement()
731 {
732     if (m_javaScriptPauseScheduled || isPaused())
733         return;
734     clearBreakDetails();
735     m_pausingOnNativeEvent = false;
736     scriptDebugServer().setPauseOnNextStatement(false);
737 }
738 
didInstallTimer(ExecutionContext * context,int timerId,int timeout,bool singleShot)739 void InspectorDebuggerAgent::didInstallTimer(ExecutionContext* context, int timerId, int timeout, bool singleShot)
740 {
741     if (asyncCallStackTracker().isEnabled())
742         asyncCallStackTracker().didInstallTimer(context, timerId, singleShot, scriptDebugServer().currentCallFramesForAsyncStack());
743 }
744 
didRemoveTimer(ExecutionContext * context,int timerId)745 void InspectorDebuggerAgent::didRemoveTimer(ExecutionContext* context, int timerId)
746 {
747     if (asyncCallStackTracker().isEnabled())
748         asyncCallStackTracker().didRemoveTimer(context, timerId);
749 }
750 
willFireTimer(ExecutionContext * context,int timerId)751 bool InspectorDebuggerAgent::willFireTimer(ExecutionContext* context, int timerId)
752 {
753     if (asyncCallStackTracker().isEnabled())
754         asyncCallStackTracker().willFireTimer(context, timerId);
755     return true;
756 }
757 
didFireTimer()758 void InspectorDebuggerAgent::didFireTimer()
759 {
760     if (asyncCallStackTracker().isEnabled())
761         asyncCallStackTracker().didFireAsyncCall();
762     cancelPauseOnNextStatement();
763 }
764 
didRequestAnimationFrame(Document * document,int callbackId)765 void InspectorDebuggerAgent::didRequestAnimationFrame(Document* document, int callbackId)
766 {
767     if (asyncCallStackTracker().isEnabled())
768         asyncCallStackTracker().didRequestAnimationFrame(document, callbackId, scriptDebugServer().currentCallFramesForAsyncStack());
769 }
770 
didCancelAnimationFrame(Document * document,int callbackId)771 void InspectorDebuggerAgent::didCancelAnimationFrame(Document* document, int callbackId)
772 {
773     if (asyncCallStackTracker().isEnabled())
774         asyncCallStackTracker().didCancelAnimationFrame(document, callbackId);
775 }
776 
willFireAnimationFrame(Document * document,int callbackId)777 bool InspectorDebuggerAgent::willFireAnimationFrame(Document* document, int callbackId)
778 {
779     if (asyncCallStackTracker().isEnabled())
780         asyncCallStackTracker().willFireAnimationFrame(document, callbackId);
781     return true;
782 }
783 
didFireAnimationFrame()784 void InspectorDebuggerAgent::didFireAnimationFrame()
785 {
786     if (asyncCallStackTracker().isEnabled())
787         asyncCallStackTracker().didFireAsyncCall();
788 }
789 
didEnqueueEvent(EventTarget * eventTarget,Event * event)790 void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* event)
791 {
792     if (asyncCallStackTracker().isEnabled())
793         asyncCallStackTracker().didEnqueueEvent(eventTarget, event, scriptDebugServer().currentCallFramesForAsyncStack());
794 }
795 
didRemoveEvent(EventTarget * eventTarget,Event * event)796 void InspectorDebuggerAgent::didRemoveEvent(EventTarget* eventTarget, Event* event)
797 {
798     if (asyncCallStackTracker().isEnabled())
799         asyncCallStackTracker().didRemoveEvent(eventTarget, event);
800 }
801 
willHandleEvent(EventTarget * eventTarget,Event * event,EventListener * listener,bool useCapture)802 void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture)
803 {
804     if (asyncCallStackTracker().isEnabled())
805         asyncCallStackTracker().willHandleEvent(eventTarget, event, listener, useCapture);
806 }
807 
didHandleEvent()808 void InspectorDebuggerAgent::didHandleEvent()
809 {
810     if (asyncCallStackTracker().isEnabled())
811         asyncCallStackTracker().didFireAsyncCall();
812     cancelPauseOnNextStatement();
813 }
814 
willLoadXHR(XMLHttpRequest * xhr,ThreadableLoaderClient *,const AtomicString &,const KURL &,bool async,PassRefPtr<FormData>,const HTTPHeaderMap &,bool)815 void InspectorDebuggerAgent::willLoadXHR(XMLHttpRequest* xhr, ThreadableLoaderClient*, const AtomicString&, const KURL&, bool async, PassRefPtr<FormData>, const HTTPHeaderMap&, bool)
816 {
817     if (asyncCallStackTracker().isEnabled() && async)
818         asyncCallStackTracker().willLoadXHR(xhr, scriptDebugServer().currentCallFramesForAsyncStack());
819 }
820 
didDispatchXHRLoadendEvent(XMLHttpRequest * xhr)821 void InspectorDebuggerAgent::didDispatchXHRLoadendEvent(XMLHttpRequest* xhr)
822 {
823     if (asyncCallStackTracker().isEnabled())
824         asyncCallStackTracker().didLoadXHR(xhr);
825 }
826 
didEnqueueMutationRecord(ExecutionContext * context,MutationObserver * observer)827 void InspectorDebuggerAgent::didEnqueueMutationRecord(ExecutionContext* context, MutationObserver* observer)
828 {
829     if (asyncCallStackTracker().isEnabled() && !asyncCallStackTracker().hasEnqueuedMutationRecord(context, observer))
830         asyncCallStackTracker().didEnqueueMutationRecord(context, observer, scriptDebugServer().currentCallFramesForAsyncStack());
831 }
832 
didClearAllMutationRecords(ExecutionContext * context,MutationObserver * observer)833 void InspectorDebuggerAgent::didClearAllMutationRecords(ExecutionContext* context, MutationObserver* observer)
834 {
835     if (asyncCallStackTracker().isEnabled())
836         asyncCallStackTracker().didClearAllMutationRecords(context, observer);
837 }
838 
willDeliverMutationRecords(ExecutionContext * context,MutationObserver * observer)839 void InspectorDebuggerAgent::willDeliverMutationRecords(ExecutionContext* context, MutationObserver* observer)
840 {
841     if (asyncCallStackTracker().isEnabled())
842         asyncCallStackTracker().willDeliverMutationRecords(context, observer);
843 }
844 
didDeliverMutationRecords()845 void InspectorDebuggerAgent::didDeliverMutationRecords()
846 {
847     if (asyncCallStackTracker().isEnabled())
848         asyncCallStackTracker().didFireAsyncCall();
849 }
850 
didPostExecutionContextTask(ExecutionContext * context,ExecutionContextTask * task)851 void InspectorDebuggerAgent::didPostExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task)
852 {
853     if (asyncCallStackTracker().isEnabled() && !task->taskNameForInstrumentation().isEmpty())
854         asyncCallStackTracker().didPostExecutionContextTask(context, task, scriptDebugServer().currentCallFramesForAsyncStack());
855 }
856 
didKillAllExecutionContextTasks(ExecutionContext * context)857 void InspectorDebuggerAgent::didKillAllExecutionContextTasks(ExecutionContext* context)
858 {
859     if (asyncCallStackTracker().isEnabled())
860         asyncCallStackTracker().didKillAllExecutionContextTasks(context);
861 }
862 
willPerformExecutionContextTask(ExecutionContext * context,ExecutionContextTask * task)863 void InspectorDebuggerAgent::willPerformExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task)
864 {
865     if (asyncCallStackTracker().isEnabled())
866         asyncCallStackTracker().willPerformExecutionContextTask(context, task);
867 }
868 
didPerformExecutionContextTask()869 void InspectorDebuggerAgent::didPerformExecutionContextTask()
870 {
871     if (asyncCallStackTracker().isEnabled())
872         asyncCallStackTracker().didFireAsyncCall();
873 }
874 
traceAsyncOperationStarting(ExecutionContext * context,const String & operationName,int prevOperationId)875 int InspectorDebuggerAgent::traceAsyncOperationStarting(ExecutionContext* context, const String& operationName, int prevOperationId)
876 {
877     if (!asyncCallStackTracker().isEnabled())
878         return 0;
879     if (prevOperationId)
880         asyncCallStackTracker().traceAsyncOperationCompleted(context, prevOperationId);
881     return asyncCallStackTracker().traceAsyncOperationStarting(context, operationName, scriptDebugServer().currentCallFramesForAsyncStack());
882 }
883 
traceAsyncOperationCompleted(ExecutionContext * context,int operationId)884 void InspectorDebuggerAgent::traceAsyncOperationCompleted(ExecutionContext* context, int operationId)
885 {
886     if (asyncCallStackTracker().isEnabled())
887         asyncCallStackTracker().traceAsyncOperationCompleted(context, operationId);
888 }
889 
traceAsyncOperationCompletedCallbackStarting(ExecutionContext * context,int operationId)890 void InspectorDebuggerAgent::traceAsyncOperationCompletedCallbackStarting(ExecutionContext* context, int operationId)
891 {
892     if (!asyncCallStackTracker().isEnabled())
893         return;
894     asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId);
895     asyncCallStackTracker().traceAsyncOperationCompleted(context, operationId);
896 }
897 
traceAsyncCallbackStarting(ExecutionContext * context,int operationId)898 void InspectorDebuggerAgent::traceAsyncCallbackStarting(ExecutionContext* context, int operationId)
899 {
900     if (asyncCallStackTracker().isEnabled())
901         asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId);
902 }
903 
traceAsyncCallbackCompleted()904 void InspectorDebuggerAgent::traceAsyncCallbackCompleted()
905 {
906     if (asyncCallStackTracker().isEnabled())
907         asyncCallStackTracker().didFireAsyncCall();
908 }
909 
v8AsyncTaskEventsEnabled() const910 bool InspectorDebuggerAgent::v8AsyncTaskEventsEnabled() const
911 {
912     return asyncCallStackTracker().isEnabled();
913 }
914 
didReceiveV8AsyncTaskEvent(ExecutionContext * context,const String & eventType,const String & eventName,int id)915 void InspectorDebuggerAgent::didReceiveV8AsyncTaskEvent(ExecutionContext* context, const String& eventType, const String& eventName, int id)
916 {
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();
924     else
925         ASSERT_NOT_REACHED();
926 }
927 
v8PromiseEventsEnabled() const928 bool InspectorDebuggerAgent::v8PromiseEventsEnabled() const
929 {
930     return promiseTracker().isEnabled() || (m_listener && m_listener->canPauseOnPromiseEvent());
931 }
932 
didReceiveV8PromiseEvent(ScriptState * scriptState,v8::Handle<v8::Object> promise,v8::Handle<v8::Value> parentPromise,int status)933 void InspectorDebuggerAgent::didReceiveV8PromiseEvent(ScriptState* scriptState, v8::Handle<v8::Object> promise, v8::Handle<v8::Value> parentPromise, int status)
934 {
935     if (promiseTracker().isEnabled())
936         promiseTracker().didReceiveV8PromiseEvent(scriptState, promise, parentPromise, status);
937     if (!m_listener)
938         return;
939     if (!parentPromise.IsEmpty() && parentPromise->IsObject())
940         return;
941     if (status < 0)
942         m_listener->didRejectPromise();
943     else if (status > 0)
944         m_listener->didResolvePromise();
945     else
946         m_listener->didCreatePromise();
947 }
948 
pause(ErrorString *)949 void InspectorDebuggerAgent::pause(ErrorString*)
950 {
951     if (m_javaScriptPauseScheduled || isPaused())
952         return;
953     clearBreakDetails();
954     m_javaScriptPauseScheduled = true;
955     scriptDebugServer().setPauseOnNextStatement(true);
956 }
957 
resume(ErrorString * errorString)958 void InspectorDebuggerAgent::resume(ErrorString* errorString)
959 {
960     if (!assertPaused(errorString))
961         return;
962     m_debuggerStepScheduled = false;
963     m_steppingFromFramework = false;
964     m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
965     scriptDebugServer().continueProgram();
966 }
967 
stepOver(ErrorString * errorString)968 void InspectorDebuggerAgent::stepOver(ErrorString* errorString)
969 {
970     if (!assertPaused(errorString))
971         return;
972     m_debuggerStepScheduled = true;
973     m_steppingFromFramework = isTopCallFrameInFramework();
974     m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
975     scriptDebugServer().stepOverStatement();
976 }
977 
stepInto(ErrorString * errorString)978 void InspectorDebuggerAgent::stepInto(ErrorString* errorString)
979 {
980     if (!assertPaused(errorString))
981         return;
982     m_debuggerStepScheduled = true;
983     m_steppingFromFramework = isTopCallFrameInFramework();
984     m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
985     scriptDebugServer().stepIntoStatement();
986     if (m_listener)
987         m_listener->stepInto();
988 }
989 
stepOut(ErrorString * errorString)990 void InspectorDebuggerAgent::stepOut(ErrorString* errorString)
991 {
992     if (!assertPaused(errorString))
993         return;
994     m_debuggerStepScheduled = true;
995     m_steppingFromFramework = isTopCallFrameInFramework();
996     m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup);
997     scriptDebugServer().stepOutOfFunction();
998 }
999 
setPauseOnExceptions(ErrorString * errorString,const String & stringPauseState)1000 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState)
1001 {
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;
1009     else {
1010         *errorString = "Unknown pause on exceptions mode: " + stringPauseState;
1011         return;
1012     }
1013     setPauseOnExceptionsImpl(errorString, pauseState);
1014 }
1015 
setPauseOnExceptionsImpl(ErrorString * errorString,int pauseState)1016 void InspectorDebuggerAgent::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState)
1017 {
1018     scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState));
1019     if (scriptDebugServer().pauseOnExceptionsState() != pauseState)
1020         *errorString = "Internal error. Could not change pause on exceptions state";
1021     else
1022         m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, pauseState);
1023 }
1024 
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)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)
1026 {
1027     if (!isPaused() || m_currentCallStack.isEmpty()) {
1028         *errorString = "Attempt to access callframe when debugger is not on pause";
1029         return;
1030     }
1031     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId);
1032     if (injectedScript.isEmpty()) {
1033         *errorString = "Inspected frame has gone";
1034         return;
1035     }
1036 
1037     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState();
1038     if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
1039         if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions)
1040             scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions);
1041         muteConsole();
1042     }
1043 
1044     Vector<ScriptValue> asyncCallStacks;
1045     const AsyncCallStackTracker::AsyncCallChain* asyncChain = asyncCallStackTracker().isEnabled() ? asyncCallStackTracker().currentAsyncCallChain() : 0;
1046     if (asyncChain) {
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();
1052     }
1053 
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)) {
1060         unmuteConsole();
1061         if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState)
1062             scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState);
1063     }
1064 }
1065 
compileScript(ErrorString * errorString,const String & expression,const String & sourceURL,const int * executionContextId,TypeBuilder::OptOutput<ScriptId> * scriptId,RefPtr<ExceptionDetails> & exceptionDetails)1066 void InspectorDebuggerAgent::compileScript(ErrorString* errorString, const String& expression, const String& sourceURL, const int* executionContextId, TypeBuilder::OptOutput<ScriptId>* scriptId, RefPtr<ExceptionDetails>& exceptionDetails)
1067 {
1068     InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
1069     if (injectedScript.isEmpty()) {
1070         *errorString = "Inspected frame has gone";
1071         return;
1072     }
1073 
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";
1082         return;
1083     }
1084     *scriptId = scriptIdValue;
1085     if (!scriptIdValue.isEmpty())
1086         return;
1087 
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());
1093 }
1094 
runScript(ErrorString * errorString,const ScriptId & scriptId,const int * executionContextId,const String * const objectGroup,const bool * const doNotPauseOnExceptionsAndMuteConsole,RefPtr<RemoteObject> & result,RefPtr<ExceptionDetails> & exceptionDetails)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)
1096 {
1097     InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId);
1098     if (injectedScript.isEmpty()) {
1099         *errorString = "Inspected frame has gone";
1100         return;
1101     }
1102 
1103     ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState();
1104     if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
1105         if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions)
1106             scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions);
1107         muteConsole();
1108     }
1109 
1110     ScriptValue value;
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";
1119         return;
1120     }
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());
1128     }
1129 
1130     if (asBool(doNotPauseOnExceptionsAndMuteConsole)) {
1131         unmuteConsole();
1132         if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState)
1133             scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState);
1134     }
1135 }
1136 
setOverlayMessage(ErrorString *,const String *)1137 void InspectorDebuggerAgent::setOverlayMessage(ErrorString*, const String*)
1138 {
1139 }
1140 
setVariableValue(ErrorString * errorString,int scopeNumber,const String & variableName,const RefPtr<JSONObject> & newValue,const String * callFrameId,const String * functionObjectId)1141 void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, int scopeNumber, const String& variableName, const RefPtr<JSONObject>& newValue, const String* callFrameId, const String* functionObjectId)
1142 {
1143     InjectedScript injectedScript;
1144     if (callFrameId) {
1145         if (!isPaused() || m_currentCallStack.isEmpty()) {
1146             *errorString = "Attempt to access callframe when debugger is not on pause";
1147             return;
1148         }
1149         injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*callFrameId);
1150         if (injectedScript.isEmpty()) {
1151             *errorString = "Inspected frame has gone";
1152             return;
1153         }
1154     } else if (functionObjectId) {
1155         injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*functionObjectId);
1156         if (injectedScript.isEmpty()) {
1157             *errorString = "Function object id cannot be resolved";
1158             return;
1159         }
1160     } else {
1161         *errorString = "Either call frame or function object must be specified";
1162         return;
1163     }
1164     String newValueString = newValue->toJSONString();
1165 
1166     injectedScript.setVariableValue(errorString, m_currentCallStack, callFrameId, functionObjectId, scopeNumber, variableName, newValueString);
1167 }
1168 
skipStackFrames(ErrorString * errorString,const String * pattern,const bool * skipContentScripts)1169 void InspectorDebuggerAgent::skipStackFrames(ErrorString* errorString, const String* pattern, const bool* skipContentScripts)
1170 {
1171     OwnPtr<ScriptRegexp> compiled;
1172     String patternValue = pattern ? *pattern : "";
1173     if (!patternValue.isEmpty()) {
1174         compiled = compileSkipCallFramePattern(patternValue);
1175         if (!compiled) {
1176             *errorString = "Invalid regular expression";
1177             return;
1178         }
1179     }
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);
1184 }
1185 
setAsyncCallStackDepth(ErrorString *,int depth)1186 void InspectorDebuggerAgent::setAsyncCallStackDepth(ErrorString*, int depth)
1187 {
1188     m_state->setLong(DebuggerAgentState::asyncCallStackDepth, depth);
1189     asyncCallStackTracker().setAsyncCallStackDepth(depth);
1190 }
1191 
enablePromiseTracker(ErrorString *)1192 void InspectorDebuggerAgent::enablePromiseTracker(ErrorString*)
1193 {
1194     m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, true);
1195     promiseTracker().setEnabled(true);
1196 }
1197 
disablePromiseTracker(ErrorString *)1198 void InspectorDebuggerAgent::disablePromiseTracker(ErrorString*)
1199 {
1200     m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, false);
1201     promiseTracker().setEnabled(false);
1202 }
1203 
getPromises(ErrorString * errorString,RefPtr<Array<PromiseDetails>> & promises)1204 void InspectorDebuggerAgent::getPromises(ErrorString* errorString, RefPtr<Array<PromiseDetails> >& promises)
1205 {
1206     if (!promiseTracker().isEnabled()) {
1207         *errorString = "Promise tracking is disabled";
1208         return;
1209     }
1210     promises = promiseTracker().promises();
1211 }
1212 
getPromiseById(ErrorString * errorString,int promiseId,const String * objectGroup,RefPtr<RemoteObject> & promise)1213 void InspectorDebuggerAgent::getPromiseById(ErrorString* errorString, int promiseId, const String* objectGroup, RefPtr<RemoteObject>& promise)
1214 {
1215     if (!promiseTracker().isEnabled()) {
1216         *errorString = "Promise tracking is disabled";
1217         return;
1218     }
1219     ScriptValue value = promiseTracker().promiseById(promiseId);
1220     if (value.isEmpty()) {
1221         *errorString = "Promise with specified ID not found.";
1222         return;
1223     }
1224     InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(value.scriptState());
1225     promise = injectedScript.wrapObject(value, objectGroup ? *objectGroup : "");
1226 }
1227 
scriptExecutionBlockedByCSP(const String & directiveText)1228 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText)
1229 {
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());
1234     }
1235 }
1236 
currentCallFrames()1237 PassRefPtr<Array<CallFrame> > InspectorDebuggerAgent::currentCallFrames()
1238 {
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();
1245     }
1246     return injectedScript.wrapCallFrames(m_currentCallStack, 0);
1247 }
1248 
currentAsyncStackTrace()1249 PassRefPtr<StackTrace> InspectorDebuggerAgent::currentAsyncStackTrace()
1250 {
1251     if (!m_pausedScriptState || !asyncCallStackTracker().isEnabled())
1252         return nullptr;
1253     const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker().currentAsyncCallChain();
1254     if (!chain)
1255         return nullptr;
1256     const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callStacks();
1257     if (callStacks.isEmpty())
1258         return nullptr;
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()) {
1266             result.clear();
1267             continue;
1268         }
1269         RefPtr<StackTrace> next = StackTrace::create()
1270             .setCallFrames(injectedScript.wrapCallFrames(callFrames, asyncOrdinal))
1271             .release();
1272         next->setDescription((*it)->description());
1273         if (result)
1274             next->setAsyncStackTrace(result.release());
1275         result.swap(next);
1276     }
1277     return result.release();
1278 }
1279 
toScriptCallStack(JavaScriptCallFrame * callFrame)1280 static PassRefPtrWillBeRawPtr<ScriptCallStack> toScriptCallStack(JavaScriptCallFrame* callFrame)
1281 {
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));
1291     }
1292     return ScriptCallStack::create(frames);
1293 }
1294 
currentAsyncStackTraceForConsole()1295 PassRefPtrWillBeRawPtr<ScriptAsyncCallStack> InspectorDebuggerAgent::currentAsyncStackTraceForConsole()
1296 {
1297     if (!asyncCallStackTracker().isEnabled())
1298         return nullptr;
1299     const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker().currentAsyncCallChain();
1300     if (!chain)
1301         return nullptr;
1302     const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callStacks();
1303     if (callStacks.isEmpty())
1304         return nullptr;
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());
1308         if (!callFrame)
1309             break;
1310         result = ScriptAsyncCallStack::create((*it)->description(), toScriptCallStack(callFrame.get()), result.release());
1311     }
1312     return result.release();
1313 }
1314 
sourceMapURLForScript(const Script & script,CompileResult compileResult)1315 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script, CompileResult compileResult)
1316 {
1317     bool hasSyntaxError = compileResult != CompileSuccess;
1318     if (hasSyntaxError) {
1319         bool deprecated;
1320         String sourceMapURL = ContentSearchUtils::findSourceMapURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated);
1321         if (!sourceMapURL.isEmpty())
1322             return sourceMapURL;
1323     }
1324 
1325     if (!script.sourceMappingURL.isEmpty())
1326         return script.sourceMappingURL;
1327 
1328     if (script.url.isEmpty())
1329         return String();
1330 
1331     InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent();
1332     if (!pageAgent)
1333         return String();
1334     return pageAgent->resourceSourceMapURL(script.url);
1335 }
1336 
1337 // ScriptDebugListener functions
1338 
didParseSource(const String & scriptId,const Script & parsedScript,CompileResult compileResult)1339 void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& parsedScript, CompileResult compileResult)
1340 {
1341     Script script = parsedScript;
1342     const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0;
1343 
1344     bool hasSyntaxError = compileResult != CompileSuccess;
1345     if (hasSyntaxError) {
1346         bool deprecated;
1347         script.sourceURL = ContentSearchUtils::findSourceURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated);
1348     }
1349 
1350     bool hasSourceURL = !script.sourceURL.isEmpty();
1351     String scriptURL = hasSourceURL ? script.sourceURL : script.url;
1352 
1353     String sourceMapURL = sourceMapURLForScript(script, compileResult);
1354     String* sourceMapURLParam = sourceMapURL.isNull() ? 0 : &sourceMapURL;
1355 
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);
1359     else
1360         m_frontend->scriptFailedToParse(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam);
1361 
1362     m_scripts.set(scriptId, script);
1363 
1364     if (scriptURL.isEmpty() || hasSyntaxError)
1365         return;
1366 
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)
1373             continue;
1374         bool isRegex;
1375         breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
1376         String url;
1377         breakpointObject->getString(DebuggerAgentState::url, &url);
1378         if (!matches(scriptURL, url, isRegex))
1379             continue;
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);
1385         if (location)
1386             m_frontend->breakpointResolved(it->key, location);
1387     }
1388 }
1389 
didPause(ScriptState * scriptState,const ScriptValue & callFrames,const ScriptValue & exception,const Vector<String> & hitBreakpoints)1390 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& callFrames, const ScriptValue& exception, const Vector<String>& hitBreakpoints)
1391 {
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();
1405     else
1406         result = ScriptDebugListener::NoSkip;
1407 
1408     if (result != ScriptDebugListener::NoSkip)
1409         return result;
1410 
1411     ASSERT(scriptState && !m_pausedScriptState);
1412     m_pausedScriptState = scriptState;
1413     m_currentCallStack = callFrames;
1414 
1415     if (!exception.isEmpty()) {
1416         InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState);
1417         if (!injectedScript.isEmpty()) {
1418             m_breakReason = InspectorFrontend::Debugger::Reason::Exception;
1419             m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors();
1420             // m_breakAuxData might be null after this.
1421         }
1422     }
1423 
1424     RefPtr<Array<String> > hitBreakpointIds = Array<String>::create();
1425 
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);
1431 
1432             BreakpointSource source = breakpointIterator->value.second;
1433             if (m_breakReason == InspectorFrontend::Debugger::Reason::Other && source == DebugCommandBreakpointSource)
1434                 m_breakReason = InspectorFrontend::Debugger::Reason::DebugCommand;
1435         }
1436     }
1437 
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;
1444 
1445     if (!m_continueToLocationBreakpointId.isEmpty()) {
1446         scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId);
1447         m_continueToLocationBreakpointId = "";
1448     }
1449     if (m_listener)
1450         m_listener->didPause();
1451     return result;
1452 }
1453 
didContinue()1454 void InspectorDebuggerAgent::didContinue()
1455 {
1456     m_pausedScriptState = nullptr;
1457     m_currentCallStack = ScriptValue();
1458     clearBreakDetails();
1459     m_frontend->resumed();
1460 }
1461 
canBreakProgram()1462 bool InspectorDebuggerAgent::canBreakProgram()
1463 {
1464     return scriptDebugServer().canBreakProgram();
1465 }
1466 
breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason,PassRefPtr<JSONObject> data)1467 void InspectorDebuggerAgent::breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data)
1468 {
1469     if (m_skipAllPauses)
1470         return;
1471     m_breakReason = breakReason;
1472     m_breakAuxData = data;
1473     m_debuggerStepScheduled = false;
1474     m_steppingFromFramework = false;
1475     m_pausingOnNativeEvent = false;
1476     scriptDebugServer().breakProgram();
1477 }
1478 
clear()1479 void InspectorDebuggerAgent::clear()
1480 {
1481     m_pausedScriptState = nullptr;
1482     m_currentCallStack = ScriptValue();
1483     m_scripts.clear();
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;
1493     ErrorString error;
1494     setOverlayMessage(&error, 0);
1495 }
1496 
assertPaused(ErrorString * errorString)1497 bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString)
1498 {
1499     if (!m_pausedScriptState) {
1500         *errorString = "Can only perform operation while paused.";
1501         return false;
1502     }
1503     return true;
1504 }
1505 
clearBreakDetails()1506 void InspectorDebuggerAgent::clearBreakDetails()
1507 {
1508     m_breakReason = InspectorFrontend::Debugger::Reason::Other;
1509     m_breakAuxData = nullptr;
1510 }
1511 
setBreakpoint(const String & scriptId,int lineNumber,int columnNumber,BreakpointSource source,const String & condition)1512 void InspectorDebuggerAgent::setBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source, const String& condition)
1513 {
1514     String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumber, source);
1515     ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition);
1516     resolveBreakpoint(breakpointId, scriptId, breakpoint, source);
1517 }
1518 
removeBreakpoint(const String & scriptId,int lineNumber,int columnNumber,BreakpointSource source)1519 void InspectorDebuggerAgent::removeBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source)
1520 {
1521     removeBreakpoint(generateBreakpointId(scriptId, lineNumber, columnNumber, source));
1522 }
1523 
reset()1524 void InspectorDebuggerAgent::reset()
1525 {
1526     m_scripts.clear();
1527     m_breakpointIdToDebugServerBreakpointIds.clear();
1528     asyncCallStackTracker().clear();
1529     promiseTracker().clear();
1530     if (m_frontend)
1531         m_frontend->globalObjectCleared();
1532 }
1533 
trace(Visitor * visitor)1534 void InspectorDebuggerAgent::trace(Visitor* visitor)
1535 {
1536     visitor->trace(m_injectedScriptManager);
1537     visitor->trace(m_listener);
1538     visitor->trace(m_asyncCallStackTracker);
1539 #if ENABLE(OILPAN)
1540     visitor->trace(m_promiseTracker);
1541 #endif
1542     InspectorBaseAgent::trace(visitor);
1543 }
1544 
1545 } // namespace blink
1546