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 4573 : std::unique_ptr<V8InspectorSessionImpl> V8InspectorSessionImpl::create(
46 : V8InspectorImpl* inspector, int contextGroupId,
47 : V8Inspector::Channel* channel, const StringView& state) {
48 : return std::unique_ptr<V8InspectorSessionImpl>(
49 9146 : new V8InspectorSessionImpl(inspector, contextGroupId, channel, state));
50 : }
51 :
52 4573 : V8InspectorSessionImpl::V8InspectorSessionImpl(V8InspectorImpl* inspector,
53 : int contextGroupId,
54 : V8Inspector::Channel* channel,
55 9146 : const StringView& savedState)
56 : : m_contextGroupId(contextGroupId),
57 : m_inspector(inspector),
58 : m_channel(channel),
59 : m_customObjectFormatterEnabled(false),
60 : m_dispatcher(this),
61 : m_state(nullptr),
62 : m_runtimeAgent(nullptr),
63 : m_debuggerAgent(nullptr),
64 : m_heapProfilerAgent(nullptr),
65 : m_profilerAgent(nullptr),
66 : m_consoleAgent(nullptr),
67 4573 : m_schemaAgent(nullptr) {
68 4573 : if (savedState.length()) {
69 : std::unique_ptr<protocol::Value> state =
70 72 : protocol::StringUtil::parseJSON(toString16(savedState));
71 36 : if (state) m_state = protocol::DictionaryValue::cast(std::move(state));
72 36 : if (!m_state) m_state = protocol::DictionaryValue::create();
73 : } else {
74 9074 : m_state = protocol::DictionaryValue::create();
75 : }
76 :
77 : m_runtimeAgent.reset(new V8RuntimeAgentImpl(
78 9146 : this, this, agentState(protocol::Runtime::Metainfo::domainName)));
79 4573 : protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
80 :
81 : m_debuggerAgent.reset(new V8DebuggerAgentImpl(
82 9146 : this, this, agentState(protocol::Debugger::Metainfo::domainName)));
83 4573 : protocol::Debugger::Dispatcher::wire(&m_dispatcher, m_debuggerAgent.get());
84 :
85 : m_profilerAgent.reset(new V8ProfilerAgentImpl(
86 9146 : this, this, agentState(protocol::Profiler::Metainfo::domainName)));
87 4573 : protocol::Profiler::Dispatcher::wire(&m_dispatcher, m_profilerAgent.get());
88 :
89 : m_heapProfilerAgent.reset(new V8HeapProfilerAgentImpl(
90 9146 : this, this, agentState(protocol::HeapProfiler::Metainfo::domainName)));
91 : protocol::HeapProfiler::Dispatcher::wire(&m_dispatcher,
92 4573 : m_heapProfilerAgent.get());
93 :
94 : m_consoleAgent.reset(new V8ConsoleAgentImpl(
95 9146 : this, this, agentState(protocol::Console::Metainfo::domainName)));
96 4573 : protocol::Console::Dispatcher::wire(&m_dispatcher, m_consoleAgent.get());
97 :
98 : m_schemaAgent.reset(new V8SchemaAgentImpl(
99 9146 : this, this, agentState(protocol::Schema::Metainfo::domainName)));
100 4573 : protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get());
101 :
102 4573 : if (savedState.length()) {
103 36 : m_runtimeAgent->restore();
104 36 : m_debuggerAgent->restore();
105 36 : m_heapProfilerAgent->restore();
106 36 : m_profilerAgent->restore();
107 36 : m_consoleAgent->restore();
108 : }
109 4573 : }
110 :
111 18292 : V8InspectorSessionImpl::~V8InspectorSessionImpl() {
112 9146 : m_consoleAgent->disable();
113 9146 : m_profilerAgent->disable();
114 9146 : m_heapProfilerAgent->disable();
115 9146 : m_debuggerAgent->disable();
116 9146 : m_runtimeAgent->disable();
117 :
118 4573 : discardInjectedScripts();
119 4573 : m_inspector->disconnect(this);
120 4573 : }
121 :
122 27438 : protocol::DictionaryValue* V8InspectorSessionImpl::agentState(
123 : const String16& name) {
124 27438 : protocol::DictionaryValue* state = m_state->getObject(name);
125 27438 : if (!state) {
126 : std::unique_ptr<protocol::DictionaryValue> newState =
127 27222 : protocol::DictionaryValue::create();
128 : state = newState.get();
129 54444 : m_state->setObject(name, std::move(newState));
130 : }
131 27438 : return state;
132 : }
133 :
134 : namespace {
135 :
136 1225482 : class MessageBuffer : public StringBuffer {
137 : public:
138 408494 : static std::unique_ptr<MessageBuffer> create(
139 : std::unique_ptr<protocol::Serializable> message) {
140 : return std::unique_ptr<MessageBuffer>(
141 816988 : new MessageBuffer(std::move(message)));
142 : }
143 :
144 408494 : const StringView& string() override {
145 408494 : if (!m_serialized) {
146 1225482 : m_serialized = StringBuffer::create(toStringView(m_message->serialize()));
147 : m_message.reset(nullptr);
148 : }
149 408494 : return m_serialized->string();
150 : }
151 :
152 : private:
153 : explicit MessageBuffer(std::unique_ptr<protocol::Serializable> message)
154 816988 : : m_message(std::move(message)) {}
155 :
156 : std::unique_ptr<protocol::Serializable> m_message;
157 : std::unique_ptr<StringBuffer> m_serialized;
158 : };
159 :
160 : } // namespace
161 :
162 209613 : void V8InspectorSessionImpl::sendProtocolResponse(
163 : int callId, std::unique_ptr<protocol::Serializable> message) {
164 1257678 : m_channel->sendResponse(callId, MessageBuffer::create(std::move(message)));
165 209613 : }
166 :
167 198881 : void V8InspectorSessionImpl::sendProtocolNotification(
168 : std::unique_ptr<protocol::Serializable> message) {
169 1193286 : m_channel->sendNotification(MessageBuffer::create(std::move(message)));
170 198881 : }
171 :
172 7580 : void V8InspectorSessionImpl::flushProtocolNotifications() {
173 7580 : m_channel->flushProtocolNotifications();
174 7580 : }
175 :
176 0 : void V8InspectorSessionImpl::reset() {
177 0 : m_debuggerAgent->reset();
178 0 : m_runtimeAgent->reset();
179 0 : discardInjectedScripts();
180 0 : }
181 :
182 4969 : void V8InspectorSessionImpl::discardInjectedScripts() {
183 : m_inspectedObjects.clear();
184 : const V8InspectorImpl::ContextByIdMap* contexts =
185 4969 : m_inspector->contextGroup(m_contextGroupId);
186 4969 : if (!contexts) return;
187 :
188 : std::vector<int> keys;
189 4969 : keys.reserve(contexts->size());
190 14907 : for (auto& idContext : *contexts) keys.push_back(idContext.first);
191 14907 : for (auto& key : keys) {
192 4969 : contexts = m_inspector->contextGroup(m_contextGroupId);
193 4969 : if (!contexts) continue;
194 : auto contextIt = contexts->find(key);
195 4969 : if (contextIt != contexts->end())
196 : contextIt->second
197 4969 : ->discardInjectedScript(); // This may destroy some contexts.
198 : }
199 : }
200 :
201 347844 : Response V8InspectorSessionImpl::findInjectedScript(
202 : int contextId, InjectedScript*& injectedScript) {
203 347844 : injectedScript = nullptr;
204 347844 : if (!contextId)
205 12 : return Response::Error("Cannot find context with specified id");
206 :
207 : const V8InspectorImpl::ContextByIdMap* contexts =
208 347838 : m_inspector->contextGroup(m_contextGroupId);
209 347838 : if (!contexts)
210 0 : return Response::Error("Cannot find context with specified id");
211 :
212 : auto contextsIt = contexts->find(contextId);
213 347838 : if (contextsIt == contexts->end())
214 12 : return Response::Error("Cannot find context with specified id");
215 :
216 : const std::unique_ptr<InspectedContext>& context = contextsIt->second;
217 347832 : if (!context->getInjectedScript()) {
218 4109 : if (!context->createInjectedScript())
219 0 : return Response::Error("Cannot access specified execution context");
220 4109 : if (m_customObjectFormatterEnabled)
221 6 : context->getInjectedScript()->setCustomObjectFormatterEnabled(true);
222 : }
223 347832 : injectedScript = context->getInjectedScript();
224 347832 : return Response::OK();
225 : }
226 :
227 136090 : Response V8InspectorSessionImpl::findInjectedScript(
228 : RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) {
229 136090 : return findInjectedScript(objectId->contextId(), injectedScript);
230 : }
231 :
232 0 : void V8InspectorSessionImpl::releaseObjectGroup(const StringView& objectGroup) {
233 0 : releaseObjectGroup(toString16(objectGroup));
234 0 : }
235 :
236 64524 : void V8InspectorSessionImpl::releaseObjectGroup(const String16& objectGroup) {
237 : const V8InspectorImpl::ContextByIdMap* contexts =
238 64524 : m_inspector->contextGroup(m_contextGroupId);
239 64524 : if (!contexts) return;
240 :
241 : std::vector<int> keys;
242 193572 : for (auto& idContext : *contexts) keys.push_back(idContext.first);
243 193572 : for (auto& key : keys) {
244 64524 : contexts = m_inspector->contextGroup(m_contextGroupId);
245 64524 : if (!contexts) continue;
246 : auto contextsIt = contexts->find(key);
247 64524 : if (contextsIt == contexts->end()) continue;
248 : InjectedScript* injectedScript = contextsIt->second->getInjectedScript();
249 64524 : if (injectedScript)
250 : injectedScript->releaseObjectGroup(
251 64524 : objectGroup); // This may destroy some contexts.
252 : }
253 : }
254 :
255 0 : bool V8InspectorSessionImpl::unwrapObject(
256 : std::unique_ptr<StringBuffer>* error, const StringView& objectId,
257 : v8::Local<v8::Value>* object, v8::Local<v8::Context>* context,
258 : std::unique_ptr<StringBuffer>* objectGroup) {
259 : String16 objectGroupString;
260 : Response response = unwrapObject(toString16(objectId), object, context,
261 0 : objectGroup ? &objectGroupString : nullptr);
262 0 : if (!response.isSuccess()) {
263 0 : if (error) {
264 : String16 errorMessage = response.errorMessage();
265 0 : *error = StringBufferImpl::adopt(errorMessage);
266 : }
267 : return false;
268 : }
269 0 : if (objectGroup) *objectGroup = StringBufferImpl::adopt(objectGroupString);
270 : return true;
271 : }
272 :
273 0 : Response V8InspectorSessionImpl::unwrapObject(const String16& objectId,
274 : v8::Local<v8::Value>* object,
275 : v8::Local<v8::Context>* context,
276 : String16* objectGroup) {
277 0 : std::unique_ptr<RemoteObjectId> remoteId;
278 0 : Response response = RemoteObjectId::parse(objectId, &remoteId);
279 0 : if (!response.isSuccess()) return response;
280 0 : InjectedScript* injectedScript = nullptr;
281 0 : response = findInjectedScript(remoteId.get(), injectedScript);
282 0 : if (!response.isSuccess()) return response;
283 0 : response = injectedScript->findObject(*remoteId, object);
284 0 : if (!response.isSuccess()) return response;
285 0 : *context = injectedScript->context()->context();
286 0 : if (objectGroup) *objectGroup = injectedScript->objectGroupName(*remoteId);
287 0 : return Response::OK();
288 : }
289 :
290 : std::unique_ptr<protocol::Runtime::API::RemoteObject>
291 0 : V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
292 : v8::Local<v8::Value> value,
293 : const StringView& groupName) {
294 0 : return wrapObject(context, value, toString16(groupName), false);
295 : }
296 :
297 : std::unique_ptr<protocol::Runtime::RemoteObject>
298 7278 : V8InspectorSessionImpl::wrapObject(v8::Local<v8::Context> context,
299 : v8::Local<v8::Value> value,
300 : const String16& groupName,
301 : bool generatePreview) {
302 7278 : InjectedScript* injectedScript = nullptr;
303 14556 : findInjectedScript(InspectedContext::contextId(context), injectedScript);
304 7278 : if (!injectedScript) return nullptr;
305 7278 : std::unique_ptr<protocol::Runtime::RemoteObject> result;
306 14556 : injectedScript->wrapObject(value, groupName, false, generatePreview, &result);
307 : return result;
308 : }
309 :
310 : std::unique_ptr<protocol::Runtime::RemoteObject>
311 120 : V8InspectorSessionImpl::wrapTable(v8::Local<v8::Context> context,
312 : v8::Local<v8::Value> table,
313 : v8::Local<v8::Value> columns) {
314 120 : InjectedScript* injectedScript = nullptr;
315 240 : findInjectedScript(InspectedContext::contextId(context), injectedScript);
316 120 : if (!injectedScript) return nullptr;
317 120 : return injectedScript->wrapTable(table, columns);
318 : }
319 :
320 408 : void V8InspectorSessionImpl::setCustomObjectFormatterEnabled(bool enabled) {
321 408 : m_customObjectFormatterEnabled = enabled;
322 : const V8InspectorImpl::ContextByIdMap* contexts =
323 408 : m_inspector->contextGroup(m_contextGroupId);
324 816 : if (!contexts) return;
325 1206 : for (auto& idContext : *contexts) {
326 : InjectedScript* injectedScript = idContext.second->getInjectedScript();
327 402 : if (injectedScript)
328 0 : injectedScript->setCustomObjectFormatterEnabled(enabled);
329 : }
330 : }
331 :
332 396 : void V8InspectorSessionImpl::reportAllContexts(V8RuntimeAgentImpl* agent) {
333 : const V8InspectorImpl::ContextByIdMap* contexts =
334 396 : m_inspector->contextGroup(m_contextGroupId);
335 792 : if (!contexts) return;
336 1098 : for (auto& idContext : *contexts)
337 366 : agent->reportExecutionContextCreated(idContext.second.get());
338 : }
339 :
340 209619 : void V8InspectorSessionImpl::dispatchProtocolMessage(
341 : const StringView& message) {
342 419238 : m_dispatcher.dispatch(protocol::StringUtil::parseJSON(message));
343 209619 : }
344 :
345 42 : std::unique_ptr<StringBuffer> V8InspectorSessionImpl::stateJSON() {
346 42 : String16 json = m_state->serialize();
347 126 : return StringBufferImpl::adopt(json);
348 : }
349 :
350 : std::vector<std::unique_ptr<protocol::Schema::API::Domain>>
351 0 : V8InspectorSessionImpl::supportedDomains() {
352 : std::vector<std::unique_ptr<protocol::Schema::Domain>> domains =
353 0 : supportedDomainsImpl();
354 : std::vector<std::unique_ptr<protocol::Schema::API::Domain>> result;
355 0 : for (size_t i = 0; i < domains.size(); ++i)
356 0 : result.push_back(std::move(domains[i]));
357 0 : return result;
358 : }
359 :
360 : std::vector<std::unique_ptr<protocol::Schema::Domain>>
361 0 : V8InspectorSessionImpl::supportedDomainsImpl() {
362 : std::vector<std::unique_ptr<protocol::Schema::Domain>> result;
363 : result.push_back(protocol::Schema::Domain::create()
364 0 : .setName(protocol::Runtime::Metainfo::domainName)
365 0 : .setVersion(protocol::Runtime::Metainfo::version)
366 0 : .build());
367 : result.push_back(protocol::Schema::Domain::create()
368 0 : .setName(protocol::Debugger::Metainfo::domainName)
369 0 : .setVersion(protocol::Debugger::Metainfo::version)
370 0 : .build());
371 : result.push_back(protocol::Schema::Domain::create()
372 0 : .setName(protocol::Profiler::Metainfo::domainName)
373 0 : .setVersion(protocol::Profiler::Metainfo::version)
374 0 : .build());
375 : result.push_back(protocol::Schema::Domain::create()
376 0 : .setName(protocol::HeapProfiler::Metainfo::domainName)
377 0 : .setVersion(protocol::HeapProfiler::Metainfo::version)
378 0 : .build());
379 : result.push_back(protocol::Schema::Domain::create()
380 0 : .setName(protocol::Schema::Metainfo::domainName)
381 0 : .setVersion(protocol::Schema::Metainfo::version)
382 0 : .build());
383 0 : return result;
384 : }
385 :
386 0 : void V8InspectorSessionImpl::addInspectedObject(
387 : std::unique_ptr<V8InspectorSession::Inspectable> inspectable) {
388 0 : m_inspectedObjects.insert(m_inspectedObjects.begin(), std::move(inspectable));
389 0 : if (m_inspectedObjects.size() > kInspectedObjectBufferSize)
390 0 : m_inspectedObjects.resize(kInspectedObjectBufferSize);
391 0 : }
392 :
393 6 : V8InspectorSession::Inspectable* V8InspectorSessionImpl::inspectedObject(
394 : unsigned num) {
395 12 : if (num >= m_inspectedObjects.size()) return nullptr;
396 0 : return m_inspectedObjects[num].get();
397 : }
398 :
399 114 : void V8InspectorSessionImpl::schedulePauseOnNextStatement(
400 : const StringView& breakReason, const StringView& breakDetails) {
401 : m_debuggerAgent->schedulePauseOnNextStatement(
402 : toString16(breakReason),
403 : protocol::DictionaryValue::cast(
404 684 : protocol::StringUtil::parseJSON(breakDetails)));
405 114 : }
406 :
407 54 : void V8InspectorSessionImpl::cancelPauseOnNextStatement() {
408 54 : m_debuggerAgent->cancelPauseOnNextStatement();
409 54 : }
410 :
411 66 : void V8InspectorSessionImpl::breakProgram(const StringView& breakReason,
412 : const StringView& breakDetails) {
413 : m_debuggerAgent->breakProgram(
414 : toString16(breakReason),
415 : protocol::DictionaryValue::cast(
416 396 : protocol::StringUtil::parseJSON(breakDetails)));
417 66 : }
418 :
419 0 : void V8InspectorSessionImpl::setSkipAllPauses(bool skip) {
420 0 : m_debuggerAgent->setSkipAllPauses(skip);
421 0 : }
422 :
423 0 : void V8InspectorSessionImpl::resume() { m_debuggerAgent->resume(); }
424 :
425 0 : void V8InspectorSessionImpl::stepOver() { m_debuggerAgent->stepOver(); }
426 :
427 : std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>>
428 0 : V8InspectorSessionImpl::searchInTextByLines(const StringView& text,
429 : const StringView& query,
430 : bool caseSensitive, bool isRegex) {
431 : // TODO(dgozman): search may operate on StringView and avoid copying |text|.
432 : std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
433 : searchInTextByLinesImpl(this, toString16(text), toString16(query),
434 0 : caseSensitive, isRegex);
435 : std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> result;
436 0 : for (size_t i = 0; i < matches.size(); ++i)
437 0 : result.push_back(std::move(matches[i]));
438 0 : return result;
439 : }
440 :
441 : } // namespace v8_inspector
|