| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 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 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 9 | #include "src/debug/debug-interface.h" |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 10 | #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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 25 | #include "src/inspector/v8-value-copier.h" |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 26 | |
| 27 | #include "include/v8-inspector.h" |
| 28 | |
| 29 | namespace v8_inspector { |
| 30 | |
| 31 | using protocol::Array; |
| 32 | using protocol::Maybe; |
| 33 | using protocol::Debugger::BreakpointId; |
| 34 | using protocol::Debugger::CallFrame; |
| 35 | using protocol::Runtime::ExceptionDetails; |
| 36 | using protocol::Runtime::ScriptId; |
| 37 | using protocol::Runtime::StackTrace; |
| 38 | using protocol::Runtime::RemoteObject; |
| 39 | |
| 40 | namespace DebuggerAgentState { |
| 41 | static const char javaScriptBreakpoints[] = "javaScriptBreakopints"; |
| 42 | static const char pauseOnExceptionsState[] = "pauseOnExceptionsState"; |
| 43 | static const char asyncCallStackDepth[] = "asyncCallStackDepth"; |
| 44 | static const char blackboxPattern[] = "blackboxPattern"; |
| 45 | static const char debuggerEnabled[] = "debuggerEnabled"; |
| 46 | |
| 47 | // Breakpoint properties. |
| 48 | static const char url[] = "url"; |
| 49 | static const char isRegex[] = "isRegex"; |
| 50 | static const char lineNumber[] = "lineNumber"; |
| 51 | static const char columnNumber[] = "columnNumber"; |
| 52 | static const char condition[] = "condition"; |
| 53 | static const char skipAllPauses[] = "skipAllPauses"; |
| 54 | |
| 55 | } // namespace DebuggerAgentState |
| 56 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 57 | static const char kBacktraceObjectGroup[] = "backtrace"; |
| 58 | static const char kDebuggerNotEnabled[] = "Debugger agent is not enabled"; |
| 59 | static const char kDebuggerNotPaused[] = |
| 60 | "Can only perform operation while paused."; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 61 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 62 | namespace { |
| 63 | |
| 64 | void 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 | |
| 83 | String16 breakpointIdSuffix(V8DebuggerAgentImpl::BreakpointSource source) { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 84 | 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 95 | String16 generateBreakpointId(const ScriptBreakpoint& breakpoint, |
| 96 | V8DebuggerAgentImpl::BreakpointSource source) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 97 | String16Builder builder; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 98 | builder.append(breakpoint.script_id); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 99 | builder.append(':'); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 100 | builder.appendNumber(breakpoint.line_number); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 101 | builder.append(':'); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 102 | builder.appendNumber(breakpoint.column_number); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 103 | builder.append(breakpointIdSuffix(source)); |
| 104 | return builder.toString(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 105 | } |
| 106 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 107 | bool positionComparator(const std::pair<int, int>& a, |
| 108 | const std::pair<int, int>& b) { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 109 | if (a.first != b.first) return a.first < b.first; |
| 110 | return a.second < b.second; |
| 111 | } |
| 112 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 113 | std::unique_ptr<protocol::Debugger::Location> buildProtocolLocation( |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 114 | 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 122 | } // namespace |
| 123 | |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 124 | V8DebuggerAgentImpl::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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 134 | m_scheduledDebuggerStep(NoStep), |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 135 | m_javaScriptPauseScheduled(false), |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 136 | m_recursionLevelForStepOut(0) { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 137 | } |
| 138 | |
| 139 | V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} |
| 140 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 141 | void V8DebuggerAgentImpl::enableImpl() { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 142 | 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 | |
| 156 | bool V8DebuggerAgentImpl::enabled() { return m_enabled; } |
| 157 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 158 | Response V8DebuggerAgentImpl::enable() { |
| 159 | if (enabled()) return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 160 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 161 | if (!m_inspector->client()->canExecuteScripts(m_session->contextGroupId())) |
| 162 | return Response::Error("Script execution is prohibited"); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 163 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 164 | enableImpl(); |
| 165 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 166 | } |
| 167 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 168 | Response V8DebuggerAgentImpl::disable() { |
| 169 | if (!enabled()) return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 170 | |
| 171 | m_state->setObject(DebuggerAgentState::javaScriptBreakpoints, |
| 172 | protocol::DictionaryValue::create()); |
| 173 | m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 174 | v8::debug::NoBreakOnException); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 175 | m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, 0); |
| 176 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 177 | if (isPaused()) m_debugger->continueProgram(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 178 | m_debugger->disable(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 179 | JavaScriptCallFrames emptyCallFrames; |
| 180 | m_pausedCallFrames.swap(emptyCallFrames); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 181 | m_blackboxedPositions.clear(); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 182 | m_blackboxPattern.reset(); |
| 183 | resetBlackboxedStateCache(); |
| 184 | m_scripts.clear(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 185 | m_breakpointIdToDebuggerBreakpointIds.clear(); |
| 186 | m_debugger->setAsyncCallStackDepth(this, 0); |
| 187 | m_continueToLocationBreakpointId = String16(); |
| 188 | clearBreakDetails(); |
| 189 | m_scheduledDebuggerStep = NoStep; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 190 | m_javaScriptPauseScheduled = false; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 191 | m_skipAllPauses = false; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 192 | m_state->setBoolean(DebuggerAgentState::skipAllPauses, false); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 193 | m_state->remove(DebuggerAgentState::blackboxPattern); |
| 194 | m_enabled = false; |
| 195 | m_state->setBoolean(DebuggerAgentState::debuggerEnabled, false); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 196 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 197 | } |
| 198 | |
| 199 | void 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 206 | enableImpl(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 207 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 208 | int pauseState = v8::debug::NoBreakOnException; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 209 | m_state->getInteger(DebuggerAgentState::pauseOnExceptionsState, &pauseState); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 210 | setPauseOnExceptionsImpl(pauseState); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 211 | |
| 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 223 | setBlackboxPattern(blackboxPattern); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 224 | } |
| 225 | } |
| 226 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 227 | Response V8DebuggerAgentImpl::setBreakpointsActive(bool active) { |
| 228 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 229 | m_debugger->setBreakpointsActivated(active); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 230 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 231 | } |
| 232 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 233 | Response V8DebuggerAgentImpl::setSkipAllPauses(bool skip) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 234 | m_state->setBoolean(DebuggerAgentState::skipAllPauses, skip); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 235 | m_skipAllPauses = skip; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 236 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 237 | } |
| 238 | |
| 239 | static std::unique_ptr<protocol::DictionaryValue> |
| 240 | buildObjectForBreakpointCookie(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 | |
| 253 | static 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 262 | Response V8DebuggerAgentImpl::setBreakpointByUrl( |
| 263 | int lineNumber, Maybe<String16> optionalURL, |
| 264 | Maybe<String16> optionalURLRegex, Maybe<int> optionalColumnNumber, |
| 265 | Maybe<String16> optionalCondition, String16* outBreakpointId, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 266 | std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations) { |
| 267 | *locations = Array<protocol::Debugger::Location>::create(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 268 | if (optionalURL.isJust() == optionalURLRegex.isJust()) |
| 269 | return Response::Error("Either url or urlRegex must be specified."); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 270 | |
| 271 | String16 url = optionalURL.isJust() ? optionalURL.fromJust() |
| 272 | : optionalURLRegex.fromJust(); |
| 273 | int columnNumber = 0; |
| 274 | if (optionalColumnNumber.isJust()) { |
| 275 | columnNumber = optionalColumnNumber.fromJust(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 276 | if (columnNumber < 0) return Response::Error("Incorrect column number"); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 277 | } |
| 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 293 | if (breakpointsCookie->get(breakpointId)) |
| 294 | return Response::Error("Breakpoint at specified location already exists."); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 295 | |
| 296 | breakpointsCookie->setObject( |
| 297 | breakpointId, buildObjectForBreakpointCookie( |
| 298 | url, lineNumber, columnNumber, condition, isRegex)); |
| 299 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 300 | ScriptBreakpoint breakpoint(String16(), lineNumber, columnNumber, condition); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 301 | for (const auto& script : m_scripts) { |
| 302 | if (!matches(m_inspector, script.second->sourceURL(), url, isRegex)) |
| 303 | continue; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 304 | breakpoint.script_id = script.first; |
| 305 | std::unique_ptr<protocol::Debugger::Location> location = |
| 306 | resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 307 | if (location) (*locations)->addItem(std::move(location)); |
| 308 | } |
| 309 | |
| 310 | *outBreakpointId = breakpointId; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 311 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 312 | } |
| 313 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 314 | Response V8DebuggerAgentImpl::setBreakpoint( |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 315 | std::unique_ptr<protocol::Debugger::Location> location, |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 316 | Maybe<String16> optionalCondition, String16* outBreakpointId, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 317 | std::unique_ptr<protocol::Debugger::Location>* actualLocation) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 318 | ScriptBreakpoint breakpoint( |
| 319 | location->getScriptId(), location->getLineNumber(), |
| 320 | location->getColumnNumber(0), optionalCondition.fromMaybe(String16())); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 321 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 322 | String16 breakpointId = |
| 323 | generateBreakpointId(breakpoint, UserBreakpointSource); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 324 | if (m_breakpointIdToDebuggerBreakpointIds.find(breakpointId) != |
| 325 | m_breakpointIdToDebuggerBreakpointIds.end()) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 326 | return Response::Error("Breakpoint at specified location already exists."); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 327 | } |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 328 | *actualLocation = |
| 329 | resolveBreakpoint(breakpointId, breakpoint, UserBreakpointSource); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 330 | if (!*actualLocation) return Response::Error("Could not resolve breakpoint"); |
| 331 | *outBreakpointId = breakpointId; |
| 332 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 333 | } |
| 334 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 335 | Response V8DebuggerAgentImpl::removeBreakpoint(const String16& breakpointId) { |
| 336 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 337 | protocol::DictionaryValue* breakpointsCookie = |
| 338 | m_state->getObject(DebuggerAgentState::javaScriptBreakpoints); |
| 339 | if (breakpointsCookie) breakpointsCookie->remove(breakpointId); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 340 | removeBreakpointImpl(breakpointId); |
| 341 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 342 | } |
| 343 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 344 | void V8DebuggerAgentImpl::removeBreakpointImpl(const String16& breakpointId) { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 345 | 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 362 | Response 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 372 | v8::debug::Location v8Start(start->getLineNumber(), |
| 373 | start->getColumnNumber(0)); |
| 374 | v8::debug::Location v8End; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 375 | 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 383 | v8End = v8::debug::Location(line, column); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 384 | } |
| 385 | auto it = m_scripts.find(scriptId); |
| 386 | if (it == m_scripts.end()) return Response::Error("Script not found"); |
| 387 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 388 | std::vector<v8::debug::Location> v8Locations; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 389 | 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 | |
| 404 | Response V8DebuggerAgentImpl::continueToLocation( |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 405 | std::unique_ptr<protocol::Debugger::Location> location) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 406 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 407 | if (!m_continueToLocationBreakpointId.isEmpty()) { |
| 408 | m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); |
| 409 | m_continueToLocationBreakpointId = ""; |
| 410 | } |
| 411 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 412 | ScriptBreakpoint breakpoint(location->getScriptId(), |
| 413 | location->getLineNumber(), |
| 414 | location->getColumnNumber(0), String16()); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 415 | |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 416 | m_continueToLocationBreakpointId = m_debugger->setBreakpoint( |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 417 | breakpoint, &breakpoint.line_number, &breakpoint.column_number); |
| 418 | // TODO(kozyatinskiy): Return actual line and column number. |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 419 | return resume(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 420 | } |
| 421 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 422 | bool 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 426 | 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 436 | auto itBlackboxedPositions = m_blackboxedPositions.find(scriptId); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 437 | if (itBlackboxedPositions == m_blackboxedPositions.end()) return false; |
| 438 | |
| 439 | const std::vector<std::pair<int, int>>& ranges = |
| 440 | itBlackboxedPositions->second; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 441 | auto itStartRange = std::lower_bound( |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 442 | ranges.begin(), ranges.end(), |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 443 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 449 | // 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 452 | return itStartRange == itEndRange && |
| 453 | std::distance(ranges.begin(), itStartRange) % 2; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 454 | } |
| 455 | |
| 456 | std::unique_ptr<protocol::Debugger::Location> |
| 457 | V8DebuggerAgentImpl::resolveBreakpoint(const String16& breakpointId, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 458 | const ScriptBreakpoint& breakpoint, |
| 459 | BreakpointSource source) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 460 | v8::HandleScope handles(m_isolate); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 461 | DCHECK(enabled()); |
| 462 | // FIXME: remove these checks once crbug.com/520702 is resolved. |
| 463 | CHECK(!breakpointId.isEmpty()); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 464 | CHECK(!breakpoint.script_id.isEmpty()); |
| 465 | ScriptsMap::iterator scriptIterator = m_scripts.find(breakpoint.script_id); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 466 | if (scriptIterator == m_scripts.end()) return nullptr; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 467 | if (breakpoint.line_number < scriptIterator->second->startLine() || |
| 468 | scriptIterator->second->endLine() < breakpoint.line_number) |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 469 | return nullptr; |
| 470 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 471 | // 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 477 | int actualLineNumber; |
| 478 | int actualColumnNumber; |
| 479 | String16 debuggerBreakpointId = m_debugger->setBreakpoint( |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 480 | translatedBreakpoint, &actualLineNumber, &actualColumnNumber); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 481 | if (debuggerBreakpointId.isEmpty()) return nullptr; |
| 482 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 483 | // 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 487 | m_serverBreakpoints[debuggerBreakpointId] = |
| 488 | std::make_pair(breakpointId, source); |
| 489 | CHECK(!breakpointId.isEmpty()); |
| 490 | |
| 491 | m_breakpointIdToDebuggerBreakpointIds[breakpointId].push_back( |
| 492 | debuggerBreakpointId); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 493 | return buildProtocolLocation(translatedBreakpoint.script_id, actualLineNumber, |
| 494 | actualColumnNumber); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 495 | } |
| 496 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 497 | Response V8DebuggerAgentImpl::searchInContent( |
| 498 | const String16& scriptId, const String16& query, |
| 499 | Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 500 | std::unique_ptr<Array<protocol::Debugger::SearchMatch>>* results) { |
| 501 | v8::HandleScope handles(m_isolate); |
| 502 | ScriptsMap::iterator it = m_scripts.find(scriptId); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 503 | if (it == m_scripts.end()) |
| 504 | return Response::Error("No script for id: " + scriptId); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 505 | |
| 506 | std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches = |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 507 | searchInTextByLinesImpl(m_session, it->second->source(m_isolate), query, |
| 508 | optionalCaseSensitive.fromMaybe(false), |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 509 | 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 513 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 514 | } |
| 515 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 516 | Response V8DebuggerAgentImpl::setScriptSource( |
| 517 | const String16& scriptId, const String16& newContent, Maybe<bool> dryRun, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 518 | Maybe<protocol::Array<protocol::Debugger::CallFrame>>* newCallFrames, |
| 519 | Maybe<bool>* stackChanged, Maybe<StackTrace>* asyncStackTrace, |
| 520 | Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 521 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 522 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 523 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 532 | v8::HandleScope handles(m_isolate); |
| 533 | v8::Local<v8::String> newSource = toV8String(m_isolate, newContent); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 534 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 539 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 540 | it->second->setSource(newSource); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 541 | std::unique_ptr<Array<CallFrame>> callFrames; |
| 542 | response = currentCallFrames(&callFrames); |
| 543 | if (!response.isSuccess()) return response; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 544 | *newCallFrames = std::move(callFrames); |
| 545 | *asyncStackTrace = currentAsyncStackTrace(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 546 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 547 | } |
| 548 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 549 | Response V8DebuggerAgentImpl::restartFrame( |
| 550 | const String16& callFrameId, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 551 | std::unique_ptr<Array<CallFrame>>* newCallFrames, |
| 552 | Maybe<StackTrace>* asyncStackTrace) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 553 | if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 554 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 560 | |
| 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 568 | return Response::InternalError(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 569 | } |
| 570 | JavaScriptCallFrames frames = m_debugger->currentCallFrames(); |
| 571 | m_pausedCallFrames.swap(frames); |
| 572 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 573 | response = currentCallFrames(newCallFrames); |
| 574 | if (!response.isSuccess()) return response; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 575 | *asyncStackTrace = currentAsyncStackTrace(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 576 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 577 | } |
| 578 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 579 | Response V8DebuggerAgentImpl::getScriptSource(const String16& scriptId, |
| 580 | String16* scriptSource) { |
| 581 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 582 | ScriptsMap::iterator it = m_scripts.find(scriptId); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 583 | if (it == m_scripts.end()) |
| 584 | return Response::Error("No script for id: " + scriptId); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 585 | v8::HandleScope handles(m_isolate); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 586 | *scriptSource = it->second->source(m_isolate); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 587 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 588 | } |
| 589 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 590 | void 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 | |
| 596 | void V8DebuggerAgentImpl::popBreakDetails() { |
| 597 | if (m_breakReason.empty()) return; |
| 598 | m_breakReason.pop_back(); |
| 599 | } |
| 600 | |
| 601 | void V8DebuggerAgentImpl::clearBreakDetails() { |
| 602 | std::vector<BreakReason> emptyBreakReason; |
| 603 | m_breakReason.swap(emptyBreakReason); |
| 604 | } |
| 605 | |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 606 | void V8DebuggerAgentImpl::schedulePauseOnNextStatement( |
| 607 | const String16& breakReason, |
| 608 | std::unique_ptr<protocol::DictionaryValue> data) { |
| 609 | if (!enabled() || m_scheduledDebuggerStep == StepInto || |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 610 | m_javaScriptPauseScheduled || isPaused() || |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 611 | !m_debugger->breakpointsActivated()) |
| 612 | return; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 613 | if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(true); |
| 614 | pushBreakDetails(breakReason, std::move(data)); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 615 | } |
| 616 | |
| 617 | void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { |
| 618 | DCHECK(enabled()); |
| 619 | if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 620 | isPaused()) |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 621 | return; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 622 | m_debugger->setPauseOnNextStatement(true); |
| 623 | } |
| 624 | |
| 625 | void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 626 | if (m_javaScriptPauseScheduled || isPaused()) return; |
| 627 | popBreakDetails(); |
| 628 | if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 629 | } |
| 630 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 631 | Response V8DebuggerAgentImpl::pause() { |
| 632 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 633 | if (m_javaScriptPauseScheduled || isPaused()) return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 634 | clearBreakDetails(); |
| 635 | m_javaScriptPauseScheduled = true; |
| 636 | m_scheduledDebuggerStep = NoStep; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 637 | m_debugger->setPauseOnNextStatement(true); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 638 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 639 | } |
| 640 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 641 | Response V8DebuggerAgentImpl::resume() { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 642 | if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 643 | m_scheduledDebuggerStep = NoStep; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 644 | m_session->releaseObjectGroup(kBacktraceObjectGroup); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 645 | m_debugger->continueProgram(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 646 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 647 | } |
| 648 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 649 | Response V8DebuggerAgentImpl::stepOver() { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 650 | if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 651 | // StepOver at function return point should fallback to StepInto. |
| 652 | JavaScriptCallFrame* frame = |
| 653 | !m_pausedCallFrames.empty() ? m_pausedCallFrames[0].get() : nullptr; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 654 | if (frame && frame->isAtReturn()) return stepInto(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 655 | m_scheduledDebuggerStep = StepOver; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 656 | m_session->releaseObjectGroup(kBacktraceObjectGroup); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 657 | m_debugger->stepOverStatement(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 658 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 659 | } |
| 660 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 661 | Response V8DebuggerAgentImpl::stepInto() { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 662 | if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 663 | m_scheduledDebuggerStep = StepInto; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 664 | m_session->releaseObjectGroup(kBacktraceObjectGroup); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 665 | m_debugger->stepIntoStatement(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 666 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 667 | } |
| 668 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 669 | Response V8DebuggerAgentImpl::stepOut() { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 670 | if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 671 | m_scheduledDebuggerStep = StepOut; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 672 | m_recursionLevelForStepOut = 1; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 673 | m_session->releaseObjectGroup(kBacktraceObjectGroup); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 674 | m_debugger->stepOutOfFunction(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 675 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 676 | } |
| 677 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 678 | Response V8DebuggerAgentImpl::setPauseOnExceptions( |
| 679 | const String16& stringPauseState) { |
| 680 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 681 | v8::debug::ExceptionBreakState pauseState; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 682 | if (stringPauseState == "none") { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 683 | pauseState = v8::debug::NoBreakOnException; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 684 | } else if (stringPauseState == "all") { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 685 | pauseState = v8::debug::BreakOnAnyException; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 686 | } else if (stringPauseState == "uncaught") { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 687 | pauseState = v8::debug::BreakOnUncaughtException; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 688 | } else { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 689 | return Response::Error("Unknown pause on exceptions mode: " + |
| 690 | stringPauseState); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 691 | } |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 692 | setPauseOnExceptionsImpl(pauseState); |
| 693 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 694 | } |
| 695 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 696 | void V8DebuggerAgentImpl::setPauseOnExceptionsImpl(int pauseState) { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 697 | m_debugger->setPauseOnExceptionsState( |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 698 | static_cast<v8::debug::ExceptionBreakState>(pauseState)); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 699 | m_state->setInteger(DebuggerAgentState::pauseOnExceptionsState, pauseState); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 700 | } |
| 701 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 702 | Response 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 706 | Maybe<bool> throwOnSideEffect, std::unique_ptr<RemoteObject>* result, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 707 | Maybe<protocol::Runtime::ExceptionDetails>* exceptionDetails) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 708 | if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 709 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 715 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 716 | if (includeCommandLineAPI.fromMaybe(false)) scope.installCommandLineAPI(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 717 | if (silent.fromMaybe(false)) scope.ignoreExceptionsAndMuteConsole(); |
| 718 | |
| 719 | v8::MaybeLocal<v8::Value> maybeResultValue = |
| 720 | m_pausedCallFrames[scope.frameOrdinal()]->evaluate( |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 721 | toV8String(m_isolate, expression), |
| 722 | throwOnSideEffect.fromMaybe(false)); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 723 | |
| 724 | // Re-initialize after running client's code, as it could have destroyed |
| 725 | // context or session. |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 726 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 732 | } |
| 733 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 734 | Response V8DebuggerAgentImpl::setVariableValue( |
| 735 | int scopeNumber, const String16& variableName, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 736 | std::unique_ptr<protocol::Runtime::CallArgument> newValueArgument, |
| 737 | const String16& callFrameId) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 738 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 739 | if (!isPaused()) return Response::Error(kDebuggerNotPaused); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 740 | InjectedScript::CallFrameScope scope(m_inspector, m_session->contextGroupId(), |
| 741 | callFrameId); |
| 742 | Response response = scope.initialize(); |
| 743 | if (!response.isSuccess()) return response; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 744 | v8::Local<v8::Value> newValue; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 745 | response = scope.injectedScript()->resolveCallArgument(newValueArgument.get(), |
| 746 | &newValue); |
| 747 | if (!response.isSuccess()) return response; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 748 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 749 | if (scope.frameOrdinal() >= m_pausedCallFrames.size()) |
| 750 | return Response::Error("Could not find call frame with given id"); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 751 | v8::MaybeLocal<v8::Value> result = |
| 752 | m_pausedCallFrames[scope.frameOrdinal()]->setVariableValue( |
| 753 | scopeNumber, toV8String(m_isolate, variableName), newValue); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 754 | if (scope.tryCatch().HasCaught() || result.IsEmpty()) |
| 755 | return Response::InternalError(); |
| 756 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 757 | } |
| 758 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 759 | Response V8DebuggerAgentImpl::setAsyncCallStackDepth(int depth) { |
| 760 | if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 761 | m_state->setInteger(DebuggerAgentState::asyncCallStackDepth, depth); |
| 762 | m_debugger->setAsyncCallStackDepth(this, depth); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 763 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 764 | } |
| 765 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 766 | Response V8DebuggerAgentImpl::setBlackboxPatterns( |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 767 | std::unique_ptr<protocol::Array<String16>> patterns) { |
| 768 | if (!patterns->length()) { |
| 769 | m_blackboxPattern = nullptr; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 770 | resetBlackboxedStateCache(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 771 | m_state->remove(DebuggerAgentState::blackboxPattern); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 772 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 773 | } |
| 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 784 | Response response = setBlackboxPattern(pattern); |
| 785 | if (!response.isSuccess()) return response; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 786 | resetBlackboxedStateCache(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 787 | m_state->setString(DebuggerAgentState::blackboxPattern, pattern); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 788 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 789 | } |
| 790 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 791 | Response V8DebuggerAgentImpl::setBlackboxPattern(const String16& pattern) { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 792 | std::unique_ptr<V8Regex> regex(new V8Regex( |
| 793 | m_inspector, pattern, true /** caseSensitive */, false /** multiline */)); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 794 | if (!regex->isValid()) |
| 795 | return Response::Error("Pattern parser error: " + regex->errorMessage()); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 796 | m_blackboxPattern = std::move(regex); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 797 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 798 | } |
| 799 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 800 | void V8DebuggerAgentImpl::resetBlackboxedStateCache() { |
| 801 | for (const auto& it : m_scripts) { |
| 802 | it.second->resetBlackboxedStateCache(); |
| 803 | } |
| 804 | } |
| 805 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 806 | Response V8DebuggerAgentImpl::setBlackboxedRanges( |
| 807 | const String16& scriptId, |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 808 | std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>> |
| 809 | inPositions) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 810 | auto it = m_scripts.find(scriptId); |
| 811 | if (it == m_scripts.end()) |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 812 | return Response::Error("No script with passed id."); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 813 | |
| 814 | if (!inPositions->length()) { |
| 815 | m_blackboxedPositions.erase(scriptId); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 816 | it->second->resetBlackboxedStateCache(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 817 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 818 | } |
| 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 824 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 828 | 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 837 | return Response::Error( |
| 838 | "Input positions array is not sorted or contains duplicate values."); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 839 | } |
| 840 | |
| 841 | m_blackboxedPositions[scriptId] = positions; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 842 | it->second->resetBlackboxedStateCache(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 843 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 844 | } |
| 845 | |
| 846 | void V8DebuggerAgentImpl::willExecuteScript(int scriptId) { |
| 847 | changeJavaScriptRecursionLevel(+1); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 848 | if (m_scheduledDebuggerStep != StepInto) return; |
| 849 | schedulePauseOnNextStatementIfSteppingInto(); |
| 850 | } |
| 851 | |
| 852 | void V8DebuggerAgentImpl::didExecuteScript() { |
| 853 | changeJavaScriptRecursionLevel(-1); |
| 854 | } |
| 855 | |
| 856 | void V8DebuggerAgentImpl::changeJavaScriptRecursionLevel(int step) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 857 | if (m_javaScriptPauseScheduled && !m_skipAllPauses && !isPaused()) { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 858 | // 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 869 | } |
| 870 | } |
| 871 | } |
| 872 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 873 | Response V8DebuggerAgentImpl::currentCallFrames( |
| 874 | std::unique_ptr<Array<CallFrame>>* result) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 875 | if (!isPaused()) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 876 | *result = Array<CallFrame>::create(); |
| 877 | return Response::OK(); |
| 878 | } |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 879 | v8::HandleScope handles(m_isolate); |
| 880 | v8::Local<v8::Context> debuggerContext = |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 881 | v8::debug::GetDebugContext(m_isolate); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 882 | 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 891 | v8::Local<v8::Object> details; |
| 892 | if (!currentCallFrame->details().ToLocal(&details)) |
| 893 | return Response::InternalError(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 894 | |
| 895 | int contextId = currentCallFrame->contextId(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 896 | |
| 897 | InjectedScript* injectedScript = nullptr; |
| 898 | if (contextId) m_session->findInjectedScript(contextId, injectedScript); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 899 | |
| 900 | String16 callFrameId = |
| 901 | RemoteCallFrameId::serialize(contextId, static_cast<int>(frameOrdinal)); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 902 | if (!details |
| 903 | ->Set(debuggerContext, |
| 904 | toV8StringInternalized(m_isolate, "callFrameId"), |
| 905 | toV8String(m_isolate, callFrameId)) |
| 906 | .FromMaybe(false)) { |
| 907 | return Response::InternalError(); |
| 908 | } |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 909 | |
| 910 | if (injectedScript) { |
| 911 | v8::Local<v8::Value> scopeChain; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 912 | if (!details |
| 913 | ->Get(debuggerContext, |
| 914 | toV8StringInternalized(m_isolate, "scopeChain")) |
| 915 | .ToLocal(&scopeChain) || |
| 916 | !scopeChain->IsArray()) { |
| 917 | return Response::InternalError(); |
| 918 | } |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 919 | v8::Local<v8::Array> scopeChainArray = scopeChain.As<v8::Array>(); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 920 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 928 | if (details |
| 929 | ->Has(debuggerContext, |
| 930 | toV8StringInternalized(m_isolate, "returnValue")) |
| 931 | .FromMaybe(false)) { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 932 | response = injectedScript->wrapObjectProperty( |
| 933 | details, toV8StringInternalized(m_isolate, "returnValue"), |
| 934 | kBacktraceObjectGroup); |
| 935 | if (!response.isSuccess()) return response; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 936 | } |
| 937 | } else { |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 938 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 945 | v8::Local<v8::Object> remoteObject = v8::Object::New(m_isolate); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 946 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 964 | } |
| 965 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 966 | if (!objects->Set(debuggerContext, static_cast<int>(frameOrdinal), details) |
| 967 | .FromMaybe(false)) { |
| 968 | return Response::InternalError(); |
| 969 | } |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 970 | } |
| 971 | |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 972 | std::unique_ptr<protocol::Value> protocolValue; |
| 973 | Response response = toProtocolValue(debuggerContext, objects, &protocolValue); |
| 974 | if (!response.isSuccess()) return response; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 975 | protocol::ErrorSupport errorSupport; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 976 | *result = Array<CallFrame>::fromValue(protocolValue.get(), &errorSupport); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 977 | if (!*result) return Response::Error(errorSupport.errors()); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 978 | TranslateWasmStackTraceLocations(result->get(), |
| 979 | m_debugger->wasmTranslation()); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 980 | return Response::OK(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 981 | } |
| 982 | |
| 983 | std::unique_ptr<StackTrace> V8DebuggerAgentImpl::currentAsyncStackTrace() { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 984 | if (!isPaused()) return nullptr; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 985 | V8StackTraceImpl* stackTrace = m_debugger->currentAsyncCallChain(); |
| 986 | return stackTrace ? stackTrace->buildInspectorObjectForTail(m_debugger) |
| 987 | : nullptr; |
| 988 | } |
| 989 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 990 | bool V8DebuggerAgentImpl::isPaused() const { return m_debugger->isPaused(); } |
| 991 | |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 992 | void V8DebuggerAgentImpl::didParseSource( |
| 993 | std::unique_ptr<V8DebuggerScript> script, bool success) { |
| 994 | v8::HandleScope handles(m_isolate); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 995 | String16 scriptSource = script->source(m_isolate); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 996 | if (!success) script->setSourceURL(findSourceURL(scriptSource, false)); |
| 997 | if (!success) |
| 998 | script->setSourceMappingURL(findSourceMapURL(scriptSource, false)); |
| 999 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1000 | int contextId = script->executionContextId(); |
| 1001 | int contextGroupId = m_inspector->contextGroupId(contextId); |
| 1002 | InspectedContext* inspected = |
| 1003 | m_inspector->getContext(contextGroupId, contextId); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1004 | std::unique_ptr<protocol::DictionaryValue> executionContextAuxData; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1005 | if (inspected) { |
| 1006 | // Script reused between different groups/sessions can have a stale |
| 1007 | // execution context id. |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1008 | executionContextAuxData = protocol::DictionaryValue::cast( |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1009 | protocol::StringUtil::parseJSON(inspected->auxData())); |
| 1010 | } |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1011 | bool isLiveEdit = script->isLiveEdit(); |
| 1012 | bool hasSourceURL = script->hasSourceURL(); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1013 | bool isModule = script->isModule(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1014 | String16 scriptId = script->scriptId(); |
| 1015 | String16 scriptURL = script->sourceURL(); |
| 1016 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1017 | 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 1029 | Maybe<protocol::DictionaryValue> executionContextAuxDataParam( |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1030 | std::move(executionContextAuxData)); |
| 1031 | const bool* isLiveEditParam = isLiveEdit ? &isLiveEdit : nullptr; |
| 1032 | const bool* hasSourceURLParam = hasSourceURL ? &hasSourceURL : nullptr; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1033 | const bool* isModuleParam = isModule ? &isModule : nullptr; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1034 | if (success) |
| 1035 | m_frontend.scriptParsed( |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1036 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1041 | else |
| 1042 | m_frontend.scriptFailedToParse( |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1043 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1047 | |
| 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1064 | breakpoint.script_id = scriptId; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1065 | breakpointObject->getInteger(DebuggerAgentState::lineNumber, |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1066 | &breakpoint.line_number); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1067 | breakpointObject->getInteger(DebuggerAgentState::columnNumber, |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1068 | &breakpoint.column_number); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1069 | breakpointObject->getString(DebuggerAgentState::condition, |
| 1070 | &breakpoint.condition); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1071 | std::unique_ptr<protocol::Debugger::Location> location = |
| 1072 | resolveBreakpoint(cookie.first, breakpoint, UserBreakpointSource); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1073 | if (location) |
| 1074 | m_frontend.breakpointResolved(cookie.first, std::move(location)); |
| 1075 | } |
| 1076 | } |
| 1077 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1078 | void 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1083 | JavaScriptCallFrames frames = m_debugger->currentCallFrames(); |
| 1084 | m_pausedCallFrames.swap(frames); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1085 | v8::HandleScope handles(m_isolate); |
| 1086 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1087 | 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 1093 | InjectedScript* injectedScript = nullptr; |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1094 | m_session->findInjectedScript(contextId, injectedScript); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1095 | if (injectedScript) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1096 | String16 breakReason = |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1097 | isPromiseRejection |
| 1098 | ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection |
| 1099 | : protocol::Debugger::Paused::ReasonEnum::Exception; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 1100 | std::unique_ptr<protocol::Runtime::RemoteObject> obj; |
| 1101 | injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false, |
| 1102 | &obj); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1103 | std::unique_ptr<protocol::DictionaryValue> breakAuxData; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 1104 | if (obj) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1105 | breakAuxData = obj->toValue(); |
| 1106 | breakAuxData->setBoolean("uncaught", isUncaught); |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 1107 | } else { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1108 | breakAuxData = nullptr; |
| Ben Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 1109 | } |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1110 | hitReasons.push_back( |
| 1111 | std::make_pair(breakReason, std::move(breakAuxData))); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1112 | } |
| 1113 | } |
| 1114 | |
| 1115 | std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create(); |
| 1116 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1117 | bool hasDebugCommandBreakpointReason = false; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1118 | 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 Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1126 | if (!hasDebugCommandBreakpointReason && |
| 1127 | source == DebugCommandBreakpointSource) { |
| 1128 | hasDebugCommandBreakpointReason = true; |
| 1129 | hitReasons.push_back(std::make_pair( |
| 1130 | protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr)); |
| 1131 | } |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1132 | } |
| 1133 | } |
| 1134 | |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1135 | 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 Murdoch | c8c1d9e | 2017-03-08 14:04:23 +0000 | [diff] [blame] | 1161 | std::unique_ptr<Array<CallFrame>> protocolCallFrames; |
| 1162 | Response response = currentCallFrames(&protocolCallFrames); |
| 1163 | if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1164 | m_frontend.paused(std::move(protocolCallFrames), breakReason, |
| 1165 | std::move(breakAuxData), std::move(hitBreakpointIds), |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1166 | currentAsyncStackTrace()); |
| 1167 | m_scheduledDebuggerStep = NoStep; |
| 1168 | m_javaScriptPauseScheduled = false; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1169 | |
| 1170 | if (!m_continueToLocationBreakpointId.isEmpty()) { |
| 1171 | m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); |
| 1172 | m_continueToLocationBreakpointId = ""; |
| 1173 | } |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1174 | } |
| 1175 | |
| 1176 | void V8DebuggerAgentImpl::didContinue() { |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1177 | JavaScriptCallFrames emptyCallFrames; |
| 1178 | m_pausedCallFrames.swap(emptyCallFrames); |
| 1179 | clearBreakDetails(); |
| 1180 | m_frontend.resumed(); |
| 1181 | } |
| 1182 | |
| 1183 | void V8DebuggerAgentImpl::breakProgram( |
| 1184 | const String16& breakReason, |
| 1185 | std::unique_ptr<protocol::DictionaryValue> data) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1186 | 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 Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1190 | m_scheduledDebuggerStep = NoStep; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1191 | m_debugger->breakProgram(); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1192 | popBreakDetails(); |
| 1193 | m_breakReason.swap(currentScheduledReason); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1194 | } |
| 1195 | |
| 1196 | void V8DebuggerAgentImpl::breakProgramOnException( |
| 1197 | const String16& breakReason, |
| 1198 | std::unique_ptr<protocol::DictionaryValue> data) { |
| 1199 | if (!enabled() || |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1200 | m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1201 | return; |
| 1202 | breakProgram(breakReason, std::move(data)); |
| 1203 | } |
| 1204 | |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1205 | void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, |
| 1206 | int lineNumber, int columnNumber, |
| 1207 | BreakpointSource source, |
| 1208 | const String16& condition) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1209 | ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition); |
| 1210 | String16 breakpointId = generateBreakpointId(breakpoint, source); |
| 1211 | resolveBreakpoint(breakpointId, breakpoint, source); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1212 | } |
| 1213 | |
| 1214 | void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, |
| 1215 | int lineNumber, int columnNumber, |
| 1216 | BreakpointSource source) { |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1217 | removeBreakpointImpl(generateBreakpointId( |
| 1218 | ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), |
| 1219 | source)); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1220 | } |
| 1221 | |
| 1222 | void V8DebuggerAgentImpl::reset() { |
| 1223 | if (!enabled()) return; |
| 1224 | m_scheduledDebuggerStep = NoStep; |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1225 | m_blackboxedPositions.clear(); |
| Ben Murdoch | 62ed631 | 2017-06-06 11:06:27 +0100 | [diff] [blame] | 1226 | resetBlackboxedStateCache(); |
| 1227 | m_scripts.clear(); |
| Ben Murdoch | f3b273f | 2017-01-17 12:11:28 +0000 | [diff] [blame] | 1228 | m_breakpointIdToDebuggerBreakpointIds.clear(); |
| 1229 | } |
| 1230 | |
| 1231 | } // namespace v8_inspector |