v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
v8-inspector-session-impl.cc
Go to the documentation of this file.
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
6
7#include "../../third_party/inspector_protocol/crdtp/cbor.h"
8#include "../../third_party/inspector_protocol/crdtp/dispatch.h"
9#include "../../third_party/inspector_protocol/crdtp/json.h"
10#include "include/v8-context.h"
12#include "src/base/logging.h"
13#include "src/base/macros.h"
16#include "src/inspector/protocol/Protocol.h"
29
30namespace v8_inspector {
31namespace {
32using v8_crdtp::span;
33using v8_crdtp::SpanFrom;
34using v8_crdtp::Status;
35using v8_crdtp::cbor::CheckCBORMessage;
36using v8_crdtp::json::ConvertCBORToJSON;
37using v8_crdtp::json::ConvertJSONToCBOR;
38
39bool IsCBORMessage(StringView msg) {
40 if (!msg.is8Bit() || msg.length() < 3) return false;
41 const uint8_t* bytes = msg.characters8();
42 return bytes[0] == 0xd8 &&
43 (bytes[1] == 0x5a || (bytes[1] == 0x18 && bytes[2] == 0x5a));
44}
45
46Status ConvertToCBOR(StringView state, std::vector<uint8_t>* cbor) {
47 return state.is8Bit()
48 ? ConvertJSONToCBOR(
49 span<uint8_t>(state.characters8(), state.length()), cbor)
50 : ConvertJSONToCBOR(
51 span<uint16_t>(state.characters16(), state.length()), cbor);
52}
53
54std::unique_ptr<protocol::DictionaryValue> ParseState(StringView state) {
55 std::vector<uint8_t> converted;
56 span<uint8_t> cbor;
57 if (IsCBORMessage(state))
58 cbor = span<uint8_t>(state.characters8(), state.length());
59 else if (ConvertToCBOR(state, &converted).ok())
60 cbor = SpanFrom(converted);
61 if (!cbor.empty()) {
62 std::unique_ptr<protocol::Value> value =
63 protocol::Value::parseBinary(cbor.data(), cbor.size());
64 std::unique_ptr<protocol::DictionaryValue> dictionaryValue =
65 protocol::DictionaryValue::cast(std::move(value));
66 if (dictionaryValue) return dictionaryValue;
67 }
68 return protocol::DictionaryValue::create();
69}
70} // namespace
71
72// static
75 protocol::Runtime::Metainfo::commandPrefix) ||
77 protocol::Debugger::Metainfo::commandPrefix) ||
79 protocol::Profiler::Metainfo::commandPrefix) ||
81 method, protocol::HeapProfiler::Metainfo::commandPrefix) ||
83 protocol::Console::Metainfo::commandPrefix) ||
85 protocol::Schema::Metainfo::commandPrefix);
86}
87
88// static
92
93std::unique_ptr<V8InspectorSessionImpl> V8InspectorSessionImpl::create(
94 V8InspectorImpl* inspector, int contextGroupId, int sessionId,
95 V8Inspector::Channel* channel, StringView state,
96 V8Inspector::ClientTrustLevel clientTrustLevel,
97 std::shared_ptr<V8DebuggerBarrier> debuggerBarrier) {
98 return std::unique_ptr<V8InspectorSessionImpl>(new V8InspectorSessionImpl(
100 std::move(debuggerBarrier)));
101}
102
104 V8InspectorImpl* inspector, int contextGroupId, int sessionId,
105 V8Inspector::Channel* channel, StringView savedState,
106 V8Inspector::ClientTrustLevel clientTrustLevel,
107 std::shared_ptr<V8DebuggerBarrier> debuggerBarrier)
108 : m_contextGroupId(contextGroupId),
109 m_sessionId(sessionId),
110 m_inspector(inspector),
111 m_channel(channel),
112 m_customObjectFormatterEnabled(false),
113 m_dispatcher(this),
114 m_state(ParseState(savedState)),
115 m_runtimeAgent(nullptr),
116 m_debuggerAgent(nullptr),
117 m_heapProfilerAgent(nullptr),
118 m_profilerAgent(nullptr),
119 m_consoleAgent(nullptr),
120 m_schemaAgent(nullptr),
121 m_clientTrustLevel(clientTrustLevel) {
122 m_state->getBoolean("use_binary_protocol", &use_binary_protocol_);
123
125 this, this, agentState(protocol::Runtime::Metainfo::domainName),
126 std::move(debuggerBarrier)));
127 protocol::Runtime::Dispatcher::wire(&m_dispatcher, m_runtimeAgent.get());
128
130 this, this, agentState(protocol::Debugger::Metainfo::domainName)));
131 protocol::Debugger::Dispatcher::wire(&m_dispatcher, m_debuggerAgent.get());
132
134 this, this, agentState(protocol::Console::Metainfo::domainName)));
135 protocol::Console::Dispatcher::wire(&m_dispatcher, m_consoleAgent.get());
136
138 this, this, agentState(protocol::Profiler::Metainfo::domainName)));
139 protocol::Profiler::Dispatcher::wire(&m_dispatcher, m_profilerAgent.get());
140
143 this, this, agentState(protocol::HeapProfiler::Metainfo::domainName)));
144 protocol::HeapProfiler::Dispatcher::wire(&m_dispatcher,
145 m_heapProfilerAgent.get());
146
148 this, this, agentState(protocol::Schema::Metainfo::domainName)));
149 protocol::Schema::Dispatcher::wire(&m_dispatcher, m_schemaAgent.get());
150 }
151 if (savedState.length()) {
152 m_runtimeAgent->restore();
153 m_debuggerAgent->restore();
155 m_profilerAgent->restore();
156 m_consoleAgent->restore();
157 }
158}
159
170
171protocol::DictionaryValue* V8InspectorSessionImpl::agentState(
172 const String16& name) {
173 protocol::DictionaryValue* state = m_state->getObject(name);
174 if (!state) {
175 std::unique_ptr<protocol::DictionaryValue> newState =
176 protocol::DictionaryValue::create();
177 state = newState.get();
178 m_state->setObject(name, std::move(newState));
179 }
180 return state;
181}
182
184 std::unique_ptr<protocol::Serializable> message) {
185 std::vector<uint8_t> cbor = message->Serialize();
186 DCHECK(CheckCBORMessage(SpanFrom(cbor)).ok());
187 if (use_binary_protocol_) return StringBufferFrom(std::move(cbor));
188 std::vector<uint8_t> json;
189 Status status = ConvertCBORToJSON(SpanFrom(cbor), &json);
190 DCHECK(status.ok());
191 USE(status);
192 // TODO(johannes): It should be OK to make a StringBuffer from |json|
193 // directly, since it's 7 Bit US-ASCII with anything else escaped.
194 // However it appears that the Node.js tests (or perhaps even production)
195 // assume that the StringBuffer is 16 Bit. It probably accesses
196 // characters16() somehwere without checking is8Bit. Until it's fixed
197 // we take a detour via String16 which makes the StringBuffer 16 bit.
198 String16 string16(reinterpret_cast<const char*>(json.data()), json.size());
199 return StringBufferFrom(std::move(string16));
200}
201
203 int callId, std::unique_ptr<protocol::Serializable> message) {
204 m_channel->sendResponse(callId, serializeForFrontend(std::move(message)));
205}
206
208 std::unique_ptr<protocol::Serializable> message) {
209 m_channel->sendNotification(serializeForFrontend(std::move(message)));
210}
211
213 const v8_crdtp::span<uint8_t> method,
214 v8_crdtp::span<uint8_t> message) {
215 // There's no other layer to handle the command.
216 UNREACHABLE();
217}
218
222
228
230 m_inspectedObjects.clear();
233 [&sessionId](InspectedContext* context) {
234 context->discardInjectedScript(sessionId);
235 });
236}
237
239 int contextId, InjectedScript*& injectedScript) {
240 injectedScript = nullptr;
241 InspectedContext* context =
243 if (!context)
244 return Response::ServerError("Cannot find context with specified id");
245 injectedScript = context->getInjectedScript(m_sessionId);
246 if (!injectedScript) {
247 injectedScript = context->createInjectedScript(m_sessionId);
249 injectedScript->setCustomObjectFormatterEnabled(true);
250 }
251 return Response::Success();
252}
253
255 RemoteObjectIdBase* objectId, InjectedScript*& injectedScript) {
256 if (objectId->isolateId() != m_inspector->isolateId())
257 return Response::ServerError("Cannot find context with specified id");
258 return findInjectedScript(objectId->contextId(), injectedScript);
259}
260
264
268 m_contextGroupId, [&objectGroup, &sessionId](InspectedContext* context) {
269 InjectedScript* injectedScript = context->getInjectedScript(sessionId);
270 if (injectedScript) injectedScript->releaseObjectGroup(objectGroup);
271 });
272}
273
275 std::unique_ptr<StringBuffer>* error, StringView objectId,
277 std::unique_ptr<StringBuffer>* objectGroup) {
278 String16 objectGroupString;
279 Response response = unwrapObject(toString16(objectId), object, context,
280 objectGroup ? &objectGroupString : nullptr);
281 if (response.IsError()) {
282 if (error) {
283 const std::string& msg = response.Message();
284 *error = StringBufferFrom(String16::fromUTF8(msg.data(), msg.size()));
285 }
286 return false;
287 }
288 if (objectGroup)
289 *objectGroup = StringBufferFrom(std::move(objectGroupString));
290 return true;
291}
292
294 v8::Local<v8::Value>* object,
295 v8::Local<v8::Context>* context,
296 String16* objectGroup) {
297 std::unique_ptr<RemoteObjectId> remoteId;
298 Response response = RemoteObjectId::parse(objectId, &remoteId);
299 if (!response.IsSuccess()) return response;
300 InjectedScript* injectedScript = nullptr;
301 response = findInjectedScript(remoteId.get(), injectedScript);
302 if (!response.IsSuccess()) return response;
303 response = injectedScript->findObject(*remoteId, object);
304 if (!response.IsSuccess()) return response;
305 *context = injectedScript->context()->context();
306 if (objectGroup) *objectGroup = injectedScript->objectGroupName(*remoteId);
307 return Response::Success();
308}
309
310std::unique_ptr<protocol::Runtime::API::RemoteObject>
313 StringView groupName, bool generatePreview) {
314 return wrapObject(context, value, toString16(groupName), generatePreview);
315}
316
317std::unique_ptr<protocol::Runtime::RemoteObject>
320 const String16& groupName,
321 bool generatePreview) {
322 InjectedScript* injectedScript = nullptr;
323 findInjectedScript(InspectedContext::contextId(context), injectedScript);
324 if (!injectedScript) return nullptr;
325 std::unique_ptr<protocol::Runtime::RemoteObject> result;
326 injectedScript->wrapObject(value, groupName,
327 generatePreview ? WrapOptions({WrapMode::kPreview})
329 &result);
330 return result;
331}
332
333std::unique_ptr<protocol::Runtime::RemoteObject>
337 InjectedScript* injectedScript = nullptr;
338 findInjectedScript(InspectedContext::contextId(context), injectedScript);
339 if (!injectedScript) return nullptr;
340 return injectedScript->wrapTable(table, columns);
341}
342
347 m_contextGroupId, [&enabled, &sessionId](InspectedContext* context) {
348 InjectedScript* injectedScript = context->getInjectedScript(sessionId);
349 if (injectedScript)
350 injectedScript->setCustomObjectFormatterEnabled(enabled);
351 });
352}
353
360
362 using v8_crdtp::span;
363 using v8_crdtp::SpanFrom;
364 span<uint8_t> cbor;
365 std::vector<uint8_t> converted_cbor;
366 if (IsCBORMessage(message)) {
368 m_state->setBoolean("use_binary_protocol", true);
369 cbor = span<uint8_t>(message.characters8(), message.length());
370 } else {
371 // We're ignoring the return value of the conversion function
372 // intentionally. It means the |parsed_message| below will be nullptr.
373 auto status = ConvertToCBOR(message, &converted_cbor);
374 if (!status.ok()) {
376 serializeForFrontend(v8_crdtp::CreateErrorNotification(
377 v8_crdtp::DispatchResponse::ParseError(status.ToASCIIString()))));
378 return;
379 }
380 cbor = SpanFrom(converted_cbor);
381 }
382 v8_crdtp::Dispatchable dispatchable(cbor);
383 if (!dispatchable.ok()) {
384 if (!dispatchable.HasCallId()) {
386 v8_crdtp::CreateErrorNotification(dispatchable.DispatchError())));
387 } else {
389 dispatchable.CallId(),
390 serializeForFrontend(v8_crdtp::CreateErrorResponse(
391 dispatchable.CallId(), dispatchable.DispatchError())));
392 }
393 return;
394 }
395 m_dispatcher.Dispatch(dispatchable).Run();
396}
397
398std::vector<uint8_t> V8InspectorSessionImpl::state() {
399 return m_state->Serialize();
400}
401
402std::vector<std::unique_ptr<protocol::Schema::API::Domain>>
404 std::vector<std::unique_ptr<protocol::Schema::Domain>> domains =
406 std::vector<std::unique_ptr<protocol::Schema::API::Domain>> result;
407 for (size_t i = 0; i < domains.size(); ++i)
408 result.push_back(std::move(domains[i]));
409 return result;
410}
411
412std::vector<std::unique_ptr<protocol::Schema::Domain>>
414 std::vector<std::unique_ptr<protocol::Schema::Domain>> result;
415 result.push_back(protocol::Schema::Domain::create()
416 .setName(protocol::Runtime::Metainfo::domainName)
417 .setVersion(protocol::Runtime::Metainfo::version)
418 .build());
419 result.push_back(protocol::Schema::Domain::create()
420 .setName(protocol::Debugger::Metainfo::domainName)
421 .setVersion(protocol::Debugger::Metainfo::version)
422 .build());
423 result.push_back(protocol::Schema::Domain::create()
424 .setName(protocol::Profiler::Metainfo::domainName)
425 .setVersion(protocol::Profiler::Metainfo::version)
426 .build());
427 result.push_back(protocol::Schema::Domain::create()
428 .setName(protocol::HeapProfiler::Metainfo::domainName)
429 .setVersion(protocol::HeapProfiler::Metainfo::version)
430 .build());
431 result.push_back(protocol::Schema::Domain::create()
432 .setName(protocol::Schema::Metainfo::domainName)
433 .setVersion(protocol::Schema::Metainfo::version)
434 .build());
435 return result;
436}
437
439 std::unique_ptr<V8InspectorSession::Inspectable> inspectable) {
440 m_inspectedObjects.insert(m_inspectedObjects.begin(), std::move(inspectable));
443}
444
446 unsigned num) {
447 if (num >= m_inspectedObjects.size()) return nullptr;
448 return m_inspectedObjects[num].get();
449}
450
452 StringView breakReason, StringView breakDetails) {
453 std::vector<uint8_t> cbor;
454 ConvertToCBOR(breakDetails, &cbor);
455 m_debuggerAgent->schedulePauseOnNextStatement(
456 toString16(breakReason),
457 protocol::DictionaryValue::cast(
458 protocol::Value::parseBinary(cbor.data(), cbor.size())));
459}
460
462 m_debuggerAgent->cancelPauseOnNextStatement();
463}
464
466 StringView breakDetails) {
467 std::vector<uint8_t> cbor;
468 ConvertToCBOR(breakDetails, &cbor);
469 m_debuggerAgent->breakProgram(
470 toString16(breakReason),
471 protocol::DictionaryValue::cast(
472 protocol::Value::parseBinary(cbor.data(), cbor.size())));
473}
474
476 m_debuggerAgent->setSkipAllPauses(skip);
477}
478
479void V8InspectorSessionImpl::resume(bool terminateOnResume) {
480 m_debuggerAgent->resume(terminateOnResume);
481}
482
484
485std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>>
487 bool caseSensitive, bool isRegex) {
488 // TODO(dgozman): search may operate on StringView and avoid copying |text|.
489 std::vector<std::unique_ptr<protocol::Debugger::SearchMatch>> matches =
491 caseSensitive, isRegex);
492 std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> result;
493 for (size_t i = 0; i < matches.size(); ++i)
494 result.push_back(std::move(matches[i]));
495 return result;
496}
497
499 StringView occasion) {
500 m_profilerAgent->triggerPreciseCoverageDeltaUpdate(toString16(occasion));
501}
502
504 v8::Local<v8::Context> context, StringView expression,
505 bool includeCommandLineAPI) {
509 if (!scope.initialize().IsSuccess()) {
510 return {EvaluateResult::ResultType::kNotRun, v8::Local<v8::Value>()};
511 }
512
513 // Temporarily allow eval.
515 scope.setTryCatchVerbose();
516 if (includeCommandLineAPI) {
517 scope.installCommandLineAPI();
518 }
519 v8::MaybeLocal<v8::Value> maybeResultValue;
520 {
521 v8::MicrotasksScope microtasksScope(scope.context(),
523 const v8::Local<v8::String> source =
524 toV8String(m_inspector->isolate(), expression);
525 maybeResultValue = v8::debug::EvaluateGlobal(
527 /*repl_mode=*/false);
528 }
529
530 if (scope.tryCatch().HasCaught()) {
531 return {EvaluateResult::ResultType::kException,
532 handleScope.Escape(scope.tryCatch().Exception())};
533 }
535 CHECK(maybeResultValue.ToLocal(&result));
536 return {EvaluateResult::ResultType::kSuccess, handleScope.Escape(result)};
537}
538
540
541} // namespace v8_inspector
V8_INLINE Local< T > Escape(Local< T > value)
V8_WARN_UNUSED_RESULT V8_INLINE bool ToLocal(Local< S > *out) const
v8::Local< v8::Context > context() const
const v8::TryCatch & tryCatch() const
Response wrapObject(v8::Local< v8::Value >, const String16 &groupName, const WrapOptions &wrapOptions, std::unique_ptr< protocol::Runtime::RemoteObject > *result)
void releaseObjectGroup(const String16 &)
InspectedContext * context() const
Response findObject(const RemoteObjectId &, v8::Local< v8::Value > *) const
std::unique_ptr< protocol::Runtime::RemoteObject > wrapTable(v8::Local< v8::Object > table, v8::MaybeLocal< v8::Array > columns)
String16 objectGroupName(const RemoteObjectId &) const
v8::Local< v8::Context > context() const
static Response parse(const String16 &, std::unique_ptr< RemoteObjectId > *)
static V8_EXPORT String16 fromUTF8(const char *stringStart, size_t length)
Definition string-16.cc:229
static int executionContextId(v8::Local< v8::Context > context)
void disconnect(V8InspectorSessionImpl *)
v8::Isolate * isolate() const
InspectedContext * getContext(int groupId, int contextId) const
void forEachContext(int contextGroupId, const std::function< void(InspectedContext *)> &callback)
protocol::DictionaryValue * agentState(const String16 &name)
V8Inspector::ClientTrustLevel clientTrustLevel()
std::vector< std::unique_ptr< protocol::Schema::Domain > > supportedDomainsImpl()
std::unique_ptr< V8ConsoleAgentImpl > m_consoleAgent
V8InspectorSession::Inspectable * inspectedObject(unsigned num)
Response findInjectedScript(int contextId, InjectedScript *&)
std::unique_ptr< protocol::DictionaryValue > m_state
std::unique_ptr< V8DebuggerAgentImpl > m_debuggerAgent
std::vector< std::unique_ptr< protocol::Schema::API::Domain > > supportedDomains() override
void addInspectedObject(std::unique_ptr< V8InspectorSession::Inspectable >) override
std::vector< std::unique_ptr< V8InspectorSession::Inspectable > > m_inspectedObjects
void schedulePauseOnNextStatement(StringView breakReason, StringView breakDetails) override
std::unique_ptr< StringBuffer > serializeForFrontend(std::unique_ptr< protocol::Serializable > message)
void FallThrough(int callId, v8_crdtp::span< uint8_t > method, v8_crdtp::span< uint8_t > message) override
void resume(bool terminateOnResume=false) override
std::unique_ptr< protocol::Runtime::RemoteObject > wrapObject(v8::Local< v8::Context >, v8::Local< v8::Value >, const String16 &groupName, bool generatePreview)
V8Inspector::ClientTrustLevel m_clientTrustLevel
std::vector< std::unique_ptr< protocol::Debugger::API::SearchMatch > > searchInTextByLines(StringView text, StringView query, bool caseSensitive, bool isRegex) override
void releaseObjectGroup(const String16 &objectGroup)
void SendProtocolResponse(int callId, std::unique_ptr< protocol::Serializable > message) override
void SendProtocolNotification(std::unique_ptr< protocol::Serializable > message) override
std::unique_ptr< V8ProfilerAgentImpl > m_profilerAgent
void breakProgram(StringView breakReason, StringView breakDetails) override
static std::unique_ptr< V8InspectorSessionImpl > create(V8InspectorImpl *, int contextGroupId, int sessionId, V8Inspector::Channel *, StringView state, v8_inspector::V8Inspector::ClientTrustLevel, std::shared_ptr< V8DebuggerBarrier >)
std::unique_ptr< V8HeapProfilerAgentImpl > m_heapProfilerAgent
std::vector< uint8_t > state() override
std::unique_ptr< V8SchemaAgentImpl > m_schemaAgent
std::unique_ptr< protocol::Runtime::RemoteObject > wrapTable(v8::Local< v8::Context >, v8::Local< v8::Object > table, v8::MaybeLocal< v8::Array > columns)
void dispatchProtocolMessage(StringView message) override
Response unwrapObject(const String16 &objectId, v8::Local< v8::Value > *, v8::Local< v8::Context > *, String16 *objectGroup)
void triggerPreciseCoverageDeltaUpdate(StringView occasion) override
std::unique_ptr< V8RuntimeAgentImpl > m_runtimeAgent
V8InspectorSessionImpl(const V8InspectorSessionImpl &)=delete
EvaluateResult evaluate(v8::Local< v8::Context > context, StringView expression, bool includeCommandLineAPI=false) override
virtual v8::Local< v8::Value > get(v8::Local< v8::Context >)=0
static bool canDispatchMethod(StringView method)
virtual void sendNotification(std::unique_ptr< StringBuffer > message)=0
virtual void flushProtocolNotifications()=0
virtual void sendResponse(int callId, std::unique_ptr< StringBuffer > message)=0
void reportExecutionContextCreated(InspectedContext *)
ZoneVector< RpoNumber > & result
unsigned short uint16_t
Definition unicode.cc:39
MaybeLocal< v8::Value > EvaluateGlobal(v8::Isolate *isolate, v8::Local< v8::String > source, EvaluateGlobalMode mode, bool repl)
bool stringViewStartsWith(const StringView &string, const char *prefix)
std::unique_ptr< StringBuffer > StringBufferFrom(String16 str)
v8::Local< v8::String > toV8String(v8::Isolate *isolate, const String16 &string)
std::vector< std::unique_ptr< protocol::Debugger::SearchMatch > > searchInTextByLinesImpl(V8InspectorSession *session, const String16 &text, const String16 &query, const bool caseSensitive, const bool isRegex)
String16 toString16(const StringView &string)
#define UNREACHABLE()
Definition logging.h:67
#define CHECK(condition)
Definition logging.h:124
#define DCHECK(condition)
Definition logging.h:482
#define USE(...)
Definition macros.h:293
Symbol method
V8InspectorImpl * m_inspector