Home | History | Annotate | Download | only in inspector
      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