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