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