1 /* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2013 Google Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of 15 * its contributors may be used to endorse or promote products derived 16 * from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY 19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY 22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include "config.h" 31 #include "core/inspector/InspectorDebuggerAgent.h" 32 33 #include "bindings/core/v8/ScriptDebugServer.h" 34 #include "bindings/core/v8/ScriptRegexp.h" 35 #include "bindings/core/v8/ScriptSourceCode.h" 36 #include "bindings/core/v8/ScriptValue.h" 37 #include "core/dom/Document.h" 38 #include "core/dom/ExecutionContextTask.h" 39 #include "core/fetch/Resource.h" 40 #include "core/inspector/ConsoleMessage.h" 41 #include "core/inspector/ContentSearchUtils.h" 42 #include "core/inspector/InjectedScriptManager.h" 43 #include "core/inspector/InspectorPageAgent.h" 44 #include "core/inspector/InspectorState.h" 45 #include "core/inspector/InstrumentingAgents.h" 46 #include "core/inspector/JavaScriptCallFrame.h" 47 #include "core/inspector/ScriptArguments.h" 48 #include "core/inspector/ScriptAsyncCallStack.h" 49 #include "core/inspector/ScriptCallFrame.h" 50 #include "core/inspector/ScriptCallStack.h" 51 #include "platform/JSONValues.h" 52 #include "wtf/text/StringBuilder.h" 53 #include "wtf/text/WTFString.h" 54 55 using blink::TypeBuilder::Array; 56 using blink::TypeBuilder::Debugger::BreakpointId; 57 using blink::TypeBuilder::Debugger::CallFrame; 58 using blink::TypeBuilder::Debugger::CollectionEntry; 59 using blink::TypeBuilder::Debugger::ExceptionDetails; 60 using blink::TypeBuilder::Debugger::FunctionDetails; 61 using blink::TypeBuilder::Debugger::PromiseDetails; 62 using blink::TypeBuilder::Debugger::ScriptId; 63 using blink::TypeBuilder::Debugger::StackTrace; 64 using blink::TypeBuilder::Runtime::RemoteObject; 65 66 namespace { 67 68 static const char v8AsyncTaskEventEnqueue[] = "enqueue"; 69 static const char v8AsyncTaskEventWillHandle[] = "willHandle"; 70 static const char v8AsyncTaskEventDidHandle[] = "didHandle"; 71 72 } 73 74 namespace blink { 75 76 namespace DebuggerAgentState { 77 static const char debuggerEnabled[] = "debuggerEnabled"; 78 static const char javaScriptBreakpoints[] = "javaScriptBreakopints"; 79 static const char pauseOnExceptionsState[] = "pauseOnExceptionsState"; 80 static const char asyncCallStackDepth[] = "asyncCallStackDepth"; 81 static const char promiseTrackerEnabled[] = "promiseTrackerEnabled"; 82 83 // Breakpoint properties. 84 static const char url[] = "url"; 85 static const char isRegex[] = "isRegex"; 86 static const char lineNumber[] = "lineNumber"; 87 static const char columnNumber[] = "columnNumber"; 88 static const char condition[] = "condition"; 89 static const char isAnti[] = "isAnti"; 90 static const char skipStackPattern[] = "skipStackPattern"; 91 static const char skipContentScripts[] = "skipContentScripts"; 92 static const char skipAllPauses[] = "skipAllPauses"; 93 static const char skipAllPausesExpiresOnReload[] = "skipAllPausesExpiresOnReload"; 94 95 }; 96 97 static const int maxSkipStepInCount = 20; 98 99 const char InspectorDebuggerAgent::backtraceObjectGroup[] = "backtrace"; 100 101 static String breakpointIdSuffix(InspectorDebuggerAgent::BreakpointSource source) 102 { 103 switch (source) { 104 case InspectorDebuggerAgent::UserBreakpointSource: 105 break; 106 case InspectorDebuggerAgent::DebugCommandBreakpointSource: 107 return ":debug"; 108 case InspectorDebuggerAgent::MonitorCommandBreakpointSource: 109 return ":monitor"; 110 } 111 return String(); 112 } 113 114 static String generateBreakpointId(const String& scriptId, int lineNumber, int columnNumber, InspectorDebuggerAgent::BreakpointSource source) 115 { 116 return scriptId + ':' + String::number(lineNumber) + ':' + String::number(columnNumber) + breakpointIdSuffix(source); 117 } 118 119 InspectorDebuggerAgent::InspectorDebuggerAgent(InjectedScriptManager* injectedScriptManager) 120 : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger") 121 , m_injectedScriptManager(injectedScriptManager) 122 , m_frontend(0) 123 , m_pausedScriptState(nullptr) 124 , m_javaScriptPauseScheduled(false) 125 , m_debuggerStepScheduled(false) 126 , m_steppingFromFramework(false) 127 , m_pausingOnNativeEvent(false) 128 , m_listener(nullptr) 129 , m_skippedStepInCount(0) 130 , m_skipAllPauses(false) 131 , m_skipContentScripts(false) 132 , m_asyncCallStackTracker(adoptPtrWillBeNoop(new AsyncCallStackTracker())) 133 , m_promiseTracker(PromiseTracker::create()) 134 { 135 } 136 137 InspectorDebuggerAgent::~InspectorDebuggerAgent() 138 { 139 #if !ENABLE(OILPAN) 140 ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent()); 141 #endif 142 } 143 144 void InspectorDebuggerAgent::init() 145 { 146 // FIXME: make breakReason optional so that there was no need to init it with "other". 147 clearBreakDetails(); 148 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions); 149 } 150 151 void InspectorDebuggerAgent::enable() 152 { 153 m_instrumentingAgents->setInspectorDebuggerAgent(this); 154 155 startListeningScriptDebugServer(); 156 // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends 157 scriptDebugServer().setBreakpointsActivated(true); 158 159 if (m_listener) 160 m_listener->debuggerWasEnabled(); 161 } 162 163 void InspectorDebuggerAgent::disable() 164 { 165 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, JSONObject::create()); 166 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions); 167 m_state->setString(DebuggerAgentState::skipStackPattern, ""); 168 m_state->setBoolean(DebuggerAgentState::skipContentScripts, false); 169 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, 0); 170 m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, false); 171 m_instrumentingAgents->setInspectorDebuggerAgent(0); 172 173 scriptDebugServer().clearBreakpoints(); 174 scriptDebugServer().clearCompiledScripts(); 175 scriptDebugServer().clearPreprocessor(); 176 stopListeningScriptDebugServer(); 177 clear(); 178 179 if (m_listener) 180 m_listener->debuggerWasDisabled(); 181 182 m_skipAllPauses = false; 183 } 184 185 bool InspectorDebuggerAgent::enabled() 186 { 187 return m_state->getBoolean(DebuggerAgentState::debuggerEnabled); 188 } 189 190 void InspectorDebuggerAgent::enable(ErrorString*) 191 { 192 if (enabled()) 193 return; 194 195 enable(); 196 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); 197 198 ASSERT(m_frontend); 199 } 200 201 void InspectorDebuggerAgent::disable(ErrorString*) 202 { 203 if (!enabled()) 204 return; 205 206 disable(); 207 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); 208 } 209 210 static PassOwnPtr<ScriptRegexp> compileSkipCallFramePattern(String patternText) 211 { 212 if (patternText.isEmpty()) 213 return nullptr; 214 OwnPtr<ScriptRegexp> result = adoptPtr(new ScriptRegexp(patternText, TextCaseSensitive)); 215 if (!result->isValid()) 216 result.clear(); 217 return result.release(); 218 } 219 220 void InspectorDebuggerAgent::restore() 221 { 222 if (enabled()) { 223 m_frontend->globalObjectCleared(); 224 enable(); 225 long pauseState = m_state->getLong(DebuggerAgentState::pauseOnExceptionsState); 226 String error; 227 setPauseOnExceptionsImpl(&error, pauseState); 228 m_cachedSkipStackRegExp = compileSkipCallFramePattern(m_state->getString(DebuggerAgentState::skipStackPattern)); 229 m_skipContentScripts = m_state->getBoolean(DebuggerAgentState::skipContentScripts); 230 m_skipAllPauses = m_state->getBoolean(DebuggerAgentState::skipAllPauses); 231 if (m_skipAllPauses && m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) { 232 m_skipAllPauses = false; 233 m_state->setBoolean(DebuggerAgentState::skipAllPauses, false); 234 } 235 asyncCallStackTracker().setAsyncCallStackDepth(m_state->getLong(DebuggerAgentState::asyncCallStackDepth)); 236 promiseTracker().setEnabled(m_state->getBoolean(DebuggerAgentState::promiseTrackerEnabled)); 237 } 238 } 239 240 void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend) 241 { 242 m_frontend = frontend->debugger(); 243 } 244 245 void InspectorDebuggerAgent::clearFrontend() 246 { 247 m_frontend = 0; 248 249 if (!enabled()) 250 return; 251 252 disable(); 253 254 // FIXME: due to m_state->mute() hack in InspectorController, debuggerEnabled is actually set to false only 255 // in InspectorState, but not in cookie. That's why after navigation debuggerEnabled will be true, 256 // but after front-end re-open it will still be false. 257 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); 258 } 259 260 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active) 261 { 262 scriptDebugServer().setBreakpointsActivated(active); 263 } 264 265 void InspectorDebuggerAgent::setSkipAllPauses(ErrorString*, bool skipped, const bool* untilReload) 266 { 267 m_skipAllPauses = skipped; 268 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses); 269 m_state->setBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload, asBool(untilReload)); 270 } 271 272 void InspectorDebuggerAgent::pageDidCommitLoad() 273 { 274 if (m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) { 275 m_skipAllPauses = false; 276 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses); 277 } 278 } 279 280 bool InspectorDebuggerAgent::isPaused() 281 { 282 return scriptDebugServer().isPaused(); 283 } 284 285 bool InspectorDebuggerAgent::runningNestedMessageLoop() 286 { 287 return scriptDebugServer().runningNestedMessageLoop(); 288 } 289 290 void InspectorDebuggerAgent::addMessageToConsole(ConsoleMessage* consoleMessage) 291 { 292 if (consoleMessage->type() == AssertMessageType && scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) 293 breakProgram(InspectorFrontend::Debugger::Reason::Assert, nullptr); 294 } 295 296 String InspectorDebuggerAgent::preprocessEventListener(LocalFrame* frame, const String& source, const String& url, const String& functionName) 297 { 298 return scriptDebugServer().preprocessEventListener(frame, source, url, functionName); 299 } 300 301 PassOwnPtr<ScriptSourceCode> InspectorDebuggerAgent::preprocess(LocalFrame* frame, const ScriptSourceCode& sourceCode) 302 { 303 return scriptDebugServer().preprocess(frame, sourceCode); 304 } 305 306 static PassRefPtr<JSONObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex, bool isAnti) 307 { 308 RefPtr<JSONObject> breakpointObject = JSONObject::create(); 309 breakpointObject->setString(DebuggerAgentState::url, url); 310 breakpointObject->setNumber(DebuggerAgentState::lineNumber, lineNumber); 311 breakpointObject->setNumber(DebuggerAgentState::columnNumber, columnNumber); 312 breakpointObject->setString(DebuggerAgentState::condition, condition); 313 breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex); 314 breakpointObject->setBoolean(DebuggerAgentState::isAnti, isAnti); 315 return breakpointObject; 316 } 317 318 static String scriptSourceURL(const ScriptDebugListener::Script& script) 319 { 320 bool hasSourceURL = !script.sourceURL.isEmpty(); 321 return hasSourceURL ? script.sourceURL : script.url; 322 } 323 324 static bool matches(const String& url, const String& pattern, bool isRegex) 325 { 326 if (isRegex) { 327 ScriptRegexp regex(pattern, TextCaseSensitive); 328 return regex.match(url) != -1; 329 } 330 return url == pattern; 331 } 332 333 void InspectorDebuggerAgent::setBreakpointByUrl(ErrorString* errorString, int lineNumber, const String* const optionalURL, const String* const optionalURLRegex, const int* const optionalColumnNumber, const String* const optionalCondition, const bool* isAntiBreakpoint, BreakpointId* outBreakpointId, RefPtr<Array<TypeBuilder::Debugger::Location> >& locations) 334 { 335 locations = Array<TypeBuilder::Debugger::Location>::create(); 336 if (!optionalURL == !optionalURLRegex) { 337 *errorString = "Either url or urlRegex must be specified."; 338 return; 339 } 340 341 bool isAntiBreakpointValue = asBool(isAntiBreakpoint); 342 343 String url = optionalURL ? *optionalURL : *optionalURLRegex; 344 int columnNumber; 345 if (optionalColumnNumber) { 346 columnNumber = *optionalColumnNumber; 347 if (columnNumber < 0) { 348 *errorString = "Incorrect column number"; 349 return; 350 } 351 } else { 352 columnNumber = isAntiBreakpointValue ? -1 : 0; 353 } 354 String condition = optionalCondition ? *optionalCondition : ""; 355 bool isRegex = optionalURLRegex; 356 357 String breakpointId = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber); 358 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 359 if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) { 360 *errorString = "Breakpoint at specified location already exists."; 361 return; 362 } 363 364 breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, isRegex, isAntiBreakpointValue)); 365 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); 366 367 if (!isAntiBreakpointValue) { 368 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); 369 for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) { 370 if (!matches(scriptSourceURL(it->value), url, isRegex)) 371 continue; 372 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(breakpointId, it->key, breakpoint, UserBreakpointSource); 373 if (location) 374 locations->addItem(location); 375 } 376 } 377 *outBreakpointId = breakpointId; 378 } 379 380 static bool parseLocation(ErrorString* errorString, PassRefPtr<JSONObject> location, String* scriptId, int* lineNumber, int* columnNumber) 381 { 382 if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) { 383 // FIXME: replace with input validation. 384 *errorString = "scriptId and lineNumber are required."; 385 return false; 386 } 387 *columnNumber = 0; 388 location->getNumber("columnNumber", columnNumber); 389 return true; 390 } 391 392 void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr<JSONObject>& location, const String* const optionalCondition, BreakpointId* outBreakpointId, RefPtr<TypeBuilder::Debugger::Location>& actualLocation) 393 { 394 String scriptId; 395 int lineNumber; 396 int columnNumber; 397 398 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber)) 399 return; 400 401 String condition = optionalCondition ? *optionalCondition : emptyString(); 402 403 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumber, UserBreakpointSource); 404 if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end()) { 405 *errorString = "Breakpoint at specified location already exists."; 406 return; 407 } 408 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); 409 actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, UserBreakpointSource); 410 if (actualLocation) 411 *outBreakpointId = breakpointId; 412 else 413 *errorString = "Could not resolve breakpoint"; 414 } 415 416 void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointId) 417 { 418 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 419 JSONObject::iterator it = breakpointsCookie->find(breakpointId); 420 bool isAntibreakpoint = false; 421 if (it != breakpointsCookie->end()) { 422 RefPtr<JSONObject> breakpointObject = it->value->asObject(); 423 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint); 424 breakpointsCookie->remove(breakpointId); 425 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); 426 } 427 428 if (!isAntibreakpoint) 429 removeBreakpoint(breakpointId); 430 } 431 432 void InspectorDebuggerAgent::removeBreakpoint(const String& breakpointId) 433 { 434 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId); 435 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end()) 436 return; 437 for (size_t i = 0; i < debugServerBreakpointIdsIterator->value.size(); ++i) { 438 const String& debugServerBreakpointId = debugServerBreakpointIdsIterator->value[i]; 439 scriptDebugServer().removeBreakpoint(debugServerBreakpointId); 440 m_serverBreakpoints.remove(debugServerBreakpointId); 441 } 442 m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator); 443 } 444 445 void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const RefPtr<JSONObject>& location, const bool* interstateLocationOpt) 446 { 447 if (!m_continueToLocationBreakpointId.isEmpty()) { 448 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId); 449 m_continueToLocationBreakpointId = ""; 450 } 451 452 String scriptId; 453 int lineNumber; 454 int columnNumber; 455 456 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber)) 457 return; 458 459 ScriptBreakpoint breakpoint(lineNumber, columnNumber, ""); 460 m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber, asBool(interstateLocationOpt)); 461 resume(errorString); 462 } 463 464 void InspectorDebuggerAgent::getStepInPositions(ErrorString* errorString, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::Location> >& positions) 465 { 466 if (!isPaused() || m_currentCallStack.isEmpty()) { 467 *errorString = "Attempt to access callframe when debugger is not on pause"; 468 return; 469 } 470 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId); 471 if (injectedScript.isEmpty()) { 472 *errorString = "Inspected frame has gone"; 473 return; 474 } 475 476 injectedScript.getStepInPositions(errorString, m_currentCallStack, callFrameId, positions); 477 } 478 479 void InspectorDebuggerAgent::getBacktrace(ErrorString* errorString, RefPtr<Array<CallFrame> >& callFrames, RefPtr<StackTrace>& asyncStackTrace) 480 { 481 if (!assertPaused(errorString)) 482 return; 483 m_currentCallStack = scriptDebugServer().currentCallFrames(); 484 callFrames = currentCallFrames(); 485 asyncStackTrace = currentAsyncStackTrace(); 486 } 487 488 PassRefPtrWillBeRawPtr<JavaScriptCallFrame> InspectorDebuggerAgent::topCallFrameSkipUnknownSources(String* scriptURL, bool* isBlackboxed) 489 { 490 for (int index = 0; ; ++index) { 491 RefPtrWillBeRawPtr<JavaScriptCallFrame> frame = scriptDebugServer().callFrameNoScopes(index); 492 if (!frame) 493 return nullptr; 494 ScriptsMap::iterator it = m_scripts.find(String::number(frame->sourceID())); 495 if (it == m_scripts.end()) 496 continue; 497 *scriptURL = scriptSourceURL(it->value); 498 *isBlackboxed = (m_skipContentScripts && it->value.isContentScript) 499 || (m_cachedSkipStackRegExp && !scriptURL->isEmpty() && m_cachedSkipStackRegExp->match(*scriptURL) != -1); 500 return frame.release(); 501 } 502 } 503 504 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipExceptionPause() 505 { 506 if (m_steppingFromFramework) 507 return ScriptDebugListener::NoSkip; 508 509 // FIXME: Fast return: if (!m_skipContentScripts && !m_cachedSkipStackRegExp && !has_any_anti_breakpoint) return ScriptDebugListener::NoSkip; 510 511 String topFrameScriptUrl; 512 bool isBlackboxed = false; 513 RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&topFrameScriptUrl, &isBlackboxed); 514 if (!topFrame) 515 return ScriptDebugListener::NoSkip; 516 if (isBlackboxed) 517 return ScriptDebugListener::Continue; 518 519 // Match against breakpoints. 520 if (topFrameScriptUrl.isEmpty()) 521 return ScriptDebugListener::NoSkip; 522 523 // Prepare top frame parameters. 524 int topFrameLineNumber = topFrame->line(); 525 int topFrameColumnNumber = topFrame->column(); 526 527 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 528 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) { 529 RefPtr<JSONObject> breakpointObject = it->value->asObject(); 530 bool isAntibreakpoint; 531 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint); 532 if (!isAntibreakpoint) 533 continue; 534 535 int breakLineNumber; 536 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakLineNumber); 537 int breakColumnNumber; 538 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakColumnNumber); 539 540 if (breakLineNumber != topFrameLineNumber) 541 continue; 542 543 if (breakColumnNumber != -1 && breakColumnNumber != topFrameColumnNumber) 544 continue; 545 546 bool isRegex; 547 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); 548 String url; 549 breakpointObject->getString(DebuggerAgentState::url, &url); 550 if (!matches(topFrameScriptUrl, url, isRegex)) 551 continue; 552 553 return ScriptDebugListener::Continue; 554 } 555 556 return ScriptDebugListener::NoSkip; 557 } 558 559 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipStepPause() 560 { 561 if (m_steppingFromFramework) 562 return ScriptDebugListener::NoSkip; 563 // Fast return. 564 if (!m_skipContentScripts && !m_cachedSkipStackRegExp) 565 return ScriptDebugListener::NoSkip; 566 567 String scriptUrl; 568 bool isBlackboxed = false; 569 RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&scriptUrl, &isBlackboxed); 570 if (!topFrame || !isBlackboxed) 571 return ScriptDebugListener::NoSkip; 572 573 if (m_skippedStepInCount == 0) { 574 m_minFrameCountForSkip = scriptDebugServer().frameCount(); 575 m_skippedStepInCount = 1; 576 return ScriptDebugListener::StepInto; 577 } 578 579 if (m_skippedStepInCount < maxSkipStepInCount && topFrame->isAtReturn() && scriptDebugServer().frameCount() <= m_minFrameCountForSkip) 580 m_skippedStepInCount = maxSkipStepInCount; 581 582 if (m_skippedStepInCount >= maxSkipStepInCount) { 583 if (m_pausingOnNativeEvent) { 584 m_pausingOnNativeEvent = false; 585 m_skippedStepInCount = 0; 586 return ScriptDebugListener::Continue; 587 } 588 return ScriptDebugListener::StepOut; 589 } 590 591 ++m_skippedStepInCount; 592 return ScriptDebugListener::StepInto; 593 } 594 595 bool InspectorDebuggerAgent::isTopCallFrameInFramework() 596 { 597 if (!m_skipContentScripts && !m_cachedSkipStackRegExp) 598 return false; 599 600 String scriptUrl; 601 bool isBlackboxed = false; 602 RefPtrWillBeRawPtr<JavaScriptCallFrame> topFrame = topCallFrameSkipUnknownSources(&scriptUrl, &isBlackboxed); 603 return topFrame && isBlackboxed; 604 } 605 606 PassRefPtr<TypeBuilder::Debugger::Location> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint& breakpoint, BreakpointSource source) 607 { 608 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); 609 if (scriptIterator == m_scripts.end()) 610 return nullptr; 611 Script& script = scriptIterator->value; 612 if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint.lineNumber) 613 return nullptr; 614 615 int actualLineNumber; 616 int actualColumnNumber; 617 String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false); 618 if (debugServerBreakpointId.isEmpty()) 619 return nullptr; 620 621 m_serverBreakpoints.set(debugServerBreakpointId, std::make_pair(breakpointId, source)); 622 623 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId); 624 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end()) 625 m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String>()).storedValue->value.append(debugServerBreakpointId); 626 else 627 debugServerBreakpointIdsIterator->value.append(debugServerBreakpointId); 628 629 RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create() 630 .setScriptId(scriptId) 631 .setLineNumber(actualLineNumber); 632 location->setColumnNumber(actualColumnNumber); 633 return location; 634 } 635 636 void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& scriptId, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Array<blink::TypeBuilder::Page::SearchMatch> >& results) 637 { 638 ScriptsMap::iterator it = m_scripts.find(scriptId); 639 if (it != m_scripts.end()) 640 results = ContentSearchUtils::searchInTextByLines(it->value.source, query, asBool(optionalCaseSensitive), asBool(optionalIsRegex)); 641 else 642 *error = "No script for id: " + scriptId; 643 } 644 645 void InspectorDebuggerAgent::setScriptSource(ErrorString* error, RefPtr<TypeBuilder::Debugger::SetScriptSourceError>& errorData, const String& scriptId, const String& newContent, const bool* const preview, RefPtr<Array<CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<StackTrace>& asyncStackTrace) 646 { 647 if (!scriptDebugServer().setScriptSource(scriptId, newContent, asBool(preview), error, errorData, &m_currentCallStack, &result)) 648 return; 649 650 newCallFrames = currentCallFrames(); 651 asyncStackTrace = currentAsyncStackTrace(); 652 653 ScriptsMap::iterator it = m_scripts.find(scriptId); 654 if (it == m_scripts.end()) 655 return; 656 String url = it->value.url; 657 if (url.isEmpty()) 658 return; 659 if (InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent()) 660 pageAgent->addEditedResourceContent(url, newContent); 661 } 662 663 void InspectorDebuggerAgent::restartFrame(ErrorString* errorString, const String& callFrameId, RefPtr<Array<CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<StackTrace>& asyncStackTrace) 664 { 665 if (!isPaused() || m_currentCallStack.isEmpty()) { 666 *errorString = "Attempt to access callframe when debugger is not on pause"; 667 return; 668 } 669 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId); 670 if (injectedScript.isEmpty()) { 671 *errorString = "Inspected frame has gone"; 672 return; 673 } 674 675 injectedScript.restartFrame(errorString, m_currentCallStack, callFrameId, &result); 676 m_currentCallStack = scriptDebugServer().currentCallFrames(); 677 newCallFrames = currentCallFrames(); 678 asyncStackTrace = currentAsyncStackTrace(); 679 } 680 681 void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptId, String* scriptSource) 682 { 683 ScriptsMap::iterator it = m_scripts.find(scriptId); 684 if (it == m_scripts.end()) { 685 *error = "No script for id: " + scriptId; 686 return; 687 } 688 689 String url = it->value.url; 690 if (!url.isEmpty()) { 691 if (InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent()) { 692 bool success = pageAgent->getEditedResourceContent(url, scriptSource); 693 if (success) 694 return; 695 } 696 } 697 *scriptSource = it->value.source; 698 } 699 700 void InspectorDebuggerAgent::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>& details) 701 { 702 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId); 703 if (injectedScript.isEmpty()) { 704 *errorString = "Function object id is obsolete"; 705 return; 706 } 707 injectedScript.getFunctionDetails(errorString, functionId, &details); 708 } 709 710 void InspectorDebuggerAgent::getCollectionEntries(ErrorString* errorString, const String& objectId, RefPtr<TypeBuilder::Array<CollectionEntry> >& entries) 711 { 712 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(objectId); 713 if (injectedScript.isEmpty()) { 714 *errorString = "Inspected frame has gone"; 715 return; 716 } 717 injectedScript.getCollectionEntries(errorString, objectId, &entries); 718 } 719 720 void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data) 721 { 722 if (m_javaScriptPauseScheduled || isPaused()) 723 return; 724 m_breakReason = breakReason; 725 m_breakAuxData = data; 726 m_pausingOnNativeEvent = true; 727 scriptDebugServer().setPauseOnNextStatement(true); 728 } 729 730 void InspectorDebuggerAgent::cancelPauseOnNextStatement() 731 { 732 if (m_javaScriptPauseScheduled || isPaused()) 733 return; 734 clearBreakDetails(); 735 m_pausingOnNativeEvent = false; 736 scriptDebugServer().setPauseOnNextStatement(false); 737 } 738 739 void InspectorDebuggerAgent::didInstallTimer(ExecutionContext* context, int timerId, int timeout, bool singleShot) 740 { 741 if (asyncCallStackTracker().isEnabled()) 742 asyncCallStackTracker().didInstallTimer(context, timerId, singleShot, scriptDebugServer().currentCallFramesForAsyncStack()); 743 } 744 745 void InspectorDebuggerAgent::didRemoveTimer(ExecutionContext* context, int timerId) 746 { 747 if (asyncCallStackTracker().isEnabled()) 748 asyncCallStackTracker().didRemoveTimer(context, timerId); 749 } 750 751 bool InspectorDebuggerAgent::willFireTimer(ExecutionContext* context, int timerId) 752 { 753 if (asyncCallStackTracker().isEnabled()) 754 asyncCallStackTracker().willFireTimer(context, timerId); 755 return true; 756 } 757 758 void InspectorDebuggerAgent::didFireTimer() 759 { 760 if (asyncCallStackTracker().isEnabled()) 761 asyncCallStackTracker().didFireAsyncCall(); 762 cancelPauseOnNextStatement(); 763 } 764 765 void InspectorDebuggerAgent::didRequestAnimationFrame(Document* document, int callbackId) 766 { 767 if (asyncCallStackTracker().isEnabled()) 768 asyncCallStackTracker().didRequestAnimationFrame(document, callbackId, scriptDebugServer().currentCallFramesForAsyncStack()); 769 } 770 771 void InspectorDebuggerAgent::didCancelAnimationFrame(Document* document, int callbackId) 772 { 773 if (asyncCallStackTracker().isEnabled()) 774 asyncCallStackTracker().didCancelAnimationFrame(document, callbackId); 775 } 776 777 bool InspectorDebuggerAgent::willFireAnimationFrame(Document* document, int callbackId) 778 { 779 if (asyncCallStackTracker().isEnabled()) 780 asyncCallStackTracker().willFireAnimationFrame(document, callbackId); 781 return true; 782 } 783 784 void InspectorDebuggerAgent::didFireAnimationFrame() 785 { 786 if (asyncCallStackTracker().isEnabled()) 787 asyncCallStackTracker().didFireAsyncCall(); 788 } 789 790 void InspectorDebuggerAgent::didEnqueueEvent(EventTarget* eventTarget, Event* event) 791 { 792 if (asyncCallStackTracker().isEnabled()) 793 asyncCallStackTracker().didEnqueueEvent(eventTarget, event, scriptDebugServer().currentCallFramesForAsyncStack()); 794 } 795 796 void InspectorDebuggerAgent::didRemoveEvent(EventTarget* eventTarget, Event* event) 797 { 798 if (asyncCallStackTracker().isEnabled()) 799 asyncCallStackTracker().didRemoveEvent(eventTarget, event); 800 } 801 802 void InspectorDebuggerAgent::willHandleEvent(EventTarget* eventTarget, Event* event, EventListener* listener, bool useCapture) 803 { 804 if (asyncCallStackTracker().isEnabled()) 805 asyncCallStackTracker().willHandleEvent(eventTarget, event, listener, useCapture); 806 } 807 808 void InspectorDebuggerAgent::didHandleEvent() 809 { 810 if (asyncCallStackTracker().isEnabled()) 811 asyncCallStackTracker().didFireAsyncCall(); 812 cancelPauseOnNextStatement(); 813 } 814 815 void InspectorDebuggerAgent::willLoadXHR(XMLHttpRequest* xhr, ThreadableLoaderClient*, const AtomicString&, const KURL&, bool async, PassRefPtr<FormData>, const HTTPHeaderMap&, bool) 816 { 817 if (asyncCallStackTracker().isEnabled() && async) 818 asyncCallStackTracker().willLoadXHR(xhr, scriptDebugServer().currentCallFramesForAsyncStack()); 819 } 820 821 void InspectorDebuggerAgent::didDispatchXHRLoadendEvent(XMLHttpRequest* xhr) 822 { 823 if (asyncCallStackTracker().isEnabled()) 824 asyncCallStackTracker().didLoadXHR(xhr); 825 } 826 827 void InspectorDebuggerAgent::didEnqueueMutationRecord(ExecutionContext* context, MutationObserver* observer) 828 { 829 if (asyncCallStackTracker().isEnabled() && !asyncCallStackTracker().hasEnqueuedMutationRecord(context, observer)) 830 asyncCallStackTracker().didEnqueueMutationRecord(context, observer, scriptDebugServer().currentCallFramesForAsyncStack()); 831 } 832 833 void InspectorDebuggerAgent::didClearAllMutationRecords(ExecutionContext* context, MutationObserver* observer) 834 { 835 if (asyncCallStackTracker().isEnabled()) 836 asyncCallStackTracker().didClearAllMutationRecords(context, observer); 837 } 838 839 void InspectorDebuggerAgent::willDeliverMutationRecords(ExecutionContext* context, MutationObserver* observer) 840 { 841 if (asyncCallStackTracker().isEnabled()) 842 asyncCallStackTracker().willDeliverMutationRecords(context, observer); 843 } 844 845 void InspectorDebuggerAgent::didDeliverMutationRecords() 846 { 847 if (asyncCallStackTracker().isEnabled()) 848 asyncCallStackTracker().didFireAsyncCall(); 849 } 850 851 void InspectorDebuggerAgent::didPostExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task) 852 { 853 if (asyncCallStackTracker().isEnabled() && !task->taskNameForInstrumentation().isEmpty()) 854 asyncCallStackTracker().didPostExecutionContextTask(context, task, scriptDebugServer().currentCallFramesForAsyncStack()); 855 } 856 857 void InspectorDebuggerAgent::didKillAllExecutionContextTasks(ExecutionContext* context) 858 { 859 if (asyncCallStackTracker().isEnabled()) 860 asyncCallStackTracker().didKillAllExecutionContextTasks(context); 861 } 862 863 void InspectorDebuggerAgent::willPerformExecutionContextTask(ExecutionContext* context, ExecutionContextTask* task) 864 { 865 if (asyncCallStackTracker().isEnabled()) 866 asyncCallStackTracker().willPerformExecutionContextTask(context, task); 867 } 868 869 void InspectorDebuggerAgent::didPerformExecutionContextTask() 870 { 871 if (asyncCallStackTracker().isEnabled()) 872 asyncCallStackTracker().didFireAsyncCall(); 873 } 874 875 int InspectorDebuggerAgent::traceAsyncOperationStarting(ExecutionContext* context, const String& operationName, int prevOperationId) 876 { 877 if (!asyncCallStackTracker().isEnabled()) 878 return 0; 879 if (prevOperationId) 880 asyncCallStackTracker().traceAsyncOperationCompleted(context, prevOperationId); 881 return asyncCallStackTracker().traceAsyncOperationStarting(context, operationName, scriptDebugServer().currentCallFramesForAsyncStack()); 882 } 883 884 void InspectorDebuggerAgent::traceAsyncOperationCompleted(ExecutionContext* context, int operationId) 885 { 886 if (asyncCallStackTracker().isEnabled()) 887 asyncCallStackTracker().traceAsyncOperationCompleted(context, operationId); 888 } 889 890 void InspectorDebuggerAgent::traceAsyncOperationCompletedCallbackStarting(ExecutionContext* context, int operationId) 891 { 892 if (!asyncCallStackTracker().isEnabled()) 893 return; 894 asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId); 895 asyncCallStackTracker().traceAsyncOperationCompleted(context, operationId); 896 } 897 898 void InspectorDebuggerAgent::traceAsyncCallbackStarting(ExecutionContext* context, int operationId) 899 { 900 if (asyncCallStackTracker().isEnabled()) 901 asyncCallStackTracker().traceAsyncCallbackStarting(context, operationId); 902 } 903 904 void InspectorDebuggerAgent::traceAsyncCallbackCompleted() 905 { 906 if (asyncCallStackTracker().isEnabled()) 907 asyncCallStackTracker().didFireAsyncCall(); 908 } 909 910 bool InspectorDebuggerAgent::v8AsyncTaskEventsEnabled() const 911 { 912 return asyncCallStackTracker().isEnabled(); 913 } 914 915 void InspectorDebuggerAgent::didReceiveV8AsyncTaskEvent(ExecutionContext* context, const String& eventType, const String& eventName, int id) 916 { 917 ASSERT(asyncCallStackTracker().isEnabled()); 918 if (eventType == v8AsyncTaskEventEnqueue) 919 asyncCallStackTracker().didEnqueueV8AsyncTask(context, eventName, id, scriptDebugServer().currentCallFramesForAsyncStack()); 920 else if (eventType == v8AsyncTaskEventWillHandle) 921 asyncCallStackTracker().willHandleV8AsyncTask(context, eventName, id); 922 else if (eventType == v8AsyncTaskEventDidHandle) 923 asyncCallStackTracker().didFireAsyncCall(); 924 else 925 ASSERT_NOT_REACHED(); 926 } 927 928 bool InspectorDebuggerAgent::v8PromiseEventsEnabled() const 929 { 930 return promiseTracker().isEnabled() || (m_listener && m_listener->canPauseOnPromiseEvent()); 931 } 932 933 void InspectorDebuggerAgent::didReceiveV8PromiseEvent(ScriptState* scriptState, v8::Handle<v8::Object> promise, v8::Handle<v8::Value> parentPromise, int status) 934 { 935 if (promiseTracker().isEnabled()) 936 promiseTracker().didReceiveV8PromiseEvent(scriptState, promise, parentPromise, status); 937 if (!m_listener) 938 return; 939 if (!parentPromise.IsEmpty() && parentPromise->IsObject()) 940 return; 941 if (status < 0) 942 m_listener->didRejectPromise(); 943 else if (status > 0) 944 m_listener->didResolvePromise(); 945 else 946 m_listener->didCreatePromise(); 947 } 948 949 void InspectorDebuggerAgent::pause(ErrorString*) 950 { 951 if (m_javaScriptPauseScheduled || isPaused()) 952 return; 953 clearBreakDetails(); 954 m_javaScriptPauseScheduled = true; 955 scriptDebugServer().setPauseOnNextStatement(true); 956 } 957 958 void InspectorDebuggerAgent::resume(ErrorString* errorString) 959 { 960 if (!assertPaused(errorString)) 961 return; 962 m_debuggerStepScheduled = false; 963 m_steppingFromFramework = false; 964 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 965 scriptDebugServer().continueProgram(); 966 } 967 968 void InspectorDebuggerAgent::stepOver(ErrorString* errorString) 969 { 970 if (!assertPaused(errorString)) 971 return; 972 m_debuggerStepScheduled = true; 973 m_steppingFromFramework = isTopCallFrameInFramework(); 974 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 975 scriptDebugServer().stepOverStatement(); 976 } 977 978 void InspectorDebuggerAgent::stepInto(ErrorString* errorString) 979 { 980 if (!assertPaused(errorString)) 981 return; 982 m_debuggerStepScheduled = true; 983 m_steppingFromFramework = isTopCallFrameInFramework(); 984 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 985 scriptDebugServer().stepIntoStatement(); 986 if (m_listener) 987 m_listener->stepInto(); 988 } 989 990 void InspectorDebuggerAgent::stepOut(ErrorString* errorString) 991 { 992 if (!assertPaused(errorString)) 993 return; 994 m_debuggerStepScheduled = true; 995 m_steppingFromFramework = isTopCallFrameInFramework(); 996 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 997 scriptDebugServer().stepOutOfFunction(); 998 } 999 1000 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState) 1001 { 1002 ScriptDebugServer::PauseOnExceptionsState pauseState; 1003 if (stringPauseState == "none") 1004 pauseState = ScriptDebugServer::DontPauseOnExceptions; 1005 else if (stringPauseState == "all") 1006 pauseState = ScriptDebugServer::PauseOnAllExceptions; 1007 else if (stringPauseState == "uncaught") 1008 pauseState = ScriptDebugServer::PauseOnUncaughtExceptions; 1009 else { 1010 *errorString = "Unknown pause on exceptions mode: " + stringPauseState; 1011 return; 1012 } 1013 setPauseOnExceptionsImpl(errorString, pauseState); 1014 } 1015 1016 void InspectorDebuggerAgent::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState) 1017 { 1018 scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState)); 1019 if (scriptDebugServer().pauseOnExceptionsState() != pauseState) 1020 *errorString = "Internal error. Could not change pause on exceptions state"; 1021 else 1022 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, pauseState); 1023 } 1024 1025 void InspectorDebuggerAgent::evaluateOnCallFrame(ErrorString* errorString, const String& callFrameId, const String& expression, const String* const objectGroup, const bool* const includeCommandLineAPI, const bool* const doNotPauseOnExceptionsAndMuteConsole, const bool* const returnByValue, const bool* generatePreview, RefPtr<RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown, RefPtr<TypeBuilder::Debugger::ExceptionDetails>& exceptionDetails) 1026 { 1027 if (!isPaused() || m_currentCallStack.isEmpty()) { 1028 *errorString = "Attempt to access callframe when debugger is not on pause"; 1029 return; 1030 } 1031 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId); 1032 if (injectedScript.isEmpty()) { 1033 *errorString = "Inspected frame has gone"; 1034 return; 1035 } 1036 1037 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState(); 1038 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { 1039 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions) 1040 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions); 1041 muteConsole(); 1042 } 1043 1044 Vector<ScriptValue> asyncCallStacks; 1045 const AsyncCallStackTracker::AsyncCallChain* asyncChain = asyncCallStackTracker().isEnabled() ? asyncCallStackTracker().currentAsyncCallChain() : 0; 1046 if (asyncChain) { 1047 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = asyncChain->callStacks(); 1048 asyncCallStacks.resize(callStacks.size()); 1049 AsyncCallStackTracker::AsyncCallStackVector::const_iterator it = callStacks.begin(); 1050 for (size_t i = 0; it != callStacks.end(); ++it, ++i) 1051 asyncCallStacks[i] = (*it)->callFrames(); 1052 } 1053 1054 injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, asyncCallStacks, callFrameId, expression, objectGroup ? *objectGroup : "", asBool(includeCommandLineAPI), asBool(returnByValue), asBool(generatePreview), &result, wasThrown, &exceptionDetails); 1055 // V8 doesn't generate afterCompile event when it's in debugger therefore there is no content of evaluated scripts on frontend 1056 // therefore contents of the stack does not provide necessary information 1057 if (exceptionDetails) 1058 exceptionDetails->setStackTrace(TypeBuilder::Array<TypeBuilder::Console::CallFrame>::create()); 1059 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { 1060 unmuteConsole(); 1061 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState) 1062 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState); 1063 } 1064 } 1065 1066 void InspectorDebuggerAgent::compileScript(ErrorString* errorString, const String& expression, const String& sourceURL, const int* executionContextId, TypeBuilder::OptOutput<ScriptId>* scriptId, RefPtr<ExceptionDetails>& exceptionDetails) 1067 { 1068 InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId); 1069 if (injectedScript.isEmpty()) { 1070 *errorString = "Inspected frame has gone"; 1071 return; 1072 } 1073 1074 String scriptIdValue; 1075 String exceptionDetailsText; 1076 int lineNumberValue = 0; 1077 int columnNumberValue = 0; 1078 RefPtrWillBeRawPtr<ScriptCallStack> stackTraceValue; 1079 scriptDebugServer().compileScript(injectedScript.scriptState(), expression, sourceURL, &scriptIdValue, &exceptionDetailsText, &lineNumberValue, &columnNumberValue, &stackTraceValue); 1080 if (!scriptIdValue && !exceptionDetailsText) { 1081 *errorString = "Script compilation failed"; 1082 return; 1083 } 1084 *scriptId = scriptIdValue; 1085 if (!scriptIdValue.isEmpty()) 1086 return; 1087 1088 exceptionDetails = ExceptionDetails::create().setText(exceptionDetailsText); 1089 exceptionDetails->setLine(lineNumberValue); 1090 exceptionDetails->setColumn(columnNumberValue); 1091 if (stackTraceValue && stackTraceValue->size() > 0) 1092 exceptionDetails->setStackTrace(stackTraceValue->buildInspectorArray()); 1093 } 1094 1095 void InspectorDebuggerAgent::runScript(ErrorString* errorString, const ScriptId& scriptId, const int* executionContextId, const String* const objectGroup, const bool* const doNotPauseOnExceptionsAndMuteConsole, RefPtr<RemoteObject>& result, RefPtr<ExceptionDetails>& exceptionDetails) 1096 { 1097 InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId); 1098 if (injectedScript.isEmpty()) { 1099 *errorString = "Inspected frame has gone"; 1100 return; 1101 } 1102 1103 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState(); 1104 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { 1105 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions) 1106 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions); 1107 muteConsole(); 1108 } 1109 1110 ScriptValue value; 1111 bool wasThrownValue; 1112 String exceptionDetailsText; 1113 int lineNumberValue = 0; 1114 int columnNumberValue = 0; 1115 RefPtrWillBeRawPtr<ScriptCallStack> stackTraceValue; 1116 scriptDebugServer().runScript(injectedScript.scriptState(), scriptId, &value, &wasThrownValue, &exceptionDetailsText, &lineNumberValue, &columnNumberValue, &stackTraceValue); 1117 if (value.isEmpty()) { 1118 *errorString = "Script execution failed"; 1119 return; 1120 } 1121 result = injectedScript.wrapObject(value, objectGroup ? *objectGroup : ""); 1122 if (wasThrownValue) { 1123 exceptionDetails = ExceptionDetails::create().setText(exceptionDetailsText); 1124 exceptionDetails->setLine(lineNumberValue); 1125 exceptionDetails->setColumn(columnNumberValue); 1126 if (stackTraceValue && stackTraceValue->size() > 0) 1127 exceptionDetails->setStackTrace(stackTraceValue->buildInspectorArray()); 1128 } 1129 1130 if (asBool(doNotPauseOnExceptionsAndMuteConsole)) { 1131 unmuteConsole(); 1132 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState) 1133 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState); 1134 } 1135 } 1136 1137 void InspectorDebuggerAgent::setOverlayMessage(ErrorString*, const String*) 1138 { 1139 } 1140 1141 void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, int scopeNumber, const String& variableName, const RefPtr<JSONObject>& newValue, const String* callFrameId, const String* functionObjectId) 1142 { 1143 InjectedScript injectedScript; 1144 if (callFrameId) { 1145 if (!isPaused() || m_currentCallStack.isEmpty()) { 1146 *errorString = "Attempt to access callframe when debugger is not on pause"; 1147 return; 1148 } 1149 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*callFrameId); 1150 if (injectedScript.isEmpty()) { 1151 *errorString = "Inspected frame has gone"; 1152 return; 1153 } 1154 } else if (functionObjectId) { 1155 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*functionObjectId); 1156 if (injectedScript.isEmpty()) { 1157 *errorString = "Function object id cannot be resolved"; 1158 return; 1159 } 1160 } else { 1161 *errorString = "Either call frame or function object must be specified"; 1162 return; 1163 } 1164 String newValueString = newValue->toJSONString(); 1165 1166 injectedScript.setVariableValue(errorString, m_currentCallStack, callFrameId, functionObjectId, scopeNumber, variableName, newValueString); 1167 } 1168 1169 void InspectorDebuggerAgent::skipStackFrames(ErrorString* errorString, const String* pattern, const bool* skipContentScripts) 1170 { 1171 OwnPtr<ScriptRegexp> compiled; 1172 String patternValue = pattern ? *pattern : ""; 1173 if (!patternValue.isEmpty()) { 1174 compiled = compileSkipCallFramePattern(patternValue); 1175 if (!compiled) { 1176 *errorString = "Invalid regular expression"; 1177 return; 1178 } 1179 } 1180 m_state->setString(DebuggerAgentState::skipStackPattern, patternValue); 1181 m_cachedSkipStackRegExp = compiled.release(); 1182 m_skipContentScripts = asBool(skipContentScripts); 1183 m_state->setBoolean(DebuggerAgentState::skipContentScripts, m_skipContentScripts); 1184 } 1185 1186 void InspectorDebuggerAgent::setAsyncCallStackDepth(ErrorString*, int depth) 1187 { 1188 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, depth); 1189 asyncCallStackTracker().setAsyncCallStackDepth(depth); 1190 } 1191 1192 void InspectorDebuggerAgent::enablePromiseTracker(ErrorString*) 1193 { 1194 m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, true); 1195 promiseTracker().setEnabled(true); 1196 } 1197 1198 void InspectorDebuggerAgent::disablePromiseTracker(ErrorString*) 1199 { 1200 m_state->setBoolean(DebuggerAgentState::promiseTrackerEnabled, false); 1201 promiseTracker().setEnabled(false); 1202 } 1203 1204 void InspectorDebuggerAgent::getPromises(ErrorString* errorString, RefPtr<Array<PromiseDetails> >& promises) 1205 { 1206 if (!promiseTracker().isEnabled()) { 1207 *errorString = "Promise tracking is disabled"; 1208 return; 1209 } 1210 promises = promiseTracker().promises(); 1211 } 1212 1213 void InspectorDebuggerAgent::getPromiseById(ErrorString* errorString, int promiseId, const String* objectGroup, RefPtr<RemoteObject>& promise) 1214 { 1215 if (!promiseTracker().isEnabled()) { 1216 *errorString = "Promise tracking is disabled"; 1217 return; 1218 } 1219 ScriptValue value = promiseTracker().promiseById(promiseId); 1220 if (value.isEmpty()) { 1221 *errorString = "Promise with specified ID not found."; 1222 return; 1223 } 1224 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(value.scriptState()); 1225 promise = injectedScript.wrapObject(value, objectGroup ? *objectGroup : ""); 1226 } 1227 1228 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText) 1229 { 1230 if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) { 1231 RefPtr<JSONObject> directive = JSONObject::create(); 1232 directive->setString("directiveText", directiveText); 1233 breakProgram(InspectorFrontend::Debugger::Reason::CSPViolation, directive.release()); 1234 } 1235 } 1236 1237 PassRefPtr<Array<CallFrame> > InspectorDebuggerAgent::currentCallFrames() 1238 { 1239 if (!m_pausedScriptState || m_currentCallStack.isEmpty()) 1240 return Array<CallFrame>::create(); 1241 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState.get()); 1242 if (injectedScript.isEmpty()) { 1243 ASSERT_NOT_REACHED(); 1244 return Array<CallFrame>::create(); 1245 } 1246 return injectedScript.wrapCallFrames(m_currentCallStack, 0); 1247 } 1248 1249 PassRefPtr<StackTrace> InspectorDebuggerAgent::currentAsyncStackTrace() 1250 { 1251 if (!m_pausedScriptState || !asyncCallStackTracker().isEnabled()) 1252 return nullptr; 1253 const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker().currentAsyncCallChain(); 1254 if (!chain) 1255 return nullptr; 1256 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callStacks(); 1257 if (callStacks.isEmpty()) 1258 return nullptr; 1259 RefPtr<StackTrace> result; 1260 int asyncOrdinal = callStacks.size(); 1261 for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it, --asyncOrdinal) { 1262 ScriptValue callFrames = (*it)->callFrames(); 1263 ScriptState* scriptState = callFrames.scriptState(); 1264 InjectedScript injectedScript = scriptState ? m_injectedScriptManager->injectedScriptFor(scriptState) : InjectedScript(); 1265 if (injectedScript.isEmpty()) { 1266 result.clear(); 1267 continue; 1268 } 1269 RefPtr<StackTrace> next = StackTrace::create() 1270 .setCallFrames(injectedScript.wrapCallFrames(callFrames, asyncOrdinal)) 1271 .release(); 1272 next->setDescription((*it)->description()); 1273 if (result) 1274 next->setAsyncStackTrace(result.release()); 1275 result.swap(next); 1276 } 1277 return result.release(); 1278 } 1279 1280 static PassRefPtrWillBeRawPtr<ScriptCallStack> toScriptCallStack(JavaScriptCallFrame* callFrame) 1281 { 1282 Vector<ScriptCallFrame> frames; 1283 for (; callFrame; callFrame = callFrame->caller()) { 1284 StringBuilder stringBuilder; 1285 stringBuilder.appendNumber(callFrame->sourceID()); 1286 String scriptId = stringBuilder.toString(); 1287 // FIXME(WK62725): Debugger line/column are 0-based, while console ones are 1-based. 1288 int line = callFrame->line() + 1; 1289 int column = callFrame->column() + 1; 1290 frames.append(ScriptCallFrame(callFrame->functionName(), scriptId, callFrame->scriptName(), line, column)); 1291 } 1292 return ScriptCallStack::create(frames); 1293 } 1294 1295 PassRefPtrWillBeRawPtr<ScriptAsyncCallStack> InspectorDebuggerAgent::currentAsyncStackTraceForConsole() 1296 { 1297 if (!asyncCallStackTracker().isEnabled()) 1298 return nullptr; 1299 const AsyncCallStackTracker::AsyncCallChain* chain = asyncCallStackTracker().currentAsyncCallChain(); 1300 if (!chain) 1301 return nullptr; 1302 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callStacks(); 1303 if (callStacks.isEmpty()) 1304 return nullptr; 1305 RefPtrWillBeRawPtr<ScriptAsyncCallStack> result = nullptr; 1306 for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it) { 1307 RefPtrWillBeRawPtr<JavaScriptCallFrame> callFrame = ScriptDebugServer::toJavaScriptCallFrameUnsafe((*it)->callFrames()); 1308 if (!callFrame) 1309 break; 1310 result = ScriptAsyncCallStack::create((*it)->description(), toScriptCallStack(callFrame.get()), result.release()); 1311 } 1312 return result.release(); 1313 } 1314 1315 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script, CompileResult compileResult) 1316 { 1317 bool hasSyntaxError = compileResult != CompileSuccess; 1318 if (hasSyntaxError) { 1319 bool deprecated; 1320 String sourceMapURL = ContentSearchUtils::findSourceMapURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated); 1321 if (!sourceMapURL.isEmpty()) 1322 return sourceMapURL; 1323 } 1324 1325 if (!script.sourceMappingURL.isEmpty()) 1326 return script.sourceMappingURL; 1327 1328 if (script.url.isEmpty()) 1329 return String(); 1330 1331 InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent(); 1332 if (!pageAgent) 1333 return String(); 1334 return pageAgent->resourceSourceMapURL(script.url); 1335 } 1336 1337 // ScriptDebugListener functions 1338 1339 void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& parsedScript, CompileResult compileResult) 1340 { 1341 Script script = parsedScript; 1342 const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0; 1343 1344 bool hasSyntaxError = compileResult != CompileSuccess; 1345 if (hasSyntaxError) { 1346 bool deprecated; 1347 script.sourceURL = ContentSearchUtils::findSourceURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated); 1348 } 1349 1350 bool hasSourceURL = !script.sourceURL.isEmpty(); 1351 String scriptURL = hasSourceURL ? script.sourceURL : script.url; 1352 1353 String sourceMapURL = sourceMapURLForScript(script, compileResult); 1354 String* sourceMapURLParam = sourceMapURL.isNull() ? 0 : &sourceMapURL; 1355 1356 bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : 0; 1357 if (!hasSyntaxError) 1358 m_frontend->scriptParsed(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam); 1359 else 1360 m_frontend->scriptFailedToParse(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam); 1361 1362 m_scripts.set(scriptId, script); 1363 1364 if (scriptURL.isEmpty() || hasSyntaxError) 1365 return; 1366 1367 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 1368 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) { 1369 RefPtr<JSONObject> breakpointObject = it->value->asObject(); 1370 bool isAntibreakpoint; 1371 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint); 1372 if (isAntibreakpoint) 1373 continue; 1374 bool isRegex; 1375 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); 1376 String url; 1377 breakpointObject->getString(DebuggerAgentState::url, &url); 1378 if (!matches(scriptURL, url, isRegex)) 1379 continue; 1380 ScriptBreakpoint breakpoint; 1381 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakpoint.lineNumber); 1382 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakpoint.columnNumber); 1383 breakpointObject->getString(DebuggerAgentState::condition, &breakpoint.condition); 1384 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(it->key, scriptId, breakpoint, UserBreakpointSource); 1385 if (location) 1386 m_frontend->breakpointResolved(it->key, location); 1387 } 1388 } 1389 1390 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& callFrames, const ScriptValue& exception, const Vector<String>& hitBreakpoints) 1391 { 1392 ScriptDebugListener::SkipPauseRequest result; 1393 if (callFrames.isEmpty()) 1394 result = ScriptDebugListener::Continue; // Skip pauses inside V8 internal scripts and on syntax errors. 1395 else if (m_javaScriptPauseScheduled) 1396 result = ScriptDebugListener::NoSkip; // Don't skip explicit pause requests from front-end. 1397 else if (m_skipAllPauses) 1398 result = ScriptDebugListener::Continue; 1399 else if (!hitBreakpoints.isEmpty()) 1400 result = ScriptDebugListener::NoSkip; // Don't skip explicit breakpoints even if set in frameworks. 1401 else if (!exception.isEmpty()) 1402 result = shouldSkipExceptionPause(); 1403 else if (m_debuggerStepScheduled || m_pausingOnNativeEvent) 1404 result = shouldSkipStepPause(); 1405 else 1406 result = ScriptDebugListener::NoSkip; 1407 1408 if (result != ScriptDebugListener::NoSkip) 1409 return result; 1410 1411 ASSERT(scriptState && !m_pausedScriptState); 1412 m_pausedScriptState = scriptState; 1413 m_currentCallStack = callFrames; 1414 1415 if (!exception.isEmpty()) { 1416 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); 1417 if (!injectedScript.isEmpty()) { 1418 m_breakReason = InspectorFrontend::Debugger::Reason::Exception; 1419 m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors(); 1420 // m_breakAuxData might be null after this. 1421 } 1422 } 1423 1424 RefPtr<Array<String> > hitBreakpointIds = Array<String>::create(); 1425 1426 for (Vector<String>::const_iterator i = hitBreakpoints.begin(); i != hitBreakpoints.end(); ++i) { 1427 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator breakpointIterator = m_serverBreakpoints.find(*i); 1428 if (breakpointIterator != m_serverBreakpoints.end()) { 1429 const String& localId = breakpointIterator->value.first; 1430 hitBreakpointIds->addItem(localId); 1431 1432 BreakpointSource source = breakpointIterator->value.second; 1433 if (m_breakReason == InspectorFrontend::Debugger::Reason::Other && source == DebugCommandBreakpointSource) 1434 m_breakReason = InspectorFrontend::Debugger::Reason::DebugCommand; 1435 } 1436 } 1437 1438 m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData, hitBreakpointIds, currentAsyncStackTrace()); 1439 m_javaScriptPauseScheduled = false; 1440 m_debuggerStepScheduled = false; 1441 m_steppingFromFramework = false; 1442 m_pausingOnNativeEvent = false; 1443 m_skippedStepInCount = 0; 1444 1445 if (!m_continueToLocationBreakpointId.isEmpty()) { 1446 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId); 1447 m_continueToLocationBreakpointId = ""; 1448 } 1449 if (m_listener) 1450 m_listener->didPause(); 1451 return result; 1452 } 1453 1454 void InspectorDebuggerAgent::didContinue() 1455 { 1456 m_pausedScriptState = nullptr; 1457 m_currentCallStack = ScriptValue(); 1458 clearBreakDetails(); 1459 m_frontend->resumed(); 1460 } 1461 1462 bool InspectorDebuggerAgent::canBreakProgram() 1463 { 1464 return scriptDebugServer().canBreakProgram(); 1465 } 1466 1467 void InspectorDebuggerAgent::breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data) 1468 { 1469 if (m_skipAllPauses) 1470 return; 1471 m_breakReason = breakReason; 1472 m_breakAuxData = data; 1473 m_debuggerStepScheduled = false; 1474 m_steppingFromFramework = false; 1475 m_pausingOnNativeEvent = false; 1476 scriptDebugServer().breakProgram(); 1477 } 1478 1479 void InspectorDebuggerAgent::clear() 1480 { 1481 m_pausedScriptState = nullptr; 1482 m_currentCallStack = ScriptValue(); 1483 m_scripts.clear(); 1484 m_breakpointIdToDebugServerBreakpointIds.clear(); 1485 asyncCallStackTracker().clear(); 1486 promiseTracker().clear(); 1487 m_continueToLocationBreakpointId = String(); 1488 clearBreakDetails(); 1489 m_javaScriptPauseScheduled = false; 1490 m_debuggerStepScheduled = false; 1491 m_steppingFromFramework = false; 1492 m_pausingOnNativeEvent = false; 1493 ErrorString error; 1494 setOverlayMessage(&error, 0); 1495 } 1496 1497 bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString) 1498 { 1499 if (!m_pausedScriptState) { 1500 *errorString = "Can only perform operation while paused."; 1501 return false; 1502 } 1503 return true; 1504 } 1505 1506 void InspectorDebuggerAgent::clearBreakDetails() 1507 { 1508 m_breakReason = InspectorFrontend::Debugger::Reason::Other; 1509 m_breakAuxData = nullptr; 1510 } 1511 1512 void InspectorDebuggerAgent::setBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source, const String& condition) 1513 { 1514 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumber, source); 1515 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); 1516 resolveBreakpoint(breakpointId, scriptId, breakpoint, source); 1517 } 1518 1519 void InspectorDebuggerAgent::removeBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source) 1520 { 1521 removeBreakpoint(generateBreakpointId(scriptId, lineNumber, columnNumber, source)); 1522 } 1523 1524 void InspectorDebuggerAgent::reset() 1525 { 1526 m_scripts.clear(); 1527 m_breakpointIdToDebugServerBreakpointIds.clear(); 1528 asyncCallStackTracker().clear(); 1529 promiseTracker().clear(); 1530 if (m_frontend) 1531 m_frontend->globalObjectCleared(); 1532 } 1533 1534 void InspectorDebuggerAgent::trace(Visitor* visitor) 1535 { 1536 visitor->trace(m_injectedScriptManager); 1537 visitor->trace(m_listener); 1538 visitor->trace(m_asyncCallStackTracker); 1539 #if ENABLE(OILPAN) 1540 visitor->trace(m_promiseTracker); 1541 #endif 1542 InspectorBaseAgent::trace(visitor); 1543 } 1544 1545 } // namespace blink 1546