Line data Source code
1 : // Copyright 2016 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-inspector-session-impl.h"
6 :
7 : #include "src/inspector/injected-script.h"
8 : #include "src/inspector/inspected-context.h"
9 : #include "src/inspector/protocol/Protocol.h"
10 : #include "src/inspector/remote-object-id.h"
11 : #include "src/inspector/search-util.h"
12 : #include "src/inspector/string-util.h"
13 : #include "src/inspector/v8-console-agent-impl.h"
14 : #include "src/inspector/v8-debugger-agent-impl.h"
15 : #include "src/inspector/v8-debugger.h"
16 : #include "src/inspector/v8-heap-profiler-agent-impl.h"
17 : #include "src/inspector/v8-inspector-impl.h"
18 : #include "src/inspector/v8-profiler-agent-impl.h"
19 : #include "src/inspector/v8-runtime-agent-impl.h"
20 : #include "src/inspector/v8-schema-agent-impl.h"
21 :
22 : namespace v8_inspector {
23 :
24 : // static
25 0 : bool V8InspectorSession::canDispatchMethod(const StringView& method) {
26 0 : return stringViewStartsWith(method,
27 0 : protocol::Runtime::Metainfo::commandPrefix) ||
28 0 : stringViewStartsWith(method,
29 0 : protocol::Debugger::Metainfo::commandPrefix) ||
30 0 : stringViewStartsWith(method,
31 0 : protocol::Profiler::Metainfo::commandPrefix) ||
32 0 : stringViewStartsWith(
33 0 : method, protocol::HeapProfiler::Metainfo::commandPrefix) ||
34 0 : stringViewStartsWith(method,
35 0 : protocol::Console::Metainfo::commandPrefix) ||
36 0 : stringViewStartsWith(method,
37 0 : protocol::Schema::Metainfo::commandPrefix);
38 : }
39 :
40 : // static
41 0 : int V8ContextInfo::executionContextId(v8::Local<v8::Context> context) {
42 0 : return InspectedContext::contextId(context);
43 : }
44 :
45 3879 : std::unique_ptr<V8InspectorSessionImpl> V8InspectorSessionImpl::create(
46 : V8InspectorImpl* inspector, int contextGroupId, int sessionId,
47 : V8Inspector::Channel* channel, const StringView& state) {
48 : return std::unique_ptr<V8InspectorSessionImpl>(new V8InspectorSessionImpl(
49 7758 : inspector, contextGroupId, sessionId, channel, state));
50 : }
51 :
52 3879 : V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector,
53 : int contextGroupId,
54 : int sessionId,
55 : V8Inspector::Channel* channel,
56 : const StringView& savedState)
57 : : m_contextGroupId(contextGroupId),
58 : m_sessionId(sessionId),
59 : m_inspector(inspector),
60 : m_channel(channel),
61 : m_customObjectFormatterEnabled(false),
62 : m_dispatcher(this),
63 : m_state(nullptr),
64 : m_runtimeAgent(nullptr),
65 : m_debuggerAgent(nullptr),
66 : m_heapProfilerAgent(nullptr),
67 : m_profilerAgent(nullptr),
68 : m_consoleAgent(nullptr),
69 7758 : m_schemaAgent(nullptr) {
70 3879 : if (savedState.length()) {
71 : std::unique_ptr<protocol::Value> state =
72 110 : protocol::StringUtil::parseJSON(toString16(savedState));
73 55 : if (state) m_state = protocol::DictionaryValue::cast(std::move(state));
74 55 : if (!m_state) m_state = protocol::DictionaryValue::create();
75 : } else {
76 : m_state = protocol::DictionaryValue::create();
77 : }
78 :
79 11637 : m_state->getBoolean("use_binary_protocol", &use_binary_protocol_);
80 :
81 3879 : m_runtimeAgent.reset(new V8RuntimeAgentImpl(
82 11637 : this, this, agentState(protocol::Runtime::Metainfo::domainName)));
83 3879 : protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
84 :
85 3879 : m_debuggerAgent.reset(new V8DebuggerAgentImpl(
86 11637 : this, this, agentState(protocol::Debugger::Metainfo::domainName)));
87 3879 : protocol::Debugger::Dispatcher::wire(&m_dispatcher, m_debuggerAgent.get());
88 :
89 3879 : m_profilerAgent.reset(new V8ProfilerAgentImpl(
90 11637 : this, this, agentState(protocol::Profiler::Metainfo::domainName)));
91 3879 : protocol::Profiler::Dispatcher::wire(&m_dispatcher, m_profilerAgent.get());
92 :
93 3879 : m_heapProfilerAgent.reset(new V8HeapProfilerAgentImpl(
94 11637 : this, this, agentState(protocol::HeapProfiler::Metainfo::domainName)));
95 : protocol::HeapProfiler::Dispatcher::wire(&m_dispatcher,
96 3879 : m_heapProfilerAgent.get());
97 :
98 3879 : m_consoleAgent.reset(new V8ConsoleAgentImpl(
99 11637 : this, this, agentState(protocol::Console::Metainfo::domainName)));
100 3879 : protocol::Console::Dispatcher::wire(&m_dispatcher, m_consoleAgent.get());
101 :
102 3879 : m_schemaAgent.reset(new V8SchemaAgentImpl(
103 11637 : this, this, agentState(protocol::Schema::Metainfo::domainName)));
104 3879 : protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get());
105 :
106 3879 : if (savedState.length()) {
107 55 : m_runtimeAgent->restore();
108 55 : m_debuggerAgent->restore();
109 55 : m_heapProfilerAgent->restore();
110 55 : m_profilerAgent->restore();
111 55 : m_consoleAgent->restore();
112 : }
113 3879 : }
114 :
115 19395 : V8InspectorSessionImpl::~V8InspectorSessionImpl() {
116 3879 : discardInjectedScripts();
117 7758 : m_consoleAgent->disable();
118 7758 : m_profilerAgent->disable();
119 7758 : m_heapProfilerAgent->disable();
120 7758 : m_debuggerAgent->disable();
121 7758 : m_runtimeAgent->disable();
122 3879 : m_inspector->disconnect(this);
123 7758 : }
124 :
125 23274 : protocol::DictionaryValue* V8InspectorSessionImpl::agentState(
126 : const String16& name) {
127 23274 : protocol::DictionaryValue* state = m_state->getObject(name);
128 23274 : if (!state) {
129 : std::unique_ptr<protocol::DictionaryValue> newState =
130 : protocol::DictionaryValue::create();
131 : state = newState.get();
132 45948 : m_state->setObject(name, std::move(newState));
133 : }
134 23274 : return state;
135 : }
136 :
137 : namespace {
138 :
139 990015 : class MessageBuffer : public StringBuffer {
140 : public:
141 : static std::unique_ptr<MessageBuffer> create(
142 : std::unique_ptr<protocol::Serializable> message, bool binary) {
143 : return std::unique_ptr<MessageBuffer>(
144 330005 : new MessageBuffer(std::move(message), binary));
145 : }
146 :
147 330005 : const StringView& string() override {
148 330005 : if (!m_serialized) {
149 330005 : if (m_binary) {
150 : // Encode binary response as an 8bit string buffer.
151 0 : m_serialized.reset(
152 0 : new BinaryStringBuffer(m_message->serializeToBinary()));
153 : } else {
154 : m_serialized =
155 990015 : StringBuffer::create(toStringView(m_message->serializeToJSON()));
156 : }
157 : m_message.reset(nullptr);
158 : }
159 330005 : return m_serialized->string();
160 : }
161 :
162 : private:
163 : explicit MessageBuffer(std::unique_ptr<protocol::Serializable> message,
164 : bool binary)
165 660010 : : m_message(std::move(message)), m_binary(binary) {}
166 :
167 : std::unique_ptr<protocol::Serializable> m_message;
168 : std::unique_ptr<StringBuffer> m_serialized;
169 : bool m_binary;
170 : };
171 :
172 : } // namespace
173 :
174 154950 : void V8InspectorSessionImpl::sendProtocolResponse(
175 : int callId, std::unique_ptr<protocol::Serializable> message) {
176 464850 : m_channel->sendResponse(
177 464850 : callId, MessageBuffer::create(std::move(message), use_binary_protocol_));
178 154950 : }
179 :
180 175055 : void V8InspectorSessionImpl::sendProtocolNotification(
181 : std::unique_ptr<protocol::Serializable> message) {
182 525165 : m_channel->sendNotification(
183 525165 : MessageBuffer::create(std::move(message), use_binary_protocol_));
184 175055 : }
185 :
186 0 : void V8InspectorSessionImpl::fallThrough(
187 : int callId, const String16& method,
188 : const protocol::ProtocolMessage& message) {
189 : // There's no other layer to handle the command.
190 0 : UNREACHABLE();
191 : }
192 :
193 7095 : void V8InspectorSessionImpl::flushProtocolNotifications() {
194 7095 : m_channel->flushProtocolNotifications();
195 7095 : }
196 :
197 4 : void V8InspectorSessionImpl::reset() {
198 4 : m_debuggerAgent->reset();
199 4 : m_runtimeAgent->reset();
200 4 : discardInjectedScripts();
201 4 : }
202 :
203 3883 : void V8InspectorSessionImpl::discardInjectedScripts() {
204 3883 : m_inspectedObjects.clear();
205 3883 : int sessionId = m_sessionId;
206 7766 : m_inspector->forEachContext(m_contextGroupId,
207 3869 : [&sessionId](InspectedContext* context) {
208 3869 : context->discardInjectedScript(sessionId);
209 3883 : });
210 3883 : }
211 :
212 268791 : Response V8InspectorSessionImpl::findInjectedScript(
213 : int contextId, InjectedScript*& injectedScript) {
214 268791 : injectedScript = nullptr;
215 : InspectedContext* context =
216 268791 : m_inspector->getContext(m_contextGroupId, contextId);
217 268820 : if (!context) return Response::Error("Cannot find context with specified id");
218 268762 : injectedScript = context->getInjectedScript(m_sessionId);
219 268762 : if (!injectedScript) {
220 3358 : injectedScript = context->createInjectedScript(m_sessionId);
221 3358 : if (m_customObjectFormatterEnabled)
222 10 : injectedScript->setCustomObjectFormatterEnabled(true);
223 : }
224 268762 : return Response::OK();
225 : }
226 :
227 93786 : Response V8InspectorSessionImpl::findInjectedScript(
228 : RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) {
229 93786 : return findInjectedScript(objectId->contextId(), injectedScript);
230 : }
231 :
232 0 : void V8InspectorSessionImpl::releaseObjectGroup(const StringView& objectGroup) {
233 0 : releaseObjectGroup(toString16(objectGroup));
234 0 : }
235 :
236 46726 : void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) {
237 46726 : int sessionId = m_sessionId;
238 93452 : m_inspector->forEachContext(
239 93452 : m_contextGroupId, [&objectGroup, &sessionId](InspectedContext* context) {
240 46726 : InjectedScript* injectedScript = context->getInjectedScript(sessionId);
241 93452 : if (injectedScript) injectedScript->releaseObjectGroup(objectGroup);
242 93452 : });
243 46726 : }
244 :
245 0 : bool V8InspectorSessionImpl::unwrapObject(
246 : std::unique_ptr<StringBuffer>* error, const StringView& objectId,
247 : v8::Local<v8::Value>* object, v8::Local<v8::Context>* context,
248 : std::unique_ptr<StringBuffer>* objectGroup) {
249 : String16 objectGroupString;
250 0 : Response response = unwrapObject(toString16(objectId), object, context,
251 0 : objectGroup ? &objectGroupString : nullptr);
252 0 : if (!response.isSuccess()) {
253 0 : if (error) {
254 : String16 errorMessage = response.errorMessage();
255 0 : *error = StringBufferImpl::adopt(errorMessage);
256 : }
257 : return false;
258 : }
259 0 : if (objectGroup) *objectGroup = StringBufferImpl::adopt(objectGroupString);
260 : return true;
261 : }
262 :
263 0 : Response V8InspectorSessionImpl::unwrapObject(const String16& objectId,
264 : v8::Local<v8::Value>* object,
265 : v8::Local<v8::Context>* context,
266 : String16* objectGroup) {
267 0 : std::unique_ptr<RemoteObjectId> remoteId;
268 0 : Response response = RemoteObjectId::parse(objectId, &remoteId);
269 0 : if (!response.isSuccess()) return response;
270 0 : InjectedScript* injectedScript = nullptr;
271 0 : response = findInjectedScript(remoteId.get(), injectedScript);
272 0 : if (!response.isSuccess()) return response;
273 0 : response = injectedScript->findObject(*remoteId, object);
274 0 : if (!response.isSuccess()) return response;
275 0 : *context = injectedScript->context()->context();
276 0 : if (objectGroup) *objectGroup = injectedScript->objectGroupName(*remoteId);
277 0 : return Response::OK();
278 : }
279 :
280 : std::unique_ptr<protocol::Runtime::API::RemoteObject>
281 5 : V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
282 : v8::Local<v8::Value> value,
283 : const StringView& groupName,
284 : bool generatePreview) {
285 15 : return wrapObject(context, value, toString16(groupName), generatePreview);
286 : }
287 :
288 : std::unique_ptr<protocol::Runtime::RemoteObject>
289 6705 : V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
290 : v8::Local<v8::Value> value,
291 : const String16& groupName,
292 : bool generatePreview) {
293 6705 : InjectedScript* injectedScript = nullptr;
294 13410 : findInjectedScript(InspectedContext::contextId(context), injectedScript);
295 6705 : if (!injectedScript) return nullptr;
296 6705 : std::unique_ptr<protocol::Runtime::RemoteObject> result;
297 : injectedScript->wrapObject(
298 : value, groupName,
299 13410 : generatePreview ? WrapMode::kWithPreview : WrapMode::kNoPreview, &result);
300 : return result;
301 : }
302 :
303 : std::unique_ptr<protocol::Runtime::RemoteObject>
304 165 : V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context,
305 : v8::Local<v8::Object> table,
306 : v8::MaybeLocal<v8::Array> columns) {
307 165 : InjectedScript* injectedScript = nullptr;
308 330 : findInjectedScript(InspectedContext::contextId(context), injectedScript);
309 165 : if (!injectedScript) return nullptr;
310 165 : return injectedScript->wrapTable(table, columns);
311 : }
312 :
313 697 : void V8InspectorSessionImpl::setCustomObjectFormatterEnabled(bool enabled) {
314 697 : m_customObjectFormatterEnabled = enabled;
315 697 : int sessionId = m_sessionId;
316 1394 : m_inspector->forEachContext(
317 1014 : m_contextGroupId, [&enabled, &sessionId](InspectedContext* context) {
318 692 : InjectedScript* injectedScript = context->getInjectedScript(sessionId);
319 692 : if (injectedScript)
320 322 : injectedScript->setCustomObjectFormatterEnabled(enabled);
321 1389 : });
322 697 : }
323 :
324 682 : void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) {
325 1364 : m_inspector->forEachContext(m_contextGroupId,
326 682 : [&agent](InspectedContext* context) {
327 682 : agent->reportExecutionContextCreated(context);
328 682 : });
329 682 : }
330 :
331 154955 : void V8InspectorSessionImpl::dispatchProtocolMessage(
332 : const StringView& message) {
333 : bool binary_protocol =
334 154955 : message.is8Bit() && message.length() && message.characters8()[0] == 0xD8;
335 154955 : if (binary_protocol) {
336 0 : use_binary_protocol_ = true;
337 0 : m_state->setBoolean("use_binary_protocol", true);
338 : }
339 :
340 : int callId;
341 : std::unique_ptr<protocol::Value> parsed_message;
342 154955 : if (binary_protocol) {
343 0 : parsed_message = protocol::Value::parseBinary(
344 : message.characters8(), static_cast<unsigned>(message.length()));
345 : } else {
346 309910 : parsed_message = protocol::StringUtil::parseJSON(message);
347 : }
348 : String16 method;
349 154955 : if (m_dispatcher.parseCommand(parsed_message.get(), &callId, &method)) {
350 : // Pass empty string instead of the actual message to save on a conversion.
351 : // We're allowed to do so because fall-through is not implemented.
352 309910 : m_dispatcher.dispatch(callId, method, std::move(parsed_message),
353 154955 : protocol::ProtocolMessage());
354 : }
355 154955 : }
356 :
357 110 : std::unique_ptr<StringBuffer> V8InspectorSessionImpl::stateJSON() {
358 110 : String16 json = m_state->toJSONString();
359 330 : return StringBufferImpl::adopt(json);
360 : }
361 :
362 : std::vector<std::unique_ptr<protocol::Schema::API::Domain>>
363 0 : V8InspectorSessionImpl::supportedDomains() {
364 : std::vector<std::unique_ptr<protocol::Schema::Domain>> domains =
365 0 : supportedDomainsImpl();
366 : std::vector<std::unique_ptr<protocol::Schema::API::Domain>> result;
367 0 : for (size_t i = 0; i < domains.size(); ++i)
368 0 : result.push_back(std::move(domains[i]));
369 0 : return result;
370 : }
371 :
372 : std::vector<std::unique_ptr<protocol::Schema::Domain>>
373 0 : V8InspectorSessionImpl::supportedDomainsImpl() {
374 : std::vector<std::unique_ptr<protocol::Schema::Domain>> result;
375 0 : result.push_back(protocol::Schema::Domain::create()
376 0 : .setName(protocol::Runtime::Metainfo::domainName)
377 0 : .setVersion(protocol::Runtime::Metainfo::version)
378 0 : .build());
379 0 : result.push_back(protocol::Schema::Domain::create()
380 0 : .setName(protocol::Debugger::Metainfo::domainName)
381 0 : .setVersion(protocol::Debugger::Metainfo::version)
382 0 : .build());
383 0 : result.push_back(protocol::Schema::Domain::create()
384 0 : .setName(protocol::Profiler::Metainfo::domainName)
385 0 : .setVersion(protocol::Profiler::Metainfo::version)
386 0 : .build());
387 0 : result.push_back(protocol::Schema::Domain::create()
388 0 : .setName(protocol::HeapProfiler::Metainfo::domainName)
389 0 : .setVersion(protocol::HeapProfiler::Metainfo::version)
390 0 : .build());
391 0 : result.push_back(protocol::Schema::Domain::create()
392 0 : .setName(protocol::Schema::Metainfo::domainName)
393 0 : .setVersion(protocol::Schema::Metainfo::version)
394 0 : .build());
395 0 : return result;
396 : }
397 :
398 10 : void V8InspectorSessionImpl::addInspectedObject(
399 : std::unique_ptr<V8InspectorSession::Inspectable> inspectable) {
400 10 : m_inspectedObjects.insert(m_inspectedObjects.begin(), std::move(inspectable));
401 10 : if (m_inspectedObjects.size() > kInspectedObjectBufferSize)
402 0 : m_inspectedObjects.resize(kInspectedObjectBufferSize);
403 10 : }
404 :
405 30 : V8InspectorSession::Inspectable* V8InspectorSessionImpl::inspectedObject(
406 : unsigned num) {
407 60 : if (num >= m_inspectedObjects.size()) return nullptr;
408 20 : return m_inspectedObjects[num].get();
409 : }
410 :
411 120 : void V8InspectorSessionImpl::schedulePauseOnNextStatement(
412 : const StringView& breakReason, const StringView& breakDetails) {
413 : m_debuggerAgent->schedulePauseOnNextStatement(
414 240 : toString16(breakReason),
415 120 : protocol::DictionaryValue::cast(
416 360 : protocol::StringUtil::parseJSON(breakDetails)));
417 120 : }
418 :
419 50 : void V8InspectorSessionImpl::cancelPauseOnNextStatement() {
420 50 : m_debuggerAgent->cancelPauseOnNextStatement();
421 50 : }
422 :
423 65 : void V8InspectorSessionImpl::breakProgram(const StringView& breakReason,
424 : const StringView& breakDetails) {
425 : m_debuggerAgent->breakProgram(
426 130 : toString16(breakReason),
427 65 : protocol::DictionaryValue::cast(
428 195 : protocol::StringUtil::parseJSON(breakDetails)));
429 65 : }
430 :
431 0 : void V8InspectorSessionImpl::setSkipAllPauses(bool skip) {
432 0 : m_debuggerAgent->setSkipAllPauses(skip);
433 0 : }
434 :
435 0 : void V8InspectorSessionImpl::resume() { m_debuggerAgent->resume(); }
436 :
437 0 : void V8InspectorSessionImpl::stepOver() { m_debuggerAgent->stepOver(); }
438 :
439 : std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>>
440 0 : V8InspectorSessionImpl::searchInTextByLines(const StringView& text,
441 : const StringView& query,
442 : bool caseSensitive, bool isRegex) {
443 : // TODO(dgozman): search may operate on StringView and avoid copying |text|.
444 : std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
445 0 : searchInTextByLinesImpl(this, toString16(text), toString16(query),
446 0 : caseSensitive, isRegex);
447 : std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> result;
448 0 : for (size_t i = 0; i < matches.size(); ++i)
449 0 : result.push_back(std::move(matches[i]));
450 0 : return result;
451 : }
452 :
453 : } // namespace v8_inspector
|