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