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#ifndef V8_V8_INSPECTOR_H_ 6#define V8_V8_INSPECTOR_H_ 7 8#include <stdint.h> 9 10#include <cctype> 11#include <memory> 12 13#include "v8-isolate.h" // NOLINT(build/include_directory) 14#include "v8-local-handle.h" // NOLINT(build/include_directory) 15 16namespace v8 { 17class Context; 18class Name; 19class Object; 20class StackTrace; 21class Value; 22} // namespace v8 23 24namespace v8_inspector { 25 26namespace internal { 27class V8DebuggerId; 28} // namespace internal 29 30namespace protocol { 31namespace Debugger { 32namespace API { 33class SearchMatch; 34} 35} // namespace Debugger 36namespace Runtime { 37namespace API { 38class RemoteObject; 39class StackTrace; 40class StackTraceId; 41} // namespace API 42} // namespace Runtime 43namespace Schema { 44namespace API { 45class Domain; 46} 47} // namespace Schema 48} // namespace protocol 49 50class V8_EXPORT StringView { 51 public: 52 StringView() : m_is8Bit(true), m_length(0), m_characters8(nullptr) {} 53 54 StringView(const uint8_t* characters, size_t length) 55 : m_is8Bit(true), m_length(length), m_characters8(characters) {} 56 57 StringView(const uint16_t* characters, size_t length) 58 : m_is8Bit(false), m_length(length), m_characters16(characters) {} 59 60 bool is8Bit() const { return m_is8Bit; } 61 size_t length() const { return m_length; } 62 63 // TODO(dgozman): add DCHECK(m_is8Bit) to accessors once platform can be used 64 // here. 65 const uint8_t* characters8() const { return m_characters8; } 66 const uint16_t* characters16() const { return m_characters16; } 67 68 private: 69 bool m_is8Bit; 70 size_t m_length; 71 union { 72 const uint8_t* m_characters8; 73 const uint16_t* m_characters16; 74 }; 75}; 76 77class V8_EXPORT StringBuffer { 78 public: 79 virtual ~StringBuffer() = default; 80 virtual StringView string() const = 0; 81 // This method copies contents. 82 static std::unique_ptr<StringBuffer> create(StringView); 83}; 84 85class V8_EXPORT V8ContextInfo { 86 public: 87 V8ContextInfo(v8::Local<v8::Context> context, int contextGroupId, 88 StringView humanReadableName) 89 : context(context), 90 contextGroupId(contextGroupId), 91 humanReadableName(humanReadableName), 92 hasMemoryOnConsole(false) {} 93 94 v8::Local<v8::Context> context; 95 // Each v8::Context is a part of a group. The group id must be non-zero. 96 int contextGroupId; 97 StringView humanReadableName; 98 StringView origin; 99 StringView auxData; 100 bool hasMemoryOnConsole; 101 102 static int executionContextId(v8::Local<v8::Context> context); 103 104 // Disallow copying and allocating this one. 105 enum NotNullTagEnum { NotNullLiteral }; 106 void* operator new(size_t) = delete; 107 void* operator new(size_t, NotNullTagEnum, void*) = delete; 108 void* operator new(size_t, void*) = delete; 109 V8ContextInfo(const V8ContextInfo&) = delete; 110 V8ContextInfo& operator=(const V8ContextInfo&) = delete; 111}; 112 113// This debugger id tries to be unique by generating two random 114// numbers, which should most likely avoid collisions. 115// Debugger id has a 1:1 mapping to context group. It is used to 116// attribute stack traces to a particular debugging, when doing any 117// cross-debugger operations (e.g. async step in). 118// See also Runtime.UniqueDebuggerId in the protocol. 119class V8_EXPORT V8DebuggerId { 120 public: 121 V8DebuggerId() = default; 122 V8DebuggerId(const V8DebuggerId&) = default; 123 V8DebuggerId& operator=(const V8DebuggerId&) = default; 124 125 std::unique_ptr<StringBuffer> toString() const; 126 bool isValid() const; 127 std::pair<int64_t, int64_t> pair() const; 128 129 private: 130 friend class internal::V8DebuggerId; 131 explicit V8DebuggerId(std::pair<int64_t, int64_t>); 132 133 int64_t m_first = 0; 134 int64_t m_second = 0; 135}; 136 137struct V8_EXPORT V8StackFrame { 138 StringView sourceURL; 139 StringView functionName; 140 int lineNumber; 141 int columnNumber; 142}; 143 144class V8_EXPORT V8StackTrace { 145 public: 146 virtual StringView firstNonEmptySourceURL() const = 0; 147 virtual bool isEmpty() const = 0; 148 virtual StringView topSourceURL() const = 0; 149 virtual int topLineNumber() const = 0; 150 virtual int topColumnNumber() const = 0; 151 virtual int topScriptId() const = 0; 152 virtual StringView topFunctionName() const = 0; 153 154 virtual ~V8StackTrace() = default; 155 virtual std::unique_ptr<protocol::Runtime::API::StackTrace> 156 buildInspectorObject(int maxAsyncDepth) const = 0; 157 virtual std::unique_ptr<StringBuffer> toString() const = 0; 158 159 // Safe to pass between threads, drops async chain. 160 virtual std::unique_ptr<V8StackTrace> clone() = 0; 161 162 virtual std::vector<V8StackFrame> frames() const = 0; 163}; 164 165class V8_EXPORT V8InspectorSession { 166 public: 167 virtual ~V8InspectorSession() = default; 168 169 // Cross-context inspectable values (DOM nodes in different worlds, etc.). 170 class V8_EXPORT Inspectable { 171 public: 172 virtual v8::Local<v8::Value> get(v8::Local<v8::Context>) = 0; 173 virtual ~Inspectable() = default; 174 }; 175 class V8_EXPORT CommandLineAPIScope { 176 public: 177 virtual ~CommandLineAPIScope() = default; 178 }; 179 virtual void addInspectedObject(std::unique_ptr<Inspectable>) = 0; 180 181 // Dispatching protocol messages. 182 static bool canDispatchMethod(StringView method); 183 virtual void dispatchProtocolMessage(StringView message) = 0; 184 virtual std::vector<uint8_t> state() = 0; 185 virtual std::vector<std::unique_ptr<protocol::Schema::API::Domain>> 186 supportedDomains() = 0; 187 188 virtual std::unique_ptr<V8InspectorSession::CommandLineAPIScope> 189 initializeCommandLineAPIScope(int executionContextId) = 0; 190 191 // Debugger actions. 192 virtual void schedulePauseOnNextStatement(StringView breakReason, 193 StringView breakDetails) = 0; 194 virtual void cancelPauseOnNextStatement() = 0; 195 virtual void breakProgram(StringView breakReason, 196 StringView breakDetails) = 0; 197 virtual void setSkipAllPauses(bool) = 0; 198 virtual void resume(bool setTerminateOnResume = false) = 0; 199 virtual void stepOver() = 0; 200 virtual std::vector<std::unique_ptr<protocol::Debugger::API::SearchMatch>> 201 searchInTextByLines(StringView text, StringView query, bool caseSensitive, 202 bool isRegex) = 0; 203 204 // Remote objects. 205 virtual std::unique_ptr<protocol::Runtime::API::RemoteObject> wrapObject( 206 v8::Local<v8::Context>, v8::Local<v8::Value>, StringView groupName, 207 bool generatePreview) = 0; 208 209 virtual bool unwrapObject(std::unique_ptr<StringBuffer>* error, 210 StringView objectId, v8::Local<v8::Value>*, 211 v8::Local<v8::Context>*, 212 std::unique_ptr<StringBuffer>* objectGroup) = 0; 213 virtual void releaseObjectGroup(StringView) = 0; 214 virtual void triggerPreciseCoverageDeltaUpdate(StringView occasion) = 0; 215 216 // Prepare for shutdown (disables debugger pausing, etc.). 217 virtual void stop() = 0; 218}; 219 220class V8_EXPORT WebDriverValue { 221 public: 222 explicit WebDriverValue(std::unique_ptr<StringBuffer> type, 223 v8::MaybeLocal<v8::Value> value = {}) 224 : type(std::move(type)), value(value) {} 225 std::unique_ptr<StringBuffer> type; 226 v8::MaybeLocal<v8::Value> value; 227}; 228 229class V8_EXPORT V8InspectorClient { 230 public: 231 virtual ~V8InspectorClient() = default; 232 233 virtual void runMessageLoopOnPause(int contextGroupId) {} 234 virtual void runMessageLoopOnInstrumentationPause(int contextGroupId) { 235 runMessageLoopOnPause(contextGroupId); 236 } 237 virtual void quitMessageLoopOnPause() {} 238 virtual void runIfWaitingForDebugger(int contextGroupId) {} 239 240 virtual void muteMetrics(int contextGroupId) {} 241 virtual void unmuteMetrics(int contextGroupId) {} 242 243 virtual void beginUserGesture() {} 244 virtual void endUserGesture() {} 245 246 virtual std::unique_ptr<WebDriverValue> serializeToWebDriverValue( 247 v8::Local<v8::Value> v8_value, int max_depth) { 248 return nullptr; 249 } 250 virtual std::unique_ptr<StringBuffer> valueSubtype(v8::Local<v8::Value>) { 251 return nullptr; 252 } 253 virtual std::unique_ptr<StringBuffer> descriptionForValueSubtype( 254 v8::Local<v8::Context>, v8::Local<v8::Value>) { 255 return nullptr; 256 } 257 virtual bool isInspectableHeapObject(v8::Local<v8::Object>) { return true; } 258 259 virtual v8::Local<v8::Context> ensureDefaultContextInGroup( 260 int contextGroupId) { 261 return v8::Local<v8::Context>(); 262 } 263 virtual void beginEnsureAllContextsInGroup(int contextGroupId) {} 264 virtual void endEnsureAllContextsInGroup(int contextGroupId) {} 265 266 virtual void installAdditionalCommandLineAPI(v8::Local<v8::Context>, 267 v8::Local<v8::Object>) {} 268 virtual void consoleAPIMessage(int contextGroupId, 269 v8::Isolate::MessageErrorLevel level, 270 const StringView& message, 271 const StringView& url, unsigned lineNumber, 272 unsigned columnNumber, V8StackTrace*) {} 273 virtual v8::MaybeLocal<v8::Value> memoryInfo(v8::Isolate*, 274 v8::Local<v8::Context>) { 275 return v8::MaybeLocal<v8::Value>(); 276 } 277 278 virtual void consoleTime(const StringView& title) {} 279 virtual void consoleTimeEnd(const StringView& title) {} 280 virtual void consoleTimeStamp(const StringView& title) {} 281 virtual void consoleClear(int contextGroupId) {} 282 virtual double currentTimeMS() { return 0; } 283 typedef void (*TimerCallback)(void*); 284 virtual void startRepeatingTimer(double, TimerCallback, void* data) {} 285 virtual void cancelTimer(void* data) {} 286 287 // TODO(dgozman): this was added to support service worker shadow page. We 288 // should not connect at all. 289 virtual bool canExecuteScripts(int contextGroupId) { return true; } 290 291 virtual void maxAsyncCallStackDepthChanged(int depth) {} 292 293 virtual std::unique_ptr<StringBuffer> resourceNameToUrl( 294 const StringView& resourceName) { 295 return nullptr; 296 } 297 298 // The caller would defer to generating a random 64 bit integer if 299 // this method returns 0. 300 virtual int64_t generateUniqueId() { return 0; } 301 302 virtual void dispatchError(v8::Local<v8::Context>, v8::Local<v8::Message>, 303 v8::Local<v8::Value>) {} 304}; 305 306// These stack trace ids are intended to be passed between debuggers and be 307// resolved later. This allows to track cross-debugger calls and step between 308// them if a single client connects to multiple debuggers. 309struct V8_EXPORT V8StackTraceId { 310 uintptr_t id; 311 std::pair<int64_t, int64_t> debugger_id; 312 bool should_pause = false; 313 314 V8StackTraceId(); 315 V8StackTraceId(const V8StackTraceId&) = default; 316 V8StackTraceId(uintptr_t id, const std::pair<int64_t, int64_t> debugger_id); 317 V8StackTraceId(uintptr_t id, const std::pair<int64_t, int64_t> debugger_id, 318 bool should_pause); 319 explicit V8StackTraceId(StringView); 320 V8StackTraceId& operator=(const V8StackTraceId&) = default; 321 V8StackTraceId& operator=(V8StackTraceId&&) noexcept = default; 322 ~V8StackTraceId() = default; 323 324 bool IsInvalid() const; 325 std::unique_ptr<StringBuffer> ToString(); 326}; 327 328class V8_EXPORT V8Inspector { 329 public: 330 static std::unique_ptr<V8Inspector> create(v8::Isolate*, V8InspectorClient*); 331 virtual ~V8Inspector() = default; 332 333 // Contexts instrumentation. 334 virtual void contextCreated(const V8ContextInfo&) = 0; 335 virtual void contextDestroyed(v8::Local<v8::Context>) = 0; 336 virtual void resetContextGroup(int contextGroupId) = 0; 337 virtual v8::MaybeLocal<v8::Context> contextById(int contextId) = 0; 338 virtual V8DebuggerId uniqueDebuggerId(int contextId) = 0; 339 340 // Various instrumentation. 341 virtual void idleStarted() = 0; 342 virtual void idleFinished() = 0; 343 344 // Async stack traces instrumentation. 345 virtual void asyncTaskScheduled(StringView taskName, void* task, 346 bool recurring) = 0; 347 virtual void asyncTaskCanceled(void* task) = 0; 348 virtual void asyncTaskStarted(void* task) = 0; 349 virtual void asyncTaskFinished(void* task) = 0; 350 virtual void allAsyncTasksCanceled() = 0; 351 352 virtual V8StackTraceId storeCurrentStackTrace(StringView description) = 0; 353 virtual void externalAsyncTaskStarted(const V8StackTraceId& parent) = 0; 354 virtual void externalAsyncTaskFinished(const V8StackTraceId& parent) = 0; 355 356 // Exceptions instrumentation. 357 virtual unsigned exceptionThrown(v8::Local<v8::Context>, StringView message, 358 v8::Local<v8::Value> exception, 359 StringView detailedMessage, StringView url, 360 unsigned lineNumber, unsigned columnNumber, 361 std::unique_ptr<V8StackTrace>, 362 int scriptId) = 0; 363 virtual void exceptionRevoked(v8::Local<v8::Context>, unsigned exceptionId, 364 StringView message) = 0; 365 virtual bool associateExceptionData(v8::Local<v8::Context>, 366 v8::Local<v8::Value> exception, 367 v8::Local<v8::Name> key, 368 v8::Local<v8::Value> value) = 0; 369 370 // Connection. 371 class V8_EXPORT Channel { 372 public: 373 virtual ~Channel() = default; 374 virtual void sendResponse(int callId, 375 std::unique_ptr<StringBuffer> message) = 0; 376 virtual void sendNotification(std::unique_ptr<StringBuffer> message) = 0; 377 virtual void flushProtocolNotifications() = 0; 378 }; 379 enum ClientTrustLevel { kUntrusted, kFullyTrusted }; 380 enum SessionPauseState { kWaitingForDebugger, kNotWaitingForDebugger }; 381 // TODO(chromium:1352175): remove default value once downstream change lands. 382 virtual std::unique_ptr<V8InspectorSession> connect( 383 int contextGroupId, Channel*, StringView state, 384 ClientTrustLevel client_trust_level, 385 SessionPauseState = kNotWaitingForDebugger) { 386 return nullptr; 387 } 388 389 // API methods. 390 virtual std::unique_ptr<V8StackTrace> createStackTrace( 391 v8::Local<v8::StackTrace>) = 0; 392 virtual std::unique_ptr<V8StackTrace> captureStackTrace(bool fullStack) = 0; 393}; 394 395} // namespace v8_inspector 396 397#endif // V8_V8_INSPECTOR_H_ 398