LCOV - code coverage report
Current view: top level - src/inspector - v8-debugger-agent-impl.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 790 842 93.8 %
Date: 2019-01-20 Functions: 65 69 94.2 %

          Line data    Source code
       1             : // Copyright 2015 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/inspector/v8-debugger-agent-impl.h"
       6             : 
       7             : #include <algorithm>
       8             : 
       9             : #include "src/debug/debug-interface.h"
      10             : #include "src/inspector/injected-script.h"
      11             : #include "src/inspector/inspected-context.h"
      12             : #include "src/inspector/protocol/Protocol.h"
      13             : #include "src/inspector/remote-object-id.h"
      14             : #include "src/inspector/search-util.h"
      15             : #include "src/inspector/string-util.h"
      16             : #include "src/inspector/v8-debugger-script.h"
      17             : #include "src/inspector/v8-debugger.h"
      18             : #include "src/inspector/v8-inspector-impl.h"
      19             : #include "src/inspector/v8-inspector-session-impl.h"
      20             : #include "src/inspector/v8-regex.h"
      21             : #include "src/inspector/v8-runtime-agent-impl.h"
      22             : #include "src/inspector/v8-stack-trace-impl.h"
      23             : #include "src/inspector/v8-value-utils.h"
      24             : 
      25             : #include "include/v8-inspector.h"
      26             : 
      27             : namespace v8_inspector {
      28             : 
      29             : using protocol::Array;
      30             : using protocol::Maybe;
      31             : using protocol::Debugger::BreakpointId;
      32             : using protocol::Debugger::CallFrame;
      33             : using protocol::Runtime::ExceptionDetails;
      34             : using protocol::Runtime::ScriptId;
      35             : using protocol::Runtime::RemoteObject;
      36             : using protocol::Debugger::Scope;
      37             : 
      38             : namespace DebuggerAgentState {
      39             : static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
      40             : static const char asyncCallStackDepth[] = "asyncCallStackDepth";
      41             : static const char blackboxPattern[] = "blackboxPattern";
      42             : static const char debuggerEnabled[] = "debuggerEnabled";
      43             : static const char skipAllPauses[] = "skipAllPauses";
      44             : 
      45             : static const char breakpointsByRegex[] = "breakpointsByRegex";
      46             : static const char breakpointsByUrl[] = "breakpointsByUrl";
      47             : static const char breakpointsByScriptHash[] = "breakpointsByScriptHash";
      48             : static const char breakpointHints[] = "breakpointHints";
      49             : 
      50             : }  // namespace DebuggerAgentState
      51             : 
      52             : static const char kBacktraceObjectGroup[] = "backtrace";
      53             : static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
      54             : static const char kDebuggerNotPaused[] =
      55             :     "Can only perform operation while paused.";
      56             : 
      57             : static const size_t kBreakpointHintMaxLength = 128;
      58             : static const intptr_t kBreakpointHintMaxSearchOffset = 80 * 10;
      59             : 
      60             : static const int kMaxScriptFailedToParseScripts = 1000;
      61             : 
      62             : namespace {
      63             : 
      64      293808 : void TranslateLocation(protocol::Debugger::Location* location,
      65             :                        WasmTranslation* wasmTranslation) {
      66             :   String16 scriptId = location->getScriptId();
      67      146904 :   int lineNumber = location->getLineNumber();
      68      146904 :   int columnNumber = location->getColumnNumber(-1);
      69      146904 :   if (wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
      70             :           &scriptId, &lineNumber, &columnNumber)) {
      71             :     location->setScriptId(std::move(scriptId));
      72         463 :     location->setLineNumber(lineNumber);
      73         463 :     location->setColumnNumber(columnNumber);
      74             :   }
      75      146904 : }
      76             : 
      77             : enum class BreakpointType {
      78             :   kByUrl = 1,
      79             :   kByUrlRegex,
      80             :   kByScriptHash,
      81             :   kByScriptId,
      82             :   kDebugCommand,
      83             :   kMonitorCommand,
      84             :   kBreakpointAtEntry
      85             : };
      86             : 
      87        2179 : String16 generateBreakpointId(BreakpointType type,
      88             :                               const String16& scriptSelector, int lineNumber,
      89             :                               int columnNumber) {
      90        2179 :   String16Builder builder;
      91        2179 :   builder.appendNumber(static_cast<int>(type));
      92        2179 :   builder.append(':');
      93        2179 :   builder.appendNumber(lineNumber);
      94        2179 :   builder.append(':');
      95        2179 :   builder.appendNumber(columnNumber);
      96        2179 :   builder.append(':');
      97        2179 :   builder.append(scriptSelector);
      98        4358 :   return builder.toString();
      99             : }
     100             : 
     101         170 : String16 generateBreakpointId(BreakpointType type,
     102             :                               v8::Local<v8::Function> function) {
     103         170 :   String16Builder builder;
     104         170 :   builder.appendNumber(static_cast<int>(type));
     105         170 :   builder.append(':');
     106         170 :   builder.appendNumber(v8::debug::GetDebuggingId(function));
     107         340 :   return builder.toString();
     108             : }
     109             : 
     110        3404 : bool parseBreakpointId(const String16& breakpointId, BreakpointType* type,
     111             :                        String16* scriptSelector = nullptr,
     112             :                        int* lineNumber = nullptr, int* columnNumber = nullptr) {
     113             :   size_t typeLineSeparator = breakpointId.find(':');
     114        3404 :   if (typeLineSeparator == String16::kNotFound) return false;
     115             : 
     116        6798 :   int rawType = breakpointId.substring(0, typeLineSeparator).toInteger();
     117        3399 :   if (rawType < static_cast<int>(BreakpointType::kByUrl) ||
     118             :       rawType > static_cast<int>(BreakpointType::kBreakpointAtEntry)) {
     119             :     return false;
     120             :   }
     121        3394 :   if (type) *type = static_cast<BreakpointType>(rawType);
     122        3394 :   if (rawType == static_cast<int>(BreakpointType::kDebugCommand) ||
     123        3394 :       rawType == static_cast<int>(BreakpointType::kMonitorCommand) ||
     124             :       rawType == static_cast<int>(BreakpointType::kBreakpointAtEntry)) {
     125             :     // The script and source position is not encoded in this case.
     126             :     return true;
     127             :   }
     128             : 
     129        3314 :   size_t lineColumnSeparator = breakpointId.find(':', typeLineSeparator + 1);
     130        3314 :   if (lineColumnSeparator == String16::kNotFound) return false;
     131             :   size_t columnSelectorSeparator =
     132        3314 :       breakpointId.find(':', lineColumnSeparator + 1);
     133        3314 :   if (columnSelectorSeparator == String16::kNotFound) return false;
     134        3314 :   if (scriptSelector) {
     135        1728 :     *scriptSelector = breakpointId.substring(columnSelectorSeparator + 1);
     136             :   }
     137        3314 :   if (lineNumber) {
     138             :     *lineNumber = breakpointId
     139             :                       .substring(typeLineSeparator + 1,
     140         110 :                                  lineColumnSeparator - typeLineSeparator - 1)
     141         220 :                       .toInteger();
     142             :   }
     143        3314 :   if (columnNumber) {
     144             :     *columnNumber =
     145             :         breakpointId
     146             :             .substring(lineColumnSeparator + 1,
     147         110 :                        columnSelectorSeparator - lineColumnSeparator - 1)
     148         220 :             .toInteger();
     149             :   }
     150             :   return true;
     151             : }
     152             : 
     153         225 : bool positionComparator(const std::pair<int, int>& a,
     154             :                         const std::pair<int, int>& b) {
     155         225 :   if (a.first != b.first) return a.first < b.first;
     156          45 :   return a.second < b.second;
     157             : }
     158             : 
     159         215 : String16 breakpointHint(const V8DebuggerScript& script, int lineNumber,
     160             :                         int columnNumber) {
     161         215 :   int offset = script.offset(lineNumber, columnNumber);
     162         215 :   if (offset == V8DebuggerScript::kNoOffset) return String16();
     163             :   String16 hint =
     164         430 :       script.source(offset, kBreakpointHintMaxLength).stripWhiteSpace();
     165        5300 :   for (size_t i = 0; i < hint.length(); ++i) {
     166        2625 :     if (hint[i] == '\r' || hint[i] == '\n' || hint[i] == ';') {
     167         190 :       return hint.substring(0, i);
     168             :     }
     169             :   }
     170          25 :   return hint;
     171             : }
     172             : 
     173         160 : void adjustBreakpointLocation(const V8DebuggerScript& script,
     174             :                               const String16& hint, int* lineNumber,
     175             :                               int* columnNumber) {
     176         160 :   if (*lineNumber < script.startLine() || *lineNumber > script.endLine())
     177         100 :     return;
     178          95 :   if (hint.isEmpty()) return;
     179          95 :   intptr_t sourceOffset = script.offset(*lineNumber, *columnNumber);
     180          95 :   if (sourceOffset == V8DebuggerScript::kNoOffset) return;
     181             : 
     182             :   intptr_t searchRegionOffset = std::max(
     183         190 :       sourceOffset - kBreakpointHintMaxSearchOffset, static_cast<intptr_t>(0));
     184          95 :   size_t offset = sourceOffset - searchRegionOffset;
     185             :   String16 searchArea = script.source(searchRegionOffset,
     186          95 :                                       offset + kBreakpointHintMaxSearchOffset);
     187             : 
     188             :   size_t nextMatch = searchArea.find(hint, offset);
     189             :   size_t prevMatch = searchArea.reverseFind(hint, offset);
     190          95 :   if (nextMatch == String16::kNotFound && prevMatch == String16::kNotFound) {
     191             :     return;
     192             :   }
     193             :   size_t bestMatch;
     194          60 :   if (nextMatch == String16::kNotFound) {
     195             :     bestMatch = prevMatch;
     196          60 :   } else if (prevMatch == String16::kNotFound) {
     197             :     bestMatch = nextMatch;
     198             :   } else {
     199          45 :     bestMatch = nextMatch - offset < offset - prevMatch ? nextMatch : prevMatch;
     200             :   }
     201          60 :   bestMatch += searchRegionOffset;
     202             :   v8::debug::Location hintPosition =
     203          60 :       script.location(static_cast<int>(bestMatch));
     204          60 :   if (hintPosition.IsEmpty()) return;
     205          60 :   *lineNumber = hintPosition.GetLineNumber();
     206          60 :   *columnNumber = hintPosition.GetColumnNumber();
     207             : }
     208             : 
     209        2480 : String16 breakLocationType(v8::debug::BreakLocationType type) {
     210        2480 :   switch (type) {
     211             :     case v8::debug::kCallBreakLocation:
     212        1135 :       return protocol::Debugger::BreakLocation::TypeEnum::Call;
     213             :     case v8::debug::kReturnBreakLocation:
     214        1335 :       return protocol::Debugger::BreakLocation::TypeEnum::Return;
     215             :     case v8::debug::kDebuggerStatementBreakLocation:
     216          10 :       return protocol::Debugger::BreakLocation::TypeEnum::DebuggerStatement;
     217             :     case v8::debug::kCommonBreakLocation:
     218           0 :       return String16();
     219             :   }
     220           0 :   return String16();
     221             : }
     222             : 
     223             : }  // namespace
     224             : 
     225      371828 : String16 scopeType(v8::debug::ScopeIterator::ScopeType type) {
     226      371828 :   switch (type) {
     227             :     case v8::debug::ScopeIterator::ScopeTypeGlobal:
     228      142575 :       return Scope::TypeEnum::Global;
     229             :     case v8::debug::ScopeIterator::ScopeTypeLocal:
     230       83802 :       return Scope::TypeEnum::Local;
     231             :     case v8::debug::ScopeIterator::ScopeTypeWith:
     232        2355 :       return Scope::TypeEnum::With;
     233             :     case v8::debug::ScopeIterator::ScopeTypeClosure:
     234        9490 :       return Scope::TypeEnum::Closure;
     235             :     case v8::debug::ScopeIterator::ScopeTypeCatch:
     236        1063 :       return Scope::TypeEnum::Catch;
     237             :     case v8::debug::ScopeIterator::ScopeTypeBlock:
     238        2658 :       return Scope::TypeEnum::Block;
     239             :     case v8::debug::ScopeIterator::ScopeTypeScript:
     240      128578 :       return Scope::TypeEnum::Script;
     241             :     case v8::debug::ScopeIterator::ScopeTypeEval:
     242          97 :       return Scope::TypeEnum::Eval;
     243             :     case v8::debug::ScopeIterator::ScopeTypeModule:
     244        1210 :       return Scope::TypeEnum::Module;
     245             :   }
     246           0 :   UNREACHABLE();
     247             :   return String16();
     248             : }
     249             : 
     250             : namespace {
     251             : 
     252      146904 : Response buildScopes(v8::Isolate* isolate, v8::debug::ScopeIterator* iterator,
     253             :                      InjectedScript* injectedScript,
     254             :                      std::unique_ptr<Array<Scope>>* scopes) {
     255             :   *scopes = Array<Scope>::create();
     256      146904 :   if (!injectedScript) return Response::OK();
     257      146795 :   if (iterator->Done()) return Response::OK();
     258             : 
     259      142575 :   String16 scriptId = String16::fromInteger(iterator->GetScriptId());
     260             : 
     261      514403 :   for (; !iterator->Done(); iterator->Advance()) {
     262      371828 :     std::unique_ptr<RemoteObject> object;
     263             :     Response result =
     264      371828 :         injectedScript->wrapObject(iterator->GetObject(), kBacktraceObjectGroup,
     265     1487312 :                                    WrapMode::kNoPreview, &object);
     266      371828 :     if (!result.isSuccess()) return result;
     267             : 
     268             :     auto scope = Scope::create()
     269     1115484 :                      .setType(scopeType(iterator->GetType()))
     270             :                      .setObject(std::move(object))
     271             :                      .build();
     272             : 
     273             :     String16 name = toProtocolStringWithTypeCheck(
     274      371828 :         isolate, iterator->GetFunctionDebugName());
     275      371828 :     if (!name.isEmpty()) scope->setName(name);
     276             : 
     277      371828 :     if (iterator->HasLocationInfo()) {
     278      154428 :       v8::debug::Location start = iterator->GetStartLocation();
     279             :       scope->setStartLocation(protocol::Debugger::Location::create()
     280      154428 :                                   .setScriptId(scriptId)
     281      154428 :                                   .setLineNumber(start.GetLineNumber())
     282      154428 :                                   .setColumnNumber(start.GetColumnNumber())
     283             :                                   .build());
     284             : 
     285      154428 :       v8::debug::Location end = iterator->GetEndLocation();
     286             :       scope->setEndLocation(protocol::Debugger::Location::create()
     287      154428 :                                 .setScriptId(scriptId)
     288      154428 :                                 .setLineNumber(end.GetLineNumber())
     289      154428 :                                 .setColumnNumber(end.GetColumnNumber())
     290             :                                 .build());
     291             :     }
     292      371828 :     (*scopes)->addItem(std::move(scope));
     293             :   }
     294      142575 :   return Response::OK();
     295             : }
     296             : 
     297         650 : protocol::DictionaryValue* getOrCreateObject(protocol::DictionaryValue* object,
     298             :                                              const String16& key) {
     299         650 :   protocol::DictionaryValue* value = object->getObject(key);
     300         650 :   if (value) return value;
     301             :   std::unique_ptr<protocol::DictionaryValue> newDictionary =
     302         495 :       protocol::DictionaryValue::create();
     303             :   value = newDictionary.get();
     304         990 :   object->setObject(key, std::move(newDictionary));
     305             :   return value;
     306             : }
     307             : }  // namespace
     308             : 
     309        3834 : V8DebuggerAgentImpl::V8DebuggerAgentImpl(
     310        3834 :     V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
     311             :     protocol::DictionaryValue* state)
     312             :     : m_inspector(session->inspector()),
     313        3834 :       m_debugger(m_inspector->debugger()),
     314             :       m_session(session),
     315             :       m_enabled(false),
     316             :       m_state(state),
     317             :       m_frontend(frontendChannel),
     318       34506 :       m_isolate(m_inspector->isolate()) {}
     319             : 
     320             : V8DebuggerAgentImpl::~V8DebuggerAgentImpl() = default;
     321             : 
     322        3466 : void V8DebuggerAgentImpl::enableImpl() {
     323        3466 :   m_enabled = true;
     324        6932 :   m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
     325        3466 :   m_debugger->enable();
     326             : 
     327             :   std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts;
     328        3466 :   m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts);
     329       73660 :   for (size_t i = 0; i < compiledScripts.size(); i++)
     330       66728 :     didParseSource(std::move(compiledScripts[i]), true);
     331             : 
     332        3466 :   m_breakpointsActive = true;
     333        3466 :   m_debugger->setBreakpointsActive(true);
     334             : 
     335        3466 :   if (isPaused()) {
     336             :     didPause(0, v8::Local<v8::Value>(), std::vector<v8::debug::BreakpointId>(),
     337          20 :              v8::debug::kException, false, false, false);
     338        3466 :   }
     339        3466 : }
     340             : 
     341        6950 : Response V8DebuggerAgentImpl::enable(String16* outDebuggerId) {
     342        6950 :   *outDebuggerId = debuggerIdToString(
     343       10401 :       m_debugger->debuggerIdFor(m_session->contextGroupId()));
     344        3475 :   if (enabled()) return Response::OK();
     345             : 
     346        6902 :   if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
     347           0 :     return Response::Error("Script execution is prohibited");
     348             : 
     349        3451 :   enableImpl();
     350        3451 :   return Response::OK();
     351             : }
     352             : 
     353        5379 : Response V8DebuggerAgentImpl::disable() {
     354        5379 :   if (!enabled()) return Response::OK();
     355             : 
     356        6932 :   m_state->remove(DebuggerAgentState::breakpointsByRegex);
     357        6932 :   m_state->remove(DebuggerAgentState::breakpointsByUrl);
     358        6932 :   m_state->remove(DebuggerAgentState::breakpointsByScriptHash);
     359        6932 :   m_state->remove(DebuggerAgentState::breakpointHints);
     360             : 
     361             :   m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState,
     362        6932 :                       v8::debug::NoBreakOnException);
     363        6932 :   m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0);
     364             : 
     365        3466 :   if (m_breakpointsActive) {
     366        3466 :     m_debugger->setBreakpointsActive(false);
     367        3466 :     m_breakpointsActive = false;
     368             :   }
     369             :   m_blackboxedPositions.clear();
     370             :   m_blackboxPattern.reset();
     371             :   resetBlackboxedStateCache();
     372             :   m_scripts.clear();
     373        8263 :   for (const auto& it : m_debuggerBreakpointIdToBreakpointId) {
     374        1331 :     v8::debug::RemoveBreakpoint(m_isolate, it.first);
     375             :   }
     376             :   m_breakpointIdToDebuggerBreakpointIds.clear();
     377             :   m_debuggerBreakpointIdToBreakpointId.clear();
     378        3466 :   m_debugger->setAsyncCallStackDepth(this, 0);
     379        3466 :   clearBreakDetails();
     380        3466 :   m_skipAllPauses = false;
     381        6932 :   m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
     382        6932 :   m_state->remove(DebuggerAgentState::blackboxPattern);
     383        3466 :   m_enabled = false;
     384        6932 :   m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
     385        3466 :   m_debugger->disable();
     386        3466 :   return Response::OK();
     387             : }
     388             : 
     389          55 : void V8DebuggerAgentImpl::restore() {
     390             :   DCHECK(!m_enabled);
     391         110 :   if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false))
     392          40 :     return;
     393          15 :   if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
     394             :     return;
     395             : 
     396          15 :   enableImpl();
     397             : 
     398          15 :   int pauseState = v8::debug::NoBreakOnException;
     399          30 :   m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState);
     400          15 :   setPauseOnExceptionsImpl(pauseState);
     401             : 
     402             :   m_skipAllPauses =
     403          30 :       m_state->booleanProperty(DebuggerAgentState::skipAllPauses, false);
     404             : 
     405          15 :   int asyncCallStackDepth = 0;
     406             :   m_state->getInteger(DebuggerAgentState::asyncCallStackDepth,
     407          30 :                       &asyncCallStackDepth);
     408          15 :   m_debugger->setAsyncCallStackDepth(this, asyncCallStackDepth);
     409             : 
     410          15 :   String16 blackboxPattern;
     411          30 :   if (m_state->getString(DebuggerAgentState::blackboxPattern,
     412          30 :                          &blackboxPattern)) {
     413           0 :     setBlackboxPattern(blackboxPattern);
     414             :   }
     415             : }
     416             : 
     417         138 : Response V8DebuggerAgentImpl::setBreakpointsActive(bool active) {
     418         138 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     419         138 :   if (m_breakpointsActive == active) return Response::OK();
     420         102 :   m_breakpointsActive = active;
     421         102 :   m_debugger->setBreakpointsActive(active);
     422         153 :   if (!active && !m_breakReason.empty()) {
     423           5 :     clearBreakDetails();
     424           5 :     m_debugger->setPauseOnNextCall(false, m_session->contextGroupId());
     425             :   }
     426         102 :   return Response::OK();
     427             : }
     428             : 
     429          35 : Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
     430          70 :   m_state->setBoolean(DebuggerAgentState::skipAllPauses, skip);
     431          35 :   m_skipAllPauses = skip;
     432          35 :   return Response::OK();
     433             : }
     434             : 
     435        1355 : static bool matches(V8InspectorImpl* inspector, const V8DebuggerScript& script,
     436             :                     BreakpointType type, const String16& selector) {
     437        1355 :   switch (type) {
     438             :     case BreakpointType::kByUrl:
     439        1295 :       return script.sourceURL() == selector;
     440             :     case BreakpointType::kByScriptHash:
     441          80 :       return script.hash() == selector;
     442             :     case BreakpointType::kByUrlRegex: {
     443          20 :       V8Regex regex(inspector, selector, true);
     444          20 :       return regex.match(script.sourceURL()) != -1;
     445             :     }
     446             :     default:
     447           0 :       UNREACHABLE();
     448             :       return false;
     449             :   }
     450             : }
     451             : 
     452         230 : Response V8DebuggerAgentImpl::setBreakpointByUrl(
     453             :     int lineNumber, Maybe<String16> optionalURL,
     454             :     Maybe<String16> optionalURLRegex, Maybe<String16> optionalScriptHash,
     455             :     Maybe<int> optionalColumnNumber, Maybe<String16> optionalCondition,
     456             :     String16* outBreakpointId,
     457             :     std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) {
     458             :   *locations = Array<protocol::Debugger::Location>::create();
     459             : 
     460         685 :   int specified = (optionalURL.isJust() ? 1 : 0) +
     461         690 :                   (optionalURLRegex.isJust() ? 1 : 0) +
     462         470 :                   (optionalScriptHash.isJust() ? 1 : 0);
     463         230 :   if (specified != 1) {
     464             :     return Response::Error(
     465           0 :         "Either url or urlRegex or scriptHash must be specified.");
     466             :   }
     467         230 :   int columnNumber = 0;
     468         230 :   if (optionalColumnNumber.isJust()) {
     469          85 :     columnNumber = optionalColumnNumber.fromJust();
     470          85 :     if (columnNumber < 0) return Response::Error("Incorrect column number");
     471             :   }
     472             : 
     473             :   BreakpointType type = BreakpointType::kByUrl;
     474         230 :   String16 selector;
     475         230 :   if (optionalURLRegex.isJust()) {
     476          10 :     selector = optionalURLRegex.fromJust();
     477             :     type = BreakpointType::kByUrlRegex;
     478         225 :   } else if (optionalURL.isJust()) {
     479         430 :     selector = optionalURL.fromJust();
     480             :     type = BreakpointType::kByUrl;
     481          10 :   } else if (optionalScriptHash.isJust()) {
     482          20 :     selector = optionalScriptHash.fromJust();
     483             :     type = BreakpointType::kByScriptHash;
     484             :   }
     485             : 
     486         460 :   String16 condition = optionalCondition.fromMaybe(String16());
     487             :   String16 breakpointId =
     488         230 :       generateBreakpointId(type, selector, lineNumber, columnNumber);
     489             :   protocol::DictionaryValue* breakpoints;
     490         230 :   switch (type) {
     491             :     case BreakpointType::kByUrlRegex:
     492             :       breakpoints =
     493          10 :           getOrCreateObject(m_state, DebuggerAgentState::breakpointsByRegex);
     494           5 :       break;
     495             :     case BreakpointType::kByUrl:
     496             :       breakpoints = getOrCreateObject(
     497             :           getOrCreateObject(m_state, DebuggerAgentState::breakpointsByUrl),
     498         430 :           selector);
     499         215 :       break;
     500             :     case BreakpointType::kByScriptHash:
     501             :       breakpoints = getOrCreateObject(
     502             :           getOrCreateObject(m_state,
     503             :                             DebuggerAgentState::breakpointsByScriptHash),
     504          20 :           selector);
     505          10 :       break;
     506             :     default:
     507           0 :       UNREACHABLE();
     508             :       break;
     509             :   }
     510         230 :   if (breakpoints->get(breakpointId)) {
     511           0 :     return Response::Error("Breakpoint at specified location already exists.");
     512             :   }
     513             : 
     514         230 :   String16 hint;
     515        1705 :   for (const auto& script : m_scripts) {
     516        2205 :     if (!matches(m_inspector, *script.second, type, selector)) continue;
     517         285 :     if (!hint.isEmpty()) {
     518             :       adjustBreakpointLocation(*script.second, hint, &lineNumber,
     519          70 :                                &columnNumber);
     520             :     }
     521             :     std::unique_ptr<protocol::Debugger::Location> location = setBreakpointImpl(
     522         285 :         breakpointId, script.first, condition, lineNumber, columnNumber);
     523         285 :     if (location && type != BreakpointType::kByUrlRegex) {
     524         645 :       hint = breakpointHint(*script.second, lineNumber, columnNumber);
     525             :     }
     526         505 :     if (location) (*locations)->addItem(std::move(location));
     527             :   }
     528         230 :   breakpoints->setString(breakpointId, condition);
     529         230 :   if (!hint.isEmpty()) {
     530             :     protocol::DictionaryValue* breakpointHints =
     531         390 :         getOrCreateObject(m_state, DebuggerAgentState::breakpointHints);
     532         195 :     breakpointHints->setString(breakpointId, hint);
     533             :   }
     534         230 :   *outBreakpointId = breakpointId;
     535         230 :   return Response::OK();
     536             : }
     537             : 
     538        1949 : Response V8DebuggerAgentImpl::setBreakpoint(
     539             :     std::unique_ptr<protocol::Debugger::Location> location,
     540             :     Maybe<String16> optionalCondition, String16* outBreakpointId,
     541             :     std::unique_ptr<protocol::Debugger::Location>* actualLocation) {
     542             :   String16 breakpointId = generateBreakpointId(
     543             :       BreakpointType::kByScriptId, location->getScriptId(),
     544        5847 :       location->getLineNumber(), location->getColumnNumber(0));
     545        1949 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
     546             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     547         288 :     return Response::Error("Breakpoint at specified location already exists.");
     548             :   }
     549       10830 :   *actualLocation = setBreakpointImpl(breakpointId, location->getScriptId(),
     550             :                                       optionalCondition.fromMaybe(String16()),
     551             :                                       location->getLineNumber(),
     552             :                                       location->getColumnNumber(0));
     553        1805 :   if (!*actualLocation) return Response::Error("Could not resolve breakpoint");
     554        1805 :   *outBreakpointId = breakpointId;
     555        1805 :   return Response::OK();
     556             : }
     557             : 
     558          20 : Response V8DebuggerAgentImpl::setBreakpointOnFunctionCall(
     559             :     const String16& functionObjectId, Maybe<String16> optionalCondition,
     560             :     String16* outBreakpointId) {
     561          20 :   InjectedScript::ObjectScope scope(m_session, functionObjectId);
     562          20 :   Response response = scope.initialize();
     563          20 :   if (!response.isSuccess()) return response;
     564          20 :   if (!scope.object()->IsFunction()) {
     565           0 :     return Response::Error("Could not find function with given id");
     566             :   }
     567             :   v8::Local<v8::Function> function =
     568          20 :       v8::Local<v8::Function>::Cast(scope.object());
     569             :   String16 breakpointId =
     570          20 :       generateBreakpointId(BreakpointType::kBreakpointAtEntry, function);
     571          20 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
     572             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     573          10 :     return Response::Error("Breakpoint at specified location already exists.");
     574             :   }
     575             :   v8::Local<v8::String> condition =
     576          60 :       toV8String(m_isolate, optionalCondition.fromMaybe(String16()));
     577          15 :   setBreakpointImpl(breakpointId, function, condition);
     578          15 :   *outBreakpointId = breakpointId;
     579          35 :   return Response::OK();
     580             : }
     581             : 
     582         789 : Response V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) {
     583         794 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     584             :   BreakpointType type;
     585         784 :   String16 selector;
     586         784 :   if (!parseBreakpointId(breakpointId, &type, &selector)) {
     587          10 :     return Response::OK();
     588             :   }
     589             :   protocol::DictionaryValue* breakpoints = nullptr;
     590         774 :   switch (type) {
     591             :     case BreakpointType::kByUrl: {
     592             :       protocol::DictionaryValue* breakpointsByUrl =
     593          80 :           m_state->getObject(DebuggerAgentState::breakpointsByUrl);
     594          40 :       if (breakpointsByUrl) {
     595          40 :         breakpoints = breakpointsByUrl->getObject(selector);
     596             :       }
     597             :     } break;
     598             :     case BreakpointType::kByScriptHash: {
     599             :       protocol::DictionaryValue* breakpointsByScriptHash =
     600          20 :           m_state->getObject(DebuggerAgentState::breakpointsByScriptHash);
     601          10 :       if (breakpointsByScriptHash) {
     602          10 :         breakpoints = breakpointsByScriptHash->getObject(selector);
     603             :       }
     604             :     } break;
     605             :     case BreakpointType::kByUrlRegex:
     606           0 :       breakpoints = m_state->getObject(DebuggerAgentState::breakpointsByRegex);
     607           0 :       break;
     608             :     default:
     609             :       break;
     610             :   }
     611         774 :   if (breakpoints) breakpoints->remove(breakpointId);
     612             :   protocol::DictionaryValue* breakpointHints =
     613        1548 :       m_state->getObject(DebuggerAgentState::breakpointHints);
     614         774 :   if (breakpointHints) breakpointHints->remove(breakpointId);
     615         774 :   removeBreakpointImpl(breakpointId);
     616         774 :   return Response::OK();
     617             : }
     618             : 
     619         844 : void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) {
     620             :   DCHECK(enabled());
     621             :   BreakpointIdToDebuggerBreakpointIdsMap::iterator
     622             :       debuggerBreakpointIdsIterator =
     623             :           m_breakpointIdToDebuggerBreakpointIds.find(breakpointId);
     624         844 :   if (debuggerBreakpointIdsIterator ==
     625             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
     626         844 :     return;
     627             :   }
     628        2547 :   for (const auto& id : debuggerBreakpointIdsIterator->second) {
     629         859 :     v8::debug::RemoveBreakpoint(m_isolate, id);
     630             :     m_debuggerBreakpointIdToBreakpointId.erase(id);
     631             :   }
     632             :   m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId);
     633             : }
     634             : 
     635         265 : Response V8DebuggerAgentImpl::getPossibleBreakpoints(
     636             :     std::unique_ptr<protocol::Debugger::Location> start,
     637             :     Maybe<protocol::Debugger::Location> end, Maybe<bool> restrictToFunction,
     638             :     std::unique_ptr<protocol::Array<protocol::Debugger::BreakLocation>>*
     639             :         locations) {
     640             :   String16 scriptId = start->getScriptId();
     641             : 
     642         530 :   if (start->getLineNumber() < 0 || start->getColumnNumber(0) < 0)
     643             :     return Response::Error(
     644           0 :         "start.lineNumber and start.columnNumber should be >= 0");
     645             : 
     646             :   v8::debug::Location v8Start(start->getLineNumber(),
     647         265 :                               start->getColumnNumber(0));
     648         265 :   v8::debug::Location v8End;
     649         265 :   if (end.isJust()) {
     650         110 :     if (end.fromJust()->getScriptId() != scriptId)
     651          10 :       return Response::Error("Locations should contain the same scriptId");
     652         105 :     int line = end.fromJust()->getLineNumber();
     653             :     int column = end.fromJust()->getColumnNumber(0);
     654         105 :     if (line < 0 || column < 0)
     655             :       return Response::Error(
     656           0 :           "end.lineNumber and end.columnNumber should be >= 0");
     657         105 :     v8End = v8::debug::Location(line, column);
     658             :   }
     659             :   auto it = m_scripts.find(scriptId);
     660         265 :   if (it == m_scripts.end()) return Response::Error("Script not found");
     661             :   std::vector<v8::debug::BreakLocation> v8Locations;
     662             :   {
     663         255 :     v8::HandleScope handleScope(m_isolate);
     664         255 :     int contextId = it->second->executionContextId();
     665         255 :     InspectedContext* inspected = m_inspector->getContext(contextId);
     666         255 :     if (!inspected) {
     667           0 :       return Response::Error("Cannot retrive script context");
     668             :     }
     669         255 :     v8::Context::Scope contextScope(inspected->context());
     670             :     v8::MicrotasksScope microtasks(m_isolate,
     671         510 :                                    v8::MicrotasksScope::kDoNotRunMicrotasks);
     672         510 :     v8::TryCatch tryCatch(m_isolate);
     673             :     it->second->getPossibleBreakpoints(
     674         765 :         v8Start, v8End, restrictToFunction.fromMaybe(false), &v8Locations);
     675             :   }
     676             : 
     677             :   *locations = protocol::Array<protocol::Debugger::BreakLocation>::create();
     678        8715 :   for (size_t i = 0; i < v8Locations.size(); ++i) {
     679             :     std::unique_ptr<protocol::Debugger::BreakLocation> breakLocation =
     680             :         protocol::Debugger::BreakLocation::create()
     681        4230 :             .setScriptId(scriptId)
     682        8460 :             .setLineNumber(v8Locations[i].GetLineNumber())
     683        4230 :             .setColumnNumber(v8Locations[i].GetColumnNumber())
     684             :             .build();
     685        8460 :     if (v8Locations[i].type() != v8::debug::kCommonBreakLocation) {
     686        4960 :       breakLocation->setType(breakLocationType(v8Locations[i].type()));
     687             :     }
     688        4230 :     (*locations)->addItem(std::move(breakLocation));
     689             :   }
     690         255 :   return Response::OK();
     691             : }
     692             : 
     693          60 : Response V8DebuggerAgentImpl::continueToLocation(
     694             :     std::unique_ptr<protocol::Debugger::Location> location,
     695          60 :     Maybe<String16> targetCallFrames) {
     696          60 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     697          60 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     698          60 :   ScriptsMap::iterator it = m_scripts.find(location->getScriptId());
     699          60 :   if (it == m_scripts.end()) {
     700           0 :     return Response::Error("Cannot continue to specified location");
     701             :   }
     702          60 :   V8DebuggerScript* script = it->second.get();
     703             :   int contextId = script->executionContextId();
     704          60 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     705          60 :   if (!inspected)
     706           0 :     return Response::Error("Cannot continue to specified location");
     707          60 :   v8::Context::Scope contextScope(inspected->context());
     708             :   return m_debugger->continueToLocation(
     709             :       m_session->contextGroupId(), script, std::move(location),
     710             :       targetCallFrames.fromMaybe(
     711         300 :           protocol::Debugger::ContinueToLocation::TargetCallFramesEnum::Any));
     712             : }
     713             : 
     714          35 : Response V8DebuggerAgentImpl::getStackTrace(
     715             :     std::unique_ptr<protocol::Runtime::StackTraceId> inStackTraceId,
     716             :     std::unique_ptr<protocol::Runtime::StackTrace>* outStackTrace) {
     717          35 :   bool isOk = false;
     718          70 :   int64_t id = inStackTraceId->getId().toInteger64(&isOk);
     719          35 :   std::pair<int64_t, int64_t> debuggerId;
     720          35 :   if (inStackTraceId->hasDebuggerId()) {
     721          50 :     debuggerId =
     722         135 :         m_debugger->debuggerIdFor(inStackTraceId->getDebuggerId(String16()));
     723             :   } else {
     724          55 :     debuggerId = m_debugger->debuggerIdFor(m_session->contextGroupId());
     725             :   }
     726          35 :   V8StackTraceId v8StackTraceId(id, debuggerId);
     727          35 :   if (!isOk || v8StackTraceId.IsInvalid()) {
     728           0 :     return Response::Error("Invalid stack trace id");
     729             :   }
     730             :   auto stack =
     731          70 :       m_debugger->stackTraceFor(m_session->contextGroupId(), v8StackTraceId);
     732          35 :   if (!stack) {
     733           0 :     return Response::Error("Stack trace with given id is not found");
     734             :   }
     735         105 :   *outStackTrace = stack->buildInspectorObject(
     736             :       m_debugger, m_debugger->maxAsyncCallChainDepth());
     737          35 :   return Response::OK();
     738             : }
     739             : 
     740       11142 : bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
     741             :                                                const v8::debug::Location& start,
     742             :                                                const v8::debug::Location& end) {
     743             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     744       11142 :   if (it == m_scripts.end()) {
     745             :     // Unknown scripts are blackboxed.
     746             :     return true;
     747             :   }
     748       11142 :   if (m_blackboxPattern) {
     749         930 :     const String16& scriptSourceURL = it->second->sourceURL();
     750        1415 :     if (!scriptSourceURL.isEmpty() &&
     751         485 :         m_blackboxPattern->match(scriptSourceURL) != -1)
     752             :       return true;
     753             :   }
     754             :   auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
     755       10892 :   if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
     756             : 
     757         315 :   const std::vector<std::pair<int, int>>& ranges =
     758             :       itBlackboxedPositions->second;
     759             :   auto itStartRange = std::lower_bound(
     760             :       ranges.begin(), ranges.end(),
     761         110 :       std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
     762         220 :       positionComparator);
     763             :   auto itEndRange = std::lower_bound(
     764             :       itStartRange, ranges.end(),
     765         110 :       std::make_pair(end.GetLineNumber(), end.GetColumnNumber()),
     766         220 :       positionComparator);
     767             :   // Ranges array contains positions in script where blackbox state is changed.
     768             :   // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
     769             :   // blackboxed...
     770         205 :   return itStartRange == itEndRange &&
     771         110 :          std::distance(ranges.begin(), itStartRange) % 2;
     772             : }
     773             : 
     774      111623 : bool V8DebuggerAgentImpl::acceptsPause(bool isOOMBreak) const {
     775      111623 :   return enabled() && (isOOMBreak || !m_skipAllPauses);
     776             : }
     777             : 
     778             : std::unique_ptr<protocol::Debugger::Location>
     779        2200 : V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
     780             :                                        const String16& scriptId,
     781             :                                        const String16& condition,
     782             :                                        int lineNumber, int columnNumber) {
     783        2200 :   v8::HandleScope handles(m_isolate);
     784             :   DCHECK(enabled());
     785             : 
     786             :   ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
     787        2200 :   if (scriptIterator == m_scripts.end()) return nullptr;
     788        2125 :   V8DebuggerScript* script = scriptIterator->second.get();
     789        2200 :   if (lineNumber < script->startLine() || script->endLine() < lineNumber) {
     790             :     return nullptr;
     791             :   }
     792             : 
     793             :   v8::debug::BreakpointId debuggerBreakpointId;
     794        2125 :   v8::debug::Location location(lineNumber, columnNumber);
     795             :   int contextId = script->executionContextId();
     796        2125 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     797        2125 :   if (!inspected) return nullptr;
     798             : 
     799             :   {
     800        2125 :     v8::Context::Scope contextScope(inspected->context());
     801        2125 :     if (!script->setBreakpoint(condition, &location, &debuggerBreakpointId)) {
     802             :       return nullptr;
     803             :     }
     804             :   }
     805             : 
     806        2095 :   m_debuggerBreakpointIdToBreakpointId[debuggerBreakpointId] = breakpointId;
     807             :   m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
     808        2095 :       debuggerBreakpointId);
     809             : 
     810             :   return protocol::Debugger::Location::create()
     811        2095 :       .setScriptId(scriptId)
     812        2095 :       .setLineNumber(location.GetLineNumber())
     813        2095 :       .setColumnNumber(location.GetColumnNumber())
     814        2200 :       .build();
     815             : }
     816             : 
     817          95 : void V8DebuggerAgentImpl::setBreakpointImpl(const String16& breakpointId,
     818             :                                             v8::Local<v8::Function> function,
     819             :                                             v8::Local<v8::String> condition) {
     820             :   v8::debug::BreakpointId debuggerBreakpointId;
     821          95 :   if (!v8::debug::SetFunctionBreakpoint(function, condition,
     822          95 :                                         &debuggerBreakpointId)) {
     823           0 :     return;
     824             :   }
     825          95 :   m_debuggerBreakpointIdToBreakpointId[debuggerBreakpointId] = breakpointId;
     826             :   m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
     827          95 :       debuggerBreakpointId);
     828             : }
     829             : 
     830           0 : Response V8DebuggerAgentImpl::searchInContent(
     831             :     const String16& scriptId, const String16& query,
     832             :     Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
     833             :     std::unique_ptr<Array<protocol::Debugger::SearchMatch>>* results) {
     834           0 :   v8::HandleScope handles(m_isolate);
     835             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     836           0 :   if (it == m_scripts.end())
     837           0 :     return Response::Error("No script for id: " + scriptId);
     838             : 
     839             :   std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
     840           0 :       searchInTextByLinesImpl(m_session, it->second->source(0), query,
     841             :                               optionalCaseSensitive.fromMaybe(false),
     842           0 :                               optionalIsRegex.fromMaybe(false));
     843             :   *results = protocol::Array<protocol::Debugger::SearchMatch>::create();
     844           0 :   for (size_t i = 0; i < matches.size(); ++i)
     845           0 :     (*results)->addItem(std::move(matches[i]));
     846           0 :   return Response::OK();
     847             : }
     848             : 
     849          55 : Response V8DebuggerAgentImpl::setScriptSource(
     850             :     const String16& scriptId, const String16& newContent, Maybe<bool> dryRun,
     851             :     Maybe<protocol::Array<protocol::Debugger::CallFrame>>* newCallFrames,
     852             :     Maybe<bool>* stackChanged,
     853             :     Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
     854             :     Maybe<protocol::Runtime::StackTraceId>* asyncStackTraceId,
     855          55 :     Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) {
     856          55 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     857             : 
     858             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     859          55 :   if (it == m_scripts.end()) {
     860          10 :     return Response::Error("No script with given id found");
     861             :   }
     862          50 :   int contextId = it->second->executionContextId();
     863          50 :   InspectedContext* inspected = m_inspector->getContext(contextId);
     864          50 :   if (!inspected) {
     865           0 :     return Response::InternalError();
     866             :   }
     867          50 :   v8::HandleScope handleScope(m_isolate);
     868          50 :   v8::Local<v8::Context> context = inspected->context();
     869             :   v8::Context::Scope contextScope(context);
     870             : 
     871             :   v8::debug::LiveEditResult result;
     872         100 :   it->second->setSource(newContent, dryRun.fromMaybe(false), &result);
     873          50 :   if (result.status != v8::debug::LiveEditResult::OK) {
     874             :     *optOutCompileError =
     875             :         protocol::Runtime::ExceptionDetails::create()
     876          30 :             .setExceptionId(m_inspector->nextExceptionId())
     877          20 :             .setText(toProtocolString(m_isolate, result.message))
     878          10 :             .setLineNumber(result.line_number != -1 ? result.line_number - 1
     879          10 :                                                     : 0)
     880          10 :             .setColumnNumber(result.column_number != -1 ? result.column_number
     881          10 :                                                         : 0)
     882             :             .build();
     883          10 :     return Response::OK();
     884             :   } else {
     885          40 :     *stackChanged = result.stack_changed;
     886             :   }
     887          40 :   std::unique_ptr<Array<CallFrame>> callFrames;
     888          40 :   Response response = currentCallFrames(&callFrames);
     889          40 :   if (!response.isSuccess()) return response;
     890             :   *newCallFrames = std::move(callFrames);
     891          80 :   *asyncStackTrace = currentAsyncStackTrace();
     892          80 :   *asyncStackTraceId = currentExternalStackTrace();
     893          90 :   return Response::OK();
     894             : }
     895             : 
     896         104 : Response V8DebuggerAgentImpl::restartFrame(
     897             :     const String16& callFrameId,
     898             :     std::unique_ptr<Array<CallFrame>>* newCallFrames,
     899             :     Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
     900             :     Maybe<protocol::Runtime::StackTraceId>* asyncStackTraceId) {
     901         109 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     902          99 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
     903          99 :   Response response = scope.initialize();
     904          99 :   if (!response.isSuccess()) return response;
     905          99 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
     906          99 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
     907          99 :   if (it->Done()) {
     908           0 :     return Response::Error("Could not find call frame with given id");
     909             :   }
     910          99 :   if (!it->Restart()) {
     911          99 :     return Response::InternalError();
     912             :   }
     913           0 :   response = currentCallFrames(newCallFrames);
     914           0 :   if (!response.isSuccess()) return response;
     915           0 :   *asyncStackTrace = currentAsyncStackTrace();
     916           0 :   *asyncStackTraceId = currentExternalStackTrace();
     917          99 :   return Response::OK();
     918             : }
     919             : 
     920       16094 : Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId,
     921       16094 :                                               String16* scriptSource) {
     922       16094 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     923             :   ScriptsMap::iterator it = m_scripts.find(scriptId);
     924       16094 :   if (it == m_scripts.end())
     925        1000 :     return Response::Error("No script for id: " + scriptId);
     926       31188 :   *scriptSource = it->second->source(0);
     927       15594 :   return Response::OK();
     928             : }
     929             : 
     930         445 : void V8DebuggerAgentImpl::pushBreakDetails(
     931             :     const String16& breakReason,
     932             :     std::unique_ptr<protocol::DictionaryValue> breakAuxData) {
     933         890 :   m_breakReason.push_back(std::make_pair(breakReason, std::move(breakAuxData)));
     934         445 : }
     935             : 
     936           0 : void V8DebuggerAgentImpl::popBreakDetails() {
     937         100 :   if (m_breakReason.empty()) return;
     938             :   m_breakReason.pop_back();
     939             : }
     940             : 
     941      114304 : void V8DebuggerAgentImpl::clearBreakDetails() {
     942             :   std::vector<BreakReason> emptyBreakReason;
     943      114304 :   m_breakReason.swap(emptyBreakReason);
     944      114304 : }
     945             : 
     946         120 : void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
     947             :     const String16& breakReason,
     948             :     std::unique_ptr<protocol::DictionaryValue> data) {
     949         360 :   if (isPaused() || !acceptsPause(false) || !m_breakpointsActive) return;
     950         120 :   if (m_breakReason.empty()) {
     951         100 :     m_debugger->setPauseOnNextCall(true, m_session->contextGroupId());
     952             :   }
     953         240 :   pushBreakDetails(breakReason, std::move(data));
     954             : }
     955             : 
     956          50 : void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
     957         150 :   if (isPaused() || !acceptsPause(false) || !m_breakpointsActive) return;
     958          90 :   if (m_breakReason.size() == 1) {
     959          15 :     m_debugger->setPauseOnNextCall(false, m_session->contextGroupId());
     960             :   }
     961             :   popBreakDetails();
     962             : }
     963             : 
     964         265 : Response V8DebuggerAgentImpl::pause() {
     965         265 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
     966         265 :   if (isPaused()) return Response::OK();
     967         265 :   if (m_debugger->canBreakProgram()) {
     968         260 :     m_debugger->interruptAndBreak(m_session->contextGroupId());
     969             :   } else {
     970         265 :     if (m_breakReason.empty()) {
     971         520 :       m_debugger->setPauseOnNextCall(true, m_session->contextGroupId());
     972             :     }
     973         795 :     pushBreakDetails(protocol::Debugger::Paused::ReasonEnum::Other, nullptr);
     974             :   }
     975         265 :   return Response::OK();
     976             : }
     977             : 
     978        2283 : Response V8DebuggerAgentImpl::resume() {
     979        2326 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     980        6720 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     981        4480 :   m_debugger->continueProgram(m_session->contextGroupId());
     982        2240 :   return Response::OK();
     983             : }
     984             : 
     985        7607 : Response V8DebuggerAgentImpl::stepOver() {
     986        7612 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     987       22806 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     988       15204 :   m_debugger->stepOverStatement(m_session->contextGroupId());
     989        7602 :   return Response::OK();
     990             : }
     991             : 
     992       36408 : Response V8DebuggerAgentImpl::stepInto(Maybe<bool> inBreakOnAsyncCall) {
     993       36413 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
     994      109209 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
     995             :   m_debugger->stepIntoStatement(m_session->contextGroupId(),
     996       72806 :                                 inBreakOnAsyncCall.fromMaybe(false));
     997       36403 :   return Response::OK();
     998             : }
     999             : 
    1000         539 : Response V8DebuggerAgentImpl::stepOut() {
    1001         544 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1002        1602 :   m_session->releaseObjectGroup(kBacktraceObjectGroup);
    1003        1068 :   m_debugger->stepOutOfFunction(m_session->contextGroupId());
    1004         534 :   return Response::OK();
    1005             : }
    1006             : 
    1007          95 : Response V8DebuggerAgentImpl::pauseOnAsyncCall(
    1008             :     std::unique_ptr<protocol::Runtime::StackTraceId> inParentStackTraceId) {
    1009          95 :   bool isOk = false;
    1010         190 :   int64_t stackTraceId = inParentStackTraceId->getId().toInteger64(&isOk);
    1011          95 :   if (!isOk) {
    1012           0 :     return Response::Error("Invalid stack trace id");
    1013             :   }
    1014             :   m_debugger->pauseOnAsyncCall(m_session->contextGroupId(), stackTraceId,
    1015         380 :                                inParentStackTraceId->getDebuggerId(String16()));
    1016          95 :   return Response::OK();
    1017             : }
    1018             : 
    1019        4746 : Response V8DebuggerAgentImpl::setPauseOnExceptions(
    1020        4746 :     const String16& stringPauseState) {
    1021        4746 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1022             :   v8::debug::ExceptionBreakState pauseState;
    1023        9492 :   if (stringPauseState == "none") {
    1024             :     pauseState = v8::debug::NoBreakOnException;
    1025        7268 :   } else if (stringPauseState == "all") {
    1026             :     pauseState = v8::debug::BreakOnAnyException;
    1027        4658 :   } else if (stringPauseState == "uncaught") {
    1028             :     pauseState = v8::debug::BreakOnUncaughtException;
    1029             :   } else {
    1030           0 :     return Response::Error("Unknown pause on exceptions mode: " +
    1031           0 :                            stringPauseState);
    1032             :   }
    1033        4746 :   setPauseOnExceptionsImpl(pauseState);
    1034        4746 :   return Response::OK();
    1035             : }
    1036             : 
    1037        4761 : void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) {
    1038             :   // TODO(dgozman): this changes the global state and forces all context groups
    1039             :   // to pause. We should make this flag be per-context-group.
    1040             :   m_debugger->setPauseOnExceptionsState(
    1041        4761 :       static_cast<v8::debug::ExceptionBreakState>(pauseState));
    1042        9522 :   m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState);
    1043        4761 : }
    1044             : 
    1045       11097 : Response V8DebuggerAgentImpl::evaluateOnCallFrame(
    1046             :     const String16& callFrameId, const String16& expression,
    1047             :     Maybe<String16> objectGroup, Maybe<bool> includeCommandLineAPI,
    1048             :     Maybe<bool> silent, Maybe<bool> returnByValue, Maybe<bool> generatePreview,
    1049             :     Maybe<bool> throwOnSideEffect, Maybe<double> timeout,
    1050             :     std::unique_ptr<RemoteObject>* result,
    1051             :     Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
    1052       11102 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1053       11092 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
    1054       11092 :   Response response = scope.initialize();
    1055       11092 :   if (!response.isSuccess()) return response;
    1056       11092 :   if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
    1057       11092 :   if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
    1058             : 
    1059       11092 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
    1060       11092 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
    1061       11092 :   if (it->Done()) {
    1062           0 :     return Response::Error("Could not find call frame with given id");
    1063             :   }
    1064             : 
    1065             :   v8::MaybeLocal<v8::Value> maybeResultValue;
    1066             :   {
    1067       11092 :     V8InspectorImpl::EvaluateScope evaluateScope(scope);
    1068       11092 :     if (timeout.isJust()) {
    1069          30 :       response = evaluateScope.setTimeout(timeout.fromJust() / 1000.0);
    1070          15 :       if (!response.isSuccess()) return response;
    1071             :     }
    1072             :     maybeResultValue = it->Evaluate(toV8String(m_isolate, expression),
    1073       22184 :                                     throwOnSideEffect.fromMaybe(false));
    1074             :   }
    1075             :   // Re-initialize after running client's code, as it could have destroyed
    1076             :   // context or session.
    1077       22184 :   response = scope.initialize();
    1078       11092 :   if (!response.isSuccess()) return response;
    1079             :   WrapMode mode = generatePreview.fromMaybe(false) ? WrapMode::kWithPreview
    1080       11092 :                                                    : WrapMode::kNoPreview;
    1081       11092 :   if (returnByValue.fromMaybe(false)) mode = WrapMode::kForceValue;
    1082             :   return scope.injectedScript()->wrapEvaluateResult(
    1083             :       maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""), mode,
    1084       55460 :       result, exceptionDetails);
    1085             : }
    1086             : 
    1087         221 : Response V8DebuggerAgentImpl::setVariableValue(
    1088             :     int scopeNumber, const String16& variableName,
    1089             :     std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument,
    1090         221 :     const String16& callFrameId) {
    1091         221 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1092         226 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1093         216 :   InjectedScript::CallFrameScope scope(m_session, callFrameId);
    1094         216 :   Response response = scope.initialize();
    1095         216 :   if (!response.isSuccess()) return response;
    1096             :   v8::Local<v8::Value> newValue;
    1097         432 :   response = scope.injectedScript()->resolveCallArgument(newValueArgument.get(),
    1098             :                                                          &newValue);
    1099         216 :   if (!response.isSuccess()) return response;
    1100             : 
    1101         216 :   int frameOrdinal = static_cast<int>(scope.frameOrdinal());
    1102         216 :   auto it = v8::debug::StackTraceIterator::Create(m_isolate, frameOrdinal);
    1103         216 :   if (it->Done()) {
    1104           0 :     return Response::Error("Could not find call frame with given id");
    1105             :   }
    1106         216 :   auto scopeIterator = it->GetScopeIterator();
    1107         557 :   while (!scopeIterator->Done() && scopeNumber > 0) {
    1108         125 :     --scopeNumber;
    1109         125 :     scopeIterator->Advance();
    1110             :   }
    1111         216 :   if (scopeNumber != 0) {
    1112           0 :     return Response::Error("Could not find scope with given number");
    1113             :   }
    1114             : 
    1115         216 :   if (!scopeIterator->SetVariableValue(toV8String(m_isolate, variableName),
    1116         413 :                                        newValue) ||
    1117         197 :       scope.tryCatch().HasCaught()) {
    1118          19 :     return Response::InternalError();
    1119             :   }
    1120         413 :   return Response::OK();
    1121             : }
    1122             : 
    1123          15 : Response V8DebuggerAgentImpl::setReturnValue(
    1124          15 :     std::unique_ptr<protocol::Runtime::CallArgument> protocolNewValue) {
    1125          15 :   if (!enabled()) return Response::Error(kDebuggerNotEnabled);
    1126          15 :   if (!isPaused()) return Response::Error(kDebuggerNotPaused);
    1127          15 :   auto iterator = v8::debug::StackTraceIterator::Create(m_isolate);
    1128          15 :   if (iterator->Done()) {
    1129           0 :     return Response::Error("Could not find top call frame");
    1130             :   }
    1131          30 :   if (iterator->GetReturnValue().IsEmpty()) {
    1132             :     return Response::Error(
    1133          10 :         "Could not update return value at non-return position");
    1134             :   }
    1135          20 :   InjectedScript::ContextScope scope(m_session, iterator->GetContextId());
    1136          10 :   Response response = scope.initialize();
    1137          10 :   if (!response.isSuccess()) return response;
    1138             :   v8::Local<v8::Value> newValue;
    1139          20 :   response = scope.injectedScript()->resolveCallArgument(protocolNewValue.get(),
    1140             :                                                          &newValue);
    1141          10 :   if (!response.isSuccess()) return response;
    1142          10 :   v8::debug::SetReturnValue(m_isolate, newValue);
    1143          10 :   return Response::OK();
    1144             : }
    1145             : 
    1146        1020 : Response V8DebuggerAgentImpl::setAsyncCallStackDepth(int depth) {
    1147        1700 :   if (!enabled() && !m_session->runtimeAgent()->enabled()) {
    1148        1340 :     return Response::Error(kDebuggerNotEnabled);
    1149             :   }
    1150         700 :   m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
    1151         350 :   m_debugger->setAsyncCallStackDepth(this, depth);
    1152         350 :   return Response::OK();
    1153             : }
    1154             : 
    1155         105 : Response V8DebuggerAgentImpl::setBlackboxPatterns(
    1156             :     std::unique_ptr<protocol::Array<String16>> patterns) {
    1157         105 :   if (!patterns->length()) {
    1158             :     m_blackboxPattern = nullptr;
    1159             :     resetBlackboxedStateCache();
    1160           0 :     m_state->remove(DebuggerAgentState::blackboxPattern);
    1161           0 :     return Response::OK();
    1162             :   }
    1163             : 
    1164         105 :   String16Builder patternBuilder;
    1165         105 :   patternBuilder.append('(');
    1166         220 :   for (size_t i = 0; i < patterns->length() - 1; ++i) {
    1167          10 :     patternBuilder.append(patterns->get(i));
    1168          10 :     patternBuilder.append("|");
    1169             :   }
    1170         210 :   patternBuilder.append(patterns->get(patterns->length() - 1));
    1171         105 :   patternBuilder.append(')');
    1172         105 :   String16 pattern = patternBuilder.toString();
    1173         105 :   Response response = setBlackboxPattern(pattern);
    1174         105 :   if (!response.isSuccess()) return response;
    1175             :   resetBlackboxedStateCache();
    1176         200 :   m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
    1177         100 :   return Response::OK();
    1178             : }
    1179             : 
    1180         105 : Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
    1181             :   std::unique_ptr<V8Regex> regex(new V8Regex(
    1182         105 :       m_inspector, pattern, true /** caseSensitive */, false /** multiline */));
    1183         105 :   if (!regex->isValid())
    1184          10 :     return Response::Error("Pattern parser error: " + regex->errorMessage());
    1185             :   m_blackboxPattern = std::move(regex);
    1186         100 :   return Response::OK();
    1187             : }
    1188             : 
    1189           0 : void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
    1190       63834 :   for (const auto& it : m_scripts) {
    1191       60263 :     it.second->resetBlackboxedStateCache();
    1192             :   }
    1193           0 : }
    1194             : 
    1195          55 : Response V8DebuggerAgentImpl::setBlackboxedRanges(
    1196             :     const String16& scriptId,
    1197             :     std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
    1198             :         inPositions) {
    1199             :   auto it = m_scripts.find(scriptId);
    1200          55 :   if (it == m_scripts.end())
    1201           0 :     return Response::Error("No script with passed id.");
    1202             : 
    1203          55 :   if (!inPositions->length()) {
    1204             :     m_blackboxedPositions.erase(scriptId);
    1205           0 :     it->second->resetBlackboxedStateCache();
    1206           0 :     return Response::OK();
    1207             :   }
    1208             : 
    1209             :   std::vector<std::pair<int, int>> positions;
    1210          55 :   positions.reserve(inPositions->length());
    1211         290 :   for (size_t i = 0; i < inPositions->length(); ++i) {
    1212         190 :     protocol::Debugger::ScriptPosition* position = inPositions->get(i);
    1213          95 :     if (position->getLineNumber() < 0)
    1214           0 :       return Response::Error("Position missing 'line' or 'line' < 0.");
    1215          95 :     if (position->getColumnNumber() < 0)
    1216          10 :       return Response::Error("Position missing 'column' or 'column' < 0.");
    1217             :     positions.push_back(
    1218         180 :         std::make_pair(position->getLineNumber(), position->getColumnNumber()));
    1219             :   }
    1220             : 
    1221         110 :   for (size_t i = 1; i < positions.size(); ++i) {
    1222         120 :     if (positions[i - 1].first < positions[i].first) continue;
    1223          20 :     if (positions[i - 1].first == positions[i].first &&
    1224          10 :         positions[i - 1].second < positions[i].second)
    1225             :       continue;
    1226             :     return Response::Error(
    1227          20 :         "Input positions array is not sorted or contains duplicate values.");
    1228             :   }
    1229             : 
    1230          40 :   m_blackboxedPositions[scriptId] = positions;
    1231          40 :   it->second->resetBlackboxedStateCache();
    1232          40 :   return Response::OK();
    1233             : }
    1234             : 
    1235       55594 : Response V8DebuggerAgentImpl::currentCallFrames(
    1236             :     std::unique_ptr<Array<CallFrame>>* result) {
    1237       55594 :   if (!isPaused()) {
    1238             :     *result = Array<CallFrame>::create();
    1239          15 :     return Response::OK();
    1240             :   }
    1241       55579 :   v8::HandleScope handles(m_isolate);
    1242             :   *result = Array<CallFrame>::create();
    1243       55579 :   auto iterator = v8::debug::StackTraceIterator::Create(m_isolate);
    1244             :   int frameOrdinal = 0;
    1245      404966 :   for (; !iterator->Done(); iterator->Advance(), frameOrdinal++) {
    1246      146904 :     int contextId = iterator->GetContextId();
    1247      146904 :     InjectedScript* injectedScript = nullptr;
    1248      293699 :     if (contextId) m_session->findInjectedScript(contextId, injectedScript);
    1249             :     String16 callFrameId =
    1250      146904 :         RemoteCallFrameId::serialize(contextId, frameOrdinal);
    1251             : 
    1252      146904 :     v8::debug::Location loc = iterator->GetSourceLocation();
    1253             : 
    1254      146904 :     std::unique_ptr<Array<Scope>> scopes;
    1255      146904 :     auto scopeIterator = iterator->GetScopeIterator();
    1256             :     Response res =
    1257      293808 :         buildScopes(m_isolate, scopeIterator.get(), injectedScript, &scopes);
    1258      146904 :     if (!res.isSuccess()) return res;
    1259             : 
    1260      146904 :     std::unique_ptr<RemoteObject> protocolReceiver;
    1261      146904 :     if (injectedScript) {
    1262             :       v8::Local<v8::Value> receiver;
    1263      293590 :       if (iterator->GetReceiver().ToLocal(&receiver)) {
    1264      432351 :         res =
    1265             :             injectedScript->wrapObject(receiver, kBacktraceObjectGroup,
    1266             :                                        WrapMode::kNoPreview, &protocolReceiver);
    1267      144117 :         if (!res.isSuccess()) return res;
    1268             :       }
    1269             :     }
    1270      146904 :     if (!protocolReceiver) {
    1271             :       protocolReceiver = RemoteObject::create()
    1272        8361 :                              .setType(RemoteObject::TypeEnum::Undefined)
    1273             :                              .build();
    1274             :     }
    1275             : 
    1276      146904 :     v8::Local<v8::debug::Script> script = iterator->GetScript();
    1277             :     DCHECK(!script.IsEmpty());
    1278             :     std::unique_ptr<protocol::Debugger::Location> location =
    1279             :         protocol::Debugger::Location::create()
    1280      440712 :             .setScriptId(String16::fromInteger(script->Id()))
    1281      146904 :             .setLineNumber(loc.GetLineNumber())
    1282      146904 :             .setColumnNumber(loc.GetColumnNumber())
    1283             :             .build();
    1284      146904 :     TranslateLocation(location.get(), m_debugger->wasmTranslation());
    1285      146904 :     String16 scriptId = String16::fromInteger(script->Id());
    1286             :     ScriptsMap::iterator scriptIterator =
    1287      146904 :         m_scripts.find(location->getScriptId());
    1288      146904 :     String16 url;
    1289      146904 :     if (scriptIterator != m_scripts.end()) {
    1290      146904 :       url = scriptIterator->second->sourceURL();
    1291             :     }
    1292             : 
    1293             :     auto frame = CallFrame::create()
    1294      146904 :                      .setCallFrameId(callFrameId)
    1295             :                      .setFunctionName(toProtocolString(
    1296      293808 :                          m_isolate, iterator->GetFunctionDebugName()))
    1297             :                      .setLocation(std::move(location))
    1298             :                      .setUrl(url)
    1299             :                      .setScopeChain(std::move(scopes))
    1300             :                      .setThis(std::move(protocolReceiver))
    1301             :                      .build();
    1302             : 
    1303      146904 :     v8::Local<v8::Function> func = iterator->GetFunction();
    1304      146904 :     if (!func.IsEmpty()) {
    1305             :       frame->setFunctionLocation(
    1306             :           protocol::Debugger::Location::create()
    1307      438669 :               .setScriptId(String16::fromInteger(func->ScriptId()))
    1308      146223 :               .setLineNumber(func->GetScriptLineNumber())
    1309      146223 :               .setColumnNumber(func->GetScriptColumnNumber())
    1310             :               .build());
    1311             :     }
    1312             : 
    1313      146904 :     v8::Local<v8::Value> returnValue = iterator->GetReturnValue();
    1314      146904 :     if (!returnValue.IsEmpty() && injectedScript) {
    1315        5707 :       std::unique_ptr<RemoteObject> value;
    1316       17121 :       res = injectedScript->wrapObject(returnValue, kBacktraceObjectGroup,
    1317             :                                        WrapMode::kNoPreview, &value);
    1318        5707 :       if (!res.isSuccess()) return res;
    1319             :       frame->setReturnValue(std::move(value));
    1320             :     }
    1321      146904 :     (*result)->addItem(std::move(frame));
    1322             :   }
    1323      111158 :   return Response::OK();
    1324             : }
    1325             : 
    1326             : std::unique_ptr<protocol::Runtime::StackTrace>
    1327       55594 : V8DebuggerAgentImpl::currentAsyncStackTrace() {
    1328             :   std::shared_ptr<AsyncStackTrace> asyncParent =
    1329       56219 :       m_debugger->currentAsyncParent();
    1330       55594 :   if (!asyncParent) return nullptr;
    1331             :   return asyncParent->buildInspectorObject(
    1332        1250 :       m_debugger, m_debugger->maxAsyncCallChainDepth() - 1);
    1333             : }
    1334             : 
    1335             : std::unique_ptr<protocol::Runtime::StackTraceId>
    1336       55594 : V8DebuggerAgentImpl::currentExternalStackTrace() {
    1337       55594 :   V8StackTraceId externalParent = m_debugger->currentExternalParent();
    1338       55594 :   if (externalParent.IsInvalid()) return nullptr;
    1339             :   return protocol::Runtime::StackTraceId::create()
    1340          75 :       .setId(stackTraceIdToString(externalParent.id))
    1341          50 :       .setDebuggerId(debuggerIdToString(externalParent.debugger_id))
    1342             :       .build();
    1343             : }
    1344             : 
    1345             : std::unique_ptr<protocol::Runtime::StackTraceId>
    1346       55554 : V8DebuggerAgentImpl::currentScheduledAsyncCall() {
    1347             :   v8_inspector::V8StackTraceId scheduledAsyncCall =
    1348       55554 :       m_debugger->scheduledAsyncCall();
    1349       55554 :   if (scheduledAsyncCall.IsInvalid()) return nullptr;
    1350             :   std::unique_ptr<protocol::Runtime::StackTraceId> asyncCallStackTrace =
    1351             :       protocol::Runtime::StackTraceId::create()
    1352         285 :           .setId(stackTraceIdToString(scheduledAsyncCall.id))
    1353             :           .build();
    1354             :   // TODO(kozyatinskiy): extract this check to IsLocal function.
    1355          95 :   if (scheduledAsyncCall.debugger_id.first ||
    1356             :       scheduledAsyncCall.debugger_id.second) {
    1357             :     asyncCallStackTrace->setDebuggerId(
    1358          20 :         debuggerIdToString(scheduledAsyncCall.debugger_id));
    1359             :   }
    1360             :   return asyncCallStackTrace;
    1361             : }
    1362             : 
    1363           0 : bool V8DebuggerAgentImpl::isPaused() const {
    1364      117829 :   return m_debugger->isPausedInContextGroup(m_session->contextGroupId());
    1365             : }
    1366             : 
    1367       60428 : void V8DebuggerAgentImpl::didParseSource(
    1368             :     std::unique_ptr<V8DebuggerScript> script, bool success) {
    1369       60428 :   v8::HandleScope handles(m_isolate);
    1370       60428 :   if (!success) {
    1371             :     DCHECK(!script->isSourceLoadedLazily());
    1372        5201 :     String16 scriptSource = script->source(0);
    1373       15603 :     script->setSourceURL(findSourceURL(scriptSource, false));
    1374       10402 :     script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
    1375             :   }
    1376             : 
    1377       60428 :   int contextId = script->executionContextId();
    1378       60428 :   int contextGroupId = m_inspector->contextGroupId(contextId);
    1379             :   InspectedContext* inspected =
    1380       60428 :       m_inspector->getContext(contextGroupId, contextId);
    1381             :   std::unique_ptr<protocol::DictionaryValue> executionContextAuxData;
    1382       60428 :   if (inspected) {
    1383             :     // Script reused between different groups/sessions can have a stale
    1384             :     // execution context id.
    1385      181269 :     executionContextAuxData = protocol::DictionaryValue::cast(
    1386             :         protocol::StringUtil::parseJSON(inspected->auxData()));
    1387             :   }
    1388       60428 :   bool isLiveEdit = script->isLiveEdit();
    1389       60428 :   bool hasSourceURLComment = script->hasSourceURLComment();
    1390       60428 :   bool isModule = script->isModule();
    1391       60428 :   String16 scriptId = script->scriptId();
    1392       60428 :   String16 scriptURL = script->sourceURL();
    1393             : 
    1394             :   m_scripts[scriptId] = std::move(script);
    1395             : 
    1396             :   ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
    1397             :   DCHECK(scriptIterator != m_scripts.end());
    1398             :   V8DebuggerScript* scriptRef = scriptIterator->second.get();
    1399             :   // V8 could create functions for parsed scripts before reporting and asks
    1400             :   // inspector about blackboxed state, we should reset state each time when we
    1401             :   // make any change that change isFunctionBlackboxed output - adding parsed
    1402             :   // script is changing.
    1403       60428 :   scriptRef->resetBlackboxedStateCache();
    1404             : 
    1405       60428 :   Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
    1406             :   Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
    1407             :       std::move(executionContextAuxData));
    1408       60428 :   const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
    1409             :   const bool* hasSourceURLParam =
    1410       60428 :       hasSourceURLComment ? &hasSourceURLComment : nullptr;
    1411       60428 :   const bool* isModuleParam = isModule ? &isModule : nullptr;
    1412             :   std::unique_ptr<V8StackTraceImpl> stack =
    1413      120856 :       V8StackTraceImpl::capture(m_inspector->debugger(), contextGroupId, 1);
    1414             :   std::unique_ptr<protocol::Runtime::StackTrace> stackTrace =
    1415       53284 :       stack && !stack->isEmpty()
    1416             :           ? stack->buildInspectorObjectImpl(m_debugger, 0)
    1417      166766 :           : nullptr;
    1418       60428 :   if (success) {
    1419             :     // TODO(herhut, dgozman): Report correct length for WASM if needed for
    1420             :     // coverage. Or do not send the length at all and change coverage instead.
    1421       55227 :     if (scriptRef->isSourceLoadedLazily()) {
    1422             :       m_frontend.scriptParsed(
    1423         102 :           scriptId, scriptURL, 0, 0, 0, 0, contextId, scriptRef->hash(),
    1424             :           std::move(executionContextAuxDataParam), isLiveEditParam,
    1425             :           std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam, 0,
    1426         714 :           std::move(stackTrace));
    1427             :     } else {
    1428             :       m_frontend.scriptParsed(
    1429      110250 :           scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
    1430      110250 :           scriptRef->endLine(), scriptRef->endColumn(), contextId,
    1431       55125 :           scriptRef->hash(), std::move(executionContextAuxDataParam),
    1432             :           isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
    1433      606375 :           isModuleParam, scriptRef->length(), std::move(stackTrace));
    1434             :     }
    1435             :   } else {
    1436             :     m_frontend.scriptFailedToParse(
    1437       10402 :         scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
    1438       10402 :         scriptRef->endLine(), scriptRef->endColumn(), contextId,
    1439        5201 :         scriptRef->hash(), std::move(executionContextAuxDataParam),
    1440             :         std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam,
    1441       52010 :         scriptRef->length(), std::move(stackTrace));
    1442             :   }
    1443             : 
    1444       60428 :   if (!success) {
    1445        5201 :     if (scriptURL.isEmpty()) {
    1446        5141 :       m_failedToParseAnonymousScriptIds.push_back(scriptId);
    1447        5141 :       cleanupOldFailedToParseAnonymousScriptsIfNeeded();
    1448             :     }
    1449       60428 :     return;
    1450             :   }
    1451             : 
    1452             :   std::vector<protocol::DictionaryValue*> potentialBreakpoints;
    1453       55227 :   if (!scriptURL.isEmpty()) {
    1454             :     protocol::DictionaryValue* breakpointsByUrl =
    1455       36470 :         m_state->getObject(DebuggerAgentState::breakpointsByUrl);
    1456       18235 :     if (breakpointsByUrl) {
    1457         540 :       potentialBreakpoints.push_back(breakpointsByUrl->getObject(scriptURL));
    1458             :     }
    1459             :     potentialBreakpoints.push_back(
    1460       54705 :         m_state->getObject(DebuggerAgentState::breakpointsByRegex));
    1461             :   }
    1462             :   protocol::DictionaryValue* breakpointsByScriptHash =
    1463      110454 :       m_state->getObject(DebuggerAgentState::breakpointsByScriptHash);
    1464       55227 :   if (breakpointsByScriptHash) {
    1465             :     potentialBreakpoints.push_back(
    1466          50 :         breakpointsByScriptHash->getObject(scriptRef->hash()));
    1467             :   }
    1468             :   protocol::DictionaryValue* breakpointHints =
    1469      110454 :       m_state->getObject(DebuggerAgentState::breakpointHints);
    1470      128984 :   for (auto breakpoints : potentialBreakpoints) {
    1471       18530 :     if (!breakpoints) continue;
    1472         330 :     for (size_t i = 0; i < breakpoints->size(); ++i) {
    1473         110 :       auto breakpointWithCondition = breakpoints->at(i);
    1474         110 :       String16 breakpointId = breakpointWithCondition.first;
    1475             : 
    1476             :       BreakpointType type;
    1477         110 :       String16 selector;
    1478         110 :       int lineNumber = 0;
    1479         110 :       int columnNumber = 0;
    1480             :       parseBreakpointId(breakpointId, &type, &selector, &lineNumber,
    1481         110 :                         &columnNumber);
    1482             : 
    1483         110 :       if (!matches(m_inspector, *scriptRef, type, selector)) continue;
    1484         110 :       String16 condition;
    1485         110 :       breakpointWithCondition.second->asString(&condition);
    1486         110 :       String16 hint;
    1487             :       bool hasHint =
    1488         110 :           breakpointHints && breakpointHints->getString(breakpointId, &hint);
    1489         110 :       if (hasHint) {
    1490          90 :         adjustBreakpointLocation(*scriptRef, hint, &lineNumber, &columnNumber);
    1491             :       }
    1492             :       std::unique_ptr<protocol::Debugger::Location> location =
    1493             :           setBreakpointImpl(breakpointId, scriptId, condition, lineNumber,
    1494         110 :                             columnNumber);
    1495         110 :       if (location)
    1496         140 :         m_frontend.breakpointResolved(breakpointId, std::move(location));
    1497             :     }
    1498       55227 :   }
    1499             : }
    1500             : 
    1501       55554 : void V8DebuggerAgentImpl::didPause(
    1502             :     int contextId, v8::Local<v8::Value> exception,
    1503             :     const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
    1504             :     v8::debug::ExceptionType exceptionType, bool isUncaught, bool isOOMBreak,
    1505             :     bool isAssert) {
    1506       55554 :   v8::HandleScope handles(m_isolate);
    1507             : 
    1508       55554 :   std::vector<BreakReason> hitReasons;
    1509             : 
    1510       55554 :   if (isOOMBreak) {
    1511             :     hitReasons.push_back(
    1512           5 :         std::make_pair(protocol::Debugger::Paused::ReasonEnum::OOM, nullptr));
    1513       55549 :   } else if (isAssert) {
    1514             :     hitReasons.push_back(std::make_pair(
    1515          60 :         protocol::Debugger::Paused::ReasonEnum::Assert, nullptr));
    1516       55489 :   } else if (!exception.IsEmpty()) {
    1517        1887 :     InjectedScript* injectedScript = nullptr;
    1518        3774 :     m_session->findInjectedScript(contextId, injectedScript);
    1519        1887 :     if (injectedScript) {
    1520             :       String16 breakReason =
    1521             :           exceptionType == v8::debug::kPromiseRejection
    1522             :               ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection
    1523        1887 :               : protocol::Debugger::Paused::ReasonEnum::Exception;
    1524        1887 :       std::unique_ptr<protocol::Runtime::RemoteObject> obj;
    1525             :       injectedScript->wrapObject(exception, kBacktraceObjectGroup,
    1526        5661 :                                  WrapMode::kNoPreview, &obj);
    1527             :       std::unique_ptr<protocol::DictionaryValue> breakAuxData;
    1528        1887 :       if (obj) {
    1529        3774 :         breakAuxData = obj->toValue();
    1530        3774 :         breakAuxData->setBoolean("uncaught", isUncaught);
    1531             :       } else {
    1532             :         breakAuxData = nullptr;
    1533             :       }
    1534             :       hitReasons.push_back(
    1535        1887 :           std::make_pair(breakReason, std::move(breakAuxData)));
    1536             :     }
    1537             :   }
    1538             : 
    1539             :   std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create();
    1540             : 
    1541      113723 :   for (const auto& id : hitBreakpoints) {
    1542             :     auto breakpointIterator = m_debuggerBreakpointIdToBreakpointId.find(id);
    1543        2615 :     if (breakpointIterator == m_debuggerBreakpointIdToBreakpointId.end()) {
    1544        2565 :       continue;
    1545             :     }
    1546        2510 :     const String16& breakpointId = breakpointIterator->second;
    1547             :     hitBreakpointIds->addItem(breakpointId);
    1548             :     BreakpointType type;
    1549        2510 :     parseBreakpointId(breakpointId, &type);
    1550        2510 :     if (type != BreakpointType::kDebugCommand) continue;
    1551             :     hitReasons.push_back(std::make_pair(
    1552          50 :         protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr));
    1553             :   }
    1554             : 
    1555       56374 :   for (size_t i = 0; i < m_breakReason.size(); ++i) {
    1556       55964 :     hitReasons.push_back(std::move(m_breakReason[i]));
    1557             :   }
    1558       55554 :   clearBreakDetails();
    1559             : 
    1560       55554 :   String16 breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
    1561             :   std::unique_ptr<protocol::DictionaryValue> breakAuxData;
    1562      111108 :   if (hitReasons.size() == 1) {
    1563        2392 :     breakReason = hitReasons[0].first;
    1564        2392 :     breakAuxData = std::move(hitReasons[0].second);
    1565       53162 :   } else if (hitReasons.size() > 1) {
    1566          20 :     breakReason = protocol::Debugger::Paused::ReasonEnum::Ambiguous;
    1567             :     std::unique_ptr<protocol::ListValue> reasons =
    1568          10 :         protocol::ListValue::create();
    1569          60 :     for (size_t i = 0; i < hitReasons.size(); ++i) {
    1570             :       std::unique_ptr<protocol::DictionaryValue> reason =
    1571          20 :           protocol::DictionaryValue::create();
    1572          80 :       reason->setString("reason", hitReasons[i].first);
    1573          40 :       if (hitReasons[i].second)
    1574          20 :         reason->setObject("auxData", std::move(hitReasons[i].second));
    1575          40 :       reasons->pushValue(std::move(reason));
    1576             :     }
    1577          20 :     breakAuxData = protocol::DictionaryValue::create();
    1578          30 :     breakAuxData->setArray("reasons", std::move(reasons));
    1579             :   }
    1580             : 
    1581       55554 :   std::unique_ptr<Array<CallFrame>> protocolCallFrames;
    1582       55554 :   Response response = currentCallFrames(&protocolCallFrames);
    1583       55554 :   if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create();
    1584             : 
    1585             :   m_frontend.paused(std::move(protocolCallFrames), breakReason,
    1586             :                     std::move(breakAuxData), std::move(hitBreakpointIds),
    1587             :                     currentAsyncStackTrace(), currentExternalStackTrace(),
    1588      777756 :                     currentScheduledAsyncCall());
    1589       55554 : }
    1590             : 
    1591       55279 : void V8DebuggerAgentImpl::didContinue() {
    1592       55279 :   clearBreakDetails();
    1593       55279 :   m_frontend.resumed();
    1594       55279 : }
    1595             : 
    1596          65 : void V8DebuggerAgentImpl::breakProgram(
    1597             :     const String16& breakReason,
    1598         120 :     std::unique_ptr<protocol::DictionaryValue> data) {
    1599          75 :   if (!enabled() || m_skipAllPauses || !m_debugger->canBreakProgram()) return;
    1600             :   std::vector<BreakReason> currentScheduledReason;
    1601             :   currentScheduledReason.swap(m_breakReason);
    1602         120 :   pushBreakDetails(breakReason, std::move(data));
    1603             : 
    1604          65 :   int contextGroupId = m_session->contextGroupId();
    1605             :   int sessionId = m_session->sessionId();
    1606          60 :   V8InspectorImpl* inspector = m_inspector;
    1607          60 :   m_debugger->breakProgram(contextGroupId);
    1608             :   // Check that session and |this| are still around.
    1609          65 :   if (!inspector->sessionById(contextGroupId, sessionId)) return;
    1610          55 :   if (!enabled()) return;
    1611             : 
    1612             :   popBreakDetails();
    1613             :   m_breakReason.swap(currentScheduledReason);
    1614          55 :   if (!m_breakReason.empty()) {
    1615          10 :     m_debugger->setPauseOnNextCall(true, m_session->contextGroupId());
    1616          55 :   }
    1617             : }
    1618             : 
    1619          80 : void V8DebuggerAgentImpl::setBreakpointFor(v8::Local<v8::Function> function,
    1620             :                                            v8::Local<v8::String> condition,
    1621             :                                            BreakpointSource source) {
    1622             :   String16 breakpointId = generateBreakpointId(
    1623             :       source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
    1624             :                                              : BreakpointType::kMonitorCommand,
    1625          80 :       function);
    1626          80 :   if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
    1627             :       m_breakpointIdToDebuggerBreakpointIds.end()) {
    1628          80 :     return;
    1629             :   }
    1630          80 :   setBreakpointImpl(breakpointId, function, condition);
    1631             : }
    1632             : 
    1633          70 : void V8DebuggerAgentImpl::removeBreakpointFor(v8::Local<v8::Function> function,
    1634             :                                               BreakpointSource source) {
    1635             :   String16 breakpointId = generateBreakpointId(
    1636             :       source == DebugCommandBreakpointSource ? BreakpointType::kDebugCommand
    1637             :                                              : BreakpointType::kMonitorCommand,
    1638          70 :       function);
    1639          70 :   removeBreakpointImpl(breakpointId);
    1640          70 : }
    1641             : 
    1642           5 : void V8DebuggerAgentImpl::reset() {
    1643          10 :   if (!enabled()) return;
    1644             :   m_blackboxedPositions.clear();
    1645             :   resetBlackboxedStateCache();
    1646             :   m_scripts.clear();
    1647             :   m_breakpointIdToDebuggerBreakpointIds.clear();
    1648             : }
    1649             : 
    1650        5141 : void V8DebuggerAgentImpl::cleanupOldFailedToParseAnonymousScriptsIfNeeded() {
    1651        5141 :   if (m_failedToParseAnonymousScriptIds.size() <=
    1652             :       kMaxScriptFailedToParseScripts)
    1653        5141 :     return;
    1654             :   static_assert(kMaxScriptFailedToParseScripts > 100,
    1655             :                 "kMaxScriptFailedToParseScripts should be greater then 100");
    1656         505 :   while (m_failedToParseAnonymousScriptIds.size() >
    1657             :          kMaxScriptFailedToParseScripts - 100 + 1) {
    1658         500 :     String16 scriptId = m_failedToParseAnonymousScriptIds.front();
    1659         500 :     m_failedToParseAnonymousScriptIds.pop_front();
    1660             :     m_scripts.erase(scriptId);
    1661             :   }
    1662             : }
    1663             : 
    1664             : }  // namespace v8_inspector

Generated by: LCOV version 1.10