1 // Copyright 2015 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_INSPECTOR_V8_DEBUGGER_AGENT_IMPL_H_
6 #define V8_INSPECTOR_V8_DEBUGGER_AGENT_IMPL_H_
7 
8 #include <deque>
9 #include <memory>
10 #include <unordered_map>
11 #include <vector>
12 
13 #include "src/base/enum-set.h"
14 #include "src/base/macros.h"
15 #include "src/debug/debug-interface.h"
16 #include "src/inspector/protocol/Debugger.h"
17 #include "src/inspector/protocol/Forward.h"
18 
19 namespace v8_inspector {
20 
21 struct ScriptBreakpoint;
22 class V8Debugger;
23 class V8DebuggerScript;
24 class V8InspectorImpl;
25 class V8InspectorSessionImpl;
26 class V8Regex;
27 
28 using protocol::Maybe;
29 using protocol::Response;
30 
31 class V8DebuggerAgentImpl : public protocol::Debugger::Backend {
32  public:
33   enum BreakpointSource {
34     UserBreakpointSource,
35     DebugCommandBreakpointSource,
36     MonitorCommandBreakpointSource
37   };
38 
39   V8DebuggerAgentImpl(V8InspectorSessionImpl*, protocol::FrontendChannel*,
40                       protocol::DictionaryValue* state);
41   ~V8DebuggerAgentImpl() override;
42   V8DebuggerAgentImpl(const V8DebuggerAgentImpl&) = delete;
43   V8DebuggerAgentImpl& operator=(const V8DebuggerAgentImpl&) = delete;
44   void restore();
45 
46   // Part of the protocol.
47   Response enable(Maybe<double> maxScriptsCacheSize,
48                   String16* outDebuggerId) override;
49   Response disable() override;
50   Response setBreakpointsActive(bool active) override;
51   Response setSkipAllPauses(bool skip) override;
52   Response setBreakpointByUrl(
53       int lineNumber, Maybe<String16> optionalURL,
54       Maybe<String16> optionalURLRegex, Maybe<String16> optionalScriptHash,
55       Maybe<int> optionalColumnNumber, Maybe<String16> optionalCondition,
56       String16*,
57       std::unique_ptr<protocol::Array<protocol::Debugger::Location>>* locations)
58       override;
59   Response setBreakpoint(
60       std::unique_ptr<protocol::Debugger::Location>,
61       Maybe<String16> optionalCondition, String16*,
62       std::unique_ptr<protocol::Debugger::Location>* actualLocation) override;
63   Response setBreakpointOnFunctionCall(const String16& functionObjectId,
64                                        Maybe<String16> optionalCondition,
65                                        String16* outBreakpointId) override;
66   Response setInstrumentationBreakpoint(const String16& instrumentation,
67                                         String16* outBreakpointId) override;
68   Response removeBreakpoint(const String16& breakpointId) override;
69   Response continueToLocation(std::unique_ptr<protocol::Debugger::Location>,
70                               Maybe<String16> targetCallFrames) override;
71   Response getStackTrace(
72       std::unique_ptr<protocol::Runtime::StackTraceId> inStackTraceId,
73       std::unique_ptr<protocol::Runtime::StackTrace>* outStackTrace) override;
74   Response searchInContent(
75       const String16& scriptId, const String16& query,
76       Maybe<bool> optionalCaseSensitive, Maybe<bool> optionalIsRegex,
77       std::unique_ptr<protocol::Array<protocol::Debugger::SearchMatch>>*)
78       override;
79   Response getPossibleBreakpoints(
80       std::unique_ptr<protocol::Debugger::Location> start,
81       Maybe<protocol::Debugger::Location> end, Maybe<bool> restrictToFunction,
82       std::unique_ptr<protocol::Array<protocol::Debugger::BreakLocation>>*
83           locations) override;
84   Response setScriptSource(
85       const String16& inScriptId, const String16& inScriptSource,
86       Maybe<bool> dryRun,
87       Maybe<protocol::Array<protocol::Debugger::CallFrame>>* optOutCallFrames,
88       Maybe<bool>* optOutStackChanged,
89       Maybe<protocol::Runtime::StackTrace>* optOutAsyncStackTrace,
90       Maybe<protocol::Runtime::StackTraceId>* optOutAsyncStackTraceId,
91       Maybe<protocol::Runtime::ExceptionDetails>* optOutCompileError) override;
92   Response restartFrame(
93       const String16& callFrameId,
94       std::unique_ptr<protocol::Array<protocol::Debugger::CallFrame>>*
95           newCallFrames,
96       Maybe<protocol::Runtime::StackTrace>* asyncStackTrace,
97       Maybe<protocol::Runtime::StackTraceId>* asyncStackTraceId) override;
98   Response getScriptSource(const String16& scriptId, String16* scriptSource,
99                            Maybe<protocol::Binary>* bytecode) override;
100   Response getWasmBytecode(const String16& scriptId,
101                            protocol::Binary* bytecode) override;
102   Response pause() override;
103   Response resume(Maybe<bool> terminateOnResume) override;
104   Response stepOver(Maybe<protocol::Array<protocol::Debugger::LocationRange>>
105                         inSkipList) override;
106   Response stepInto(Maybe<bool> inBreakOnAsyncCall,
107                     Maybe<protocol::Array<protocol::Debugger::LocationRange>>
108                         inSkipList) override;
109   Response stepOut() override;
110   Response pauseOnAsyncCall(std::unique_ptr<protocol::Runtime::StackTraceId>
111                                 inParentStackTraceId) override;
112   Response setPauseOnExceptions(const String16& pauseState) override;
113   Response evaluateOnCallFrame(
114       const String16& callFrameId, const String16& expression,
115       Maybe<String16> objectGroup, Maybe<bool> includeCommandLineAPI,
116       Maybe<bool> silent, Maybe<bool> returnByValue,
117       Maybe<bool> generatePreview, Maybe<bool> throwOnSideEffect,
118       Maybe<double> timeout,
119       std::unique_ptr<protocol::Runtime::RemoteObject>* result,
120       Maybe<protocol::Runtime::ExceptionDetails>*) override;
121   Response setVariableValue(
122       int scopeNumber, const String16& variableName,
123       std::unique_ptr<protocol::Runtime::CallArgument> newValue,
124       const String16& callFrame) override;
125   Response setReturnValue(
126       std::unique_ptr<protocol::Runtime::CallArgument> newValue) override;
127   Response setAsyncCallStackDepth(int depth) override;
128   Response setBlackboxPatterns(
129       std::unique_ptr<protocol::Array<String16>> patterns) override;
130   Response setBlackboxedRanges(
131       const String16& scriptId,
132       std::unique_ptr<protocol::Array<protocol::Debugger::ScriptPosition>>
133           positions) override;
134 
enabled() const135   bool enabled() const { return m_enabled; }
136 
137   void setBreakpointFor(v8::Local<v8::Function> function,
138                         v8::Local<v8::String> condition,
139                         BreakpointSource source);
140   void removeBreakpointFor(v8::Local<v8::Function> function,
141                            BreakpointSource source);
142   void schedulePauseOnNextStatement(
143       const String16& breakReason,
144       std::unique_ptr<protocol::DictionaryValue> data);
145   void cancelPauseOnNextStatement();
146   void breakProgram(const String16& breakReason,
147                     std::unique_ptr<protocol::DictionaryValue> data);
148 
149   void reset();
150 
151   // Interface for V8InspectorImpl
152   void didPauseOnInstrumentation(v8::debug::BreakpointId instrumentationId);
153 
154   void didPause(int contextId, v8::Local<v8::Value> exception,
155                 const std::vector<v8::debug::BreakpointId>& hitBreakpoints,
156                 v8::debug::ExceptionType exceptionType, bool isUncaught,
157                 v8::debug::BreakReasons breakReasons);
158   void didContinue();
159   void didParseSource(std::unique_ptr<V8DebuggerScript>, bool success);
160 
161   bool isFunctionBlackboxed(const String16& scriptId,
162                             const v8::debug::Location& start,
163                             const v8::debug::Location& end);
164   bool shouldBeSkipped(const String16& scriptId, int line, int column);
165 
166   bool acceptsPause(bool isOOMBreak) const;
167 
168   void ScriptCollected(const V8DebuggerScript* script);
169 
isolate()170   v8::Isolate* isolate() { return m_isolate; }
171 
172   void clearBreakDetails();
173 
174  private:
175   void enableImpl();
176 
177   Response currentCallFrames(
178       std::unique_ptr<protocol::Array<protocol::Debugger::CallFrame>>*);
179   std::unique_ptr<protocol::Runtime::StackTrace> currentAsyncStackTrace();
180   std::unique_ptr<protocol::Runtime::StackTraceId> currentExternalStackTrace();
181 
182   void setPauseOnExceptionsImpl(int);
183 
184   std::unique_ptr<protocol::Debugger::Location> setBreakpointImpl(
185       const String16& breakpointId, const String16& scriptId,
186       const String16& condition, int lineNumber, int columnNumber);
187   void setBreakpointImpl(const String16& breakpointId,
188                          v8::Local<v8::Function> function,
189                          v8::Local<v8::String> condition);
190   void removeBreakpointImpl(const String16& breakpointId,
191                             const std::vector<V8DebuggerScript*>& scripts);
192 
193   void internalSetAsyncCallStackDepth(int);
194   void increaseCachedSkipStackGeneration();
195 
196   Response setBlackboxPattern(const String16& pattern);
197   void resetBlackboxedStateCache();
198 
199   bool isPaused() const;
200 
201   void setScriptInstrumentationBreakpointIfNeeded(V8DebuggerScript* script);
202 
203   Response processSkipList(
204       protocol::Array<protocol::Debugger::LocationRange>* skipList);
205 
206   using ScriptsMap =
207       std::unordered_map<String16, std::unique_ptr<V8DebuggerScript>>;
208   using BreakpointIdToDebuggerBreakpointIdsMap =
209       std::unordered_map<String16, std::vector<v8::debug::BreakpointId>>;
210   using DebuggerBreakpointIdToBreakpointIdMap =
211       std::unordered_map<v8::debug::BreakpointId, String16>;
212 
213   V8InspectorImpl* m_inspector;
214   V8Debugger* m_debugger;
215   V8InspectorSessionImpl* m_session;
216   bool m_enabled;
217   protocol::DictionaryValue* m_state;
218   protocol::Debugger::Frontend m_frontend;
219   v8::Isolate* m_isolate;
220   ScriptsMap m_scripts;
221   BreakpointIdToDebuggerBreakpointIdsMap m_breakpointIdToDebuggerBreakpointIds;
222   DebuggerBreakpointIdToBreakpointIdMap m_debuggerBreakpointIdToBreakpointId;
223   std::unordered_map<v8::debug::BreakpointId,
224                      std::unique_ptr<protocol::DictionaryValue>>
225       m_breakpointsOnScriptRun;
226 
227   size_t m_maxScriptCacheSize = 0;
228   size_t m_cachedScriptSize = 0;
229   struct CachedScript {
230     String16 scriptId;
231     String16 source;
232     std::vector<uint8_t> bytecode;
233 
sizev8_inspector::V8DebuggerAgentImpl::CachedScript234     size_t size() const {
235       return source.length() * sizeof(UChar) + bytecode.size();
236     }
237   };
238   std::deque<CachedScript> m_cachedScripts;
239 
240   using BreakReason =
241       std::pair<String16, std::unique_ptr<protocol::DictionaryValue>>;
242   std::vector<BreakReason> m_breakReason;
243 
244   void pushBreakDetails(
245       const String16& breakReason,
246       std::unique_ptr<protocol::DictionaryValue> breakAuxData);
247   void popBreakDetails();
248 
249   bool m_skipAllPauses = false;
250   bool m_breakpointsActive = false;
251 
252   std::unique_ptr<V8Regex> m_blackboxPattern;
253   std::unordered_map<String16, std::vector<std::pair<int, int>>>
254       m_blackboxedPositions;
255   std::unordered_map<String16, std::vector<std::pair<int, int>>> m_skipList;
256 };
257 
258 }  // namespace v8_inspector
259 
260 #endif  // V8_INSPECTOR_V8_DEBUGGER_AGENT_IMPL_H_
261