1 /* 2 * Copyright (C) 2010 Apple Inc. All rights reserved. 3 * Copyright (C) 2010-2011 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 #include "core/inspector/JavaScriptCallFrame.h" 33 34 #include "bindings/v8/ScriptDebugServer.h" 35 #include "bindings/v8/ScriptObject.h" 36 #include "bindings/v8/ScriptRegexp.h" 37 #include "bindings/v8/ScriptSourceCode.h" 38 #include "core/dom/Document.h" 39 #include "core/fetch/Resource.h" 40 #include "core/inspector/ContentSearchUtils.h" 41 #include "core/inspector/InjectedScriptManager.h" 42 #include "core/inspector/InspectorPageAgent.h" 43 #include "core/inspector/InspectorState.h" 44 #include "core/inspector/InstrumentingAgents.h" 45 #include "core/inspector/ScriptArguments.h" 46 #include "core/inspector/ScriptCallStack.h" 47 #include "platform/JSONValues.h" 48 #include "wtf/text/WTFString.h" 49 50 using WebCore::TypeBuilder::Array; 51 using WebCore::TypeBuilder::Debugger::BreakpointId; 52 using WebCore::TypeBuilder::Debugger::CallFrame; 53 using WebCore::TypeBuilder::Debugger::FunctionDetails; 54 using WebCore::TypeBuilder::Debugger::ScriptId; 55 using WebCore::TypeBuilder::Debugger::StackTrace; 56 using WebCore::TypeBuilder::Runtime::RemoteObject; 57 58 namespace WebCore { 59 60 namespace DebuggerAgentState { 61 static const char debuggerEnabled[] = "debuggerEnabled"; 62 static const char javaScriptBreakpoints[] = "javaScriptBreakopints"; 63 static const char pauseOnExceptionsState[] = "pauseOnExceptionsState"; 64 static const char asyncCallStackDepth[] = "asyncCallStackDepth"; 65 66 // Breakpoint properties. 67 static const char url[] = "url"; 68 static const char isRegex[] = "isRegex"; 69 static const char lineNumber[] = "lineNumber"; 70 static const char columnNumber[] = "columnNumber"; 71 static const char condition[] = "condition"; 72 static const char isAnti[] = "isAnti"; 73 static const char skipStackPattern[] = "skipStackPattern"; 74 static const char skipAllPauses[] = "skipAllPauses"; 75 static const char skipAllPausesExpiresOnReload[] = "skipAllPausesExpiresOnReload"; 76 77 }; 78 79 static const int numberOfStepsBeforeStepOut = 10; 80 81 const char InspectorDebuggerAgent::backtraceObjectGroup[] = "backtrace"; 82 83 static String breakpointIdSuffix(InspectorDebuggerAgent::BreakpointSource source) 84 { 85 switch (source) { 86 case InspectorDebuggerAgent::UserBreakpointSource: 87 break; 88 case InspectorDebuggerAgent::DebugCommandBreakpointSource: 89 return ":debug"; 90 case InspectorDebuggerAgent::MonitorCommandBreakpointSource: 91 return ":monitor"; 92 } 93 return String(); 94 } 95 96 static String generateBreakpointId(const String& scriptId, int lineNumber, int columnNumber, InspectorDebuggerAgent::BreakpointSource source) 97 { 98 return scriptId + ':' + String::number(lineNumber) + ':' + String::number(columnNumber) + breakpointIdSuffix(source); 99 } 100 101 InspectorDebuggerAgent::InspectorDebuggerAgent(InstrumentingAgents* instrumentingAgents, InspectorCompositeState* inspectorState, InjectedScriptManager* injectedScriptManager) 102 : InspectorBaseAgent<InspectorDebuggerAgent>("Debugger", instrumentingAgents, inspectorState) 103 , m_injectedScriptManager(injectedScriptManager) 104 , m_frontend(0) 105 , m_pausedScriptState(0) 106 , m_javaScriptPauseScheduled(false) 107 , m_listener(0) 108 , m_skipStepInCount(numberOfStepsBeforeStepOut) 109 , m_skipAllPauses(false) 110 { 111 // FIXME: make breakReason optional so that there was no need to init it with "other". 112 clearBreakDetails(); 113 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions); 114 } 115 116 InspectorDebuggerAgent::~InspectorDebuggerAgent() 117 { 118 ASSERT(!m_instrumentingAgents->inspectorDebuggerAgent()); 119 } 120 121 void InspectorDebuggerAgent::enable() 122 { 123 m_instrumentingAgents->setInspectorDebuggerAgent(this); 124 125 // FIXME(WK44513): breakpoints activated flag should be synchronized between all front-ends 126 scriptDebugServer().setBreakpointsActivated(true); 127 startListeningScriptDebugServer(); 128 129 if (m_listener) 130 m_listener->debuggerWasEnabled(); 131 } 132 133 void InspectorDebuggerAgent::disable() 134 { 135 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, JSONObject::create()); 136 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, ScriptDebugServer::DontPauseOnExceptions); 137 m_state->setString(DebuggerAgentState::skipStackPattern, ""); 138 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, 0); 139 m_instrumentingAgents->setInspectorDebuggerAgent(0); 140 141 stopListeningScriptDebugServer(); 142 scriptDebugServer().clearBreakpoints(); 143 scriptDebugServer().clearCompiledScripts(); 144 clear(); 145 146 if (m_listener) 147 m_listener->debuggerWasDisabled(); 148 149 m_skipAllPauses = false; 150 } 151 152 bool InspectorDebuggerAgent::enabled() 153 { 154 return m_state->getBoolean(DebuggerAgentState::debuggerEnabled); 155 } 156 157 void InspectorDebuggerAgent::enable(ErrorString*) 158 { 159 if (enabled()) 160 return; 161 162 enable(); 163 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); 164 165 ASSERT(m_frontend); 166 } 167 168 void InspectorDebuggerAgent::disable(ErrorString*) 169 { 170 if (!enabled()) 171 return; 172 173 disable(); 174 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); 175 } 176 177 static PassOwnPtr<ScriptRegexp> compileSkipCallFramePattern(String patternText) 178 { 179 if (patternText.isEmpty()) 180 return nullptr; 181 OwnPtr<ScriptRegexp> result = adoptPtr(new ScriptRegexp(patternText, TextCaseSensitive)); 182 if (!result->isValid()) 183 result.clear(); 184 return result.release(); 185 } 186 187 void InspectorDebuggerAgent::restore() 188 { 189 if (enabled()) { 190 m_frontend->globalObjectCleared(); 191 enable(); 192 long pauseState = m_state->getLong(DebuggerAgentState::pauseOnExceptionsState); 193 String error; 194 setPauseOnExceptionsImpl(&error, pauseState); 195 m_cachedSkipStackRegExp = compileSkipCallFramePattern(m_state->getString(DebuggerAgentState::skipStackPattern)); 196 m_skipAllPauses = m_state->getBoolean(DebuggerAgentState::skipAllPauses); 197 if (m_skipAllPauses && m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) { 198 m_skipAllPauses = false; 199 m_state->setBoolean(DebuggerAgentState::skipAllPauses, false); 200 } 201 m_asyncCallStackTracker.setAsyncCallStackDepth(m_state->getLong(DebuggerAgentState::asyncCallStackDepth)); 202 } 203 } 204 205 void InspectorDebuggerAgent::setFrontend(InspectorFrontend* frontend) 206 { 207 m_frontend = frontend->debugger(); 208 } 209 210 void InspectorDebuggerAgent::clearFrontend() 211 { 212 m_frontend = 0; 213 214 if (!enabled()) 215 return; 216 217 disable(); 218 219 // FIXME: due to m_state->mute() hack in InspectorController, debuggerEnabled is actually set to false only 220 // in InspectorState, but not in cookie. That's why after navigation debuggerEnabled will be true, 221 // but after front-end re-open it will still be false. 222 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); 223 } 224 225 void InspectorDebuggerAgent::setBreakpointsActive(ErrorString*, bool active) 226 { 227 scriptDebugServer().setBreakpointsActivated(active); 228 } 229 230 void InspectorDebuggerAgent::setSkipAllPauses(ErrorString*, bool skipped, const bool* untilReload) 231 { 232 m_skipAllPauses = skipped; 233 bool untilReloadValue = untilReload && *untilReload; 234 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses); 235 m_state->setBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload, untilReloadValue); 236 } 237 238 void InspectorDebuggerAgent::pageDidCommitLoad() 239 { 240 if (m_state->getBoolean(DebuggerAgentState::skipAllPausesExpiresOnReload)) { 241 m_skipAllPauses = false; 242 m_state->setBoolean(DebuggerAgentState::skipAllPauses, m_skipAllPauses); 243 } 244 } 245 246 bool InspectorDebuggerAgent::isPaused() 247 { 248 return scriptDebugServer().isPaused(); 249 } 250 251 bool InspectorDebuggerAgent::runningNestedMessageLoop() 252 { 253 return scriptDebugServer().runningNestedMessageLoop(); 254 } 255 256 void InspectorDebuggerAgent::addMessageToConsole(MessageSource source, MessageType type) 257 { 258 if (source == ConsoleAPIMessageSource && type == AssertMessageType && scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) 259 breakProgram(InspectorFrontend::Debugger::Reason::Assert, 0); 260 } 261 262 void InspectorDebuggerAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel, const String&, PassRefPtr<ScriptCallStack>, unsigned long) 263 { 264 addMessageToConsole(source, type); 265 } 266 267 void InspectorDebuggerAgent::addMessageToConsole(MessageSource source, MessageType type, MessageLevel, const String&, ScriptState*, PassRefPtr<ScriptArguments>, unsigned long) 268 { 269 addMessageToConsole(source, type); 270 } 271 272 String InspectorDebuggerAgent::preprocessEventListener(Frame* frame, const String& source, const String& url, const String& functionName) 273 { 274 return scriptDebugServer().preprocessEventListener(frame, source, url, functionName); 275 } 276 277 PassOwnPtr<ScriptSourceCode> InspectorDebuggerAgent::preprocess(Frame* frame, const ScriptSourceCode& sourceCode) 278 { 279 return scriptDebugServer().preprocess(frame, sourceCode); 280 } 281 282 static PassRefPtr<JSONObject> buildObjectForBreakpointCookie(const String& url, int lineNumber, int columnNumber, const String& condition, bool isRegex, bool isAnti) 283 { 284 RefPtr<JSONObject> breakpointObject = JSONObject::create(); 285 breakpointObject->setString(DebuggerAgentState::url, url); 286 breakpointObject->setNumber(DebuggerAgentState::lineNumber, lineNumber); 287 breakpointObject->setNumber(DebuggerAgentState::columnNumber, columnNumber); 288 breakpointObject->setString(DebuggerAgentState::condition, condition); 289 breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex); 290 breakpointObject->setBoolean(DebuggerAgentState::isAnti, isAnti); 291 return breakpointObject; 292 } 293 294 static bool matches(const String& url, const String& pattern, bool isRegex) 295 { 296 if (isRegex) { 297 ScriptRegexp regex(pattern, TextCaseSensitive); 298 return regex.match(url) != -1; 299 } 300 return url == pattern; 301 } 302 303 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) 304 { 305 locations = Array<TypeBuilder::Debugger::Location>::create(); 306 if (!optionalURL == !optionalURLRegex) { 307 *errorString = "Either url or urlRegex must be specified."; 308 return; 309 } 310 311 bool isAntiBreakpointValue = isAntiBreakpoint && *isAntiBreakpoint; 312 313 String url = optionalURL ? *optionalURL : *optionalURLRegex; 314 int columnNumber; 315 if (optionalColumnNumber) { 316 columnNumber = *optionalColumnNumber; 317 if (columnNumber < 0) { 318 *errorString = "Incorrect column number"; 319 return; 320 } 321 } else { 322 columnNumber = isAntiBreakpointValue ? -1 : 0; 323 } 324 String condition = optionalCondition ? *optionalCondition : ""; 325 bool isRegex = optionalURLRegex; 326 327 String breakpointId = (isRegex ? "/" + url + "/" : url) + ':' + String::number(lineNumber) + ':' + String::number(columnNumber); 328 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 329 if (breakpointsCookie->find(breakpointId) != breakpointsCookie->end()) { 330 *errorString = "Breakpoint at specified location already exists."; 331 return; 332 } 333 334 breakpointsCookie->setObject(breakpointId, buildObjectForBreakpointCookie(url, lineNumber, columnNumber, condition, isRegex, isAntiBreakpointValue)); 335 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); 336 337 if (!isAntiBreakpointValue) { 338 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); 339 for (ScriptsMap::iterator it = m_scripts.begin(); it != m_scripts.end(); ++it) { 340 if (!matches(it->value.url, url, isRegex)) 341 continue; 342 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(breakpointId, it->key, breakpoint, UserBreakpointSource); 343 if (location) 344 locations->addItem(location); 345 } 346 } 347 *outBreakpointId = breakpointId; 348 } 349 350 static bool parseLocation(ErrorString* errorString, PassRefPtr<JSONObject> location, String* scriptId, int* lineNumber, int* columnNumber) 351 { 352 if (!location->getString("scriptId", scriptId) || !location->getNumber("lineNumber", lineNumber)) { 353 // FIXME: replace with input validation. 354 *errorString = "scriptId and lineNumber are required."; 355 return false; 356 } 357 *columnNumber = 0; 358 location->getNumber("columnNumber", columnNumber); 359 return true; 360 } 361 362 void InspectorDebuggerAgent::setBreakpoint(ErrorString* errorString, const RefPtr<JSONObject>& location, const String* const optionalCondition, BreakpointId* outBreakpointId, RefPtr<TypeBuilder::Debugger::Location>& actualLocation) 363 { 364 String scriptId; 365 int lineNumber; 366 int columnNumber; 367 368 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber)) 369 return; 370 371 String condition = optionalCondition ? *optionalCondition : emptyString(); 372 373 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumber, UserBreakpointSource); 374 if (m_breakpointIdToDebugServerBreakpointIds.find(breakpointId) != m_breakpointIdToDebugServerBreakpointIds.end()) { 375 *errorString = "Breakpoint at specified location already exists."; 376 return; 377 } 378 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); 379 actualLocation = resolveBreakpoint(breakpointId, scriptId, breakpoint, UserBreakpointSource); 380 if (actualLocation) 381 *outBreakpointId = breakpointId; 382 else 383 *errorString = "Could not resolve breakpoint"; 384 } 385 386 void InspectorDebuggerAgent::removeBreakpoint(ErrorString*, const String& breakpointId) 387 { 388 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 389 JSONObject::iterator it = breakpointsCookie->find(breakpointId); 390 bool isAntibreakpoint = false; 391 if (it != breakpointsCookie->end()) { 392 RefPtr<JSONObject> breakpointObject = it->value->asObject(); 393 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint); 394 breakpointsCookie->remove(breakpointId); 395 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, breakpointsCookie); 396 } 397 398 if (!isAntibreakpoint) 399 removeBreakpoint(breakpointId); 400 } 401 402 void InspectorDebuggerAgent::removeBreakpoint(const String& breakpointId) 403 { 404 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId); 405 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end()) 406 return; 407 for (size_t i = 0; i < debugServerBreakpointIdsIterator->value.size(); ++i) { 408 const String& debugServerBreakpointId = debugServerBreakpointIdsIterator->value[i]; 409 scriptDebugServer().removeBreakpoint(debugServerBreakpointId); 410 m_serverBreakpoints.remove(debugServerBreakpointId); 411 } 412 m_breakpointIdToDebugServerBreakpointIds.remove(debugServerBreakpointIdsIterator); 413 } 414 415 void InspectorDebuggerAgent::continueToLocation(ErrorString* errorString, const RefPtr<JSONObject>& location, const bool* interstateLocationOpt) 416 { 417 bool interstateLocation = interstateLocationOpt ? *interstateLocationOpt : false; 418 if (!m_continueToLocationBreakpointId.isEmpty()) { 419 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId); 420 m_continueToLocationBreakpointId = ""; 421 } 422 423 String scriptId; 424 int lineNumber; 425 int columnNumber; 426 427 if (!parseLocation(errorString, location, &scriptId, &lineNumber, &columnNumber)) 428 return; 429 430 ScriptBreakpoint breakpoint(lineNumber, columnNumber, ""); 431 m_continueToLocationBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &lineNumber, &columnNumber, interstateLocation); 432 resume(errorString); 433 } 434 435 void InspectorDebuggerAgent::getStepInPositions(ErrorString* errorString, const String& callFrameId, RefPtr<Array<TypeBuilder::Debugger::Location> >& positions) 436 { 437 if (!isPaused() || m_currentCallStack.hasNoValue()) { 438 *errorString = "Attempt to access callframe when debugger is not on pause"; 439 return; 440 } 441 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId); 442 if (injectedScript.hasNoValue()) { 443 *errorString = "Inspected frame has gone"; 444 return; 445 } 446 447 injectedScript.getStepInPositions(errorString, m_currentCallStack, callFrameId, positions); 448 } 449 450 void InspectorDebuggerAgent::getBacktrace(ErrorString* errorString, RefPtr<Array<CallFrame> >& callFrames, RefPtr<StackTrace>& asyncStackTrace) 451 { 452 if (!assertPaused(errorString)) 453 return; 454 m_currentCallStack = scriptDebugServer().currentCallFrames(); 455 callFrames = currentCallFrames(); 456 asyncStackTrace = currentAsyncStackTrace(); 457 } 458 459 String InspectorDebuggerAgent::scriptURL(JavaScriptCallFrame* frame) 460 { 461 String scriptIdString = String::number(frame->sourceID()); 462 ScriptsMap::iterator it = m_scripts.find(scriptIdString); 463 if (it == m_scripts.end()) 464 return String(); 465 return it->value.url; 466 } 467 468 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipExceptionPause(RefPtr<JavaScriptCallFrame>& topFrame) 469 { 470 if (m_skipAllPauses) 471 return ScriptDebugListener::Continue; 472 if (!topFrame) 473 return ScriptDebugListener::NoSkip; 474 475 String topFrameScriptUrl = scriptURL(topFrame.get()); 476 if (m_cachedSkipStackRegExp && !topFrameScriptUrl.isEmpty() && m_cachedSkipStackRegExp->match(topFrameScriptUrl) != -1) 477 return ScriptDebugListener::Continue; 478 479 // Match against breakpoints. 480 if (topFrameScriptUrl.isEmpty()) 481 return ScriptDebugListener::NoSkip; 482 483 // Prepare top frame parameters. 484 int topFrameLineNumber = topFrame->line(); 485 int topFrameColumnNumber = topFrame->column(); 486 487 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 488 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) { 489 RefPtr<JSONObject> breakpointObject = it->value->asObject(); 490 bool isAntibreakpoint; 491 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint); 492 if (!isAntibreakpoint) 493 continue; 494 495 int breakLineNumber; 496 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakLineNumber); 497 int breakColumnNumber; 498 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakColumnNumber); 499 500 if (breakLineNumber != topFrameLineNumber) 501 continue; 502 503 if (breakColumnNumber != -1 && breakColumnNumber != topFrameColumnNumber) 504 continue; 505 506 bool isRegex; 507 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); 508 String url; 509 breakpointObject->getString(DebuggerAgentState::url, &url); 510 if (!matches(topFrameScriptUrl, url, isRegex)) 511 continue; 512 513 return ScriptDebugListener::Continue; 514 } 515 516 return ScriptDebugListener::NoSkip; 517 } 518 519 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipBreakpointPause(RefPtr<JavaScriptCallFrame>& topFrame) 520 { 521 if (m_skipAllPauses) 522 return ScriptDebugListener::Continue; 523 if (!topFrame) 524 return ScriptDebugListener::NoSkip; 525 return ScriptDebugListener::NoSkip; 526 } 527 528 ScriptDebugListener::SkipPauseRequest InspectorDebuggerAgent::shouldSkipStepPause(RefPtr<JavaScriptCallFrame>& topFrame) 529 { 530 if (m_skipAllPauses) 531 return ScriptDebugListener::Continue; 532 if (!topFrame) 533 return ScriptDebugListener::NoSkip; 534 535 if (m_cachedSkipStackRegExp) { 536 String scriptUrl = scriptURL(topFrame.get()); 537 if (!scriptUrl.isEmpty() && m_cachedSkipStackRegExp->match(scriptUrl) != -1) { 538 if (m_skipStepInCount > 0) { 539 --m_skipStepInCount; 540 return ScriptDebugListener::StepInto; 541 } 542 return ScriptDebugListener::StepOut; 543 } 544 } 545 return ScriptDebugListener::NoSkip; 546 } 547 548 PassRefPtr<TypeBuilder::Debugger::Location> InspectorDebuggerAgent::resolveBreakpoint(const String& breakpointId, const String& scriptId, const ScriptBreakpoint& breakpoint, BreakpointSource source) 549 { 550 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId); 551 if (scriptIterator == m_scripts.end()) 552 return 0; 553 Script& script = scriptIterator->value; 554 if (breakpoint.lineNumber < script.startLine || script.endLine < breakpoint.lineNumber) 555 return 0; 556 557 int actualLineNumber; 558 int actualColumnNumber; 559 String debugServerBreakpointId = scriptDebugServer().setBreakpoint(scriptId, breakpoint, &actualLineNumber, &actualColumnNumber, false); 560 if (debugServerBreakpointId.isEmpty()) 561 return 0; 562 563 m_serverBreakpoints.set(debugServerBreakpointId, std::make_pair(breakpointId, source)); 564 565 BreakpointIdToDebugServerBreakpointIdsMap::iterator debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.find(breakpointId); 566 if (debugServerBreakpointIdsIterator == m_breakpointIdToDebugServerBreakpointIds.end()) 567 debugServerBreakpointIdsIterator = m_breakpointIdToDebugServerBreakpointIds.set(breakpointId, Vector<String>()).iterator; 568 debugServerBreakpointIdsIterator->value.append(debugServerBreakpointId); 569 570 RefPtr<TypeBuilder::Debugger::Location> location = TypeBuilder::Debugger::Location::create() 571 .setScriptId(scriptId) 572 .setLineNumber(actualLineNumber); 573 location->setColumnNumber(actualColumnNumber); 574 return location; 575 } 576 577 static PassRefPtr<JSONObject> scriptToInspectorObject(ScriptObject scriptObject) 578 { 579 if (scriptObject.hasNoValue()) 580 return 0; 581 RefPtr<JSONValue> value = scriptObject.toJSONValue(scriptObject.scriptState()); 582 if (!value) 583 return 0; 584 return value->asObject(); 585 } 586 587 void InspectorDebuggerAgent::searchInContent(ErrorString* error, const String& scriptId, const String& query, const bool* const optionalCaseSensitive, const bool* const optionalIsRegex, RefPtr<Array<WebCore::TypeBuilder::Page::SearchMatch> >& results) 588 { 589 bool isRegex = optionalIsRegex ? *optionalIsRegex : false; 590 bool caseSensitive = optionalCaseSensitive ? *optionalCaseSensitive : false; 591 592 ScriptsMap::iterator it = m_scripts.find(scriptId); 593 if (it != m_scripts.end()) 594 results = ContentSearchUtils::searchInTextByLines(it->value.source, query, caseSensitive, isRegex); 595 else 596 *error = "No script for id: " + scriptId; 597 } 598 599 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) 600 { 601 bool previewOnly = preview && *preview; 602 ScriptObject resultObject; 603 if (!scriptDebugServer().setScriptSource(scriptId, newContent, previewOnly, error, errorData, &m_currentCallStack, &resultObject)) 604 return; 605 newCallFrames = currentCallFrames(); 606 asyncStackTrace = currentAsyncStackTrace(); 607 RefPtr<JSONObject> object = scriptToInspectorObject(resultObject); 608 if (object) 609 result = object; 610 } 611 612 void InspectorDebuggerAgent::restartFrame(ErrorString* errorString, const String& callFrameId, RefPtr<Array<CallFrame> >& newCallFrames, RefPtr<JSONObject>& result, RefPtr<StackTrace>& asyncStackTrace) 613 { 614 if (!isPaused() || m_currentCallStack.hasNoValue()) { 615 *errorString = "Attempt to access callframe when debugger is not on pause"; 616 return; 617 } 618 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId); 619 if (injectedScript.hasNoValue()) { 620 *errorString = "Inspected frame has gone"; 621 return; 622 } 623 624 injectedScript.restartFrame(errorString, m_currentCallStack, callFrameId, &result); 625 m_currentCallStack = scriptDebugServer().currentCallFrames(); 626 newCallFrames = currentCallFrames(); 627 asyncStackTrace = currentAsyncStackTrace(); 628 } 629 630 void InspectorDebuggerAgent::getScriptSource(ErrorString* error, const String& scriptId, String* scriptSource) 631 { 632 ScriptsMap::iterator it = m_scripts.find(scriptId); 633 if (it != m_scripts.end()) 634 *scriptSource = it->value.source; 635 else 636 *error = "No script for id: " + scriptId; 637 } 638 639 void InspectorDebuggerAgent::getFunctionDetails(ErrorString* errorString, const String& functionId, RefPtr<FunctionDetails>& details) 640 { 641 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(functionId); 642 if (injectedScript.hasNoValue()) { 643 *errorString = "Function object id is obsolete"; 644 return; 645 } 646 injectedScript.getFunctionDetails(errorString, functionId, &details); 647 } 648 649 void InspectorDebuggerAgent::schedulePauseOnNextStatement(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data) 650 { 651 if (m_javaScriptPauseScheduled) 652 return; 653 m_breakReason = breakReason; 654 m_breakAuxData = data; 655 scriptDebugServer().setPauseOnNextStatement(true); 656 } 657 658 void InspectorDebuggerAgent::cancelPauseOnNextStatement() 659 { 660 if (m_javaScriptPauseScheduled) 661 return; 662 clearBreakDetails(); 663 scriptDebugServer().setPauseOnNextStatement(false); 664 } 665 666 void InspectorDebuggerAgent::didInstallTimer(ExecutionContext* context, int timerId, int timeout, bool singleShot) 667 { 668 if (m_asyncCallStackTracker.isEnabled()) 669 m_asyncCallStackTracker.didInstallTimer(context, timerId, singleShot, scriptDebugServer().currentCallFrames()); 670 } 671 672 void InspectorDebuggerAgent::didRemoveTimer(ExecutionContext* context, int timerId) 673 { 674 m_asyncCallStackTracker.didRemoveTimer(context, timerId); 675 } 676 677 bool InspectorDebuggerAgent::willFireTimer(ExecutionContext* context, int timerId) 678 { 679 m_asyncCallStackTracker.willFireTimer(context, timerId); 680 return true; 681 } 682 683 void InspectorDebuggerAgent::didFireTimer() 684 { 685 m_asyncCallStackTracker.didFireAsyncCall(); 686 cancelPauseOnNextStatement(); 687 } 688 689 void InspectorDebuggerAgent::didRequestAnimationFrame(Document* document, int callbackId) 690 { 691 if (m_asyncCallStackTracker.isEnabled()) 692 m_asyncCallStackTracker.didRequestAnimationFrame(document, callbackId, scriptDebugServer().currentCallFrames()); 693 } 694 695 void InspectorDebuggerAgent::didCancelAnimationFrame(Document* document, int callbackId) 696 { 697 m_asyncCallStackTracker.didCancelAnimationFrame(document, callbackId); 698 } 699 700 bool InspectorDebuggerAgent::willFireAnimationFrame(Document* document, int callbackId) 701 { 702 m_asyncCallStackTracker.willFireAnimationFrame(document, callbackId); 703 return true; 704 } 705 706 void InspectorDebuggerAgent::didFireAnimationFrame() 707 { 708 m_asyncCallStackTracker.didFireAsyncCall(); 709 } 710 711 void InspectorDebuggerAgent::didHandleEvent() 712 { 713 cancelPauseOnNextStatement(); 714 } 715 716 void InspectorDebuggerAgent::pause(ErrorString*) 717 { 718 if (m_javaScriptPauseScheduled) 719 return; 720 clearBreakDetails(); 721 scriptDebugServer().setPauseOnNextStatement(true); 722 m_javaScriptPauseScheduled = true; 723 } 724 725 void InspectorDebuggerAgent::resume(ErrorString* errorString) 726 { 727 if (!assertPaused(errorString)) 728 return; 729 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 730 scriptDebugServer().continueProgram(); 731 } 732 733 ScriptValue InspectorDebuggerAgent::resolveCallFrame(ErrorString* errorString, const String* callFrameId) 734 { 735 if (!callFrameId) 736 return ScriptValue(); 737 if (!isPaused() || m_currentCallStack.hasNoValue()) { 738 *errorString = "Attempt to access callframe when debugger is not on pause"; 739 return ScriptValue(); 740 } 741 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*callFrameId); 742 if (injectedScript.hasNoValue()) { 743 *errorString = "Inspected frame has gone"; 744 return ScriptValue(); 745 } 746 return injectedScript.findCallFrameById(errorString, m_currentCallStack, *callFrameId); 747 } 748 749 void InspectorDebuggerAgent::stepOver(ErrorString* errorString, const String* callFrameId) 750 { 751 if (!assertPaused(errorString)) 752 return; 753 ScriptValue frame = resolveCallFrame(errorString, callFrameId); 754 if (!errorString->isEmpty()) 755 return; 756 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 757 scriptDebugServer().stepOverStatement(frame); 758 } 759 760 void InspectorDebuggerAgent::stepInto(ErrorString* errorString) 761 { 762 if (!assertPaused(errorString)) 763 return; 764 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 765 scriptDebugServer().stepIntoStatement(); 766 if (m_listener) 767 m_listener->stepInto(); 768 } 769 770 void InspectorDebuggerAgent::stepOut(ErrorString* errorString, const String* callFrameId) 771 { 772 if (!assertPaused(errorString)) 773 return; 774 ScriptValue frame = resolveCallFrame(errorString, callFrameId); 775 if (!errorString->isEmpty()) 776 return; 777 m_injectedScriptManager->releaseObjectGroup(InspectorDebuggerAgent::backtraceObjectGroup); 778 scriptDebugServer().stepOutOfFunction(frame); 779 } 780 781 void InspectorDebuggerAgent::setPauseOnExceptions(ErrorString* errorString, const String& stringPauseState) 782 { 783 ScriptDebugServer::PauseOnExceptionsState pauseState; 784 if (stringPauseState == "none") 785 pauseState = ScriptDebugServer::DontPauseOnExceptions; 786 else if (stringPauseState == "all") 787 pauseState = ScriptDebugServer::PauseOnAllExceptions; 788 else if (stringPauseState == "uncaught") 789 pauseState = ScriptDebugServer::PauseOnUncaughtExceptions; 790 else { 791 *errorString = "Unknown pause on exceptions mode: " + stringPauseState; 792 return; 793 } 794 setPauseOnExceptionsImpl(errorString, pauseState); 795 } 796 797 void InspectorDebuggerAgent::setPauseOnExceptionsImpl(ErrorString* errorString, int pauseState) 798 { 799 scriptDebugServer().setPauseOnExceptionsState(static_cast<ScriptDebugServer::PauseOnExceptionsState>(pauseState)); 800 if (scriptDebugServer().pauseOnExceptionsState() != pauseState) 801 *errorString = "Internal error. Could not change pause on exceptions state"; 802 else 803 m_state->setLong(DebuggerAgentState::pauseOnExceptionsState, pauseState); 804 } 805 806 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) 807 { 808 if (!isPaused() || m_currentCallStack.hasNoValue()) { 809 *errorString = "Attempt to access callframe when debugger is not on pause"; 810 return; 811 } 812 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptForObjectId(callFrameId); 813 if (injectedScript.hasNoValue()) { 814 *errorString = "Inspected frame has gone"; 815 return; 816 } 817 818 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState(); 819 if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) { 820 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions) 821 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions); 822 muteConsole(); 823 } 824 825 injectedScript.evaluateOnCallFrame(errorString, m_currentCallStack, callFrameId, expression, objectGroup ? *objectGroup : "", includeCommandLineAPI ? *includeCommandLineAPI : false, returnByValue ? *returnByValue : false, generatePreview ? *generatePreview : false, &result, wasThrown); 826 827 if (doNotPauseOnExceptionsAndMuteConsole ? *doNotPauseOnExceptionsAndMuteConsole : false) { 828 unmuteConsole(); 829 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState) 830 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState); 831 } 832 } 833 834 void InspectorDebuggerAgent::compileScript(ErrorString* errorString, const String& expression, const String& sourceURL, TypeBuilder::OptOutput<ScriptId>* scriptId, TypeBuilder::OptOutput<String>* syntaxErrorMessage) 835 { 836 InjectedScript injectedScript = injectedScriptForEval(errorString, 0); 837 if (injectedScript.hasNoValue()) { 838 *errorString = "Inspected frame has gone"; 839 return; 840 } 841 842 String scriptIdValue; 843 String exceptionMessage; 844 scriptDebugServer().compileScript(injectedScript.scriptState(), expression, sourceURL, &scriptIdValue, &exceptionMessage); 845 if (!scriptIdValue && !exceptionMessage) { 846 *errorString = "Script compilation failed"; 847 return; 848 } 849 *syntaxErrorMessage = exceptionMessage; 850 *scriptId = scriptIdValue; 851 } 852 853 void InspectorDebuggerAgent::runScript(ErrorString* errorString, const ScriptId& scriptId, const int* executionContextId, const String* const objectGroup, const bool* const doNotPauseOnExceptionsAndMuteConsole, RefPtr<RemoteObject>& result, TypeBuilder::OptOutput<bool>* wasThrown) 854 { 855 InjectedScript injectedScript = injectedScriptForEval(errorString, executionContextId); 856 if (injectedScript.hasNoValue()) { 857 *errorString = "Inspected frame has gone"; 858 return; 859 } 860 861 ScriptDebugServer::PauseOnExceptionsState previousPauseOnExceptionsState = scriptDebugServer().pauseOnExceptionsState(); 862 if (doNotPauseOnExceptionsAndMuteConsole && *doNotPauseOnExceptionsAndMuteConsole) { 863 if (previousPauseOnExceptionsState != ScriptDebugServer::DontPauseOnExceptions) 864 scriptDebugServer().setPauseOnExceptionsState(ScriptDebugServer::DontPauseOnExceptions); 865 muteConsole(); 866 } 867 868 ScriptValue value; 869 bool wasThrownValue; 870 String exceptionMessage; 871 scriptDebugServer().runScript(injectedScript.scriptState(), scriptId, &value, &wasThrownValue, &exceptionMessage); 872 *wasThrown = wasThrownValue; 873 if (value.hasNoValue()) { 874 *errorString = "Script execution failed"; 875 return; 876 } 877 result = injectedScript.wrapObject(value, objectGroup ? *objectGroup : ""); 878 if (wasThrownValue) 879 result->setDescription(exceptionMessage); 880 881 if (doNotPauseOnExceptionsAndMuteConsole && *doNotPauseOnExceptionsAndMuteConsole) { 882 unmuteConsole(); 883 if (scriptDebugServer().pauseOnExceptionsState() != previousPauseOnExceptionsState) 884 scriptDebugServer().setPauseOnExceptionsState(previousPauseOnExceptionsState); 885 } 886 } 887 888 void InspectorDebuggerAgent::setOverlayMessage(ErrorString*, const String*) 889 { 890 } 891 892 void InspectorDebuggerAgent::setVariableValue(ErrorString* errorString, int scopeNumber, const String& variableName, const RefPtr<JSONObject>& newValue, const String* callFrameId, const String* functionObjectId) 893 { 894 InjectedScript injectedScript; 895 if (callFrameId) { 896 if (!isPaused() || m_currentCallStack.hasNoValue()) { 897 *errorString = "Attempt to access callframe when debugger is not on pause"; 898 return; 899 } 900 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*callFrameId); 901 if (injectedScript.hasNoValue()) { 902 *errorString = "Inspected frame has gone"; 903 return; 904 } 905 } else if (functionObjectId) { 906 injectedScript = m_injectedScriptManager->injectedScriptForObjectId(*functionObjectId); 907 if (injectedScript.hasNoValue()) { 908 *errorString = "Function object id cannot be resolved"; 909 return; 910 } 911 } else { 912 *errorString = "Either call frame or function object must be specified"; 913 return; 914 } 915 String newValueString = newValue->toJSONString(); 916 917 injectedScript.setVariableValue(errorString, m_currentCallStack, callFrameId, functionObjectId, scopeNumber, variableName, newValueString); 918 } 919 920 void InspectorDebuggerAgent::skipStackFrames(ErrorString* errorString, const String* pattern) 921 { 922 OwnPtr<ScriptRegexp> compiled; 923 String patternValue = pattern ? *pattern : ""; 924 if (!patternValue.isEmpty()) { 925 compiled = compileSkipCallFramePattern(patternValue); 926 if (!compiled) { 927 *errorString = "Invalid regular expression"; 928 return; 929 } 930 } 931 m_state->setString(DebuggerAgentState::skipStackPattern, patternValue); 932 m_cachedSkipStackRegExp = compiled.release(); 933 } 934 935 void InspectorDebuggerAgent::setAsyncCallStackDepth(ErrorString*, int depth) 936 { 937 m_state->setLong(DebuggerAgentState::asyncCallStackDepth, depth); 938 m_asyncCallStackTracker.setAsyncCallStackDepth(depth); 939 } 940 941 void InspectorDebuggerAgent::scriptExecutionBlockedByCSP(const String& directiveText) 942 { 943 if (scriptDebugServer().pauseOnExceptionsState() != ScriptDebugServer::DontPauseOnExceptions) { 944 RefPtr<JSONObject> directive = JSONObject::create(); 945 directive->setString("directiveText", directiveText); 946 breakProgram(InspectorFrontend::Debugger::Reason::CSPViolation, directive.release()); 947 } 948 } 949 950 PassRefPtr<Array<CallFrame> > InspectorDebuggerAgent::currentCallFrames() 951 { 952 if (!m_pausedScriptState || m_currentCallStack.hasNoValue()) 953 return Array<CallFrame>::create(); 954 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState); 955 if (injectedScript.hasNoValue()) { 956 ASSERT_NOT_REACHED(); 957 return Array<CallFrame>::create(); 958 } 959 return injectedScript.wrapCallFrames(m_currentCallStack); 960 } 961 962 PassRefPtr<StackTrace> InspectorDebuggerAgent::currentAsyncStackTrace() 963 { 964 if (!m_pausedScriptState || !m_asyncCallStackTracker.isEnabled()) 965 return 0; 966 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(m_pausedScriptState); 967 if (injectedScript.hasNoValue()) { 968 ASSERT_NOT_REACHED(); 969 return 0; 970 } 971 const AsyncCallStackTracker::AsyncCallChain* chain = m_asyncCallStackTracker.currentAsyncCallChain(); 972 if (!chain) 973 return 0; 974 const AsyncCallStackTracker::AsyncCallStackVector& callStacks = chain->callStacks(); 975 if (callStacks.isEmpty()) 976 return 0; 977 RefPtr<StackTrace> result; 978 for (AsyncCallStackTracker::AsyncCallStackVector::const_reverse_iterator it = callStacks.rbegin(); it != callStacks.rend(); ++it) { 979 RefPtr<StackTrace> next = StackTrace::create() 980 .setCallFrames(injectedScript.wrapCallFrames((*it)->callFrames())) 981 .release(); 982 next->setDescription((*it)->description()); 983 if (result) 984 next->setAsyncStackTrace(result.release()); 985 result.swap(next); 986 } 987 return result.release(); 988 } 989 990 String InspectorDebuggerAgent::sourceMapURLForScript(const Script& script) 991 { 992 bool deprecated; 993 String sourceMapURL = ContentSearchUtils::findSourceMapURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated); 994 if (!sourceMapURL.isEmpty()) { 995 // FIXME: add deprecated console message here. 996 return sourceMapURL; 997 } 998 999 if (script.url.isEmpty()) 1000 return String(); 1001 1002 InspectorPageAgent* pageAgent = m_instrumentingAgents->inspectorPageAgent(); 1003 if (!pageAgent) 1004 return String(); 1005 return pageAgent->resourceSourceMapURL(script.url); 1006 } 1007 1008 // JavaScriptDebugListener functions 1009 1010 void InspectorDebuggerAgent::didParseSource(const String& scriptId, const Script& script) 1011 { 1012 // Don't send script content to the front end until it's really needed. 1013 const bool* isContentScript = script.isContentScript ? &script.isContentScript : 0; 1014 String sourceMapURL = sourceMapURLForScript(script); 1015 String* sourceMapURLParam = sourceMapURL.isNull() ? 0 : &sourceMapURL; 1016 String sourceURL; 1017 if (!script.startLine && !script.startColumn) { 1018 bool deprecated; 1019 sourceURL = ContentSearchUtils::findSourceURL(script.source, ContentSearchUtils::JavaScriptMagicComment, &deprecated); 1020 // FIXME: add deprecated console message here. 1021 } 1022 bool hasSourceURL = !sourceURL.isEmpty(); 1023 String scriptURL = hasSourceURL ? sourceURL : script.url; 1024 bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : 0; 1025 m_frontend->scriptParsed(scriptId, scriptURL, script.startLine, script.startColumn, script.endLine, script.endColumn, isContentScript, sourceMapURLParam, hasSourceURLParam); 1026 1027 m_scripts.set(scriptId, script); 1028 1029 if (scriptURL.isEmpty()) 1030 return; 1031 1032 RefPtr<JSONObject> breakpointsCookie = m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); 1033 for (JSONObject::iterator it = breakpointsCookie->begin(); it != breakpointsCookie->end(); ++it) { 1034 RefPtr<JSONObject> breakpointObject = it->value->asObject(); 1035 bool isAntibreakpoint; 1036 breakpointObject->getBoolean(DebuggerAgentState::isAnti, &isAntibreakpoint); 1037 if (isAntibreakpoint) 1038 continue; 1039 bool isRegex; 1040 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex); 1041 String url; 1042 breakpointObject->getString(DebuggerAgentState::url, &url); 1043 if (!matches(scriptURL, url, isRegex)) 1044 continue; 1045 ScriptBreakpoint breakpoint; 1046 breakpointObject->getNumber(DebuggerAgentState::lineNumber, &breakpoint.lineNumber); 1047 breakpointObject->getNumber(DebuggerAgentState::columnNumber, &breakpoint.columnNumber); 1048 breakpointObject->getString(DebuggerAgentState::condition, &breakpoint.condition); 1049 RefPtr<TypeBuilder::Debugger::Location> location = resolveBreakpoint(it->key, scriptId, breakpoint, UserBreakpointSource); 1050 if (location) 1051 m_frontend->breakpointResolved(it->key, location); 1052 } 1053 } 1054 1055 void InspectorDebuggerAgent::failedToParseSource(const String& url, const String& data, int firstLine, int errorLine, const String& errorMessage) 1056 { 1057 m_frontend->scriptFailedToParse(url, data, firstLine, errorLine, errorMessage); 1058 } 1059 1060 void InspectorDebuggerAgent::didPause(ScriptState* scriptState, const ScriptValue& callFrames, const ScriptValue& exception, const Vector<String>& hitBreakpoints) 1061 { 1062 ASSERT(scriptState && !m_pausedScriptState); 1063 m_pausedScriptState = scriptState; 1064 m_currentCallStack = callFrames; 1065 1066 m_skipStepInCount = numberOfStepsBeforeStepOut; 1067 1068 if (!exception.hasNoValue()) { 1069 InjectedScript injectedScript = m_injectedScriptManager->injectedScriptFor(scriptState); 1070 if (!injectedScript.hasNoValue()) { 1071 m_breakReason = InspectorFrontend::Debugger::Reason::Exception; 1072 m_breakAuxData = injectedScript.wrapObject(exception, InspectorDebuggerAgent::backtraceObjectGroup)->openAccessors(); 1073 // m_breakAuxData might be null after this. 1074 } 1075 } 1076 1077 RefPtr<Array<String> > hitBreakpointIds = Array<String>::create(); 1078 1079 for (Vector<String>::const_iterator i = hitBreakpoints.begin(); i != hitBreakpoints.end(); ++i) { 1080 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator breakpointIterator = m_serverBreakpoints.find(*i); 1081 if (breakpointIterator != m_serverBreakpoints.end()) { 1082 const String& localId = breakpointIterator->value.first; 1083 hitBreakpointIds->addItem(localId); 1084 1085 BreakpointSource source = breakpointIterator->value.second; 1086 if (m_breakReason == InspectorFrontend::Debugger::Reason::Other && source == DebugCommandBreakpointSource) 1087 m_breakReason = InspectorFrontend::Debugger::Reason::DebugCommand; 1088 } 1089 } 1090 1091 m_frontend->paused(currentCallFrames(), m_breakReason, m_breakAuxData, hitBreakpointIds, currentAsyncStackTrace()); 1092 m_javaScriptPauseScheduled = false; 1093 1094 if (!m_continueToLocationBreakpointId.isEmpty()) { 1095 scriptDebugServer().removeBreakpoint(m_continueToLocationBreakpointId); 1096 m_continueToLocationBreakpointId = ""; 1097 } 1098 if (m_listener) 1099 m_listener->didPause(); 1100 } 1101 1102 void InspectorDebuggerAgent::didContinue() 1103 { 1104 m_pausedScriptState = 0; 1105 m_currentCallStack = ScriptValue(); 1106 clearBreakDetails(); 1107 m_frontend->resumed(); 1108 } 1109 1110 bool InspectorDebuggerAgent::canBreakProgram() 1111 { 1112 return scriptDebugServer().canBreakProgram(); 1113 } 1114 1115 void InspectorDebuggerAgent::breakProgram(InspectorFrontend::Debugger::Reason::Enum breakReason, PassRefPtr<JSONObject> data) 1116 { 1117 if (m_skipAllPauses) 1118 return; 1119 m_breakReason = breakReason; 1120 m_breakAuxData = data; 1121 scriptDebugServer().breakProgram(); 1122 } 1123 1124 void InspectorDebuggerAgent::clear() 1125 { 1126 m_pausedScriptState = 0; 1127 m_currentCallStack = ScriptValue(); 1128 m_scripts.clear(); 1129 m_breakpointIdToDebugServerBreakpointIds.clear(); 1130 m_asyncCallStackTracker.clear(); 1131 m_continueToLocationBreakpointId = String(); 1132 clearBreakDetails(); 1133 m_javaScriptPauseScheduled = false; 1134 ErrorString error; 1135 setOverlayMessage(&error, 0); 1136 } 1137 1138 bool InspectorDebuggerAgent::assertPaused(ErrorString* errorString) 1139 { 1140 if (!m_pausedScriptState) { 1141 *errorString = "Can only perform operation while paused."; 1142 return false; 1143 } 1144 return true; 1145 } 1146 1147 void InspectorDebuggerAgent::clearBreakDetails() 1148 { 1149 m_breakReason = InspectorFrontend::Debugger::Reason::Other; 1150 m_breakAuxData = 0; 1151 } 1152 1153 void InspectorDebuggerAgent::setBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source, const String& condition) 1154 { 1155 String breakpointId = generateBreakpointId(scriptId, lineNumber, columnNumber, source); 1156 ScriptBreakpoint breakpoint(lineNumber, columnNumber, condition); 1157 resolveBreakpoint(breakpointId, scriptId, breakpoint, source); 1158 } 1159 1160 void InspectorDebuggerAgent::removeBreakpoint(const String& scriptId, int lineNumber, int columnNumber, BreakpointSource source) 1161 { 1162 removeBreakpoint(generateBreakpointId(scriptId, lineNumber, columnNumber, source)); 1163 } 1164 1165 void InspectorDebuggerAgent::reset() 1166 { 1167 m_scripts.clear(); 1168 m_breakpointIdToDebugServerBreakpointIds.clear(); 1169 m_asyncCallStackTracker.clear(); 1170 if (m_frontend) 1171 m_frontend->globalObjectCleared(); 1172 } 1173 1174 } // namespace WebCore 1175 1176