OLD | NEW |
1 // Copyright 2015 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/inspector/v8-debugger-agent-impl.h" | 5 #include "src/inspector/v8-debugger-agent-impl.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 | 8 |
9 #include "src/debug/debug-interface.h" | 9 #include "src/debug/debug-interface.h" |
10 #include "src/inspector/injected-script.h" | 10 #include "src/inspector/injected-script.h" |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
124 V8DebuggerAgentImpl::V8DebuggerAgentImpl( | 124 V8DebuggerAgentImpl::V8DebuggerAgentImpl( |
125 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, | 125 V8InspectorSessionImpl* session, protocol::FrontendChannel* frontendChannel, |
126 protocol::DictionaryValue* state) | 126 protocol::DictionaryValue* state) |
127 : m_inspector(session->inspector()), | 127 : m_inspector(session->inspector()), |
128 m_debugger(m_inspector->debugger()), | 128 m_debugger(m_inspector->debugger()), |
129 m_session(session), | 129 m_session(session), |
130 m_enabled(false), | 130 m_enabled(false), |
131 m_state(state), | 131 m_state(state), |
132 m_frontend(frontendChannel), | 132 m_frontend(frontendChannel), |
133 m_isolate(m_inspector->isolate()), | 133 m_isolate(m_inspector->isolate()), |
134 m_breakReason(protocol::Debugger::Paused::ReasonEnum::Other), | |
135 m_scheduledDebuggerStep(NoStep), | 134 m_scheduledDebuggerStep(NoStep), |
136 m_javaScriptPauseScheduled(false), | 135 m_javaScriptPauseScheduled(false), |
137 m_recursionLevelForStepOut(0) { | 136 m_recursionLevelForStepOut(0) { |
138 clearBreakDetails(); | |
139 } | 137 } |
140 | 138 |
141 V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} | 139 V8DebuggerAgentImpl::~V8DebuggerAgentImpl() {} |
142 | 140 |
143 void V8DebuggerAgentImpl::enableImpl() { | 141 void V8DebuggerAgentImpl::enableImpl() { |
144 m_enabled = true; | 142 m_enabled = true; |
145 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); | 143 m_state->setBoolean(DebuggerAgentState::debuggerEnabled, true); |
146 m_debugger->enable(); | 144 m_debugger->enable(); |
147 | 145 |
148 std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts; | 146 std::vector<std::unique_ptr<V8DebuggerScript>> compiledScripts; |
(...skipping 433 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
582 String16* scriptSource) { | 580 String16* scriptSource) { |
583 if (!enabled()) return Response::Error(kDebuggerNotEnabled); | 581 if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
584 ScriptsMap::iterator it = m_scripts.find(scriptId); | 582 ScriptsMap::iterator it = m_scripts.find(scriptId); |
585 if (it == m_scripts.end()) | 583 if (it == m_scripts.end()) |
586 return Response::Error("No script for id: " + scriptId); | 584 return Response::Error("No script for id: " + scriptId); |
587 v8::HandleScope handles(m_isolate); | 585 v8::HandleScope handles(m_isolate); |
588 *scriptSource = it->second->source(m_isolate); | 586 *scriptSource = it->second->source(m_isolate); |
589 return Response::OK(); | 587 return Response::OK(); |
590 } | 588 } |
591 | 589 |
| 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 |
592 void V8DebuggerAgentImpl::schedulePauseOnNextStatement( | 606 void V8DebuggerAgentImpl::schedulePauseOnNextStatement( |
593 const String16& breakReason, | 607 const String16& breakReason, |
594 std::unique_ptr<protocol::DictionaryValue> data) { | 608 std::unique_ptr<protocol::DictionaryValue> data) { |
595 if (!enabled() || m_scheduledDebuggerStep == StepInto || | 609 if (!enabled() || m_scheduledDebuggerStep == StepInto || |
596 m_javaScriptPauseScheduled || isPaused() || | 610 m_javaScriptPauseScheduled || isPaused() || |
597 !m_debugger->breakpointsActivated()) | 611 !m_debugger->breakpointsActivated()) |
598 return; | 612 return; |
599 m_breakReason = breakReason; | 613 if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(true); |
600 m_breakAuxData = std::move(data); | 614 pushBreakDetails(breakReason, std::move(data)); |
601 m_debugger->setPauseOnNextStatement(true); | |
602 } | 615 } |
603 | 616 |
604 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { | 617 void V8DebuggerAgentImpl::schedulePauseOnNextStatementIfSteppingInto() { |
605 DCHECK(enabled()); | 618 DCHECK(enabled()); |
606 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || | 619 if (m_scheduledDebuggerStep != StepInto || m_javaScriptPauseScheduled || |
607 isPaused()) | 620 isPaused()) |
608 return; | 621 return; |
609 clearBreakDetails(); | |
610 m_debugger->setPauseOnNextStatement(true); | 622 m_debugger->setPauseOnNextStatement(true); |
611 } | 623 } |
612 | 624 |
613 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { | 625 void V8DebuggerAgentImpl::cancelPauseOnNextStatement() { |
614 if (m_javaScriptPauseScheduled || isPaused()) return; | 626 if (m_javaScriptPauseScheduled || isPaused()) return; |
615 clearBreakDetails(); | 627 popBreakDetails(); |
616 m_debugger->setPauseOnNextStatement(false); | 628 if (m_breakReason.empty()) m_debugger->setPauseOnNextStatement(false); |
617 } | 629 } |
618 | 630 |
619 Response V8DebuggerAgentImpl::pause() { | 631 Response V8DebuggerAgentImpl::pause() { |
620 if (!enabled()) return Response::Error(kDebuggerNotEnabled); | 632 if (!enabled()) return Response::Error(kDebuggerNotEnabled); |
621 if (m_javaScriptPauseScheduled || isPaused()) return Response::OK(); | 633 if (m_javaScriptPauseScheduled || isPaused()) return Response::OK(); |
622 clearBreakDetails(); | 634 clearBreakDetails(); |
623 m_javaScriptPauseScheduled = true; | 635 m_javaScriptPauseScheduled = true; |
624 m_scheduledDebuggerStep = NoStep; | 636 m_scheduledDebuggerStep = NoStep; |
625 m_debugger->setPauseOnNextStatement(true); | 637 m_debugger->setPauseOnNextStatement(true); |
626 return Response::OK(); | 638 return Response::OK(); |
(...skipping 437 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1064 | 1076 |
1065 void V8DebuggerAgentImpl::didPause(int contextId, | 1077 void V8DebuggerAgentImpl::didPause(int contextId, |
1066 v8::Local<v8::Value> exception, | 1078 v8::Local<v8::Value> exception, |
1067 const std::vector<String16>& hitBreakpoints, | 1079 const std::vector<String16>& hitBreakpoints, |
1068 bool isPromiseRejection, bool isUncaught, | 1080 bool isPromiseRejection, bool isUncaught, |
1069 bool isOOMBreak) { | 1081 bool isOOMBreak) { |
1070 JavaScriptCallFrames frames = m_debugger->currentCallFrames(); | 1082 JavaScriptCallFrames frames = m_debugger->currentCallFrames(); |
1071 m_pausedCallFrames.swap(frames); | 1083 m_pausedCallFrames.swap(frames); |
1072 v8::HandleScope handles(m_isolate); | 1084 v8::HandleScope handles(m_isolate); |
1073 | 1085 |
| 1086 std::vector<BreakReason> hitReasons; |
| 1087 |
1074 if (isOOMBreak) { | 1088 if (isOOMBreak) { |
1075 m_breakReason = protocol::Debugger::Paused::ReasonEnum::OOM; | 1089 hitReasons.push_back( |
1076 m_breakAuxData = nullptr; | 1090 std::make_pair(protocol::Debugger::Paused::ReasonEnum::OOM, nullptr)); |
1077 } else if (!exception.IsEmpty()) { | 1091 } else if (!exception.IsEmpty()) { |
1078 InjectedScript* injectedScript = nullptr; | 1092 InjectedScript* injectedScript = nullptr; |
1079 m_session->findInjectedScript(contextId, injectedScript); | 1093 m_session->findInjectedScript(contextId, injectedScript); |
1080 if (injectedScript) { | 1094 if (injectedScript) { |
1081 m_breakReason = | 1095 String16 breakReason = |
1082 isPromiseRejection | 1096 isPromiseRejection |
1083 ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection | 1097 ? protocol::Debugger::Paused::ReasonEnum::PromiseRejection |
1084 : protocol::Debugger::Paused::ReasonEnum::Exception; | 1098 : protocol::Debugger::Paused::ReasonEnum::Exception; |
1085 std::unique_ptr<protocol::Runtime::RemoteObject> obj; | 1099 std::unique_ptr<protocol::Runtime::RemoteObject> obj; |
1086 injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false, | 1100 injectedScript->wrapObject(exception, kBacktraceObjectGroup, false, false, |
1087 &obj); | 1101 &obj); |
| 1102 std::unique_ptr<protocol::DictionaryValue> breakAuxData; |
1088 if (obj) { | 1103 if (obj) { |
1089 m_breakAuxData = obj->toValue(); | 1104 breakAuxData = obj->toValue(); |
1090 m_breakAuxData->setBoolean("uncaught", isUncaught); | 1105 breakAuxData->setBoolean("uncaught", isUncaught); |
1091 } else { | 1106 } else { |
1092 m_breakAuxData = nullptr; | 1107 breakAuxData = nullptr; |
1093 } | 1108 } |
1094 // m_breakAuxData might be null after this. | 1109 hitReasons.push_back( |
| 1110 std::make_pair(breakReason, std::move(breakAuxData))); |
1095 } | 1111 } |
1096 } | 1112 } |
1097 | 1113 |
1098 std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create(); | 1114 std::unique_ptr<Array<String16>> hitBreakpointIds = Array<String16>::create(); |
1099 | 1115 |
| 1116 bool hasDebugCommandBreakpointReason = false; |
1100 for (const auto& point : hitBreakpoints) { | 1117 for (const auto& point : hitBreakpoints) { |
1101 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator | 1118 DebugServerBreakpointToBreakpointIdAndSourceMap::iterator |
1102 breakpointIterator = m_serverBreakpoints.find(point); | 1119 breakpointIterator = m_serverBreakpoints.find(point); |
1103 if (breakpointIterator != m_serverBreakpoints.end()) { | 1120 if (breakpointIterator != m_serverBreakpoints.end()) { |
1104 const String16& localId = breakpointIterator->second.first; | 1121 const String16& localId = breakpointIterator->second.first; |
1105 hitBreakpointIds->addItem(localId); | 1122 hitBreakpointIds->addItem(localId); |
1106 | 1123 |
1107 BreakpointSource source = breakpointIterator->second.second; | 1124 BreakpointSource source = breakpointIterator->second.second; |
1108 if (m_breakReason == protocol::Debugger::Paused::ReasonEnum::Other && | 1125 if (!hasDebugCommandBreakpointReason && |
1109 source == DebugCommandBreakpointSource) | 1126 source == DebugCommandBreakpointSource) { |
1110 m_breakReason = protocol::Debugger::Paused::ReasonEnum::DebugCommand; | 1127 hasDebugCommandBreakpointReason = true; |
| 1128 hitReasons.push_back(std::make_pair( |
| 1129 protocol::Debugger::Paused::ReasonEnum::DebugCommand, nullptr)); |
| 1130 } |
1111 } | 1131 } |
1112 } | 1132 } |
1113 | 1133 |
| 1134 for (size_t i = 0; i < m_breakReason.size(); ++i) { |
| 1135 hitReasons.push_back(std::move(m_breakReason[i])); |
| 1136 } |
| 1137 clearBreakDetails(); |
| 1138 |
| 1139 String16 breakReason = protocol::Debugger::Paused::ReasonEnum::Other; |
| 1140 std::unique_ptr<protocol::DictionaryValue> breakAuxData; |
| 1141 if (hitReasons.size() == 1) { |
| 1142 breakReason = hitReasons[0].first; |
| 1143 breakAuxData = std::move(hitReasons[0].second); |
| 1144 } else if (hitReasons.size() > 1) { |
| 1145 breakReason = protocol::Debugger::Paused::ReasonEnum::Ambiguous; |
| 1146 std::unique_ptr<protocol::ListValue> reasons = |
| 1147 protocol::ListValue::create(); |
| 1148 for (size_t i = 0; i < hitReasons.size(); ++i) { |
| 1149 std::unique_ptr<protocol::DictionaryValue> reason = |
| 1150 protocol::DictionaryValue::create(); |
| 1151 reason->setString("reason", hitReasons[i].first); |
| 1152 if (hitReasons[i].second) |
| 1153 reason->setObject("auxData", std::move(hitReasons[i].second)); |
| 1154 reasons->pushValue(std::move(reason)); |
| 1155 } |
| 1156 breakAuxData = protocol::DictionaryValue::create(); |
| 1157 breakAuxData->setArray("reasons", std::move(reasons)); |
| 1158 } |
| 1159 |
1114 std::unique_ptr<Array<CallFrame>> protocolCallFrames; | 1160 std::unique_ptr<Array<CallFrame>> protocolCallFrames; |
1115 Response response = currentCallFrames(&protocolCallFrames); | 1161 Response response = currentCallFrames(&protocolCallFrames); |
1116 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); | 1162 if (!response.isSuccess()) protocolCallFrames = Array<CallFrame>::create(); |
1117 m_frontend.paused(std::move(protocolCallFrames), m_breakReason, | 1163 m_frontend.paused(std::move(protocolCallFrames), breakReason, |
1118 std::move(m_breakAuxData), std::move(hitBreakpointIds), | 1164 std::move(breakAuxData), std::move(hitBreakpointIds), |
1119 currentAsyncStackTrace()); | 1165 currentAsyncStackTrace()); |
1120 m_scheduledDebuggerStep = NoStep; | 1166 m_scheduledDebuggerStep = NoStep; |
1121 m_javaScriptPauseScheduled = false; | 1167 m_javaScriptPauseScheduled = false; |
1122 | 1168 |
1123 if (!m_continueToLocationBreakpointId.isEmpty()) { | 1169 if (!m_continueToLocationBreakpointId.isEmpty()) { |
1124 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); | 1170 m_debugger->removeBreakpoint(m_continueToLocationBreakpointId); |
1125 m_continueToLocationBreakpointId = ""; | 1171 m_continueToLocationBreakpointId = ""; |
1126 } | 1172 } |
1127 } | 1173 } |
1128 | 1174 |
1129 void V8DebuggerAgentImpl::didContinue() { | 1175 void V8DebuggerAgentImpl::didContinue() { |
1130 JavaScriptCallFrames emptyCallFrames; | 1176 JavaScriptCallFrames emptyCallFrames; |
1131 m_pausedCallFrames.swap(emptyCallFrames); | 1177 m_pausedCallFrames.swap(emptyCallFrames); |
1132 clearBreakDetails(); | 1178 clearBreakDetails(); |
1133 m_frontend.resumed(); | 1179 m_frontend.resumed(); |
1134 } | 1180 } |
1135 | 1181 |
1136 void V8DebuggerAgentImpl::breakProgram( | 1182 void V8DebuggerAgentImpl::breakProgram( |
1137 const String16& breakReason, | 1183 const String16& breakReason, |
1138 std::unique_ptr<protocol::DictionaryValue> data) { | 1184 std::unique_ptr<protocol::DictionaryValue> data) { |
1139 if (!enabled() || !m_debugger->canBreakProgram() || m_skipAllPauses) return; | 1185 if (!enabled() || !m_debugger->canBreakProgram() || m_skipAllPauses) return; |
1140 m_breakReason = breakReason; | 1186 std::vector<BreakReason> currentScheduledReason; |
1141 m_breakAuxData = std::move(data); | 1187 currentScheduledReason.swap(m_breakReason); |
| 1188 pushBreakDetails(breakReason, std::move(data)); |
1142 m_scheduledDebuggerStep = NoStep; | 1189 m_scheduledDebuggerStep = NoStep; |
1143 m_debugger->breakProgram(); | 1190 m_debugger->breakProgram(); |
| 1191 popBreakDetails(); |
| 1192 m_breakReason.swap(currentScheduledReason); |
1144 } | 1193 } |
1145 | 1194 |
1146 void V8DebuggerAgentImpl::breakProgramOnException( | 1195 void V8DebuggerAgentImpl::breakProgramOnException( |
1147 const String16& breakReason, | 1196 const String16& breakReason, |
1148 std::unique_ptr<protocol::DictionaryValue> data) { | 1197 std::unique_ptr<protocol::DictionaryValue> data) { |
1149 if (!enabled() || | 1198 if (!enabled() || |
1150 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) | 1199 m_debugger->getPauseOnExceptionsState() == v8::debug::NoBreakOnException) |
1151 return; | 1200 return; |
1152 breakProgram(breakReason, std::move(data)); | 1201 breakProgram(breakReason, std::move(data)); |
1153 } | 1202 } |
1154 | 1203 |
1155 void V8DebuggerAgentImpl::clearBreakDetails() { | |
1156 m_breakReason = protocol::Debugger::Paused::ReasonEnum::Other; | |
1157 m_breakAuxData = nullptr; | |
1158 } | |
1159 | |
1160 void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, | 1204 void V8DebuggerAgentImpl::setBreakpointAt(const String16& scriptId, |
1161 int lineNumber, int columnNumber, | 1205 int lineNumber, int columnNumber, |
1162 BreakpointSource source, | 1206 BreakpointSource source, |
1163 const String16& condition) { | 1207 const String16& condition) { |
1164 ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition); | 1208 ScriptBreakpoint breakpoint(scriptId, lineNumber, columnNumber, condition); |
1165 String16 breakpointId = generateBreakpointId(breakpoint, source); | 1209 String16 breakpointId = generateBreakpointId(breakpoint, source); |
1166 resolveBreakpoint(breakpointId, breakpoint, source); | 1210 resolveBreakpoint(breakpointId, breakpoint, source); |
1167 } | 1211 } |
1168 | 1212 |
1169 void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, | 1213 void V8DebuggerAgentImpl::removeBreakpointAt(const String16& scriptId, |
1170 int lineNumber, int columnNumber, | 1214 int lineNumber, int columnNumber, |
1171 BreakpointSource source) { | 1215 BreakpointSource source) { |
1172 removeBreakpointImpl(generateBreakpointId( | 1216 removeBreakpointImpl(generateBreakpointId( |
1173 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), | 1217 ScriptBreakpoint(scriptId, lineNumber, columnNumber, String16()), |
1174 source)); | 1218 source)); |
1175 } | 1219 } |
1176 | 1220 |
1177 void V8DebuggerAgentImpl::reset() { | 1221 void V8DebuggerAgentImpl::reset() { |
1178 if (!enabled()) return; | 1222 if (!enabled()) return; |
1179 m_scheduledDebuggerStep = NoStep; | 1223 m_scheduledDebuggerStep = NoStep; |
1180 m_blackboxedPositions.clear(); | 1224 m_blackboxedPositions.clear(); |
1181 resetBlackboxedStateCache(); | 1225 resetBlackboxedStateCache(); |
1182 m_scripts.clear(); | 1226 m_scripts.clear(); |
1183 m_breakpointIdToDebuggerBreakpointIds.clear(); | 1227 m_breakpointIdToDebuggerBreakpointIds.clear(); |
1184 } | 1228 } |
1185 | 1229 |
1186 } // namespace v8_inspector | 1230 } // namespace v8_inspector |
OLD | NEW |