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 : return stringViewStartsWith(method,
27 0 : protocol::Runtime::Metainfo::commandPrefix) ||
28 : stringViewStartsWith(method,
29 0 : protocol::Debugger::Metainfo::commandPrefix) ||
30 : stringViewStartsWith(method,
31 0 : protocol::Profiler::Metainfo::commandPrefix) ||
32 : stringViewStartsWith(
33 0 : method, protocol::HeapProfiler::Metainfo::commandPrefix) ||
34 : stringViewStartsWith(method,
35 0 : protocol::Console::Metainfo::commandPrefix) ||
36 : 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 3834 : 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 7668 : inspector, contextGroupId, sessionId, channel, state));
50 : }
51 :
52 3834 : V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector,
53 : int contextGroupId,
54 : int sessionId,
55 : V8Inspector::Channel* channel,
56 7668 : 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 3834 : m_schemaAgent(nullptr) {
70 3834 : 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 7558 : m_state = protocol::DictionaryValue::create();
77 : }
78 :
79 : m_runtimeAgent.reset(new V8RuntimeAgentImpl(
80 7668 : this, this, agentState(protocol::Runtime::Metainfo::domainName)));
81 3834 : protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
82 :
83 : m_debuggerAgent.reset(new V8DebuggerAgentImpl(
84 7668 : this, this, agentState(protocol::Debugger::Metainfo::domainName)));
85 3834 : protocol::Debugger::Dispatcher::wire(&m_dispatcher, m_debuggerAgent.get());
86 :
87 : m_profilerAgent.reset(new V8ProfilerAgentImpl(
88 7668 : this, this, agentState(protocol::Profiler::Metainfo::domainName)));
89 3834 : protocol::Profiler::Dispatcher::wire(&m_dispatcher, m_profilerAgent.get());
90 :
91 : m_heapProfilerAgent.reset(new V8HeapProfilerAgentImpl(
92 7668 : this, this, agentState(protocol::HeapProfiler::Metainfo::domainName)));
93 : protocol::HeapProfiler::Dispatcher::wire(&m_dispatcher,
94 3834 : m_heapProfilerAgent.get());
95 :
96 : m_consoleAgent.reset(new V8ConsoleAgentImpl(
97 7668 : this, this, agentState(protocol::Console::Metainfo::domainName)));
98 3834 : protocol::Console::Dispatcher::wire(&m_dispatcher, m_consoleAgent.get());
99 :
100 : m_schemaAgent.reset(new V8SchemaAgentImpl(
101 7668 : this, this, agentState(protocol::Schema::Metainfo::domainName)));
102 3834 : protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get());
103 :
104 3834 : if (savedState.length()) {
105 55 : m_runtimeAgent->restore();
106 55 : m_debuggerAgent->restore();
107 55 : m_heapProfilerAgent->restore();
108 55 : m_profilerAgent->restore();
109 55 : m_consoleAgent->restore();
110 : }
111 3834 : }
112 :
113 15336 : V8InspectorSessionImpl::~V8InspectorSessionImpl() {
114 3834 : discardInjectedScripts();
115 7668 : m_consoleAgent->disable();
116 7668 : m_profilerAgent->disable();
117 7668 : m_heapProfilerAgent->disable();
118 7668 : m_debuggerAgent->disable();
119 7668 : m_runtimeAgent->disable();
120 3834 : m_inspector->disconnect(this);
121 3834 : }
122 :
123 23004 : protocol::DictionaryValue* V8InspectorSessionImpl::agentState(
124 : const String16& name) {
125 23004 : protocol::DictionaryValue* state = m_state->getObject(name);
126 23004 : if (!state) {
127 : std::unique_ptr<protocol::DictionaryValue> newState =
128 22704 : protocol::DictionaryValue::create();
129 : state = newState.get();
130 45408 : m_state->setObject(name, std::move(newState));
131 : }
132 23004 : return state;
133 : }
134 :
135 : namespace {
136 :
137 1045800 : class MessageBuffer : public StringBuffer {
138 : public:
139 348600 : static std::unique_ptr<MessageBuffer> create(
140 : std::unique_ptr<protocol::Serializable> message) {
141 : return std::unique_ptr<MessageBuffer>(
142 348600 : new MessageBuffer(std::move(message)));
143 : }
144 :
145 348600 : const StringView& string() override {
146 348600 : if (!m_serialized) {
147 1045800 : m_serialized = StringBuffer::create(toStringView(m_message->serialize()));
148 : m_message.reset(nullptr);
149 : }
150 348600 : return m_serialized->string();
151 : }
152 :
153 : private:
154 : explicit MessageBuffer(std::unique_ptr<protocol::Serializable> message)
155 697200 : : m_message(std::move(message)) {}
156 :
157 : std::unique_ptr<protocol::Serializable> m_message;
158 : std::unique_ptr<StringBuffer> m_serialized;
159 : };
160 :
161 : } // namespace
162 :
163 169234 : void V8InspectorSessionImpl::sendProtocolResponse(
164 : int callId, std::unique_ptr<protocol::Serializable> message) {
165 1015404 : m_channel->sendResponse(callId, MessageBuffer::create(std::move(message)));
166 169234 : }
167 :
168 179366 : void V8InspectorSessionImpl::sendProtocolNotification(
169 : std::unique_ptr<protocol::Serializable> message) {
170 1076196 : m_channel->sendNotification(MessageBuffer::create(std::move(message)));
171 179366 : }
172 :
173 0 : void V8InspectorSessionImpl::fallThrough(int callId, const String16& method,
174 : const String16& message) {
175 : // There's no other layer to handle the command.
176 0 : UNREACHABLE();
177 : }
178 :
179 7065 : void V8InspectorSessionImpl::flushProtocolNotifications() {
180 7065 : m_channel->flushProtocolNotifications();
181 7065 : }
182 :
183 5 : void V8InspectorSessionImpl::reset() {
184 5 : m_debuggerAgent->reset();
185 5 : m_runtimeAgent->reset();
186 5 : discardInjectedScripts();
187 5 : }
188 :
189 3839 : void V8InspectorSessionImpl::discardInjectedScripts() {
190 : m_inspectedObjects.clear();
191 3839 : int sessionId = m_sessionId;
192 : m_inspector->forEachContext(m_contextGroupId,
193 : [&sessionId](InspectedContext* context) {
194 3824 : context->discardInjectedScript(sessionId);
195 7678 : });
196 3839 : }
197 :
198 267134 : Response V8InspectorSessionImpl::findInjectedScript(
199 : int contextId, InjectedScript*& injectedScript) {
200 267134 : injectedScript = nullptr;
201 : InspectedContext* context =
202 267134 : m_inspector->getContext(m_contextGroupId, contextId);
203 267164 : if (!context) return Response::Error("Cannot find context with specified id");
204 267104 : injectedScript = context->getInjectedScript(m_sessionId);
205 267104 : if (!injectedScript) {
206 3311 : injectedScript = context->createInjectedScript(m_sessionId);
207 3311 : if (m_customObjectFormatterEnabled)
208 10 : injectedScript->setCustomObjectFormatterEnabled(true);
209 : }
210 267104 : return Response::OK();
211 : }
212 :
213 93126 : Response V8InspectorSessionImpl::findInjectedScript(
214 : RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) {
215 93126 : return findInjectedScript(objectId->contextId(), injectedScript);
216 : }
217 :
218 0 : void V8InspectorSessionImpl::releaseObjectGroup(const StringView& objectGroup) {
219 0 : releaseObjectGroup(toString16(objectGroup));
220 0 : }
221 :
222 46839 : void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) {
223 46839 : int sessionId = m_sessionId;
224 : m_inspector->forEachContext(
225 46839 : m_contextGroupId, [&objectGroup, &sessionId](InspectedContext* context) {
226 46839 : InjectedScript* injectedScript = context->getInjectedScript(sessionId);
227 46839 : if (injectedScript) injectedScript->releaseObjectGroup(objectGroup);
228 140517 : });
229 46839 : }
230 :
231 0 : bool V8InspectorSessionImpl::unwrapObject(
232 : std::unique_ptr<StringBuffer>* error, const StringView& objectId,
233 : v8::Local<v8::Value>* object, v8::Local<v8::Context>* context,
234 : std::unique_ptr<StringBuffer>* objectGroup) {
235 0 : String16 objectGroupString;
236 : Response response = unwrapObject(toString16(objectId), object, context,
237 0 : objectGroup ? &objectGroupString : nullptr);
238 0 : if (!response.isSuccess()) {
239 0 : if (error) {
240 0 : String16 errorMessage = response.errorMessage();
241 0 : *error = StringBufferImpl::adopt(errorMessage);
242 : }
243 : return false;
244 : }
245 0 : if (objectGroup) *objectGroup = StringBufferImpl::adopt(objectGroupString);
246 : return true;
247 : }
248 :
249 0 : Response V8InspectorSessionImpl::unwrapObject(const String16& objectId,
250 : v8::Local<v8::Value>* object,
251 : v8::Local<v8::Context>* context,
252 : String16* objectGroup) {
253 0 : std::unique_ptr<RemoteObjectId> remoteId;
254 0 : Response response = RemoteObjectId::parse(objectId, &remoteId);
255 0 : if (!response.isSuccess()) return response;
256 0 : InjectedScript* injectedScript = nullptr;
257 0 : response = findInjectedScript(remoteId.get(), injectedScript);
258 0 : if (!response.isSuccess()) return response;
259 0 : response = injectedScript->findObject(*remoteId, object);
260 0 : if (!response.isSuccess()) return response;
261 0 : *context = injectedScript->context()->context();
262 0 : if (objectGroup) *objectGroup = injectedScript->objectGroupName(*remoteId);
263 0 : return Response::OK();
264 : }
265 :
266 : std::unique_ptr<protocol::Runtime::API::RemoteObject>
267 5 : V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
268 : v8::Local<v8::Value> value,
269 : const StringView& groupName,
270 : bool generatePreview) {
271 15 : return wrapObject(context, value, toString16(groupName), generatePreview);
272 : }
273 :
274 : std::unique_ptr<protocol::Runtime::RemoteObject>
275 6685 : V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
276 : v8::Local<v8::Value> value,
277 : const String16& groupName,
278 : bool generatePreview) {
279 6685 : InjectedScript* injectedScript = nullptr;
280 13370 : findInjectedScript(InspectedContext::contextId(context), injectedScript);
281 6685 : if (!injectedScript) return nullptr;
282 6685 : std::unique_ptr<protocol::Runtime::RemoteObject> result;
283 : injectedScript->wrapObject(
284 : value, groupName,
285 13370 : generatePreview ? WrapMode::kWithPreview : WrapMode::kNoPreview, &result);
286 : return result;
287 : }
288 :
289 : std::unique_ptr<protocol::Runtime::RemoteObject>
290 150 : V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context,
291 : v8::Local<v8::Object> table,
292 : v8::MaybeLocal<v8::Array> columns) {
293 150 : InjectedScript* injectedScript = nullptr;
294 300 : findInjectedScript(InspectedContext::contextId(context), injectedScript);
295 150 : if (!injectedScript) return nullptr;
296 150 : return injectedScript->wrapTable(table, columns);
297 : }
298 :
299 710 : void V8InspectorSessionImpl::setCustomObjectFormatterEnabled(bool enabled) {
300 710 : m_customObjectFormatterEnabled = enabled;
301 710 : int sessionId = m_sessionId;
302 : m_inspector->forEachContext(
303 705 : m_contextGroupId, [&enabled, &sessionId](InspectedContext* context) {
304 705 : InjectedScript* injectedScript = context->getInjectedScript(sessionId);
305 705 : if (injectedScript)
306 355 : injectedScript->setCustomObjectFormatterEnabled(enabled);
307 2125 : });
308 710 : }
309 :
310 695 : void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) {
311 : m_inspector->forEachContext(m_contextGroupId,
312 : [&agent](InspectedContext* context) {
313 695 : agent->reportExecutionContextCreated(context);
314 1390 : });
315 695 : }
316 :
317 169239 : void V8InspectorSessionImpl::dispatchProtocolMessage(
318 : const StringView& message) {
319 : int callId;
320 169239 : String16 method;
321 : std::unique_ptr<protocol::Value> parsedMessage =
322 169239 : protocol::StringUtil::parseJSON(message);
323 169239 : if (m_dispatcher.parseCommand(parsedMessage.get(), &callId, &method)) {
324 : // Pass empty string instead of the actual message to save on a conversion.
325 : // We're allowed to do so because fall-through is not implemented.
326 676956 : m_dispatcher.dispatch(callId, method, std::move(parsedMessage), "");
327 : }
328 169239 : }
329 :
330 110 : std::unique_ptr<StringBuffer> V8InspectorSessionImpl::stateJSON() {
331 110 : String16 json = m_state->serialize();
332 330 : return StringBufferImpl::adopt(json);
333 : }
334 :
335 : std::vector<std::unique_ptr<protocol::Schema::API::Domain>>
336 0 : V8InspectorSessionImpl::supportedDomains() {
337 : std::vector<std::unique_ptr<protocol::Schema::Domain>> domains =
338 0 : supportedDomainsImpl();
339 : std::vector<std::unique_ptr<protocol::Schema::API::Domain>> result;
340 0 : for (size_t i = 0; i < domains.size(); ++i)
341 0 : result.push_back(std::move(domains[i]));
342 0 : return result;
343 : }
344 :
345 : std::vector<std::unique_ptr<protocol::Schema::Domain>>
346 0 : V8InspectorSessionImpl::supportedDomainsImpl() {
347 : std::vector<std::unique_ptr<protocol::Schema::Domain>> result;
348 : result.push_back(protocol::Schema::Domain::create()
349 0 : .setName(protocol::Runtime::Metainfo::domainName)
350 0 : .setVersion(protocol::Runtime::Metainfo::version)
351 0 : .build());
352 : result.push_back(protocol::Schema::Domain::create()
353 0 : .setName(protocol::Debugger::Metainfo::domainName)
354 0 : .setVersion(protocol::Debugger::Metainfo::version)
355 0 : .build());
356 : result.push_back(protocol::Schema::Domain::create()
357 0 : .setName(protocol::Profiler::Metainfo::domainName)
358 0 : .setVersion(protocol::Profiler::Metainfo::version)
359 0 : .build());
360 : result.push_back(protocol::Schema::Domain::create()
361 0 : .setName(protocol::HeapProfiler::Metainfo::domainName)
362 0 : .setVersion(protocol::HeapProfiler::Metainfo::version)
363 0 : .build());
364 : result.push_back(protocol::Schema::Domain::create()
365 0 : .setName(protocol::Schema::Metainfo::domainName)
366 0 : .setVersion(protocol::Schema::Metainfo::version)
367 0 : .build());
368 0 : return result;
369 : }
370 :
371 10 : void V8InspectorSessionImpl::addInspectedObject(
372 : std::unique_ptr<V8InspectorSession::Inspectable> inspectable) {
373 20 : m_inspectedObjects.insert(m_inspectedObjects.begin(), std::move(inspectable));
374 10 : if (m_inspectedObjects.size() > kInspectedObjectBufferSize)
375 0 : m_inspectedObjects.resize(kInspectedObjectBufferSize);
376 10 : }
377 :
378 30 : V8InspectorSession::Inspectable* V8InspectorSessionImpl::inspectedObject(
379 : unsigned num) {
380 60 : if (num >= m_inspectedObjects.size()) return nullptr;
381 20 : return m_inspectedObjects[num].get();
382 : }
383 :
384 120 : void V8InspectorSessionImpl::schedulePauseOnNextStatement(
385 : const StringView& breakReason, const StringView& breakDetails) {
386 : m_debuggerAgent->schedulePauseOnNextStatement(
387 : toString16(breakReason),
388 : protocol::DictionaryValue::cast(
389 720 : protocol::StringUtil::parseJSON(breakDetails)));
390 120 : }
391 :
392 50 : void V8InspectorSessionImpl::cancelPauseOnNextStatement() {
393 50 : m_debuggerAgent->cancelPauseOnNextStatement();
394 50 : }
395 :
396 65 : void V8InspectorSessionImpl::breakProgram(const StringView& breakReason,
397 : const StringView& breakDetails) {
398 : m_debuggerAgent->breakProgram(
399 : toString16(breakReason),
400 : protocol::DictionaryValue::cast(
401 390 : protocol::StringUtil::parseJSON(breakDetails)));
402 65 : }
403 :
404 0 : void V8InspectorSessionImpl::setSkipAllPauses(bool skip) {
405 0 : m_debuggerAgent->setSkipAllPauses(skip);
406 0 : }
407 :
408 0 : void V8InspectorSessionImpl::resume() { m_debuggerAgent->resume(); }
409 :
410 0 : void V8InspectorSessionImpl::stepOver() { m_debuggerAgent->stepOver(); }
411 :
412 : std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>>
413 0 : V8InspectorSessionImpl::searchInTextByLines(const StringView& text,
414 : const StringView& query,
415 : bool caseSensitive, bool isRegex) {
416 : // TODO(dgozman): search may operate on StringView and avoid copying |text|.
417 : std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
418 : searchInTextByLinesImpl(this, toString16(text), toString16(query),
419 0 : caseSensitive, isRegex);
420 : std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> result;
421 0 : for (size_t i = 0; i < matches.size(); ++i)
422 0 : result.push_back(std::move(matches[i]));
423 0 : return result;
424 : }
425 :
426 : } // namespace v8_inspector
|