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