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 <unordered_map> 10 #include <unordered_set> 11 #include <vector> 12 13 #include "src/base/macros.h" 14 #include "src/debug/debug-interface.h" 15 #include "src/inspector/protocol/Debugger.h" 16 #include "src/inspector/protocol/Forward.h" 17 #include "src/inspector/protocol/Runtime.h" 18 #include "src/inspector/v8-debugger-script.h" 19 #include "src/inspector/wasm-translation.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 using protocol::Response; 34 using ScheduleStepIntoAsyncCallback = 35 protocol::Debugger::Backend::ScheduleStepIntoAsyncCallback; 36 using TerminateExecutionCallback = 37 protocol::Runtime::Backend::TerminateExecutionCallback; 38 39 class V8Debugger : public v8::debug::DebugDelegate, 40 public v8::debug::AsyncEventDelegate { 41 public: 42 V8Debugger(v8::Isolate*, V8InspectorImpl*); 43 ~V8Debugger(); 44 45 bool enabled() const; isolate()46 v8::Isolate* isolate() const { return m_isolate; } 47 48 void setBreakpointsActive(bool); 49 50 v8::debug::ExceptionBreakState getPauseOnExceptionsState(); 51 void setPauseOnExceptionsState(v8::debug::ExceptionBreakState); 52 bool canBreakProgram(); 53 void breakProgram(int targetContextGroupId); 54 void interruptAndBreak(int targetContextGroupId); 55 void continueProgram(int targetContextGroupId); 56 void breakProgramOnAssert(int targetContextGroupId); 57 58 void setPauseOnNextCall(bool, int targetContextGroupId); 59 void stepIntoStatement(int targetContextGroupId, bool breakOnAsyncCall); 60 void stepOverStatement(int targetContextGroupId); 61 void stepOutOfFunction(int targetContextGroupId); 62 void scheduleStepIntoAsync( 63 std::unique_ptr<ScheduleStepIntoAsyncCallback> callback, 64 int targetContextGroupId); 65 void pauseOnAsyncCall(int targetContextGroupId, uintptr_t task, 66 const String16& debuggerId); 67 68 void terminateExecution(std::unique_ptr<TerminateExecutionCallback> callback); 69 70 Response continueToLocation(int targetContextGroupId, 71 V8DebuggerScript* script, 72 std::unique_ptr<protocol::Debugger::Location>, 73 const String16& targetCallFramess); 74 75 // Each script inherits debug data from v8::Context where it has been 76 // compiled. 77 // Only scripts whose debug data matches |contextGroupId| will be reported. 78 // Passing 0 will result in reporting all scripts. 79 void getCompiledScripts(int contextGroupId, 80 std::vector<std::unique_ptr<V8DebuggerScript>>&); 81 void enable(); 82 void disable(); 83 isPaused()84 bool isPaused() const { return m_pausedContextGroupId; } 85 bool isPausedInContextGroup(int contextGroupId) const; 86 maxAsyncCallChainDepth()87 int maxAsyncCallChainDepth() { return m_maxAsyncCallStackDepth; } 88 void setAsyncCallStackDepth(V8DebuggerAgentImpl*, int); 89 90 std::shared_ptr<AsyncStackTrace> currentAsyncParent(); 91 V8StackTraceId currentExternalParent(); 92 93 std::shared_ptr<StackFrame> symbolize(v8::Local<v8::StackFrame> v8Frame); 94 95 std::unique_ptr<V8StackTraceImpl> createStackTrace(v8::Local<v8::StackTrace>); 96 std::unique_ptr<V8StackTraceImpl> captureStackTrace(bool fullStack); 97 98 v8::MaybeLocal<v8::Array> internalProperties(v8::Local<v8::Context>, 99 v8::Local<v8::Value>); 100 101 v8::Local<v8::Array> queryObjects(v8::Local<v8::Context> context, 102 v8::Local<v8::Object> prototype); 103 104 void asyncTaskScheduled(const StringView& taskName, void* task, 105 bool recurring); 106 void asyncTaskCanceled(void* task); 107 void asyncTaskStarted(void* task); 108 void asyncTaskFinished(void* task); 109 void allAsyncTasksCanceled(); 110 111 V8StackTraceId storeCurrentStackTrace(const StringView& description); 112 void externalAsyncTaskStarted(const V8StackTraceId& parent); 113 void externalAsyncTaskFinished(const V8StackTraceId& parent); 114 115 uintptr_t storeStackTrace(std::shared_ptr<AsyncStackTrace> stack); 116 117 void muteScriptParsedEvents(); 118 void unmuteScriptParsedEvents(); 119 inspector()120 V8InspectorImpl* inspector() { return m_inspector; } 121 wasmTranslation()122 WasmTranslation* wasmTranslation() { return &m_wasmTranslation; } 123 124 void setMaxAsyncTaskStacksForTest(int limit); 125 void dumpAsyncTaskStacksStateForTest(); 126 scheduledAsyncCall()127 v8_inspector::V8StackTraceId scheduledAsyncCall() { 128 return m_scheduledAsyncCall; 129 } 130 131 std::pair<int64_t, int64_t> debuggerIdFor(int contextGroupId); 132 std::pair<int64_t, int64_t> debuggerIdFor( 133 const String16& serializedDebuggerId); 134 std::shared_ptr<AsyncStackTrace> stackTraceFor(int contextGroupId, 135 const V8StackTraceId& id); 136 137 private: 138 void clearContinueToLocation(); 139 bool shouldContinueToCurrentLocation(); 140 141 static size_t nearHeapLimitCallback(void* data, size_t current_heap_limit, 142 size_t initial_heap_limit); 143 static void terminateExecutionCompletedCallback(v8::Isolate* isolate); 144 145 void handleProgramBreak( 146 v8::Local<v8::Context> pausedContext, v8::Local<v8::Value> exception, 147 const std::vector<v8::debug::BreakpointId>& hitBreakpoints, 148 bool isPromiseRejection = false, bool isUncaught = false); 149 150 enum ScopeTargetKind { 151 FUNCTION, 152 GENERATOR, 153 }; 154 v8::MaybeLocal<v8::Value> getTargetScopes(v8::Local<v8::Context>, 155 v8::Local<v8::Value>, 156 ScopeTargetKind); 157 158 v8::MaybeLocal<v8::Value> functionScopes(v8::Local<v8::Context>, 159 v8::Local<v8::Function>); 160 v8::MaybeLocal<v8::Value> generatorScopes(v8::Local<v8::Context>, 161 v8::Local<v8::Value>); 162 163 void asyncTaskScheduledForStack(const String16& taskName, void* task, 164 bool recurring); 165 void asyncTaskCanceledForStack(void* task); 166 void asyncTaskStartedForStack(void* task); 167 void asyncTaskFinishedForStack(void* task); 168 169 void asyncTaskCandidateForStepping(void* task, bool isLocal); 170 void asyncTaskStartedForStepping(void* task); 171 void asyncTaskFinishedForStepping(void* task); 172 void asyncTaskCanceledForStepping(void* task); 173 174 // v8::debug::DebugEventListener implementation. 175 void AsyncEventOccurred(v8::debug::DebugAsyncActionType type, int id, 176 bool isBlackboxed) override; 177 void ScriptCompiled(v8::Local<v8::debug::Script> script, bool is_live_edited, 178 bool has_compile_error) override; 179 void BreakProgramRequested( 180 v8::Local<v8::Context> paused_context, 181 const std::vector<v8::debug::BreakpointId>& break_points_hit) override; 182 void ExceptionThrown(v8::Local<v8::Context> paused_context, 183 v8::Local<v8::Value> exception, 184 v8::Local<v8::Value> promise, bool is_uncaught) override; 185 bool IsFunctionBlackboxed(v8::Local<v8::debug::Script> script, 186 const v8::debug::Location& start, 187 const v8::debug::Location& end) override; 188 189 int currentContextGroupId(); 190 bool asyncStepOutOfFunction(int targetContextGroupId, bool onlyAtReturn); 191 192 v8::Isolate* m_isolate; 193 V8InspectorImpl* m_inspector; 194 int m_enableCount; 195 int m_breakpointsActiveCount = 0; 196 int m_ignoreScriptParsedEventsCounter; 197 size_t m_originalHeapLimit = 0; 198 bool m_scheduledOOMBreak = false; 199 bool m_scheduledAssertBreak = false; 200 int m_targetContextGroupId = 0; 201 int m_pausedContextGroupId = 0; 202 int m_continueToLocationBreakpointId; 203 String16 m_continueToLocationTargetCallFrames; 204 std::unique_ptr<V8StackTraceImpl> m_continueToLocationStack; 205 206 using AsyncTaskToStackTrace = 207 std::unordered_map<void*, std::weak_ptr<AsyncStackTrace>>; 208 AsyncTaskToStackTrace m_asyncTaskStacks; 209 std::unordered_set<void*> m_recurringTasks; 210 211 int m_maxAsyncCallStacks; 212 int m_maxAsyncCallStackDepth; 213 214 std::vector<void*> m_currentTasks; 215 std::vector<std::shared_ptr<AsyncStackTrace>> m_currentAsyncParent; 216 std::vector<V8StackTraceId> m_currentExternalParent; 217 218 void collectOldAsyncStacksIfNeeded(); 219 int m_asyncStacksCount = 0; 220 // V8Debugger owns all the async stacks, while most of the other references 221 // are weak, which allows to collect some stacks when there are too many. 222 std::list<std::shared_ptr<AsyncStackTrace>> m_allAsyncStacks; 223 std::unordered_map<int, std::weak_ptr<StackFrame>> m_framesCache; 224 225 std::unordered_map<V8DebuggerAgentImpl*, int> m_maxAsyncCallStackDepthMap; 226 void* m_taskWithScheduledBreak = nullptr; 227 String16 m_taskWithScheduledBreakDebuggerId; 228 229 std::unique_ptr<ScheduleStepIntoAsyncCallback> m_stepIntoAsyncCallback; 230 bool m_breakRequested = false; 231 232 v8::debug::ExceptionBreakState m_pauseOnExceptionsState; 233 bool m_pauseOnAsyncCall = false; 234 v8_inspector::V8StackTraceId m_scheduledAsyncCall; 235 236 using StackTraceIdToStackTrace = 237 std::unordered_map<uintptr_t, std::weak_ptr<AsyncStackTrace>>; 238 StackTraceIdToStackTrace m_storedStackTraces; 239 uintptr_t m_lastStackTraceId = 0; 240 241 std::unordered_map<int, std::pair<int64_t, int64_t>> 242 m_contextGroupIdToDebuggerId; 243 std::unordered_map<String16, std::pair<int64_t, int64_t>> 244 m_serializedDebuggerIdToDebuggerId; 245 246 std::unique_ptr<TerminateExecutionCallback> m_terminateExecutionCallback; 247 248 WasmTranslation m_wasmTranslation; 249 250 DISALLOW_COPY_AND_ASSIGN(V8Debugger); 251 }; 252 253 } // namespace v8_inspector 254 255 #endif // V8_INSPECTOR_V8_DEBUGGER_H_ 256