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