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