Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(135)

Side by Side Diff: sky/engine/core/inspector/InspectorDebuggerAgent.cpp

Issue 727593004: Wire up the Inspector V8 Debugger (Closed) Base URL: git@github.com:domokit/mojo.git@master
Patch Set: Actually works Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698