blob: 7de46a1787818170d3e91cd0902a0b2f977ecfcf [file] [log] [blame]
Ben Murdochf3b273f2017-01-17 12:11:28 +00001// 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
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00009#include "src/debug/debug-interface.h"
Ben Murdochf3b273f2017-01-17 12:11:28 +000010#include "src/inspector/injected-script.h"
11#include "src/inspector/inspected-context.h"
12#include "src/inspector/java-script-call-frame.h"
13#include "src/inspector/protocol/Protocol.h"
14#include "src/inspector/remote-object-id.h"
15#include "src/inspector/script-breakpoint.h"
16#include "src/inspector/search-util.h"
17#include "src/inspector/string-util.h"
18#include "src/inspector/v8-debugger-script.h"
19#include "src/inspector/v8-debugger.h"
20#include "src/inspector/v8-inspector-impl.h"
21#include "src/inspector/v8-inspector-session-impl.h"
22#include "src/inspector/v8-regex.h"
23#include "src/inspector/v8-runtime-agent-impl.h"
24#include "src/inspector/v8-stack-trace-impl.h"
Ben Murdochc8c1d9e2017-03-08 14:04:23 +000025#include "src/inspector/v8-value-copier.h"
Ben Murdochf3b273f2017-01-17 12:11:28 +000026
27#include "include/v8-inspector.h"
28
29namespace v8_inspector {
30
31using protocol::Array;
32using protocol::Maybe;
33using protocol::Debugger::BreakpointId;
34using protocol::Debugger::CallFrame;
35using protocol::Runtime::ExceptionDetails;
36using protocol::Runtime::ScriptId;
37using protocol::Runtime::StackTrace;
38using protocol::Runtime::RemoteObject;
39
40namespace DebuggerAgentState {
41static const char javaScriptBreakpoints[] = "javaScriptBreakopints";
42static const char pauseOnExceptionsState[] = "pauseOnExceptionsState";
43static const char asyncCallStackDepth[] = "asyncCallStackDepth";
44static const char blackboxPattern[] = "blackboxPattern";
45static const char debuggerEnabled[] = "debuggerEnabled";
46
47// Breakpoint properties.
48static const char url[] = "url";
49static const char isRegex[] = "isRegex";
50static const char lineNumber[] = "lineNumber";
51static const char columnNumber[] = "columnNumber";
52static const char condition[] = "condition";
53static const char skipAllPauses[] = "skipAllPauses";
54
55} // namespace DebuggerAgentState
56
Ben Murdochc8c1d9e2017-03-08 14:04:23 +000057static const char kBacktraceObjectGroup[] = "backtrace";
58static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled";
59static const char kDebuggerNotPaused[] =
60 "Can only perform operation while paused.";
Ben Murdochf3b273f2017-01-17 12:11:28 +000061
Ben Murdoch62ed6312017-06-06 11:06:27 +010062namespace {
63
64void TranslateWasmStackTraceLocations(Array<CallFrame>* stackTrace,
65 WasmTranslation* wasmTranslation) {
66 for (size_t i = 0, e = stackTrace->length(); i != e; ++i) {
67 protocol::Debugger::Location* location = stackTrace->get(i)->getLocation();
68 String16 scriptId = location->getScriptId();
69 int lineNumber = location->getLineNumber();
70 int columnNumber = location->getColumnNumber(-1);
71
72 if (!wasmTranslation->TranslateWasmScriptLocationToProtocolLocation(
73 &scriptId, &lineNumber, &columnNumber)) {
74 continue;
75 }
76
77 location->setScriptId(std::move(scriptId));
78 location->setLineNumber(lineNumber);
79 location->setColumnNumber(columnNumber);
80 }
81}
82
83String16 breakpointIdSuffix(V8DebuggerAgentImpl::BreakpointSource source) {
Ben Murdochf3b273f2017-01-17 12:11:28 +000084 switch (source) {
85 case V8DebuggerAgentImpl::UserBreakpointSource:
86 break;
87 case V8DebuggerAgentImpl::DebugCommandBreakpointSource:
88 return ":debug";
89 case V8DebuggerAgentImpl::MonitorCommandBreakpointSource:
90 return ":monitor";
91 }
92 return String16();
93}
94
Ben Murdoch62ed6312017-06-06 11:06:27 +010095String16 generateBreakpointId(const ScriptBreakpoint& breakpoint,
96 V8DebuggerAgentImpl::BreakpointSource source) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +000097 String16Builder builder;
Ben Murdoch62ed6312017-06-06 11:06:27 +010098 builder.append(breakpoint.script_id);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +000099 builder.append(':');
Ben Murdoch62ed6312017-06-06 11:06:27 +0100100 builder.appendNumber(breakpoint.line_number);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000101 builder.append(':');
Ben Murdoch62ed6312017-06-06 11:06:27 +0100102 builder.appendNumber(breakpoint.column_number);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000103 builder.append(breakpointIdSuffix(source));
104 return builder.toString();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000105}
106
Ben Murdoch62ed6312017-06-06 11:06:27 +0100107bool positionComparator(const std::pair<int, int>& a,
108 const std::pair<int, int>& b) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000109 if (a.first != b.first) return a.first < b.first;
110 return a.second < b.second;
111}
112
Ben Murdoch62ed6312017-06-06 11:06:27 +0100113std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation(
Ben Murdochf3b273f2017-01-17 12:11:28 +0000114 const String16& scriptId, int lineNumber, int columnNumber) {
115 return protocol::Debugger::Location::create()
116 .setScriptId(scriptId)
117 .setLineNumber(lineNumber)
118 .setColumnNumber(columnNumber)
119 .build();
120}
121
Ben Murdoch62ed6312017-06-06 11:06:27 +0100122} // namespace
123
Ben Murdochf3b273f2017-01-17 12:11:28 +0000124V8DebuggerAgentImpl::V8DebuggerAgentImpl(
125 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel,
126 protocol::DictionaryValue* state)
127 : m_inspector(session->inspector()),
128 m_debugger(m_inspector->debugger()),
129 m_session(session),
130 m_enabled(false),
131 m_state(state),
132 m_frontend(frontendChannel),
133 m_isolate(m_inspector->isolate()),
Ben Murdochf3b273f2017-01-17 12:11:28 +0000134 m_scheduledDebuggerStep(NoStep),
Ben Murdochf3b273f2017-01-17 12:11:28 +0000135 m_javaScriptPauseScheduled(false),
Ben Murdoch62ed6312017-06-06 11:06:27 +0100136 m_recursionLevelForStepOut(0) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000137}
138
139V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {}
140
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000141void V8DebuggerAgentImpl::enableImpl() {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000142 m_enabled = true;
143 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true);
144 m_debugger->enable();
145
146 std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts;
147 m_debugger->getCompiledScripts(m_session->contextGroupId(), compiledScripts);
148 for (size_t i = 0; i < compiledScripts.size(); i++)
149 didParseSource(std::move(compiledScripts[i]), true);
150
151 // FIXME(WK44513): breakpoints activated flag should be synchronized between
152 // all front-ends
153 m_debugger->setBreakpointsActivated(true);
154}
155
156bool V8DebuggerAgentImpl::enabled() { return m_enabled; }
157
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000158Response V8DebuggerAgentImpl::enable() {
159 if (enabled()) return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000160
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000161 if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
162 return Response::Error("Script execution is prohibited");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000163
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000164 enableImpl();
165 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000166}
167
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000168Response V8DebuggerAgentImpl::disable() {
169 if (!enabled()) return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000170
171 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints,
172 protocol::DictionaryValue::create());
173 m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState,
Ben Murdoch62ed6312017-06-06 11:06:27 +0100174 v8::debug::NoBreakOnException);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000175 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0);
176
Ben Murdoch62ed6312017-06-06 11:06:27 +0100177 if (isPaused()) m_debugger->continueProgram();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000178 m_debugger->disable();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000179 JavaScriptCallFrames emptyCallFrames;
180 m_pausedCallFrames.swap(emptyCallFrames);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000181 m_blackboxedPositions.clear();
Ben Murdoch62ed6312017-06-06 11:06:27 +0100182 m_blackboxPattern.reset();
183 resetBlackboxedStateCache();
184 m_scripts.clear();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000185 m_breakpointIdToDebuggerBreakpointIds.clear();
186 m_debugger->setAsyncCallStackDepth(this, 0);
187 m_continueToLocationBreakpointId = String16();
188 clearBreakDetails();
189 m_scheduledDebuggerStep = NoStep;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000190 m_javaScriptPauseScheduled = false;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000191 m_skipAllPauses = false;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100192 m_state->setBoolean(DebuggerAgentState::skipAllPauses, false);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000193 m_state->remove(DebuggerAgentState::blackboxPattern);
194 m_enabled = false;
195 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000196 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000197}
198
199void V8DebuggerAgentImpl::restore() {
200 DCHECK(!m_enabled);
201 if (!m_state->booleanProperty(DebuggerAgentState::debuggerEnabled, false))
202 return;
203 if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId()))
204 return;
205
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000206 enableImpl();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000207
Ben Murdoch62ed6312017-06-06 11:06:27 +0100208 int pauseState = v8::debug::NoBreakOnException;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000209 m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000210 setPauseOnExceptionsImpl(pauseState);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000211
212 m_skipAllPauses =
213 m_state->booleanProperty(DebuggerAgentState::skipAllPauses, false);
214
215 int asyncCallStackDepth = 0;
216 m_state->getInteger(DebuggerAgentState::asyncCallStackDepth,
217 &asyncCallStackDepth);
218 m_debugger->setAsyncCallStackDepth(this, asyncCallStackDepth);
219
220 String16 blackboxPattern;
221 if (m_state->getString(DebuggerAgentState::blackboxPattern,
222 &blackboxPattern)) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000223 setBlackboxPattern(blackboxPattern);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000224 }
225}
226
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000227Response V8DebuggerAgentImpl::setBreakpointsActive(bool active) {
228 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000229 m_debugger->setBreakpointsActivated(active);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000230 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000231}
232
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000233Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100234 m_state->setBoolean(DebuggerAgentState::skipAllPauses, skip);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000235 m_skipAllPauses = skip;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000236 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000237}
238
239static std::unique_ptr<protocol::DictionaryValue>
240buildObjectForBreakpointCookie(const String16& url, int lineNumber,
241 int columnNumber, const String16& condition,
242 bool isRegex) {
243 std::unique_ptr<protocol::DictionaryValue> breakpointObject =
244 protocol::DictionaryValue::create();
245 breakpointObject->setString(DebuggerAgentState::url, url);
246 breakpointObject->setInteger(DebuggerAgentState::lineNumber, lineNumber);
247 breakpointObject->setInteger(DebuggerAgentState::columnNumber, columnNumber);
248 breakpointObject->setString(DebuggerAgentState::condition, condition);
249 breakpointObject->setBoolean(DebuggerAgentState::isRegex, isRegex);
250 return breakpointObject;
251}
252
253static bool matches(V8InspectorImpl* inspector, const String16& url,
254 const String16& pattern, bool isRegex) {
255 if (isRegex) {
256 V8Regex regex(inspector, pattern, true);
257 return regex.match(url) != -1;
258 }
259 return url == pattern;
260}
261
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000262Response V8DebuggerAgentImpl::setBreakpointByUrl(
263 int lineNumber, Maybe<String16> optionalURL,
264 Maybe<String16> optionalURLRegex, Maybe<int> optionalColumnNumber,
265 Maybe<String16> optionalCondition, String16* outBreakpointId,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000266 std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) {
267 *locations = Array<protocol::Debugger::Location>::create();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000268 if (optionalURL.isJust() == optionalURLRegex.isJust())
269 return Response::Error("Either url or urlRegex must be specified.");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000270
271 String16 url = optionalURL.isJust() ? optionalURL.fromJust()
272 : optionalURLRegex.fromJust();
273 int columnNumber = 0;
274 if (optionalColumnNumber.isJust()) {
275 columnNumber = optionalColumnNumber.fromJust();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000276 if (columnNumber < 0) return Response::Error("Incorrect column number");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000277 }
278 String16 condition = optionalCondition.fromMaybe("");
279 bool isRegex = optionalURLRegex.isJust();
280
281 String16 breakpointId = (isRegex ? "/" + url + "/" : url) + ":" +
282 String16::fromInteger(lineNumber) + ":" +
283 String16::fromInteger(columnNumber);
284 protocol::DictionaryValue* breakpointsCookie =
285 m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
286 if (!breakpointsCookie) {
287 std::unique_ptr<protocol::DictionaryValue> newValue =
288 protocol::DictionaryValue::create();
289 breakpointsCookie = newValue.get();
290 m_state->setObject(DebuggerAgentState::javaScriptBreakpoints,
291 std::move(newValue));
292 }
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000293 if (breakpointsCookie->get(breakpointId))
294 return Response::Error("Breakpoint at specified location already exists.");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000295
296 breakpointsCookie->setObject(
297 breakpointId, buildObjectForBreakpointCookie(
298 url, lineNumber, columnNumber, condition, isRegex));
299
Ben Murdoch62ed6312017-06-06 11:06:27 +0100300 ScriptBreakpoint breakpoint(String16(), lineNumber, columnNumber, condition);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000301 for (const auto& script : m_scripts) {
302 if (!matches(m_inspector, script.second->sourceURL(), url, isRegex))
303 continue;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100304 breakpoint.script_id = script.first;
305 std::unique_ptr<protocol::Debugger::Location> location =
306 resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000307 if (location) (*locations)->addItem(std::move(location));
308 }
309
310 *outBreakpointId = breakpointId;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000311 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000312}
313
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000314Response V8DebuggerAgentImpl::setBreakpoint(
Ben Murdochf3b273f2017-01-17 12:11:28 +0000315 std::unique_ptr<protocol::Debugger::Location> location,
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000316 Maybe<String16> optionalCondition, String16* outBreakpointId,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000317 std::unique_ptr<protocol::Debugger::Location>* actualLocation) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100318 ScriptBreakpoint breakpoint(
319 location->getScriptId(), location->getLineNumber(),
320 location->getColumnNumber(0), optionalCondition.fromMaybe(String16()));
Ben Murdochf3b273f2017-01-17 12:11:28 +0000321
Ben Murdoch62ed6312017-06-06 11:06:27 +0100322 String16 breakpointId =
323 generateBreakpointId(breakpoint, UserBreakpointSource);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000324 if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) !=
325 m_breakpointIdToDebuggerBreakpointIds.end()) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000326 return Response::Error("Breakpoint at specified location already exists.");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000327 }
Ben Murdoch62ed6312017-06-06 11:06:27 +0100328 *actualLocation =
329 resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000330 if (!*actualLocation) return Response::Error("Could not resolve breakpoint");
331 *outBreakpointId = breakpointId;
332 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000333}
334
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000335Response V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) {
336 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000337 protocol::DictionaryValue* breakpointsCookie =
338 m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
339 if (breakpointsCookie) breakpointsCookie->remove(breakpointId);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000340 removeBreakpointImpl(breakpointId);
341 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000342}
343
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000344void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000345 DCHECK(enabled());
346 BreakpointIdToDebuggerBreakpointIdsMap::iterator
347 debuggerBreakpointIdsIterator =
348 m_breakpointIdToDebuggerBreakpointIds.find(breakpointId);
349 if (debuggerBreakpointIdsIterator ==
350 m_breakpointIdToDebuggerBreakpointIds.end())
351 return;
352 const std::vector<String16>& ids = debuggerBreakpointIdsIterator->second;
353 for (size_t i = 0; i < ids.size(); ++i) {
354 const String16& debuggerBreakpointId = ids[i];
355
356 m_debugger->removeBreakpoint(debuggerBreakpointId);
357 m_serverBreakpoints.erase(debuggerBreakpointId);
358 }
359 m_breakpointIdToDebuggerBreakpointIds.erase(breakpointId);
360}
361
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000362Response V8DebuggerAgentImpl::getPossibleBreakpoints(
363 std::unique_ptr<protocol::Debugger::Location> start,
364 Maybe<protocol::Debugger::Location> end,
365 std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) {
366 String16 scriptId = start->getScriptId();
367
368 if (start->getLineNumber() < 0 || start->getColumnNumber(0) < 0)
369 return Response::Error(
370 "start.lineNumber and start.columnNumber should be >= 0");
371
Ben Murdoch62ed6312017-06-06 11:06:27 +0100372 v8::debug::Location v8Start(start->getLineNumber(),
373 start->getColumnNumber(0));
374 v8::debug::Location v8End;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000375 if (end.isJust()) {
376 if (end.fromJust()->getScriptId() != scriptId)
377 return Response::Error("Locations should contain the same scriptId");
378 int line = end.fromJust()->getLineNumber();
379 int column = end.fromJust()->getColumnNumber(0);
380 if (line < 0 || column < 0)
381 return Response::Error(
382 "end.lineNumber and end.columnNumber should be >= 0");
Ben Murdoch62ed6312017-06-06 11:06:27 +0100383 v8End = v8::debug::Location(line, column);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000384 }
385 auto it = m_scripts.find(scriptId);
386 if (it == m_scripts.end()) return Response::Error("Script not found");
387
Ben Murdoch62ed6312017-06-06 11:06:27 +0100388 std::vector<v8::debug::Location> v8Locations;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000389 if (!it->second->getPossibleBreakpoints(v8Start, v8End, &v8Locations))
390 return Response::InternalError();
391
392 *locations = protocol::Array<protocol::Debugger::Location>::create();
393 for (size_t i = 0; i < v8Locations.size(); ++i) {
394 (*locations)
395 ->addItem(protocol::Debugger::Location::create()
396 .setScriptId(scriptId)
397 .setLineNumber(v8Locations[i].GetLineNumber())
398 .setColumnNumber(v8Locations[i].GetColumnNumber())
399 .build());
400 }
401 return Response::OK();
402}
403
404Response V8DebuggerAgentImpl::continueToLocation(
Ben Murdochf3b273f2017-01-17 12:11:28 +0000405 std::unique_ptr<protocol::Debugger::Location> location) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000406 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000407 if (!m_continueToLocationBreakpointId.isEmpty()) {
408 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
409 m_continueToLocationBreakpointId = "";
410 }
411
Ben Murdoch62ed6312017-06-06 11:06:27 +0100412 ScriptBreakpoint breakpoint(location->getScriptId(),
413 location->getLineNumber(),
414 location->getColumnNumber(0), String16());
Ben Murdochf3b273f2017-01-17 12:11:28 +0000415
Ben Murdochf3b273f2017-01-17 12:11:28 +0000416 m_continueToLocationBreakpointId = m_debugger->setBreakpoint(
Ben Murdoch62ed6312017-06-06 11:06:27 +0100417 breakpoint, &breakpoint.line_number, &breakpoint.column_number);
418 // TODO(kozyatinskiy): Return actual line and column number.
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000419 return resume();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000420}
421
Ben Murdoch62ed6312017-06-06 11:06:27 +0100422bool V8DebuggerAgentImpl::isFunctionBlackboxed(const String16& scriptId,
423 const v8::debug::Location& start,
424 const v8::debug::Location& end) {
425 ScriptsMap::iterator it = m_scripts.find(scriptId);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000426 if (it == m_scripts.end()) {
427 // Unknown scripts are blackboxed.
428 return true;
429 }
430 if (m_blackboxPattern) {
431 const String16& scriptSourceURL = it->second->sourceURL();
432 if (!scriptSourceURL.isEmpty() &&
433 m_blackboxPattern->match(scriptSourceURL) != -1)
434 return true;
435 }
Ben Murdoch62ed6312017-06-06 11:06:27 +0100436 auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000437 if (itBlackboxedPositions == m_blackboxedPositions.end()) return false;
438
439 const std::vector<std::pair<int, int>>& ranges =
440 itBlackboxedPositions->second;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100441 auto itStartRange = std::lower_bound(
Ben Murdochf3b273f2017-01-17 12:11:28 +0000442 ranges.begin(), ranges.end(),
Ben Murdoch62ed6312017-06-06 11:06:27 +0100443 std::make_pair(start.GetLineNumber(), start.GetColumnNumber()),
444 positionComparator);
445 auto itEndRange = std::lower_bound(
446 itStartRange, ranges.end(),
447 std::make_pair(end.GetLineNumber(), end.GetColumnNumber()),
448 positionComparator);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000449 // Ranges array contains positions in script where blackbox state is changed.
450 // [(0,0) ... ranges[0]) isn't blackboxed, [ranges[0] ... ranges[1]) is
451 // blackboxed...
Ben Murdoch62ed6312017-06-06 11:06:27 +0100452 return itStartRange == itEndRange &&
453 std::distance(ranges.begin(), itStartRange) % 2;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000454}
455
456std::unique_ptr<protocol::Debugger::Location>
457V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000458 const ScriptBreakpoint& breakpoint,
459 BreakpointSource source) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100460 v8::HandleScope handles(m_isolate);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000461 DCHECK(enabled());
462 // FIXME: remove these checks once crbug.com/520702 is resolved.
463 CHECK(!breakpointId.isEmpty());
Ben Murdoch62ed6312017-06-06 11:06:27 +0100464 CHECK(!breakpoint.script_id.isEmpty());
465 ScriptsMap::iterator scriptIterator = m_scripts.find(breakpoint.script_id);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000466 if (scriptIterator == m_scripts.end()) return nullptr;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100467 if (breakpoint.line_number < scriptIterator->second->startLine() ||
468 scriptIterator->second->endLine() < breakpoint.line_number)
Ben Murdochf3b273f2017-01-17 12:11:28 +0000469 return nullptr;
470
Ben Murdoch62ed6312017-06-06 11:06:27 +0100471 // Translate from protocol location to v8 location for the debugger.
472 ScriptBreakpoint translatedBreakpoint = breakpoint;
473 m_debugger->wasmTranslation()->TranslateProtocolLocationToWasmScriptLocation(
474 &translatedBreakpoint.script_id, &translatedBreakpoint.line_number,
475 &translatedBreakpoint.column_number);
476
Ben Murdochf3b273f2017-01-17 12:11:28 +0000477 int actualLineNumber;
478 int actualColumnNumber;
479 String16 debuggerBreakpointId = m_debugger->setBreakpoint(
Ben Murdoch62ed6312017-06-06 11:06:27 +0100480 translatedBreakpoint, &actualLineNumber, &actualColumnNumber);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000481 if (debuggerBreakpointId.isEmpty()) return nullptr;
482
Ben Murdoch62ed6312017-06-06 11:06:27 +0100483 // Translate back from v8 location to protocol location for the return value.
484 m_debugger->wasmTranslation()->TranslateWasmScriptLocationToProtocolLocation(
485 &translatedBreakpoint.script_id, &actualLineNumber, &actualColumnNumber);
486
Ben Murdochf3b273f2017-01-17 12:11:28 +0000487 m_serverBreakpoints[debuggerBreakpointId] =
488 std::make_pair(breakpointId, source);
489 CHECK(!breakpointId.isEmpty());
490
491 m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back(
492 debuggerBreakpointId);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100493 return buildProtocolLocation(translatedBreakpoint.script_id, actualLineNumber,
494 actualColumnNumber);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000495}
496
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000497Response V8DebuggerAgentImpl::searchInContent(
498 const String16& scriptId, const String16& query,
499 Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000500 std::unique_ptr<Array<protocol::Debugger::SearchMatch>>* results) {
501 v8::HandleScope handles(m_isolate);
502 ScriptsMap::iterator it = m_scripts.find(scriptId);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000503 if (it == m_scripts.end())
504 return Response::Error("No script for id: " + scriptId);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000505
506 std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
Ben Murdoch62ed6312017-06-06 11:06:27 +0100507 searchInTextByLinesImpl(m_session, it->second->source(m_isolate), query,
508 optionalCaseSensitive.fromMaybe(false),
Ben Murdochf3b273f2017-01-17 12:11:28 +0000509 optionalIsRegex.fromMaybe(false));
510 *results = protocol::Array<protocol::Debugger::SearchMatch>::create();
511 for (size_t i = 0; i < matches.size(); ++i)
512 (*results)->addItem(std::move(matches[i]));
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000513 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000514}
515
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000516Response V8DebuggerAgentImpl::setScriptSource(
517 const String16& scriptId, const String16& newContent, Maybe<bool> dryRun,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000518 Maybe<protocol::Array<protocol::Debugger::CallFrame>>* newCallFrames,
519 Maybe<bool>* stackChanged, Maybe<StackTrace>* asyncStackTrace,
520 Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000521 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000522
Ben Murdoch62ed6312017-06-06 11:06:27 +0100523 ScriptsMap::iterator it = m_scripts.find(scriptId);
524 if (it == m_scripts.end()) {
525 return Response::Error("No script with given id found");
526 }
527 if (it->second->isModule()) {
528 // TODO(kozyatinskiy): LiveEdit should support ES6 module
529 return Response::Error("Editing module's script is not supported.");
530 }
531
Ben Murdochf3b273f2017-01-17 12:11:28 +0000532 v8::HandleScope handles(m_isolate);
533 v8::Local<v8::String> newSource = toV8String(m_isolate, newContent);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000534 bool compileError = false;
535 Response response = m_debugger->setScriptSource(
536 scriptId, newSource, dryRun.fromMaybe(false), optOutCompileError,
537 &m_pausedCallFrames, stackChanged, &compileError);
538 if (!response.isSuccess() || compileError) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000539
Ben Murdoch62ed6312017-06-06 11:06:27 +0100540 it->second->setSource(newSource);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000541 std::unique_ptr<Array<CallFrame>> callFrames;
542 response = currentCallFrames(&callFrames);
543 if (!response.isSuccess()) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000544 *newCallFrames = std::move(callFrames);
545 *asyncStackTrace = currentAsyncStackTrace();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000546 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000547}
548
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000549Response V8DebuggerAgentImpl::restartFrame(
550 const String16& callFrameId,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000551 std::unique_ptr<Array<CallFrame>>* newCallFrames,
552 Maybe<StackTrace>* asyncStackTrace) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100553 if (!isPaused()) return Response::Error(kDebuggerNotPaused);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000554 InjectedScript::CallFrameScope scope(m_inspector, m_session->contextGroupId(),
555 callFrameId);
556 Response response = scope.initialize();
557 if (!response.isSuccess()) return response;
558 if (scope.frameOrdinal() >= m_pausedCallFrames.size())
559 return Response::Error("Could not find call frame with given id");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000560
561 v8::Local<v8::Value> resultValue;
562 v8::Local<v8::Boolean> result;
563 if (!m_pausedCallFrames[scope.frameOrdinal()]->restart().ToLocal(
564 &resultValue) ||
565 scope.tryCatch().HasCaught() ||
566 !resultValue->ToBoolean(scope.context()).ToLocal(&result) ||
567 !result->Value()) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000568 return Response::InternalError();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000569 }
570 JavaScriptCallFrames frames = m_debugger->currentCallFrames();
571 m_pausedCallFrames.swap(frames);
572
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000573 response = currentCallFrames(newCallFrames);
574 if (!response.isSuccess()) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000575 *asyncStackTrace = currentAsyncStackTrace();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000576 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000577}
578
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000579Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId,
580 String16* scriptSource) {
581 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000582 ScriptsMap::iterator it = m_scripts.find(scriptId);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000583 if (it == m_scripts.end())
584 return Response::Error("No script for id: " + scriptId);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000585 v8::HandleScope handles(m_isolate);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100586 *scriptSource = it->second->source(m_isolate);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000587 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000588}
589
Ben Murdoch62ed6312017-06-06 11:06:27 +0100590void V8DebuggerAgentImpl::pushBreakDetails(
591 const String16& breakReason,
592 std::unique_ptr<protocol::DictionaryValue> breakAuxData) {
593 m_breakReason.push_back(std::make_pair(breakReason, std::move(breakAuxData)));
594}
595
596void V8DebuggerAgentImpl::popBreakDetails() {
597 if (m_breakReason.empty()) return;
598 m_breakReason.pop_back();
599}
600
601void V8DebuggerAgentImpl::clearBreakDetails() {
602 std::vector<BreakReason> emptyBreakReason;
603 m_breakReason.swap(emptyBreakReason);
604}
605
Ben Murdochf3b273f2017-01-17 12:11:28 +0000606void V8DebuggerAgentImpl::schedulePauseOnNextStatement(
607 const String16& breakReason,
608 std::unique_ptr<protocol::DictionaryValue> data) {
609 if (!enabled() || m_scheduledDebuggerStep == StepInto ||
Ben Murdoch62ed6312017-06-06 11:06:27 +0100610 m_javaScriptPauseScheduled || isPaused() ||
Ben Murdochf3b273f2017-01-17 12:11:28 +0000611 !m_debugger->breakpointsActivated())
612 return;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100613 if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(true);
614 pushBreakDetails(breakReason, std::move(data));
Ben Murdochf3b273f2017-01-17 12:11:28 +0000615}
616
617void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() {
618 DCHECK(enabled());
619 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled ||
Ben Murdoch62ed6312017-06-06 11:06:27 +0100620 isPaused())
Ben Murdochf3b273f2017-01-17 12:11:28 +0000621 return;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000622 m_debugger->setPauseOnNextStatement(true);
623}
624
625void V8DebuggerAgentImpl::cancelPauseOnNextStatement() {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100626 if (m_javaScriptPauseScheduled || isPaused()) return;
627 popBreakDetails();
628 if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000629}
630
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000631Response V8DebuggerAgentImpl::pause() {
632 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100633 if (m_javaScriptPauseScheduled || isPaused()) return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000634 clearBreakDetails();
635 m_javaScriptPauseScheduled = true;
636 m_scheduledDebuggerStep = NoStep;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000637 m_debugger->setPauseOnNextStatement(true);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000638 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000639}
640
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000641Response V8DebuggerAgentImpl::resume() {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100642 if (!isPaused()) return Response::Error(kDebuggerNotPaused);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000643 m_scheduledDebuggerStep = NoStep;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000644 m_session->releaseObjectGroup(kBacktraceObjectGroup);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000645 m_debugger->continueProgram();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000646 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000647}
648
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000649Response V8DebuggerAgentImpl::stepOver() {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100650 if (!isPaused()) return Response::Error(kDebuggerNotPaused);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000651 // StepOver at function return point should fallback to StepInto.
652 JavaScriptCallFrame* frame =
653 !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000654 if (frame && frame->isAtReturn()) return stepInto();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000655 m_scheduledDebuggerStep = StepOver;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000656 m_session->releaseObjectGroup(kBacktraceObjectGroup);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000657 m_debugger->stepOverStatement();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000658 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000659}
660
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000661Response V8DebuggerAgentImpl::stepInto() {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100662 if (!isPaused()) return Response::Error(kDebuggerNotPaused);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000663 m_scheduledDebuggerStep = StepInto;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000664 m_session->releaseObjectGroup(kBacktraceObjectGroup);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000665 m_debugger->stepIntoStatement();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000666 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000667}
668
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000669Response V8DebuggerAgentImpl::stepOut() {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100670 if (!isPaused()) return Response::Error(kDebuggerNotPaused);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000671 m_scheduledDebuggerStep = StepOut;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000672 m_recursionLevelForStepOut = 1;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000673 m_session->releaseObjectGroup(kBacktraceObjectGroup);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000674 m_debugger->stepOutOfFunction();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000675 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000676}
677
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000678Response V8DebuggerAgentImpl::setPauseOnExceptions(
679 const String16& stringPauseState) {
680 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100681 v8::debug::ExceptionBreakState pauseState;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000682 if (stringPauseState == "none") {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100683 pauseState = v8::debug::NoBreakOnException;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000684 } else if (stringPauseState == "all") {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100685 pauseState = v8::debug::BreakOnAnyException;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000686 } else if (stringPauseState == "uncaught") {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100687 pauseState = v8::debug::BreakOnUncaughtException;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000688 } else {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000689 return Response::Error("Unknown pause on exceptions mode: " +
690 stringPauseState);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000691 }
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000692 setPauseOnExceptionsImpl(pauseState);
693 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000694}
695
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000696void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000697 m_debugger->setPauseOnExceptionsState(
Ben Murdoch62ed6312017-06-06 11:06:27 +0100698 static_cast<v8::debug::ExceptionBreakState>(pauseState));
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000699 m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000700}
701
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000702Response V8DebuggerAgentImpl::evaluateOnCallFrame(
703 const String16& callFrameId, const String16& expression,
704 Maybe<String16> objectGroup, Maybe<bool> includeCommandLineAPI,
705 Maybe<bool> silent, Maybe<bool> returnByValue, Maybe<bool> generatePreview,
Ben Murdoch62ed6312017-06-06 11:06:27 +0100706 Maybe<bool> throwOnSideEffect, std::unique_ptr<RemoteObject>* result,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000707 Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100708 if (!isPaused()) return Response::Error(kDebuggerNotPaused);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000709 InjectedScript::CallFrameScope scope(m_inspector, m_session->contextGroupId(),
710 callFrameId);
711 Response response = scope.initialize();
712 if (!response.isSuccess()) return response;
713 if (scope.frameOrdinal() >= m_pausedCallFrames.size())
714 return Response::Error("Could not find call frame with given id");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000715
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000716 if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000717 if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole();
718
719 v8::MaybeLocal<v8::Value> maybeResultValue =
720 m_pausedCallFrames[scope.frameOrdinal()]->evaluate(
Ben Murdoch62ed6312017-06-06 11:06:27 +0100721 toV8String(m_isolate, expression),
722 throwOnSideEffect.fromMaybe(false));
Ben Murdochf3b273f2017-01-17 12:11:28 +0000723
724 // Re-initialize after running client's code, as it could have destroyed
725 // context or session.
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000726 response = scope.initialize();
727 if (!response.isSuccess()) return response;
728 return scope.injectedScript()->wrapEvaluateResult(
729 maybeResultValue, scope.tryCatch(), objectGroup.fromMaybe(""),
730 returnByValue.fromMaybe(false), generatePreview.fromMaybe(false), result,
731 exceptionDetails);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000732}
733
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000734Response V8DebuggerAgentImpl::setVariableValue(
735 int scopeNumber, const String16& variableName,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000736 std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument,
737 const String16& callFrameId) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000738 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100739 if (!isPaused()) return Response::Error(kDebuggerNotPaused);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000740 InjectedScript::CallFrameScope scope(m_inspector, m_session->contextGroupId(),
741 callFrameId);
742 Response response = scope.initialize();
743 if (!response.isSuccess()) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000744 v8::Local<v8::Value> newValue;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000745 response = scope.injectedScript()->resolveCallArgument(newValueArgument.get(),
746 &newValue);
747 if (!response.isSuccess()) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000748
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000749 if (scope.frameOrdinal() >= m_pausedCallFrames.size())
750 return Response::Error("Could not find call frame with given id");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000751 v8::MaybeLocal<v8::Value> result =
752 m_pausedCallFrames[scope.frameOrdinal()]->setVariableValue(
753 scopeNumber, toV8String(m_isolate, variableName), newValue);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000754 if (scope.tryCatch().HasCaught() || result.IsEmpty())
755 return Response::InternalError();
756 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000757}
758
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000759Response V8DebuggerAgentImpl::setAsyncCallStackDepth(int depth) {
760 if (!enabled()) return Response::Error(kDebuggerNotEnabled);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000761 m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth);
762 m_debugger->setAsyncCallStackDepth(this, depth);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000763 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000764}
765
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000766Response V8DebuggerAgentImpl::setBlackboxPatterns(
Ben Murdochf3b273f2017-01-17 12:11:28 +0000767 std::unique_ptr<protocol::Array<String16>> patterns) {
768 if (!patterns->length()) {
769 m_blackboxPattern = nullptr;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100770 resetBlackboxedStateCache();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000771 m_state->remove(DebuggerAgentState::blackboxPattern);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000772 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000773 }
774
775 String16Builder patternBuilder;
776 patternBuilder.append('(');
777 for (size_t i = 0; i < patterns->length() - 1; ++i) {
778 patternBuilder.append(patterns->get(i));
779 patternBuilder.append("|");
780 }
781 patternBuilder.append(patterns->get(patterns->length() - 1));
782 patternBuilder.append(')');
783 String16 pattern = patternBuilder.toString();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000784 Response response = setBlackboxPattern(pattern);
785 if (!response.isSuccess()) return response;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100786 resetBlackboxedStateCache();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000787 m_state->setString(DebuggerAgentState::blackboxPattern, pattern);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000788 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000789}
790
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000791Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000792 std::unique_ptr<V8Regex> regex(new V8Regex(
793 m_inspector, pattern, true /** caseSensitive */, false /** multiline */));
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000794 if (!regex->isValid())
795 return Response::Error("Pattern parser error: " + regex->errorMessage());
Ben Murdochf3b273f2017-01-17 12:11:28 +0000796 m_blackboxPattern = std::move(regex);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000797 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000798}
799
Ben Murdoch62ed6312017-06-06 11:06:27 +0100800void V8DebuggerAgentImpl::resetBlackboxedStateCache() {
801 for (const auto& it : m_scripts) {
802 it.second->resetBlackboxedStateCache();
803 }
804}
805
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000806Response V8DebuggerAgentImpl::setBlackboxedRanges(
807 const String16& scriptId,
Ben Murdochf3b273f2017-01-17 12:11:28 +0000808 std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
809 inPositions) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100810 auto it = m_scripts.find(scriptId);
811 if (it == m_scripts.end())
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000812 return Response::Error("No script with passed id.");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000813
814 if (!inPositions->length()) {
815 m_blackboxedPositions.erase(scriptId);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100816 it->second->resetBlackboxedStateCache();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000817 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000818 }
819
820 std::vector<std::pair<int, int>> positions;
821 positions.reserve(inPositions->length());
822 for (size_t i = 0; i < inPositions->length(); ++i) {
823 protocol::Debugger::ScriptPosition* position = inPositions->get(i);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000824 if (position->getLineNumber() < 0)
825 return Response::Error("Position missing 'line' or 'line' < 0.");
826 if (position->getColumnNumber() < 0)
827 return Response::Error("Position missing 'column' or 'column' < 0.");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000828 positions.push_back(
829 std::make_pair(position->getLineNumber(), position->getColumnNumber()));
830 }
831
832 for (size_t i = 1; i < positions.size(); ++i) {
833 if (positions[i - 1].first < positions[i].first) continue;
834 if (positions[i - 1].first == positions[i].first &&
835 positions[i - 1].second < positions[i].second)
836 continue;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000837 return Response::Error(
838 "Input positions array is not sorted or contains duplicate values.");
Ben Murdochf3b273f2017-01-17 12:11:28 +0000839 }
840
841 m_blackboxedPositions[scriptId] = positions;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100842 it->second->resetBlackboxedStateCache();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000843 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000844}
845
846void V8DebuggerAgentImpl::willExecuteScript(int scriptId) {
847 changeJavaScriptRecursionLevel(+1);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000848 if (m_scheduledDebuggerStep != StepInto) return;
849 schedulePauseOnNextStatementIfSteppingInto();
850}
851
852void V8DebuggerAgentImpl::didExecuteScript() {
853 changeJavaScriptRecursionLevel(-1);
854}
855
856void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100857 if (m_javaScriptPauseScheduled && !m_skipAllPauses && !isPaused()) {
Ben Murdochf3b273f2017-01-17 12:11:28 +0000858 // Do not ever loose user's pause request until we have actually paused.
859 m_debugger->setPauseOnNextStatement(true);
860 }
861 if (m_scheduledDebuggerStep == StepOut) {
862 m_recursionLevelForStepOut += step;
863 if (!m_recursionLevelForStepOut) {
864 // When StepOut crosses a task boundary (i.e. js -> c++) from where it was
865 // requested,
866 // switch stepping to step into a next JS task, as if we exited to a
867 // blackboxed framework.
868 m_scheduledDebuggerStep = StepInto;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000869 }
870 }
871}
872
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000873Response V8DebuggerAgentImpl::currentCallFrames(
874 std::unique_ptr<Array<CallFrame>>* result) {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100875 if (!isPaused()) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000876 *result = Array<CallFrame>::create();
877 return Response::OK();
878 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000879 v8::HandleScope handles(m_isolate);
880 v8::Local<v8::Context> debuggerContext =
Ben Murdoch62ed6312017-06-06 11:06:27 +0100881 v8::debug::GetDebugContext(m_isolate);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000882 v8::Context::Scope contextScope(debuggerContext);
883
884 v8::Local<v8::Array> objects = v8::Array::New(m_isolate);
885
886 for (size_t frameOrdinal = 0; frameOrdinal < m_pausedCallFrames.size();
887 ++frameOrdinal) {
888 const std::unique_ptr<JavaScriptCallFrame>& currentCallFrame =
889 m_pausedCallFrames[frameOrdinal];
890
Ben Murdoch62ed6312017-06-06 11:06:27 +0100891 v8::Local<v8::Object> details;
892 if (!currentCallFrame->details().ToLocal(&details))
893 return Response::InternalError();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000894
895 int contextId = currentCallFrame->contextId();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000896
897 InjectedScript* injectedScript = nullptr;
898 if (contextId) m_session->findInjectedScript(contextId, injectedScript);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000899
900 String16 callFrameId =
901 RemoteCallFrameId::serialize(contextId, static_cast<int>(frameOrdinal));
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000902 if (!details
903 ->Set(debuggerContext,
904 toV8StringInternalized(m_isolate, "callFrameId"),
905 toV8String(m_isolate, callFrameId))
906 .FromMaybe(false)) {
907 return Response::InternalError();
908 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000909
910 if (injectedScript) {
911 v8::Local<v8::Value> scopeChain;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000912 if (!details
913 ->Get(debuggerContext,
914 toV8StringInternalized(m_isolate, "scopeChain"))
915 .ToLocal(&scopeChain) ||
916 !scopeChain->IsArray()) {
917 return Response::InternalError();
918 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000919 v8::Local<v8::Array> scopeChainArray = scopeChain.As<v8::Array>();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000920 Response response = injectedScript->wrapPropertyInArray(
921 scopeChainArray, toV8StringInternalized(m_isolate, "object"),
922 kBacktraceObjectGroup);
923 if (!response.isSuccess()) return response;
924 response = injectedScript->wrapObjectProperty(
925 details, toV8StringInternalized(m_isolate, "this"),
926 kBacktraceObjectGroup);
927 if (!response.isSuccess()) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000928 if (details
929 ->Has(debuggerContext,
930 toV8StringInternalized(m_isolate, "returnValue"))
931 .FromMaybe(false)) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000932 response = injectedScript->wrapObjectProperty(
933 details, toV8StringInternalized(m_isolate, "returnValue"),
934 kBacktraceObjectGroup);
935 if (!response.isSuccess()) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000936 }
937 } else {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000938 if (!details
939 ->Set(debuggerContext,
940 toV8StringInternalized(m_isolate, "scopeChain"),
941 v8::Array::New(m_isolate, 0))
942 .FromMaybe(false)) {
943 return Response::InternalError();
944 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000945 v8::Local<v8::Object> remoteObject = v8::Object::New(m_isolate);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000946 if (!remoteObject
947 ->Set(debuggerContext, toV8StringInternalized(m_isolate, "type"),
948 toV8StringInternalized(m_isolate, "undefined"))
949 .FromMaybe(false)) {
950 return Response::InternalError();
951 }
952 if (!details
953 ->Set(debuggerContext, toV8StringInternalized(m_isolate, "this"),
954 remoteObject)
955 .FromMaybe(false)) {
956 return Response::InternalError();
957 }
958 if (!details
959 ->Delete(debuggerContext,
960 toV8StringInternalized(m_isolate, "returnValue"))
961 .FromMaybe(false)) {
962 return Response::InternalError();
963 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000964 }
965
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000966 if (!objects->Set(debuggerContext, static_cast<int>(frameOrdinal), details)
967 .FromMaybe(false)) {
968 return Response::InternalError();
969 }
Ben Murdochf3b273f2017-01-17 12:11:28 +0000970 }
971
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000972 std::unique_ptr<protocol::Value> protocolValue;
973 Response response = toProtocolValue(debuggerContext, objects, &protocolValue);
974 if (!response.isSuccess()) return response;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000975 protocol::ErrorSupport errorSupport;
Ben Murdoch62ed6312017-06-06 11:06:27 +0100976 *result = Array<CallFrame>::fromValue(protocolValue.get(), &errorSupport);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000977 if (!*result) return Response::Error(errorSupport.errors());
Ben Murdoch62ed6312017-06-06 11:06:27 +0100978 TranslateWasmStackTraceLocations(result->get(),
979 m_debugger->wasmTranslation());
Ben Murdochc8c1d9e2017-03-08 14:04:23 +0000980 return Response::OK();
Ben Murdochf3b273f2017-01-17 12:11:28 +0000981}
982
983std::unique_ptr<StackTrace> V8DebuggerAgentImpl::currentAsyncStackTrace() {
Ben Murdoch62ed6312017-06-06 11:06:27 +0100984 if (!isPaused()) return nullptr;
Ben Murdochf3b273f2017-01-17 12:11:28 +0000985 V8StackTraceImpl* stackTrace = m_debugger->currentAsyncCallChain();
986 return stackTrace ? stackTrace->buildInspectorObjectForTail(m_debugger)
987 : nullptr;
988}
989
Ben Murdoch62ed6312017-06-06 11:06:27 +0100990bool V8DebuggerAgentImpl::isPaused() const { return m_debugger->isPaused(); }
991
Ben Murdochf3b273f2017-01-17 12:11:28 +0000992void V8DebuggerAgentImpl::didParseSource(
993 std::unique_ptr<V8DebuggerScript> script, bool success) {
994 v8::HandleScope handles(m_isolate);
Ben Murdoch62ed6312017-06-06 11:06:27 +0100995 String16 scriptSource = script->source(m_isolate);
Ben Murdochf3b273f2017-01-17 12:11:28 +0000996 if (!success) script->setSourceURL(findSourceURL(scriptSource, false));
997 if (!success)
998 script->setSourceMappingURL(findSourceMapURL(scriptSource, false));
999
Ben Murdoch62ed6312017-06-06 11:06:27 +01001000 int contextId = script->executionContextId();
1001 int contextGroupId = m_inspector->contextGroupId(contextId);
1002 InspectedContext* inspected =
1003 m_inspector->getContext(contextGroupId, contextId);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001004 std::unique_ptr<protocol::DictionaryValue> executionContextAuxData;
Ben Murdoch62ed6312017-06-06 11:06:27 +01001005 if (inspected) {
1006 // Script reused between different groups/sessions can have a stale
1007 // execution context id.
Ben Murdochf3b273f2017-01-17 12:11:28 +00001008 executionContextAuxData = protocol::DictionaryValue::cast(
Ben Murdoch62ed6312017-06-06 11:06:27 +01001009 protocol::StringUtil::parseJSON(inspected->auxData()));
1010 }
Ben Murdochf3b273f2017-01-17 12:11:28 +00001011 bool isLiveEdit = script->isLiveEdit();
1012 bool hasSourceURL = script->hasSourceURL();
Ben Murdoch62ed6312017-06-06 11:06:27 +01001013 bool isModule = script->isModule();
Ben Murdochf3b273f2017-01-17 12:11:28 +00001014 String16 scriptId = script->scriptId();
1015 String16 scriptURL = script->sourceURL();
1016
Ben Murdoch62ed6312017-06-06 11:06:27 +01001017 m_scripts[scriptId] = std::move(script);
1018
1019 ScriptsMap::iterator scriptIterator = m_scripts.find(scriptId);
1020 DCHECK(scriptIterator != m_scripts.end());
1021 V8DebuggerScript* scriptRef = scriptIterator->second.get();
1022 // V8 could create functions for parsed scripts before reporting and asks
1023 // inspector about blackboxed state, we should reset state each time when we
1024 // make any change that change isFunctionBlackboxed output - adding parsed
1025 // script is changing.
1026 scriptRef->resetBlackboxedStateCache();
1027
1028 Maybe<String16> sourceMapURLParam = scriptRef->sourceMappingURL();
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001029 Maybe<protocol::DictionaryValue> executionContextAuxDataParam(
Ben Murdochf3b273f2017-01-17 12:11:28 +00001030 std::move(executionContextAuxData));
1031 const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr;
1032 const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr;
Ben Murdoch62ed6312017-06-06 11:06:27 +01001033 const bool* isModuleParam = isModule ? &isModule : nullptr;
Ben Murdochf3b273f2017-01-17 12:11:28 +00001034 if (success)
1035 m_frontend.scriptParsed(
Ben Murdoch62ed6312017-06-06 11:06:27 +01001036 scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
1037 scriptRef->endLine(), scriptRef->endColumn(), contextId,
1038 scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam),
1039 isLiveEditParam, std::move(sourceMapURLParam), hasSourceURLParam,
1040 isModuleParam);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001041 else
1042 m_frontend.scriptFailedToParse(
Ben Murdoch62ed6312017-06-06 11:06:27 +01001043 scriptId, scriptURL, scriptRef->startLine(), scriptRef->startColumn(),
1044 scriptRef->endLine(), scriptRef->endColumn(), contextId,
1045 scriptRef->hash(m_isolate), std::move(executionContextAuxDataParam),
1046 std::move(sourceMapURLParam), hasSourceURLParam, isModuleParam);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001047
1048 if (scriptURL.isEmpty() || !success) return;
1049
1050 protocol::DictionaryValue* breakpointsCookie =
1051 m_state->getObject(DebuggerAgentState::javaScriptBreakpoints);
1052 if (!breakpointsCookie) return;
1053
1054 for (size_t i = 0; i < breakpointsCookie->size(); ++i) {
1055 auto cookie = breakpointsCookie->at(i);
1056 protocol::DictionaryValue* breakpointObject =
1057 protocol::DictionaryValue::cast(cookie.second);
1058 bool isRegex;
1059 breakpointObject->getBoolean(DebuggerAgentState::isRegex, &isRegex);
1060 String16 url;
1061 breakpointObject->getString(DebuggerAgentState::url, &url);
1062 if (!matches(m_inspector, scriptURL, url, isRegex)) continue;
1063 ScriptBreakpoint breakpoint;
Ben Murdoch62ed6312017-06-06 11:06:27 +01001064 breakpoint.script_id = scriptId;
Ben Murdochf3b273f2017-01-17 12:11:28 +00001065 breakpointObject->getInteger(DebuggerAgentState::lineNumber,
Ben Murdoch62ed6312017-06-06 11:06:27 +01001066 &breakpoint.line_number);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001067 breakpointObject->getInteger(DebuggerAgentState::columnNumber,
Ben Murdoch62ed6312017-06-06 11:06:27 +01001068 &breakpoint.column_number);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001069 breakpointObject->getString(DebuggerAgentState::condition,
1070 &breakpoint.condition);
Ben Murdoch62ed6312017-06-06 11:06:27 +01001071 std::unique_ptr<protocol::Debugger::Location> location =
1072 resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001073 if (location)
1074 m_frontend.breakpointResolved(cookie.first, std::move(location));
1075 }
1076}
1077
Ben Murdoch62ed6312017-06-06 11:06:27 +01001078void V8DebuggerAgentImpl::didPause(int contextId,
1079 v8::Local<v8::Value> exception,
1080 const std::vector<String16>& hitBreakpoints,
1081 bool isPromiseRejection, bool isUncaught,
1082 bool isOOMBreak) {
Ben Murdochf3b273f2017-01-17 12:11:28 +00001083 JavaScriptCallFrames frames = m_debugger->currentCallFrames();
1084 m_pausedCallFrames.swap(frames);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001085 v8::HandleScope handles(m_isolate);
1086
Ben Murdoch62ed6312017-06-06 11:06:27 +01001087 std::vector<BreakReason> hitReasons;
1088
1089 if (isOOMBreak) {
1090 hitReasons.push_back(
1091 std::make_pair(protocol::Debugger::Paused::ReasonEnum::OOM, nullptr));
1092 } else if (!exception.IsEmpty()) {
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001093 InjectedScript* injectedScript = nullptr;
Ben Murdoch62ed6312017-06-06 11:06:27 +01001094 m_session->findInjectedScript(contextId, injectedScript);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001095 if (injectedScript) {
Ben Murdoch62ed6312017-06-06 11:06:27 +01001096 String16 breakReason =
Ben Murdochf3b273f2017-01-17 12:11:28 +00001097 isPromiseRejection
1098 ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection
1099 : protocol::Debugger::Paused::ReasonEnum::Exception;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001100 std::unique_ptr<protocol::Runtime::RemoteObject> obj;
1101 injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false,
1102 &obj);
Ben Murdoch62ed6312017-06-06 11:06:27 +01001103 std::unique_ptr<protocol::DictionaryValue> breakAuxData;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001104 if (obj) {
Ben Murdoch62ed6312017-06-06 11:06:27 +01001105 breakAuxData = obj->toValue();
1106 breakAuxData->setBoolean("uncaught", isUncaught);
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001107 } else {
Ben Murdoch62ed6312017-06-06 11:06:27 +01001108 breakAuxData = nullptr;
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001109 }
Ben Murdoch62ed6312017-06-06 11:06:27 +01001110 hitReasons.push_back(
1111 std::make_pair(breakReason, std::move(breakAuxData)));
Ben Murdochf3b273f2017-01-17 12:11:28 +00001112 }
1113 }
1114
1115 std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create();
1116
Ben Murdoch62ed6312017-06-06 11:06:27 +01001117 bool hasDebugCommandBreakpointReason = false;
Ben Murdochf3b273f2017-01-17 12:11:28 +00001118 for (const auto& point : hitBreakpoints) {
1119 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator
1120 breakpointIterator = m_serverBreakpoints.find(point);
1121 if (breakpointIterator != m_serverBreakpoints.end()) {
1122 const String16& localId = breakpointIterator->second.first;
1123 hitBreakpointIds->addItem(localId);
1124
1125 BreakpointSource source = breakpointIterator->second.second;
Ben Murdoch62ed6312017-06-06 11:06:27 +01001126 if (!hasDebugCommandBreakpointReason &&
1127 source == DebugCommandBreakpointSource) {
1128 hasDebugCommandBreakpointReason = true;
1129 hitReasons.push_back(std::make_pair(
1130 protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr));
1131 }
Ben Murdochf3b273f2017-01-17 12:11:28 +00001132 }
1133 }
1134
Ben Murdoch62ed6312017-06-06 11:06:27 +01001135 for (size_t i = 0; i < m_breakReason.size(); ++i) {
1136 hitReasons.push_back(std::move(m_breakReason[i]));
1137 }
1138 clearBreakDetails();
1139
1140 String16 breakReason = protocol::Debugger::Paused::ReasonEnum::Other;
1141 std::unique_ptr<protocol::DictionaryValue> breakAuxData;
1142 if (hitReasons.size() == 1) {
1143 breakReason = hitReasons[0].first;
1144 breakAuxData = std::move(hitReasons[0].second);
1145 } else if (hitReasons.size() > 1) {
1146 breakReason = protocol::Debugger::Paused::ReasonEnum::Ambiguous;
1147 std::unique_ptr<protocol::ListValue> reasons =
1148 protocol::ListValue::create();
1149 for (size_t i = 0; i < hitReasons.size(); ++i) {
1150 std::unique_ptr<protocol::DictionaryValue> reason =
1151 protocol::DictionaryValue::create();
1152 reason->setString("reason", hitReasons[i].first);
1153 if (hitReasons[i].second)
1154 reason->setObject("auxData", std::move(hitReasons[i].second));
1155 reasons->pushValue(std::move(reason));
1156 }
1157 breakAuxData = protocol::DictionaryValue::create();
1158 breakAuxData->setArray("reasons", std::move(reasons));
1159 }
1160
Ben Murdochc8c1d9e2017-03-08 14:04:23 +00001161 std::unique_ptr<Array<CallFrame>> protocolCallFrames;
1162 Response response = currentCallFrames(&protocolCallFrames);
1163 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create();
Ben Murdoch62ed6312017-06-06 11:06:27 +01001164 m_frontend.paused(std::move(protocolCallFrames), breakReason,
1165 std::move(breakAuxData), std::move(hitBreakpointIds),
Ben Murdochf3b273f2017-01-17 12:11:28 +00001166 currentAsyncStackTrace());
1167 m_scheduledDebuggerStep = NoStep;
1168 m_javaScriptPauseScheduled = false;
Ben Murdochf3b273f2017-01-17 12:11:28 +00001169
1170 if (!m_continueToLocationBreakpointId.isEmpty()) {
1171 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId);
1172 m_continueToLocationBreakpointId = "";
1173 }
Ben Murdochf3b273f2017-01-17 12:11:28 +00001174}
1175
1176void V8DebuggerAgentImpl::didContinue() {
Ben Murdochf3b273f2017-01-17 12:11:28 +00001177 JavaScriptCallFrames emptyCallFrames;
1178 m_pausedCallFrames.swap(emptyCallFrames);
1179 clearBreakDetails();
1180 m_frontend.resumed();
1181}
1182
1183void V8DebuggerAgentImpl::breakProgram(
1184 const String16& breakReason,
1185 std::unique_ptr<protocol::DictionaryValue> data) {
Ben Murdoch62ed6312017-06-06 11:06:27 +01001186 if (!enabled() || !m_debugger->canBreakProgram() || m_skipAllPauses) return;
1187 std::vector<BreakReason> currentScheduledReason;
1188 currentScheduledReason.swap(m_breakReason);
1189 pushBreakDetails(breakReason, std::move(data));
Ben Murdochf3b273f2017-01-17 12:11:28 +00001190 m_scheduledDebuggerStep = NoStep;
Ben Murdochf3b273f2017-01-17 12:11:28 +00001191 m_debugger->breakProgram();
Ben Murdoch62ed6312017-06-06 11:06:27 +01001192 popBreakDetails();
1193 m_breakReason.swap(currentScheduledReason);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001194}
1195
1196void V8DebuggerAgentImpl::breakProgramOnException(
1197 const String16& breakReason,
1198 std::unique_ptr<protocol::DictionaryValue> data) {
1199 if (!enabled() ||
Ben Murdoch62ed6312017-06-06 11:06:27 +01001200 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException)
Ben Murdochf3b273f2017-01-17 12:11:28 +00001201 return;
1202 breakProgram(breakReason, std::move(data));
1203}
1204
Ben Murdochf3b273f2017-01-17 12:11:28 +00001205void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId,
1206 int lineNumber, int columnNumber,
1207 BreakpointSource source,
1208 const String16& condition) {
Ben Murdoch62ed6312017-06-06 11:06:27 +01001209 ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition);
1210 String16 breakpointId = generateBreakpointId(breakpoint, source);
1211 resolveBreakpoint(breakpointId, breakpoint, source);
Ben Murdochf3b273f2017-01-17 12:11:28 +00001212}
1213
1214void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId,
1215 int lineNumber, int columnNumber,
1216 BreakpointSource source) {
Ben Murdoch62ed6312017-06-06 11:06:27 +01001217 removeBreakpointImpl(generateBreakpointId(
1218 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()),
1219 source));
Ben Murdochf3b273f2017-01-17 12:11:28 +00001220}
1221
1222void V8DebuggerAgentImpl::reset() {
1223 if (!enabled()) return;
1224 m_scheduledDebuggerStep = NoStep;
Ben Murdochf3b273f2017-01-17 12:11:28 +00001225 m_blackboxedPositions.clear();
Ben Murdoch62ed6312017-06-06 11:06:27 +01001226 resetBlackboxedStateCache();
1227 m_scripts.clear();
Ben Murdochf3b273f2017-01-17 12:11:28 +00001228 m_breakpointIdToDebuggerBreakpointIds.clear();
1229}
1230
1231} // namespace v8_inspector