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_INSPECTOR_V8_DEBUGGER_H_ 6 #define V8_INSPECTOR_V8_DEBUGGER_H_ 7 8 #include <list> 9 #include <memory> 10 #include <unordered_map> 11 #include <unordered_set> 12 #include <vector> 13 14 #include "src/base/macros.h" 15 #include "src/inspector/inspected-context.h" 16 #include "src/inspector/protocol/Debugger.h" 17 #include "src/inspector/protocol/Forward.h" 18 #include "src/inspector/protocol/Runtime.h" 19 #include "src/inspector/v8-debugger-script.h" 20 21 #include "include/v8-inspector.h" 22 23 namespace v8_inspector { 24 25 class AsyncStackTrace; 26 class StackFrame; 27 class V8Debugger; 28 class V8DebuggerAgentImpl; 29 class V8InspectorImpl; 30 class V8StackTraceImpl; 31 struct V8StackTraceId; 32 33 enum class WrapMode { kForceValue, kNoPreview, kWithPreview }; 34 35 using protocol::Response; 36 using TerminateExecutionCallback = 37 protocol::Runtime::Backend::TerminateExecutionCallback; 38 39 // This debugger id tries to be unique by generating two random 40 // numbers, which should most likely avoid collisions. 41 // Debugger id has a 1:1 mapping to context group. It is used to 42 // attribute stack traces to a particular debugging, when doing any 43 // cross-debugger operations (e.g. async step in). 44 // See also Runtime.UniqueDebuggerId in the protocol. 45 class V8DebuggerId { 46 public: 47 V8DebuggerId() = default; 48 explicit V8DebuggerId(std::pair<int64_t, int64_t>); 49 explicit V8DebuggerId(const String16&); 50 V8DebuggerId(const V8DebuggerId&) V8_NOEXCEPT = default; 51 ~V8DebuggerId() = default; 52 53 static V8DebuggerId generate(v8::Isolate*); 54 55 String16 toString() const; 56 bool isValid() const; 57 std::pair<int64_t, int64_t> pair() const; 58 59 private: 60 int64_t m_first = 0; 61 int64_t m_second = 0; 62 }; 63 64 class V8Debugger : public v8::debug::DebugDelegate, 65 public v8::debug::AsyncEventDelegate { 66 public: 67 V8Debugger(v8::Isolate*, V8InspectorImpl*); 68 ~V8Debugger() override; 69 70 bool enabled() const; isolate()71 v8::Isolate* isolate() const { return m_isolate; } 72 73 void setBreakpointsActive(bool); 74 75 v8::debug::ExceptionBreakState getPauseOnExceptionsState(); 76 void setPauseOnExceptionsState(v8::debug::ExceptionBreakState); 77 bool canBreakProgram(); 78 void breakProgram(int targetContextGroupId); 79 void interruptAndBreak(int targetContextGroupId); 80 void continueProgram(int targetContextGroupId, 81 bool terminateOnResume = false); 82 void breakProgramOnAssert(int targetContextGroupId); 83 84 void setPauseOnNextCall(bool, int targetContextGroupId); 85 void stepIntoStatement(int targetContextGroupId, bool breakOnAsyncCall); 86 void stepOverStatement(int targetContextGroupId); 87 void stepOutOfFunction(int targetContextGroupId); 88 89 void terminateExecution(std::unique_ptr<TerminateExecutionCallback> callback); 90 91 Response continueToLocation(int targetContextGroupId, 92 V8DebuggerScript* script, 93 std::unique_ptr<protocol::Debugger::Location>, 94 const String16& targetCallFramess); 95 96 // Each script inherits debug data from v8::Context where it has been 97 // compiled. 98 // Only scripts whose debug data matches |contextGroupId| will be reported. 99 // Passing 0 will result in reporting all scripts. 100 std::vector<std::unique_ptr<V8DebuggerScript>> getCompiledScripts( 101 int contextGroupId, V8DebuggerAgentImpl* agent); 102 void enable(); 103 void disable(); 104 isPaused()105 bool isPaused() const { return m_pausedContextGroupId; } 106 bool isPausedInContextGroup(int contextGroupId) const; 107 maxAsyncCallChainDepth()108 int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; } 109 void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int); 110 111 std::shared_ptr<AsyncStackTrace> currentAsyncParent(); 112 V8StackTraceId currentExternalParent(); 113 114 std::shared_ptr<StackFrame> symbolize(v8::Local<v8::StackFrame> v8Frame); 115 116 std::unique_ptr<V8StackTraceImpl> createStackTrace(v8::Local<v8::StackTrace>); 117 std::unique_ptr<V8StackTraceImpl> captureStackTrace(bool fullStack); 118 119 v8::MaybeLocal<v8::Array> internalProperties(v8::Local<v8::Context>, 120 v8::Local<v8::Value>); 121 122 v8::Local<v8::Array> queryObjects(v8::Local<v8::Context> context, 123 v8::Local<v8::Object> prototype); 124 125 void asyncTaskScheduled(const StringView& taskName, void* task, 126 bool recurring); 127 void asyncTaskCanceled(void* task); 128 void asyncTaskStarted(void* task); 129 void asyncTaskFinished(void* task); 130 void allAsyncTasksCanceled(); 131 132 V8StackTraceId storeCurrentStackTrace(const StringView& description); 133 void externalAsyncTaskStarted(const V8StackTraceId& parent); 134 void externalAsyncTaskFinished(const V8StackTraceId& parent); 135 136 uintptr_t storeStackTrace(std::shared_ptr<AsyncStackTrace> stack); 137 138 void muteScriptParsedEvents(); 139 void unmuteScriptParsedEvents(); 140 inspector()141 V8InspectorImpl* inspector() { return m_inspector; } 142 143 void setMaxAsyncTaskStacksForTest(int limit); 144 void dumpAsyncTaskStacksStateForTest(); 145 146 V8DebuggerId debuggerIdFor(int contextGroupId); 147 std::shared_ptr<AsyncStackTrace> stackTraceFor(int contextGroupId, 148 const V8StackTraceId& id); 149 150 void reportTermination(); 151 152 private: 153 bool addInternalObject(v8::Local<v8::Context> context, 154 v8::Local<v8::Object> object, 155 V8InternalValueType type); 156 157 void clearContinueToLocation(); 158 bool shouldContinueToCurrentLocation(); 159 160 static size_t nearHeapLimitCallback(void* data, size_t current_heap_limit, 161 size_t initial_heap_limit); 162 static void terminateExecutionCompletedCallback(v8::Isolate* isolate); 163 static void terminateExecutionCompletedCallbackIgnoringData( 164 v8::Isolate* isolate, void*); 165 void handleProgramBreak( 166 v8::Local<v8::Context> pausedContext, v8::Local<v8::Value> exception, 167 const std::vector<v8::debug::BreakpointId>& hitBreakpoints, 168 v8::debug::ExceptionType exception_type = v8::debug::kException, 169 bool isUncaught = false); 170 171 enum ScopeTargetKind { 172 FUNCTION, 173 GENERATOR, 174 }; 175 v8::MaybeLocal<v8::Value> getTargetScopes(v8::Local<v8::Context>, 176 v8::Local<v8::Value>, 177 ScopeTargetKind); 178 179 v8::MaybeLocal<v8::Value> functionScopes(v8::Local<v8::Context>, 180 v8::Local<v8::Function>); 181 v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>, 182 v8::Local<v8::Value>); 183 v8::MaybeLocal<v8::Array> collectionsEntries(v8::Local<v8::Context> context, 184 v8::Local<v8::Value> value); 185 186 void asyncTaskScheduledForStack(const String16& taskName, void* task, 187 bool recurring); 188 void asyncTaskCanceledForStack(void* task); 189 void asyncTaskStartedForStack(void* task); 190 void asyncTaskFinishedForStack(void* task); 191 192 void asyncTaskCandidateForStepping(void* task); 193 void asyncTaskStartedForStepping(void* task); 194 void asyncTaskFinishedForStepping(void* task); 195 void asyncTaskCanceledForStepping(void* task); 196 197 // v8::debug::DebugEventListener implementation. 198 void AsyncEventOccurred(v8::debug::DebugAsyncActionType type, int id, 199 bool isBlackboxed) override; 200 void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited, 201 bool has_compile_error) override; 202 void BreakProgramRequested( 203 v8::Local<v8::Context> paused_context, 204 const std::vector<v8::debug::BreakpointId>& break_points_hit) override; 205 void ExceptionThrown(v8::Local<v8::Context> paused_context, 206 v8::Local<v8::Value> exception, 207 v8::Local<v8::Value> promise, bool is_uncaught, 208 v8::debug::ExceptionType exception_type) override; 209 bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, 210 const v8::debug::Location& start, 211 const v8::debug::Location& end) override; 212 213 bool ShouldBeSkipped(v8::Local<v8::debug::Script> script, int line, 214 int column) override; 215 216 int currentContextGroupId(); 217 bool asyncStepOutOfFunction(int targetContextGroupId, bool onlyAtReturn); 218 219 bool hasScheduledBreakOnNextFunctionCall() const; 220 221 v8::Isolate* m_isolate; 222 V8InspectorImpl* m_inspector; 223 int m_enableCount; 224 225 int m_breakpointsActiveCount = 0; 226 int m_ignoreScriptParsedEventsCounter; 227 size_t m_originalHeapLimit = 0; 228 bool m_scheduledOOMBreak = false; 229 bool m_scheduledAssertBreak = false; 230 int m_targetContextGroupId = 0; 231 int m_pausedContextGroupId = 0; 232 int m_continueToLocationBreakpointId; 233 String16 m_continueToLocationTargetCallFrames; 234 std::unique_ptr<V8StackTraceImpl> m_continueToLocationStack; 235 236 using AsyncTaskToStackTrace = 237 std::unordered_map<void*, std::weak_ptr<AsyncStackTrace>>; 238 AsyncTaskToStackTrace m_asyncTaskStacks; 239 std::unordered_set<void*> m_recurringTasks; 240 241 int m_maxAsyncCallStacks; 242 int m_maxAsyncCallStackDepth; 243 244 std::vector<void*> m_currentTasks; 245 std::vector<std::shared_ptr<AsyncStackTrace>> m_currentAsyncParent; 246 std::vector<V8StackTraceId> m_currentExternalParent; 247 248 void collectOldAsyncStacksIfNeeded(); 249 int m_asyncStacksCount = 0; 250 // V8Debugger owns all the async stacks, while most of the other references 251 // are weak, which allows to collect some stacks when there are too many. 252 std::list<std::shared_ptr<AsyncStackTrace>> m_allAsyncStacks; 253 254 std::unordered_map<V8DebuggerAgentImpl*, int> m_maxAsyncCallStackDepthMap; 255 void* m_taskWithScheduledBreak = nullptr; 256 257 // If any of the following three is true, we schedule pause on next JS 258 // execution using SetBreakOnNextFunctionCall. 259 bool m_externalAsyncTaskPauseRequested = false; // External async task. 260 bool m_taskWithScheduledBreakPauseRequested = false; // Local async task. 261 bool m_pauseOnNextCallRequested = false; // setPauseOnNextCall API call. 262 263 v8::debug::ExceptionBreakState m_pauseOnExceptionsState; 264 // Whether we should pause on async call execution (if any) while stepping in. 265 // See Debugger.stepInto for details. 266 bool m_pauseOnAsyncCall = false; 267 268 using StackTraceIdToStackTrace = 269 std::unordered_map<uintptr_t, std::weak_ptr<AsyncStackTrace>>; 270 StackTraceIdToStackTrace m_storedStackTraces; 271 uintptr_t m_lastStackTraceId = 0; 272 273 std::unordered_map<int, V8DebuggerId> m_contextGroupIdToDebuggerId; 274 275 std::unique_ptr<TerminateExecutionCallback> m_terminateExecutionCallback; 276 277 DISALLOW_COPY_AND_ASSIGN(V8Debugger); 278 }; 279 280 } // namespace v8_inspector 281 282 #endif // V8_INSPECTOR_V8_DEBUGGER_H_ 283