OLD | NEW |
---|---|
(Empty) | |
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/fetch/Resource.h" | |
39 #include "core/inspector/ConsoleMessage.h" | |
40 #include "core/inspector/ContentSearchUtils.h" | |
41 #include "core/inspector/InjectedScriptManager.h" | |
42 #include "core/inspector/InspectorState.h" | |
43 #include "core/inspector/JavaScriptCallFrame.h" | |
44 #include "core/inspector/ScriptArguments.h" | |
45 #include "core/inspector/ScriptAsyncCallStack.h" | |
46 #include "core/inspector/ScriptCallFrame.h" | |
47 #include "core/inspector/ScriptCallStack.h" | |
48 #include "platform/JSONValues.h" | |
49 #include "wtf/text/StringBuilder.h" | |
50 #include "wtf/text/WTFString.h" | |
51 | |
52 using blink::TypeBuilder::Array; | |
53 using blink::TypeBuilder::Debugger::BreakpointId; | |
54 using blink::TypeBuilder::Debugger::CallFrame; | |
55 using blink::TypeBuilder::Debugger::CollectionEntry; | |
56 using blink::TypeBuilder::Debugger::ExceptionDetails; | |
57 using blink::TypeBuilder::Debugger::FunctionDetails; | |
58 using blink::TypeBuilder::Debugger::ScriptId; | |
59 using blink::TypeBuilder::Debugger::StackTrace; | |
60 using blink::TypeBuilder::Runtime::RemoteObject; | |
61 | |
62 namespace { | |
63 | |
64 static const char v8AsyncTaskEventEnqueue[] = "enqueue"; | |
65 static const char v8AsyncTaskEventWillHandle[] = "willHandle"; | |
66 static const char v8AsyncTaskEventDidHandle[] = "didHandle"; | |
67 | |
68 } | |
69 | |
70 namespace blink { | |
71 | |
72 namespace DebuggerAgentState { | |
73 static const char debuggerEnabled[] = "debuggerEnabled"; | |
74 static const char javaScriptBreakpoints[] = "javaScriptBreakopints"; | |
75 static const char pauseOnExceptionsState[] = "pauseOnExceptionsState"; | |
76 static const char asyncCallStackDepth[] = "asyncCallStackDepth"; | |
77 | |
78 // Breakpoint properties. | |
79 static const char url[] = "url"; | |
80 static const char isRegex[] = "isRegex"; | |
81 static const char lineNumber[] = "lineNumber"; | |
82 static const char columnNumber[] = "columnNumber"; | |
83 static const char condition[] = "condition"; | |
84 static const char isAnti[] = "isAnti"; | |
85 static const char skipStackPattern[] = "skipStackPattern"; | |
86 static const char skipAllPauses[] = "skipAllPauses"; | |
87 static const char skipAllPausesExpiresOnReload[] = "skipAllPausesExpiresOnReload "; | |
88 | |
89 }; | |
90 | |
91 static const int maxSkipStepInCount = 20; | |
92 | |
93 const char InspectorDebuggerAgent::backtraceObjectGroup[] = "backtrace"; | |
94 | |
95 static String breakpointIdSuffix(InspectorDebuggerAgent::BreakpointSource source ) | |
96 { | |
97 switch (source) { | |
98 case InspectorDebuggerAgent::UserBreakpointSource: | |
99 break; | |
100 case InspectorDebuggerAgent::DebugCommandBreakpointSource: | |
101 return ":debug"; | |
102 case InspectorDebuggerAgent::MonitorCommandBreakpointSource: | |
103 return ":monitor"; | |
104 } | |
105 return String(); | |
106 } | |
107 | |
108 static String generateBreakpointId(const String& scriptId, int lineNumber, int c olumnNumber, InspectorDebuggerAgent::BreakpointSource source) | |
109 { | |
110 return scriptId + ':' + String::number(lineNumber) + ':' + String::number(co lumnNumber) + breakpointIdSuffix(source); | |
111 } | |
112 | |
113 InspectorDebuggerAgent::InspectorDebuggerAgent(InjectedScriptManager* injectedSc riptManager) | |
114 : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger") | |
115 , m_injectedScriptManager(injectedScriptManager) | |
116 , m_frontend(0) | |
117 , m_pausedScriptState(nullptr) | |
118 , m_javaScriptPauseScheduled(false) | |
119 , m_debuggerStepScheduled(false) | |
120 , m_steppingFromFramework(false) | |
121 , m_pausingOnNativeEvent(false) | |
122 , m_listener(nullptr) | |
123 , m_skippedStepInCount(0) | |
124 , m_skipAllPauses(false) | |
125 , m_asyncCallStackTracker(adoptPtr(new AsyncCallStackTracker())) | |
126 { | |
127 } | |
128 | |
129 InspectorDebuggerAgent::~InspectorDebuggerAgent() | |
130 { | |
131 } | |
132 | |
133 void InspectorDebuggerAgent::virtualInit() | |
134 { | |
135 // FIXME: make breakReason optional so that there was no need to init it wit h "other". | |
136 clearBreakDetails(); | |
137 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServ er::DontPauseOnExceptions); | |
138 } | |
139 | |
140 void InspectorDebuggerAgent::enable() | |
141 { | |
142 startListeningScriptDebugServer(); | |
143 // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends | |
144 scriptDebugServer().setBreakpointsActivated(true); | |
145 | |
146 if (m_listener) | |
147 m_listener->debuggerWasEnabled(); | |
148 } | |
149 | |
150 void InspectorDebuggerAgent::disable() | |
151 { | |
152 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, JSONObject::cr eate()); | |
153 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServ er::DontPauseOnExceptions); | |
154 m_state->setString(DebuggerAgentState::skipStackPattern, ""); | |
155 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, 0); | |
156 | |
157 scriptDebugServer().clearBreakpoints(); | |
158 scriptDebugServer().clearCompiledScripts(); | |
159 scriptDebugServer().clearPreprocessor(); | |
160 stopListeningScriptDebugServer(); | |
161 clear(); | |
162 | |
163 if (m_listener) | |
164 m_listener->debuggerWasDisabled(); | |
165 | |
166 m_skipAllPauses = false; | |
167 } | |
168 | |
169 bool InspectorDebuggerAgent::enabled() | |
170 { | |
171 return m_state->getBoolean(DebuggerAgentState::debuggerEnabled); | |
172 } | |
173 | |
174 void InspectorDebuggerAgent::enable(ErrorString*) | |
175 { | |
176 if (enabled()) | |
177 return; | |
178 | |
179 enable(); | |
180 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); | |
181 | |
182 ASSERT(m_frontend); | |
183 } | |
184 | |
185 void InspectorDebuggerAgent::disable(ErrorString*) | |
186 { | |
187 if (!enabled()) | |
188 return; | |
189 | |
190 disable(); | |
191 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); | |
192 } | |
193 | |
194 static PassOwnPtr<ScriptRegexp> compileSkipCallFramePattern(String patternText) | |
195 { | |
196 if (patternText.isEmpty()) | |
197 return nullptr; | |
198 OwnPtr<ScriptRegexp> result = adoptPtr(new ScriptRegexp(patternText, TextCas eSensitive)); | |
199 if (!result->isValid()) | |
200 result.clear(); | |
201 return result.release(); | |
202 } | |
203 | |
204 void InspectorDebuggerAgent::restore() | |
205 { | |
206 if (enabled()) { | |
207 m_frontend->globalObjectCleared(); | |
208 enable(); | |
209 long pauseState = m_state->getLong(DebuggerAgentState::pauseOnExceptions State); | |
210 String error; | |
211 setPauseOnExceptionsImpl(&error, pauseState); | |
212 m_cachedSkipStackRegExp = compileSkipCallFramePattern(m_state->getString (DebuggerAgentState::skipStackPattern)); | |
213 m_skipAllPauses = m_state->getBoolean(DebuggerAgentState::skipAllPauses) ; | |
214 if (m_skipAllPauses && m_state->getBoolean(DebuggerAgentState::skipAllPa usesExpiresOnReload)) { | |
215 m_skipAllPauses = false; | |
216 m_state->setBoolean(DebuggerAgentState::skipAllPauses, false); | |
217 } | |
218 asyncCallStackTracker().setAsyncCallStackDepth(m_state->getLong(Debugger AgentState::asyncCallStackDepth)); | |
219 } | |
220 } | |
221 | |
222 void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend) | |
223 { | |
224 m_frontend = frontend->debugger(); | |
225 } | |
226 | |
227 void InspectorDebuggerAgent::clearFrontend() | |
228 { | |
229 m_frontend = 0; | |
230 | |
231 if (!enabled()) | |
232 return; | |
233 | |
234 disable(); | |
235 | |
236 // FIXME: due to m_state->mute() hack in InspectorController, debuggerEnable d is actually set to false only | |
237 // in InspectorState, but not in cookie. That's why after navigation debugge rEnabled will be true, | |
238 // but after front-end re-open it will still be false. | |
239 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); | |
240 } | |
241 | |
242 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active) | |
243 { | |
244 scriptDebugServer().setBreakpointsActivated(active); | |
245 } | |
246 | |
247 void InspectorDebuggerAgent::setSkipAllPauses(ErrorString*, bool skipped, const bool* untilReload) | |
248 { | |
249 m_skipAllPauses = skipped; | |
250 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses); | |
251 m_state->setBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload, asBool (untilReload)); | |
252 } | |
253 | |
254 void InspectorDebuggerAgent::pageDidCommitLoad() | |
255 { | |
256 if (m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) { | |
257 m_skipAllPauses = false; | |
258 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses); | |
259 } | |
260 } | |
261 | |
262 bool InspectorDebuggerAgent::isPaused() | |
263 { | |
264 return scriptDebugServer().isPaused(); | |
265 } | |
266 | |
267 bool InspectorDebuggerAgent::runningNestedMessageLoop() | |
268 { | |
269 return scriptDebugServer().runningNestedMessageLoop(); | |
270 } | |
271 | |
272 void InspectorDebuggerAgent::addMessageToConsole(ConsoleMessage* consoleMessage) | |
273 { | |
274 if (consoleMessage->type() == AssertMessageType && scriptDebugServer().pause OnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) | |
275 breakProgram(InspectorFrontend::Debugger::Reason::Assert, nullptr); | |
276 } | |
277 | |
278 String InspectorDebuggerAgent::preprocessEventListener(LocalFrame* frame, const String& source, const String& url, const String& functionName) | |
279 { | |
280 return scriptDebugServer().preprocessEventListener(frame, source, url, funct ionName); | |
281 } | |
282 | |
283 PassOwnPtr<ScriptSourceCode> InspectorDebuggerAgent::preprocess(LocalFrame* fram e, const ScriptSourceCode& sourceCode) | |
284 { | |
285 return scriptDebugServer().preprocess(frame, sourceCode); | |
286 } | |
287 | |
288 static PassRefPtr<JSONObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex, bool is Anti) | |
289 { | |
290 RefPtr<JSONObject> breakpointObject = JSONObject::create(); | |
291 breakpointObject->setString(DebuggerAgentState::url, url); | |
292 breakpointObject->setNumber(DebuggerAgentState::lineNumber, lineNumber); | |
293 breakpointObject->setNumber(DebuggerAgentState::columnNumber, columnNumber); | |
294 breakpointObject->setString(DebuggerAgentState::condition, condition); | |
295 breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex); | |
296 breakpointObject->setBoolean(DebuggerAgentState::isAnti, isAnti); | |
297 return breakpointObject; | |
298 } | |
299 | |
300 static String scriptSourceURL(const ScriptDebugListener::Script& script) | |
301 { | |
302 bool hasSourceURL = !script.sourceURL.isEmpty(); | |
303 return hasSourceURL ? script.sourceURL : script.url; | |
304 } | |
305 | |
306 static bool matches(const String& url, const String& pattern, bool isRegex) | |
307 { | |
308 if (isRegex) { | |
309 ScriptRegexp regex(pattern, TextCaseSensitive); | |
310 return regex.match(url) != -1; | |
311 } | |
312 return url == pattern; | |
313 } | |
314 | |
315 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int li neNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const String* const optionalCondition, c onst bool* isAntiBreakpoint, BreakpointId* outBreakpointId, RefPtr<Array<TypeBui lder::Debugger::Location> >& locations) | |
316 { | |
317 locations = Array<TypeBuilder::Debugger::Location>::create(); | |
318 if (!optionalURL == !optionalURLRegex) { | |
319 *errorString = "Either url or urlRegex must be specified."; | |
320 return; | |
321 } | |
322 | |
323 bool isAntiBreakpointValue = asBool(isAntiBreakpoint); | |
324 | |
325 String url = optionalURL ? *optionalURL : *optionalURLRegex; | |
326 int columnNumber; | |
327 if (optionalColumnNumber) { | |
328 columnNumber = *optionalColumnNumber; | |
329 if (columnNumber < 0) { | |
330 *errorString = "Incorrect column number"; | |
331 return; | |
332 } | |
333 } else { | |
334 columnNumber = isAntiBreakpointValue ? -1 : 0; | |
335 } | |
336 String condition = optionalCondition ? *optionalCondition : ""; | |
337 bool isRegex = optionalURLRegex; | |
338 | |
339 String breakpointId = (isRegex ? "/" + url + "/" : url) + ':' + String::numb er(lineNumber) + ':' + String::number(columnNumber); | |
340 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState ::javaScriptBreakpoints); | |
341 if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) { | |
342 *errorString = "Breakpoint at specified location already exists."; | |
343 return; | |
344 } | |
345 | |
346 breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(ur l, lineNumber, columnNumber, condition, isRegex, isAntiBreakpointValue)); | |
347 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCoo kie); | |
348 | |
349 if (!isAntiBreakpointValue) { | |
350 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); | |
351 for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) { | |
352 if (!matches(scriptSourceURL(it->value), url, isRegex)) | |
353 continue; | |
354 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint (breakpointId, it->key, breakpoint, UserBreakpointSource); | |
355 if (location) | |
356 locations->addItem(location); | |
357 } | |
358 } | |
359 *outBreakpointId = breakpointId; | |
360 } | |
361 | |
362 static bool parseLocation(ErrorString* errorString, PassRefPtr<JSONObject> locat ion, String* scriptId, int* lineNumber, int* columnNumber) | |
363 { | |
364 if (!location->getString("scriptId", scriptId) || !location->getNumber("line Number", lineNumber)) { | |
365 // FIXME: replace with input validation. | |
366 *errorString = "scriptId and lineNumber are required."; | |
367 return false; | |
368 } | |
369 *columnNumber = 0; | |
370 location->getNumber("columnNumber", columnNumber); | |
371 return true; | |
372 } | |
373 | |
374 void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPt r<JSONObject>& location, const String* const optionalCondition, BreakpointId* ou tBreakpointId, RefPtr<TypeBuilder::Debugger::Location>& actualLocation) | |
375 { | |
376 String scriptId; | |
377 int lineNumber; | |
378 int columnNumber; | |
379 | |
380 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNum ber)) | |
381 return; | |
382 | |
383 String condition = optionalCondition ? *optionalCondition : emptyString(); | |
384 | |
385 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumbe r, UserBreakpointSource); | |
386 if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpo intIdToDebugServerBreakpointIds.end()) { | |
387 *errorString = "Breakpoint at specified location already exists."; | |
388 return; | |
389 } | |
390 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); | |
391 actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, UserB reakpointSource); | |
392 if (actualLocation) | |
393 *outBreakpointId = breakpointId; | |
394 else | |
395 *errorString = "Could not resolve breakpoint"; | |
396 } | |
397 | |
398 void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakp ointId) | |
399 { | |
400 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState ::javaScriptBreakpoints); | |
401 JSONObject::iterator it = breakpointsCookie->find(breakpointId); | |
402 bool isAntibreakpoint = false; | |
403 if (it != breakpointsCookie->end()) { | |
404 RefPtr<JSONObject> breakpointObject = it->value->asObject(); | |
405 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoi nt); | |
406 breakpointsCookie->remove(breakpointId); | |
407 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpoint sCookie); | |
408 } | |
409 | |
410 if (!isAntibreakpoint) | |
411 removeBreakpoint(breakpointId); | |
412 } | |
413 | |
414 void InspectorDebuggerAgent::removeBreakpoint(const String& breakpointId) | |
415 { | |
416 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIds Iterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId); | |
417 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpoin tIds.end()) | |
418 return; | |
419 for (size_t i = 0; i < debugServerBreakpointIdsIterator->value.size(); ++i) { | |
420 const String& debugServerBreakpointId = debugServerBreakpointIdsIterator ->value[i]; | |
421 scriptDebugServer().removeBreakpoint(debugServerBreakpointId); | |
422 m_serverBreakpoints.remove(debugServerBreakpointId); | |
423 } | |
424 m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIter ator); | |
425 } | |
426 | |
427 void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const RefPtr<JSONObject>& location, const bool* interstateLocationOpt) | |
428 { | |
429 if (!m_continueToLocationBreakpointId.isEmpty()) { | |
430 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId); | |
431 m_continueToLocationBreakpointId = ""; | |
432 } | |
433 | |
434 String scriptId; | |
435 int lineNumber; | |
436 int columnNumber; | |
437 | |
438 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNum ber)) | |
439 return; | |
440 | |
441 ScriptBreakpoint breakpoint(lineNumber, columnNumber, ""); | |
442 m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptI d, breakpoint, &lineNumber, &columnNumber, asBool(interstateLocationOpt)); | |
443 resume(errorString); | |
444 } | |
445 | |
446 void InspectorDebuggerAgent::getStepInPositions(ErrorString* errorString, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::Location> >& positions) | |
447 { | |
448 if (!isPaused() || m_currentCallStack.isEmpty()) { | |
449 *errorString = "Attempt to access callframe when debugger is not on paus e"; | |
450 return; | |
451 } | |
452 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForOb jectId(callFrameId); | |
453 if (injectedScript.isEmpty()) { | |
454 *errorString = "Inspected frame has gone"; | |
455 return; | |
456 } | |
457 | |
458 injectedScript.getStepInPositions(errorString, m_currentCallStack, callFrame Id, positions); | |
459 } | |
460 | |
461 void InspectorDebuggerAgent::getBacktrace(ErrorString* errorString, RefPtr<Array <CallFrame> >& callFrames, RefPtr<StackTrace>& asyncStackTrace) | |
462 { | |
463 if (!assertPaused(errorString)) | |
464 return; | |
465 m_currentCallStack = scriptDebugServer().currentCallFrames(); | |
466 callFrames = currentCallFrames(); | |
467 asyncStackTrace = currentAsyncStackTrace(); | |
468 } | |
469 | |
470 PassRefPtr<JavaScriptCallFrame> InspectorDebuggerAgent::topCallFrameSkipUnknownS ources() | |
471 { | |
472 for (int index = 0; ; ++index) { | |
473 RefPtr<JavaScriptCallFrame> frame = scriptDebugServer().callFrameNoScope s(index); | |
474 if (!frame) | |
475 return nullptr; | |
476 String scriptIdString = String::number(frame->sourceID()); | |
477 if (m_scripts.contains(scriptIdString)) | |
478 return frame.release(); | |
479 } | |
480 } | |
481 | |
482 String InspectorDebuggerAgent::scriptURL(JavaScriptCallFrame* frame) | |
483 { | |
484 String scriptIdString = String::number(frame->sourceID()); | |
485 ScriptsMap::iterator it = m_scripts.find(scriptIdString); | |
486 if (it == m_scripts.end()) | |
487 return String(); | |
488 return scriptSourceURL(it->value); | |
489 } | |
490 | |
491 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipExceptio nPause() | |
492 { | |
493 if (m_steppingFromFramework) | |
494 return ScriptDebugListener::NoSkip; | |
495 | |
496 // FIXME: Fast return: if (!m_cachedSkipStackRegExp && !has_any_anti_breakpo int) return ScriptDebugListener::NoSkip; | |
497 | |
498 RefPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(); | |
499 if (!topFrame) | |
500 return ScriptDebugListener::NoSkip; | |
501 | |
502 String topFrameScriptUrl = scriptURL(topFrame.get()); | |
503 if (m_cachedSkipStackRegExp && !topFrameScriptUrl.isEmpty() && m_cachedSkipS tackRegExp->match(topFrameScriptUrl) != -1) | |
504 return ScriptDebugListener::Continue; | |
505 | |
506 // Match against breakpoints. | |
507 if (topFrameScriptUrl.isEmpty()) | |
508 return ScriptDebugListener::NoSkip; | |
509 | |
510 // Prepare top frame parameters. | |
511 int topFrameLineNumber = topFrame->line(); | |
512 int topFrameColumnNumber = topFrame->column(); | |
513 | |
514 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState ::javaScriptBreakpoints); | |
515 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpoints Cookie->end(); ++it) { | |
516 RefPtr<JSONObject> breakpointObject = it->value->asObject(); | |
517 bool isAntibreakpoint; | |
518 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoi nt); | |
519 if (!isAntibreakpoint) | |
520 continue; | |
521 | |
522 int breakLineNumber; | |
523 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakLineNu mber); | |
524 int breakColumnNumber; | |
525 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakColu mnNumber); | |
526 | |
527 if (breakLineNumber != topFrameLineNumber) | |
528 continue; | |
529 | |
530 if (breakColumnNumber != -1 && breakColumnNumber != topFrameColumnNumber ) | |
531 continue; | |
532 | |
533 bool isRegex; | |
534 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); | |
535 String url; | |
536 breakpointObject->getString(DebuggerAgentState::url, &url); | |
537 if (!matches(topFrameScriptUrl, url, isRegex)) | |
538 continue; | |
539 | |
540 return ScriptDebugListener::Continue; | |
541 } | |
542 | |
543 return ScriptDebugListener::NoSkip; | |
544 } | |
545 | |
546 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipStepPaus e() | |
547 { | |
548 if (!m_cachedSkipStackRegExp || m_steppingFromFramework) | |
549 return ScriptDebugListener::NoSkip; | |
550 | |
551 RefPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(); | |
552 String scriptUrl = scriptURL(topFrame.get()); | |
553 if (scriptUrl.isEmpty() || m_cachedSkipStackRegExp->match(scriptUrl) == -1) | |
554 return ScriptDebugListener::NoSkip; | |
555 | |
556 if (m_skippedStepInCount == 0) { | |
557 m_minFrameCountForSkip = scriptDebugServer().frameCount(); | |
558 m_skippedStepInCount = 1; | |
559 return ScriptDebugListener::StepInto; | |
560 } | |
561 | |
562 if (m_skippedStepInCount < maxSkipStepInCount && topFrame->isAtReturn() && s criptDebugServer().frameCount() <= m_minFrameCountForSkip) | |
563 m_skippedStepInCount = maxSkipStepInCount; | |
564 | |
565 if (m_skippedStepInCount >= maxSkipStepInCount) { | |
566 if (m_pausingOnNativeEvent) { | |
567 m_pausingOnNativeEvent = false; | |
568 m_skippedStepInCount = 0; | |
569 return ScriptDebugListener::Continue; | |
570 } | |
571 return ScriptDebugListener::StepOut; | |
572 } | |
573 | |
574 ++m_skippedStepInCount; | |
575 return ScriptDebugListener::StepInto; | |
576 } | |
577 | |
578 bool InspectorDebuggerAgent::isTopCallFrameInFramework() | |
579 { | |
580 if (!m_cachedSkipStackRegExp) | |
581 return false; | |
582 | |
583 RefPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(); | |
584 if (!topFrame) | |
585 return false; | |
586 | |
587 String scriptUrl = scriptURL(topFrame.get()); | |
588 return !scriptUrl.isEmpty() && m_cachedSkipStackRegExp->match(scriptUrl) != -1; | |
589 } | |
590 | |
591 PassRefPtr<TypeBuilder::Debugger::Location> InspectorDebuggerAgent::resolveBreak point(const String& breakpointId, const String& scriptId, const ScriptBreakpoint & breakpoint, BreakpointSource source) | |
592 { | |
593 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); | |
594 if (scriptIterator == m_scripts.end()) | |
595 return nullptr; | |
596 Script& script = scriptIterator->value; | |
597 if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint. lineNumber) | |
598 return nullptr; | |
599 | |
600 int actualLineNumber; | |
601 int actualColumnNumber; | |
602 String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false); | |
603 if (debugServerBreakpointId.isEmpty()) | |
604 return nullptr; | |
605 | |
606 m_serverBreakpoints.set(debugServerBreakpointId, std::make_pair(breakpointId , source)); | |
607 | |
608 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIds Iterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId); | |
609 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpoin tIds.end()) | |
610 m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String >()).storedValue->value.append(debugServerBreakpointId); | |
611 else | |
612 debugServerBreakpointIdsIterator->value.append(debugServerBreakpointId); | |
613 | |
614 RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Lo cation::create() | |
615 .setScriptId(scriptId) | |
616 .setLineNumber(actualLineNumber); | |
617 location->setColumnNumber(actualColumnNumber); | |
618 return location; | |
619 } | |
620 | |
621 void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& s criptId, const String& query, const bool* const optionalCaseSensitive, const boo l* const optionalIsRegex, RefPtr<Array<blink::TypeBuilder::Page::SearchMatch> >& results) | |
622 { | |
623 ScriptsMap::iterator it = m_scripts.find(scriptId); | |
624 if (it != m_scripts.end()) | |
625 results = ContentSearchUtils::searchInTextByLines(it->value.source, quer y, asBool(optionalCaseSensitive), asBool(optionalIsRegex)); | |
626 else | |
627 *error = "No script for id: " + scriptId; | |
628 } | |
629 | |
630 void InspectorDebuggerAgent::setScriptSource(ErrorString* error, RefPtr<TypeBuil der::Debugger::SetScriptSourceError>& errorData, const String& scriptId, const S tring& newContent, const bool* const preview, RefPtr<Array<CallFrame> >& newCall Frames, RefPtr<JSONObject>& result, RefPtr<StackTrace>& asyncStackTrace) | |
631 { | |
632 if (!scriptDebugServer().setScriptSource(scriptId, newContent, asBool(previe w), error, errorData, &m_currentCallStack, &result)) | |
633 return; | |
634 | |
635 newCallFrames = currentCallFrames(); | |
636 asyncStackTrace = currentAsyncStackTrace(); | |
637 // FIXME(sky): Used to tell the page agent. | |
638 } | |
639 | |
640 void InspectorDebuggerAgent::restartFrame(ErrorString* errorString, const String & callFrameId, RefPtr<Array<CallFrame> >& newCallFrames, RefPtr<JSONObject>& res ult, RefPtr<StackTrace>& asyncStackTrace) | |
641 { | |
642 if (!isPaused() || m_currentCallStack.isEmpty()) { | |
643 *errorString = "Attempt to access callframe when debugger is not on paus e"; | |
644 return; | |
645 } | |
646 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForOb jectId(callFrameId); | |
647 if (injectedScript.isEmpty()) { | |
648 *errorString = "Inspected frame has gone"; | |
649 return; | |
650 } | |
651 | |
652 injectedScript.restartFrame(errorString, m_currentCallStack, callFrameId, &r esult); | |
653 m_currentCallStack = scriptDebugServer().currentCallFrames(); | |
654 newCallFrames = currentCallFrames(); | |
655 asyncStackTrace = currentAsyncStackTrace(); | |
656 } | |
657 | |
658 void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& s criptId, String* scriptSource) | |
659 { | |
660 ScriptsMap::iterator it = m_scripts.find(scriptId); | |
661 if (it == m_scripts.end()) { | |
662 *error = "No script for id: " + scriptId; | |
663 return; | |
664 } | |
665 | |
666 String url = it->value.url; | |
667 // FIXME(sky): Fetch the script from the page agent? | |
668 *scriptSource = it->value.source; | |
669 } | |
670 | |
671 void InspectorDebuggerAgent::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>& details) | |
672 { | |
673 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForOb jectId(functionId); | |
674 if (injectedScript.isEmpty()) { | |
675 *errorString = "Function object id is obsolete"; | |
676 return; | |
677 } | |
678 injectedScript.getFunctionDetails(errorString, functionId, &details); | |
679 } | |
680 | |
681 void InspectorDebuggerAgent::getCollectionEntries(ErrorString* errorString, cons t String& objectId, RefPtr<TypeBuilder::Array<CollectionEntry> >& entries) | |
682 { | |
683 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForOb jectId(objectId); | |
684 if (injectedScript.isEmpty()) { | |
685 *errorString = "Inspected frame has gone"; | |
686 return; | |
687 } | |
688 injectedScript.getCollectionEntries(errorString, objectId, &entries); | |
689 } | |
690 | |
691 void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorFrontend::Deb ugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data) | |
692 { | |
693 if (m_javaScriptPauseScheduled || isPaused()) | |
694 return; | |
695 m_breakReason = breakReason; | |
696 m_breakAuxData = data; | |
697 m_pausingOnNativeEvent = true; | |
698 scriptDebugServer().setPauseOnNextStatement(true); | |
699 } | |
700 | |
701 void InspectorDebuggerAgent::cancelPauseOnNextStatement() | |
702 { | |
703 if (m_javaScriptPauseScheduled || isPaused()) | |
704 return; | |
705 clearBreakDetails(); | |
706 m_pausingOnNativeEvent = false; | |
707 scriptDebugServer().setPauseOnNextStatement(false); | |
708 } | |
709 | |
710 void InspectorDebuggerAgent::didInstallTimer(ExecutionContext* context, int time rId, int timeout, bool singleShot) | |
711 { | |
712 if (asyncCallStackTracker().isEnabled()) | |
713 asyncCallStackTracker().didInstallTimer(context, timerId, singleShot, sc riptDebugServer().currentCallFramesForAsyncStack()); | |
714 } | |
715 | |
716 void InspectorDebuggerAgent::didRemoveTimer(ExecutionContext* context, int timer Id) | |
717 { | |
718 if (asyncCallStackTracker().isEnabled()) | |
719 asyncCallStackTracker().didRemoveTimer(context, timerId); | |
720 } | |
721 | |
722 bool InspectorDebuggerAgent::willFireTimer(ExecutionContext* context, int timerI d) | |
723 { | |
724 if (asyncCallStackTracker().isEnabled()) | |
725 asyncCallStackTracker().willFireTimer(context, timerId); | |
726 return true; | |
727 } | |
728 | |
729 void InspectorDebuggerAgent::didFireTimer() | |
730 { | |
731 if (asyncCallStackTracker().isEnabled()) | |
732 asyncCallStackTracker().didFireAsyncCall(); | |
733 cancelPauseOnNextStatement(); | |
734 } | |
735 | |
736 void InspectorDebuggerAgent::didRequestAnimationFrame(Document* document, int ca llbackId) | |
737 { | |
738 if (asyncCallStackTracker().isEnabled()) | |
739 asyncCallStackTracker().didRequestAnimationFrame(document, callbackId, s criptDebugServer().currentCallFramesForAsyncStack()); | |
740 } | |
741 | |
742 void InspectorDebuggerAgent::didCancelAnimationFrame(Document* document, int cal lbackId) | |
743 { | |
744 if (asyncCallStackTracker().isEnabled()) | |
745 asyncCallStackTracker().didCancelAnimationFrame(document, callbackId); | |
746 } | |
747 | |
748 bool InspectorDebuggerAgent::willFireAnimationFrame(Document* document, int call backId) | |
749 { | |
750 if (asyncCallStackTracker().isEnabled()) | |
751 asyncCallStackTracker().willFireAnimationFrame(document, callbackId); | |
752 return true; | |
753 } | |
754 | |
755 void InspectorDebuggerAgent::didFireAnimationFrame() | |
756 { | |
757 if (asyncCallStackTracker().isEnabled()) | |
758 asyncCallStackTracker().didFireAsyncCall(); | |
759 } | |
760 | |
761 void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* ev ent) | |
762 { | |
763 if (asyncCallStackTracker().isEnabled()) | |
764 asyncCallStackTracker().didEnqueueEvent(eventTarget, event, scriptDebugS erver().currentCallFramesForAsyncStack()); | |
765 } | |
766 | |
767 void InspectorDebuggerAgent::didRemoveEvent(EventTarget* eventTarget, Event* eve nt) | |
768 { | |
769 if (asyncCallStackTracker().isEnabled()) | |
770 asyncCallStackTracker().didRemoveEvent(eventTarget, event); | |
771 } | |
772 | |
773 void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* ev ent, EventListener* listener, bool useCapture) | |
774 { | |
775 if (asyncCallStackTracker().isEnabled()) | |
776 asyncCallStackTracker().willHandleEvent(eventTarget, event, listener, us eCapture); | |
777 } | |
778 | |
779 void InspectorDebuggerAgent::didHandleEvent() | |
780 { | |
781 if (asyncCallStackTracker().isEnabled()) | |
782 asyncCallStackTracker().didFireAsyncCall(); | |
783 cancelPauseOnNextStatement(); | |
784 } | |
785 | |
786 void InspectorDebuggerAgent::didEnqueueMutationRecord(ExecutionContext* context, MutationObserver* observer) | |
787 { | |
788 if (asyncCallStackTracker().isEnabled() && !asyncCallStackTracker().hasEnque uedMutationRecord(context, observer)) | |
789 asyncCallStackTracker().didEnqueueMutationRecord(context, observer, scri ptDebugServer().currentCallFramesForAsyncStack()); | |
790 } | |
791 | |
792 void InspectorDebuggerAgent::didClearAllMutationRecords(ExecutionContext* contex t, MutationObserver* observer) | |
793 { | |
794 if (asyncCallStackTracker().isEnabled()) | |
795 asyncCallStackTracker().didClearAllMutationRecords(context, observer); | |
796 } | |
797 | |
798 void InspectorDebuggerAgent::willDeliverMutationRecords(ExecutionContext* contex t, MutationObserver* observer) | |
799 { | |
800 if (asyncCallStackTracker().isEnabled()) | |
801 asyncCallStackTracker().willDeliverMutationRecords(context, observer); | |
802 } | |
803 | |
804 void InspectorDebuggerAgent::didDeliverMutationRecords() | |
805 { | |
806 if (asyncCallStackTracker().isEnabled()) | |
807 asyncCallStackTracker().didFireAsyncCall(); | |
808 } | |
809 | |
810 // void InspectorDebuggerAgent::didPostExecutionContextTask(ExecutionContext* co ntext, ExecutionContextTask* task) | |
811 // { | |
812 // if (asyncCallStackTracker().isEnabled() && !task->taskNameForInstrumentat ion().isEmpty()) | |
813 // asyncCallStackTracker().didPostExecutionContextTask(context, task, sc riptDebugServer().currentCallFramesForAsyncStack()); | |
814 // } | |
815 | |
816 // void InspectorDebuggerAgent::didKillAllExecutionContextTasks(ExecutionContext * context) | |
817 // { | |
818 // if (asyncCallStackTracker().isEnabled()) | |
819 // asyncCallStackTracker().didKillAllExecutionContextTasks(context); | |
820 // } | |
821 | |
822 // void InspectorDebuggerAgent::willPerformExecutionContextTask(ExecutionContext * context, ExecutionContextTask* task) | |
823 // { | |
824 // if (asyncCallStackTracker().isEnabled()) | |
825 // asyncCallStackTracker().willPerformExecutionContextTask(context, task ); | |
826 // } | |
827 | |
828 // void InspectorDebuggerAgent::didPerformExecutionContextTask() | |
829 // { | |
830 // if (asyncCallStackTracker().isEnabled()) | |
831 // asyncCallStackTracker().didFireAsyncCall(); | |
832 // } | |
833 | |
834 int InspectorDebuggerAgent::traceAsyncOperationStarting(ExecutionContext* contex t, const String& operationName, int prevOperationId) | |
835 { | |
836 if (!asyncCallStackTracker().isEnabled()) | |
837 return 0; | |
838 if (prevOperationId) | |
839 asyncCallStackTracker().traceAsyncOperationCompleted(context, prevOperat ionId); | |
840 return asyncCallStackTracker().traceAsyncOperationStarting(context, operatio nName, scriptDebugServer().currentCallFramesForAsyncStack()); | |
841 } | |
842 | |
843 void InspectorDebuggerAgent::traceAsyncOperationCompleted(ExecutionContext* cont ext, int operationId) | |
844 { | |
845 if (asyncCallStackTracker().isEnabled()) | |
846 asyncCallStackTracker().traceAsyncOperationCompleted(context, operationI d); | |
847 } | |
848 | |
849 void InspectorDebuggerAgent::traceAsyncOperationCompletedCallbackStarting(Execut ionContext* context, int operationId) | |
850 { | |
851 if (!asyncCallStackTracker().isEnabled()) | |
852 return; | |
853 asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId); | |
854 asyncCallStackTracker().traceAsyncOperationCompleted(context, operationId); | |
855 } | |
856 | |
857 void InspectorDebuggerAgent::traceAsyncCallbackStarting(ExecutionContext* contex t, int operationId) | |
858 { | |
859 if (asyncCallStackTracker().isEnabled()) | |
860 asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId) ; | |
861 } | |
862 | |
863 void InspectorDebuggerAgent::traceAsyncCallbackCompleted() | |
864 { | |
865 if (asyncCallStackTracker().isEnabled()) | |
866 asyncCallStackTracker().didFireAsyncCall(); | |
867 } | |
868 | |
869 void InspectorDebuggerAgent::didReceiveV8AsyncTaskEvent(ExecutionContext* contex t, const String& eventType, const String& eventName, int id) | |
870 { | |
871 if (!asyncCallStackTracker().isEnabled()) | |
872 return; | |
873 if (eventType == v8AsyncTaskEventEnqueue) | |
874 asyncCallStackTracker().didEnqueueV8AsyncTask(context, eventName, id, sc riptDebugServer().currentCallFramesForAsyncStack()); | |
875 else if (eventType == v8AsyncTaskEventWillHandle) | |
876 asyncCallStackTracker().willHandleV8AsyncTask(context, eventName, id); | |
877 else if (eventType == v8AsyncTaskEventDidHandle) | |
878 asyncCallStackTracker().didFireAsyncCall(); | |
879 else | |
880 ASSERT_NOT_REACHED(); | |
881 } | |
882 | |
883 void InspectorDebuggerAgent::didReceiveV8PromiseEvent(ScriptState* scriptState, v8::Handle<v8::Object> promise, v8::Handle<v8::Value> parentPromise, int status) | |
884 { | |
885 if (!m_promiseTracker.isEnabled()) | |
886 return; | |
887 m_promiseTracker.didReceiveV8PromiseEvent(scriptState, promise, parentPromis e, status); | |
888 } | |
889 | |
890 void InspectorDebuggerAgent::pause(ErrorString*) | |
891 { | |
892 if (m_javaScriptPauseScheduled || isPaused()) | |
893 return; | |
894 clearBreakDetails(); | |
895 m_javaScriptPauseScheduled = true; | |
896 scriptDebugServer().setPauseOnNextStatement(true); | |
897 } | |
898 | |
899 void InspectorDebuggerAgent::resume(ErrorString* errorString) | |
900 { | |
901 if (!assertPaused(errorString)) | |
902 return; | |
903 m_debuggerStepScheduled = false; | |
904 m_steppingFromFramework = false; | |
905 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtrac eObjectGroup); | |
906 scriptDebugServer().continueProgram(); | |
907 } | |
908 | |
909 void InspectorDebuggerAgent::stepOver(ErrorString* errorString) | |
910 { | |
911 if (!assertPaused(errorString)) | |
912 return; | |
913 m_debuggerStepScheduled = true; | |
914 m_steppingFromFramework = isTopCallFrameInFramework(); | |
915 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtrac eObjectGroup); | |
916 scriptDebugServer().stepOverStatement(); | |
917 } | |
918 | |
919 void InspectorDebuggerAgent::stepInto(ErrorString* errorString) | |
920 { | |
921 if (!assertPaused(errorString)) | |
922 return; | |
923 m_debuggerStepScheduled = true; | |
924 m_steppingFromFramework = isTopCallFrameInFramework(); | |
925 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtrac eObjectGroup); | |
926 scriptDebugServer().stepIntoStatement(); | |
927 if (m_listener) | |
928 m_listener->stepInto(); | |
929 } | |
930 | |
931 void InspectorDebuggerAgent::stepOut(ErrorString* errorString) | |
932 { | |
933 if (!assertPaused(errorString)) | |
934 return; | |
935 m_debuggerStepScheduled = true; | |
936 m_steppingFromFramework = isTopCallFrameInFramework(); | |
937 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtrac eObjectGroup); | |
938 scriptDebugServer().stepOutOfFunction(); | |
939 } | |
940 | |
941 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, cons t String& stringPauseState) | |
942 { | |
943 ScriptDebugServer::PauseOnExceptionsState pauseState; | |
944 if (stringPauseState == "none") | |
945 pauseState = ScriptDebugServer::DontPauseOnExceptions; | |
946 else if (stringPauseState == "all") | |
947 pauseState = ScriptDebugServer::PauseOnAllExceptions; | |
948 else if (stringPauseState == "uncaught") | |
949 pauseState = ScriptDebugServer::PauseOnUncaughtExceptions; | |
950 else { | |
951 *errorString = "Unknown pause on exceptions mode: " + stringPauseState; | |
952 return; | |
953 } | |
954 setPauseOnExceptionsImpl(errorString, pauseState); | |
955 } | |
956 | |
957 void InspectorDebuggerAgent::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState) | |
958 { | |
959 scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer: :PauseOnExceptionsState>(pauseState)); | |
960 if (scriptDebugServer().pauseOnExceptionsState() != pauseState) | |
961 *errorString = "Internal error. Could not change pause on exceptions sta te"; | |
962 else | |
963 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, pauseState) ; | |
964 } | |
965 | |
966 void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptio nsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<Ty peBuilder::Debugger::ExceptionDetails>& exceptionDetails) | |
967 { | |
968 if (!isPaused() || m_currentCallStack.isEmpty()) { | |
969 *errorString = "Attempt to access callframe when debugger is not on paus e"; | |
970 return; | |
971 } | |
972 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForOb jectId(callFrameId); | |
973 if (injectedScript.isEmpty()) { | |
974 *errorString = "Inspected frame has gone"; | |
975 return; | |
976 } | |
977 | |
978 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = s criptDebugServer().pauseOnExceptionsState(); | |
979 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { | |
980 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExce ptions) | |
981 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::Don tPauseOnExceptions); | |
982 muteConsole(); | |
983 } | |
984 | |
985 Vector<ScriptValue> asyncCallStacks; | |
986 const AsyncCallStackTracker::AsyncCallChain* asyncChain = asyncCallStackTrac ker().isEnabled() ? asyncCallStackTracker().currentAsyncCallChain() : 0; | |
987 if (asyncChain) { | |
988 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = asyncCha in->callStacks(); | |
989 asyncCallStacks.resize(callStacks.size()); | |
990 AsyncCallStackTracker::AsyncCallStackVector::const_iterator it = callSta cks.begin(); | |
991 for (size_t i = 0; it != callStacks.end(); ++it, ++i) | |
992 asyncCallStacks[i] = (*it)->callFrames(); | |
993 } | |
994 | |
995 injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, asyncCal lStacks, callFrameId, expression, objectGroup ? *objectGroup : "", asBool(includ eCommandLineAPI), asBool(returnByValue), asBool(generatePreview), &result, wasTh rown, &exceptionDetails); | |
996 // V8 doesn't generate afterCompile event when it's in debugger therefore th ere is no content of evaluated scripts on frontend | |
997 // therefore contents of the stack does not provide necessary information | |
998 if (exceptionDetails) | |
999 exceptionDetails->setStackTrace(TypeBuilder::Array<TypeBuilder::Console: :CallFrame>::create()); | |
1000 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { | |
1001 unmuteConsole(); | |
1002 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExcep tionsState) | |
1003 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExcepti onsState); | |
1004 } | |
1005 } | |
1006 | |
1007 void InspectorDebuggerAgent::compileScript(ErrorString* errorString, const Strin g& expression, const String& sourceURL, const int* executionContextId, TypeBuild er::OptOutput<ScriptId>* scriptId, RefPtr<ExceptionDetails>& exceptionDetails) | |
1008 { | |
1009 InjectedScript injectedScript = injectedScriptForEval(errorString, execution ContextId); | |
1010 if (injectedScript.isEmpty()) { | |
1011 *errorString = "Inspected frame has gone"; | |
1012 return; | |
1013 } | |
1014 | |
1015 String scriptIdValue; | |
1016 String exceptionDetailsText; | |
1017 int lineNumberValue = 0; | |
1018 int columnNumberValue = 0; | |
1019 RefPtr<ScriptCallStack> stackTraceValue; | |
1020 scriptDebugServer().compileScript(injectedScript.scriptState(), expression, sourceURL, &scriptIdValue, &exceptionDetailsText, &lineNumberValue, &columnNumbe rValue, &stackTraceValue); | |
1021 if (!scriptIdValue && !exceptionDetailsText) { | |
1022 *errorString = "Script compilation failed"; | |
1023 return; | |
1024 } | |
1025 *scriptId = scriptIdValue; | |
1026 if (!scriptIdValue.isEmpty()) | |
1027 return; | |
1028 | |
1029 exceptionDetails = ExceptionDetails::create().setText(exceptionDetailsText); | |
1030 exceptionDetails->setLine(lineNumberValue); | |
1031 exceptionDetails->setColumn(columnNumberValue); | |
1032 if (stackTraceValue && stackTraceValue->size() > 0) | |
1033 exceptionDetails->setStackTrace(stackTraceValue->buildInspectorArray()); | |
1034 } | |
1035 | |
1036 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) | |
1037 { | |
1038 InjectedScript injectedScript = injectedScriptForEval(errorString, execution ContextId); | |
1039 if (injectedScript.isEmpty()) { | |
1040 *errorString = "Inspected frame has gone"; | |
1041 return; | |
1042 } | |
1043 | |
1044 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = s criptDebugServer().pauseOnExceptionsState(); | |
1045 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { | |
1046 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExce ptions) | |
1047 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::Don tPauseOnExceptions); | |
1048 muteConsole(); | |
1049 } | |
1050 | |
1051 ScriptValue value; | |
1052 bool wasThrownValue; | |
1053 String exceptionDetailsText; | |
1054 int lineNumberValue = 0; | |
1055 int columnNumberValue = 0; | |
1056 RefPtr<ScriptCallStack> stackTraceValue; | |
1057 scriptDebugServer().runScript(injectedScript.scriptState(), scriptId, &value , &wasThrownValue, &exceptionDetailsText, &lineNumberValue, &columnNumberValue, &stackTraceValue); | |
1058 if (value.isEmpty()) { | |
1059 *errorString = "Script execution failed"; | |
1060 return; | |
1061 } | |
1062 result = injectedScript.wrapObject(value, objectGroup ? *objectGroup : ""); | |
1063 if (wasThrownValue) { | |
1064 exceptionDetails = ExceptionDetails::create().setText(exceptionDetailsTe xt); | |
1065 exceptionDetails->setLine(lineNumberValue); | |
1066 exceptionDetails->setColumn(columnNumberValue); | |
1067 if (stackTraceValue && stackTraceValue->size() > 0) | |
1068 exceptionDetails->setStackTrace(stackTraceValue->buildInspectorArray ()); | |
1069 } | |
1070 | |
1071 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { | |
1072 unmuteConsole(); | |
1073 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExcep tionsState) | |
1074 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExcepti onsState); | |
1075 } | |
1076 } | |
1077 | |
1078 void InspectorDebuggerAgent::setOverlayMessage(ErrorString*, const String*) | |
1079 { | |
1080 } | |
1081 | |
1082 void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, int scop eNumber, const String& variableName, const RefPtr<JSONObject>& newValue, const S tring* callFrameId, const String* functionObjectId) | |
1083 { | |
1084 InjectedScript injectedScript; | |
1085 if (callFrameId) { | |
1086 if (!isPaused() || m_currentCallStack.isEmpty()) { | |
1087 *errorString = "Attempt to access callframe when debugger is not on pause"; | |
1088 return; | |
1089 } | |
1090 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*cal lFrameId); | |
1091 if (injectedScript.isEmpty()) { | |
1092 *errorString = "Inspected frame has gone"; | |
1093 return; | |
1094 } | |
1095 } else if (functionObjectId) { | |
1096 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*fun ctionObjectId); | |
1097 if (injectedScript.isEmpty()) { | |
1098 *errorString = "Function object id cannot be resolved"; | |
1099 return; | |
1100 } | |
1101 } else { | |
1102 *errorString = "Either call frame or function object must be specified"; | |
1103 return; | |
1104 } | |
1105 String newValueString = newValue->toJSONString(); | |
1106 | |
1107 injectedScript.setVariableValue(errorString, m_currentCallStack, callFrameId , functionObjectId, scopeNumber, variableName, newValueString); | |
1108 } | |
1109 | |
1110 void InspectorDebuggerAgent::skipStackFrames(ErrorString* errorString, const Str ing* pattern) | |
1111 { | |
1112 OwnPtr<ScriptRegexp> compiled; | |
1113 String patternValue = pattern ? *pattern : ""; | |
1114 if (!patternValue.isEmpty()) { | |
1115 compiled = compileSkipCallFramePattern(patternValue); | |
1116 if (!compiled) { | |
1117 *errorString = "Invalid regular expression"; | |
1118 return; | |
1119 } | |
1120 } | |
1121 m_state->setString(DebuggerAgentState::skipStackPattern, patternValue); | |
1122 m_cachedSkipStackRegExp = compiled.release(); | |
1123 } | |
1124 | |
1125 void InspectorDebuggerAgent::setAsyncCallStackDepth(ErrorString*, int depth) | |
1126 { | |
1127 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, depth); | |
1128 asyncCallStackTracker().setAsyncCallStackDepth(depth); | |
1129 } | |
1130 | |
1131 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directive Text) | |
1132 { | |
1133 if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontP auseOnExceptions) { | |
1134 RefPtr<JSONObject> directive = JSONObject::create(); | |
1135 directive->setString("directiveText", directiveText); | |
1136 breakProgram(InspectorFrontend::Debugger::Reason::CSPViolation, directiv e.release()); | |
1137 } | |
1138 } | |
1139 | |
1140 PassRefPtr<Array<CallFrame> > InspectorDebuggerAgent::currentCallFrames() | |
1141 { | |
1142 if (!m_pausedScriptState || m_currentCallStack.isEmpty()) | |
1143 return Array<CallFrame>::create(); | |
1144 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m _pausedScriptState.get()); | |
1145 if (injectedScript.isEmpty()) { | |
1146 ASSERT_NOT_REACHED(); | |
1147 return Array<CallFrame>::create(); | |
1148 } | |
1149 return injectedScript.wrapCallFrames(m_currentCallStack, 0); | |
1150 } | |
1151 | |
1152 PassRefPtr<StackTrace> InspectorDebuggerAgent::currentAsyncStackTrace() | |
1153 { | |
1154 if (!m_pausedScriptState || !asyncCallStackTracker().isEnabled()) | |
1155 return nullptr; | |
1156 const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker() .currentAsyncCallChain(); | |
1157 if (!chain) | |
1158 return nullptr; | |
1159 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callS tacks(); | |
1160 if (callStacks.isEmpty()) | |
1161 return nullptr; | |
1162 RefPtr<StackTrace> result; | |
1163 int asyncOrdinal = callStacks.size(); | |
1164 for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it, --asyncOrdinal) { | |
1165 ScriptValue callFrames = (*it)->callFrames(); | |
1166 ScriptState* scriptState = callFrames.scriptState(); | |
1167 InjectedScript injectedScript = scriptState ? m_injectedScriptManager->i njectedScriptFor(scriptState) : InjectedScript(); | |
1168 if (injectedScript.isEmpty()) { | |
1169 result.clear(); | |
1170 continue; | |
1171 } | |
1172 RefPtr<StackTrace> next = StackTrace::create() | |
1173 .setCallFrames(injectedScript.wrapCallFrames(callFrames, asyncOrdina l)) | |
1174 .release(); | |
1175 next->setDescription((*it)->description()); | |
1176 if (result) | |
1177 next->setAsyncStackTrace(result.release()); | |
1178 result.swap(next); | |
1179 } | |
1180 return result.release(); | |
1181 } | |
1182 | |
1183 static PassRefPtr<ScriptCallStack> toScriptCallStack(JavaScriptCallFrame* callFr ame) | |
1184 { | |
1185 Vector<ScriptCallFrame> frames; | |
1186 for (; callFrame; callFrame = callFrame->caller()) { | |
1187 StringBuilder stringBuilder; | |
1188 stringBuilder.appendNumber(callFrame->sourceID()); | |
1189 String scriptId = stringBuilder.toString(); | |
1190 // FIXME(WK62725): Debugger line/column are 0-based, while console ones are 1-based. | |
1191 int line = callFrame->line() + 1; | |
1192 int column = callFrame->column() + 1; | |
1193 frames.append(ScriptCallFrame(callFrame->functionName(), scriptId, callF rame->scriptName(), line, column)); | |
1194 } | |
1195 return ScriptCallStack::create(frames); | |
1196 } | |
1197 | |
1198 PassRefPtr<ScriptAsyncCallStack> InspectorDebuggerAgent::currentAsyncStackTraceF orConsole() | |
1199 { | |
1200 if (!asyncCallStackTracker().isEnabled()) | |
1201 return nullptr; | |
1202 const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker() .currentAsyncCallChain(); | |
1203 if (!chain) | |
1204 return nullptr; | |
1205 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callS tacks(); | |
1206 if (callStacks.isEmpty()) | |
1207 return nullptr; | |
1208 RefPtr<ScriptAsyncCallStack> result = nullptr; | |
1209 for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it) { | |
1210 RefPtr<JavaScriptCallFrame> callFrame = ScriptDebugServer::toJavaScriptC allFrameUnsafe((*it)->callFrames()); | |
1211 if (!callFrame) | |
1212 break; | |
1213 result = ScriptAsyncCallStack::create((*it)->description(), toScriptCall Stack(callFrame.get()), result.release()); | |
1214 } | |
1215 return result.release(); | |
1216 } | |
1217 | |
1218 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script, Compi leResult compileResult) | |
1219 { | |
1220 bool hasSyntaxError = compileResult != CompileSuccess; | |
1221 if (hasSyntaxError) { | |
1222 bool deprecated; | |
1223 String sourceMapURL = ContentSearchUtils::findSourceMapURL(script.source , ContentSearchUtils::JavaScriptMagicComment, &deprecated); | |
1224 if (!sourceMapURL.isEmpty()) | |
1225 return sourceMapURL; | |
1226 } | |
1227 | |
1228 if (!script.sourceMappingURL.isEmpty()) | |
1229 return script.sourceMappingURL; | |
1230 | |
1231 return String(); | |
1232 // FIXME(sky): Fetch from page agent. | |
1233 } | |
1234 | |
1235 // ScriptDebugListener functions | |
1236 | |
1237 void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script & parsedScript, CompileResult compileResult) | |
1238 { | |
1239 Script script = parsedScript; | |
1240 const bool* isContentScript = script.isContentScript ? &script.isContentScri pt : 0; | |
1241 | |
1242 bool hasSyntaxError = compileResult != CompileSuccess; | |
1243 if (!script.startLine && !script.startColumn) { | |
1244 if (hasSyntaxError) { | |
1245 bool deprecated; | |
1246 script.sourceURL = ContentSearchUtils::findSourceURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated); | |
1247 } | |
1248 } else { | |
1249 script.sourceURL = String(); | |
1250 } | |
1251 | |
1252 bool hasSourceURL = !script.sourceURL.isEmpty(); | |
1253 String scriptURL = hasSourceURL ? script.sourceURL : script.url; | |
1254 | |
1255 String sourceMapURL = sourceMapURLForScript(script, compileResult); | |
1256 String* sourceMapURLParam = sourceMapURL.isNull() ? 0 : &sourceMapURL; | |
1257 | |
1258 bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : 0; | |
1259 if (!hasSyntaxError) | |
1260 m_frontend->scriptParsed(scriptId, scriptURL, script.startLine, script.s tartColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam , hasSourceURLParam); | |
1261 else | |
1262 m_frontend->scriptFailedToParse(scriptId, scriptURL, script.startLine, s cript.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapU RLParam, hasSourceURLParam); | |
1263 | |
1264 m_scripts.set(scriptId, script); | |
1265 | |
1266 if (scriptURL.isEmpty() || hasSyntaxError) | |
1267 return; | |
1268 | |
1269 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState ::javaScriptBreakpoints); | |
1270 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpoints Cookie->end(); ++it) { | |
1271 RefPtr<JSONObject> breakpointObject = it->value->asObject(); | |
1272 bool isAntibreakpoint; | |
1273 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoi nt); | |
1274 if (isAntibreakpoint) | |
1275 continue; | |
1276 bool isRegex; | |
1277 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); | |
1278 String url; | |
1279 breakpointObject->getString(DebuggerAgentState::url, &url); | |
1280 if (!matches(scriptURL, url, isRegex)) | |
1281 continue; | |
1282 ScriptBreakpoint breakpoint; | |
1283 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakpoint. lineNumber); | |
1284 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakpoin t.columnNumber); | |
1285 breakpointObject->getString(DebuggerAgentState::condition, &breakpoint.c ondition); | |
1286 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(it- >key, scriptId, breakpoint, UserBreakpointSource); | |
1287 if (location) | |
1288 m_frontend->breakpointResolved(it->key, location); | |
1289 } | |
1290 } | |
1291 | |
1292 // This is a hack to make the debugger not break in the js inspector | |
1293 // so it works even while v8 is paused. | |
1294 bool InspectorDebuggerAgent::shouldSkipInspectorInternals() | |
eseidel
2014/11/18 19:29:26
This is the code to ignore the sky js files.
| |
1295 { | |
1296 RefPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(); | |
1297 if (!topFrame) | |
1298 return false; | |
1299 | |
1300 KURL url = KURL(ParsedURLString, scriptURL(topFrame.get())); | |
1301 return url.path().startsWith("/sky/framework") | |
1302 || url.path().startsWith("/sky/services") | |
1303 || url.path().startsWith("/mojo"); | |
1304 } | |
abarth-chromium
2014/11/18 22:37:36
This is kind of goofy to hardcode in the binary...
| |
1305 | |
1306 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::didPause(ScriptSta te* scriptState, const ScriptValue& callFrames, const ScriptValue& exception, co nst Vector<String>& hitBreakpoints) | |
1307 { | |
1308 ScriptDebugListener::SkipPauseRequest result; | |
1309 if (callFrames.isEmpty() || shouldSkipInspectorInternals()) | |
1310 result = ScriptDebugListener::Continue; // Skip pauses inside V8 interna l scripts and on syntax errors. | |
1311 else if (m_javaScriptPauseScheduled) | |
1312 result = ScriptDebugListener::NoSkip; // Don't skip explicit pause reque sts from front-end. | |
1313 else if (m_skipAllPauses) | |
1314 result = ScriptDebugListener::Continue; | |
1315 else if (!hitBreakpoints.isEmpty()) | |
1316 result = ScriptDebugListener::NoSkip; // Don't skip explicit breakpoints even if set in frameworks. | |
1317 else if (!exception.isEmpty()) | |
1318 result = shouldSkipExceptionPause(); | |
1319 else if (m_debuggerStepScheduled || m_pausingOnNativeEvent) | |
1320 result = shouldSkipStepPause(); | |
1321 else | |
1322 result = ScriptDebugListener::NoSkip; | |
1323 | |
1324 if (result != ScriptDebugListener::NoSkip) | |
1325 return result; | |
1326 | |
1327 ASSERT(scriptState && !m_pausedScriptState); | |
1328 m_pausedScriptState = scriptState; | |
1329 m_currentCallStack = callFrames; | |
1330 | |
1331 if (!exception.isEmpty()) { | |
1332 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptF or(scriptState); | |
1333 if (!injectedScript.isEmpty()) { | |
1334 m_breakReason = InspectorFrontend::Debugger::Reason::Exception; | |
1335 m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebug gerAgent::backtraceObjectGroup)->openAccessors(); | |
1336 // m_breakAuxData might be null after this. | |
1337 } | |
1338 } | |
1339 | |
1340 RefPtr<Array<String> > hitBreakpointIds = Array<String>::create(); | |
1341 | |
1342 for (Vector<String>::const_iterator i = hitBreakpoints.begin(); i != hitBrea kpoints.end(); ++i) { | |
1343 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator breakpointIter ator = m_serverBreakpoints.find(*i); | |
1344 if (breakpointIterator != m_serverBreakpoints.end()) { | |
1345 const String& localId = breakpointIterator->value.first; | |
1346 hitBreakpointIds->addItem(localId); | |
1347 | |
1348 BreakpointSource source = breakpointIterator->value.second; | |
1349 if (m_breakReason == InspectorFrontend::Debugger::Reason::Other && s ource == DebugCommandBreakpointSource) | |
1350 m_breakReason = InspectorFrontend::Debugger::Reason::DebugComman d; | |
1351 } | |
1352 } | |
1353 | |
1354 m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData, hitBr eakpointIds, currentAsyncStackTrace()); | |
1355 m_javaScriptPauseScheduled = false; | |
1356 m_debuggerStepScheduled = false; | |
1357 m_steppingFromFramework = false; | |
1358 m_pausingOnNativeEvent = false; | |
1359 m_skippedStepInCount = 0; | |
1360 | |
1361 if (!m_continueToLocationBreakpointId.isEmpty()) { | |
1362 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId); | |
1363 m_continueToLocationBreakpointId = ""; | |
1364 } | |
1365 if (m_listener) | |
1366 m_listener->didPause(); | |
1367 return result; | |
1368 } | |
1369 | |
1370 void InspectorDebuggerAgent::didContinue() | |
1371 { | |
1372 m_pausedScriptState = nullptr; | |
1373 m_currentCallStack = ScriptValue(); | |
1374 clearBreakDetails(); | |
1375 m_frontend->resumed(); | |
1376 } | |
1377 | |
1378 bool InspectorDebuggerAgent::canBreakProgram() | |
1379 { | |
1380 return scriptDebugServer().canBreakProgram(); | |
1381 } | |
1382 | |
1383 void InspectorDebuggerAgent::breakProgram(InspectorFrontend::Debugger::Reason::E num breakReason, PassRefPtr<JSONObject> data) | |
1384 { | |
1385 if (m_skipAllPauses) | |
1386 return; | |
1387 m_breakReason = breakReason; | |
1388 m_breakAuxData = data; | |
1389 m_debuggerStepScheduled = false; | |
1390 m_steppingFromFramework = false; | |
1391 m_pausingOnNativeEvent = false; | |
1392 scriptDebugServer().breakProgram(); | |
1393 } | |
1394 | |
1395 void InspectorDebuggerAgent::clear() | |
1396 { | |
1397 m_pausedScriptState = nullptr; | |
1398 m_currentCallStack = ScriptValue(); | |
1399 m_scripts.clear(); | |
1400 m_breakpointIdToDebugServerBreakpointIds.clear(); | |
1401 asyncCallStackTracker().clear(); | |
1402 m_promiseTracker.clear(); | |
1403 m_continueToLocationBreakpointId = String(); | |
1404 clearBreakDetails(); | |
1405 m_javaScriptPauseScheduled = false; | |
1406 m_debuggerStepScheduled = false; | |
1407 m_steppingFromFramework = false; | |
1408 m_pausingOnNativeEvent = false; | |
1409 ErrorString error; | |
1410 setOverlayMessage(&error, 0); | |
1411 } | |
1412 | |
1413 bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString) | |
1414 { | |
1415 if (!m_pausedScriptState) { | |
1416 *errorString = "Can only perform operation while paused."; | |
1417 return false; | |
1418 } | |
1419 return true; | |
1420 } | |
1421 | |
1422 void InspectorDebuggerAgent::clearBreakDetails() | |
1423 { | |
1424 m_breakReason = InspectorFrontend::Debugger::Reason::Other; | |
1425 m_breakAuxData = nullptr; | |
1426 } | |
1427 | |
1428 void InspectorDebuggerAgent::setBreakpoint(const String& scriptId, int lineNumbe r, int columnNumber, BreakpointSource source, const String& condition) | |
1429 { | |
1430 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumbe r, source); | |
1431 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); | |
1432 resolveBreakpoint(breakpointId, scriptId, breakpoint, source); | |
1433 } | |
1434 | |
1435 void InspectorDebuggerAgent::removeBreakpoint(const String& scriptId, int lineNu mber, int columnNumber, BreakpointSource source) | |
1436 { | |
1437 removeBreakpoint(generateBreakpointId(scriptId, lineNumber, columnNumber, so urce)); | |
1438 } | |
1439 | |
1440 void InspectorDebuggerAgent::reset() | |
1441 { | |
1442 m_scripts.clear(); | |
1443 m_breakpointIdToDebugServerBreakpointIds.clear(); | |
1444 asyncCallStackTracker().clear(); | |
1445 m_promiseTracker.clear(); | |
1446 if (m_frontend) | |
1447 m_frontend->globalObjectCleared(); | |
1448 } | |
1449 | |
1450 } // namespace blink | |
1451 | |
OLD | NEW |