OLD | NEW |
1 // Copyright 2016 the V8 project authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/inspector/v8-debugger.h" | 5 #include "src/inspector/v8-debugger.h" |
6 | 6 |
7 #include "src/inspector/debugger-script.h" | 7 #include "src/inspector/debugger-script.h" |
| 8 #include "src/inspector/inspected-context.h" |
8 #include "src/inspector/protocol/Protocol.h" | 9 #include "src/inspector/protocol/Protocol.h" |
9 #include "src/inspector/script-breakpoint.h" | 10 #include "src/inspector/script-breakpoint.h" |
10 #include "src/inspector/string-util.h" | 11 #include "src/inspector/string-util.h" |
11 #include "src/inspector/v8-debugger-agent-impl.h" | 12 #include "src/inspector/v8-debugger-agent-impl.h" |
12 #include "src/inspector/v8-inspector-impl.h" | 13 #include "src/inspector/v8-inspector-impl.h" |
13 #include "src/inspector/v8-internal-value-type.h" | 14 #include "src/inspector/v8-internal-value-type.h" |
14 #include "src/inspector/v8-stack-trace-impl.h" | 15 #include "src/inspector/v8-stack-trace-impl.h" |
15 #include "src/inspector/v8-value-copier.h" | 16 #include "src/inspector/v8-value-copier.h" |
16 | 17 |
17 #include "include/v8-util.h" | 18 #include "include/v8-util.h" |
(...skipping 25 matching lines...) Expand all Loading... |
43 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( | 44 v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast( |
44 debuggerScript | 45 debuggerScript |
45 ->Get(context, toV8StringInternalized(m_isolate, functionName)) | 46 ->Get(context, toV8StringInternalized(m_isolate, functionName)) |
46 .ToLocalChecked()); | 47 .ToLocalChecked()); |
47 return function->Call(context, debuggerScript, argc, argv); | 48 return function->Call(context, debuggerScript, argc, argv); |
48 } | 49 } |
49 | 50 |
50 V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) | 51 V8Debugger::V8Debugger(v8::Isolate* isolate, V8InspectorImpl* inspector) |
51 : m_isolate(isolate), | 52 : m_isolate(isolate), |
52 m_inspector(inspector), | 53 m_inspector(inspector), |
53 m_lastContextId(0), | |
54 m_enableCount(0), | 54 m_enableCount(0), |
55 m_breakpointsActivated(true), | 55 m_breakpointsActivated(true), |
56 m_runningNestedMessageLoop(false), | 56 m_runningNestedMessageLoop(false), |
57 m_ignoreScriptParsedEventsCounter(0), | 57 m_ignoreScriptParsedEventsCounter(0), |
58 m_maxAsyncCallStackDepth(0), | 58 m_maxAsyncCallStackDepth(0), |
59 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), | 59 m_pauseOnExceptionsState(v8::debug::NoBreakOnException), |
60 m_wasmTranslation(isolate) {} | 60 m_wasmTranslation(isolate) {} |
61 | 61 |
62 V8Debugger::~V8Debugger() {} | 62 V8Debugger::~V8Debugger() {} |
63 | 63 |
(...skipping 15 matching lines...) Expand all Loading... |
79 clearBreakpoints(); | 79 clearBreakpoints(); |
80 m_debuggerScript.Reset(); | 80 m_debuggerScript.Reset(); |
81 m_debuggerContext.Reset(); | 81 m_debuggerContext.Reset(); |
82 allAsyncTasksCanceled(); | 82 allAsyncTasksCanceled(); |
83 m_wasmTranslation.Clear(); | 83 m_wasmTranslation.Clear(); |
84 v8::debug::SetDebugEventListener(m_isolate, nullptr); | 84 v8::debug::SetDebugEventListener(m_isolate, nullptr); |
85 } | 85 } |
86 | 86 |
87 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } | 87 bool V8Debugger::enabled() const { return !m_debuggerScript.IsEmpty(); } |
88 | 88 |
89 // static | |
90 int V8Debugger::contextId(v8::Local<v8::Context> context) { | |
91 v8::Local<v8::Value> data = | |
92 context->GetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex)); | |
93 if (data.IsEmpty() || !data->IsString()) return 0; | |
94 String16 dataString = toProtocolString(data.As<v8::String>()); | |
95 if (dataString.isEmpty()) return 0; | |
96 size_t commaPos = dataString.find(","); | |
97 if (commaPos == String16::kNotFound) return 0; | |
98 size_t commaPos2 = dataString.find(",", commaPos + 1); | |
99 if (commaPos2 == String16::kNotFound) return 0; | |
100 return dataString.substring(commaPos + 1, commaPos2 - commaPos - 1) | |
101 .toInteger(); | |
102 } | |
103 | |
104 // static | |
105 int V8Debugger::getGroupId(v8::Local<v8::Context> context) { | |
106 v8::Local<v8::Value> data = | |
107 context->GetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex)); | |
108 if (data.IsEmpty() || !data->IsString()) return 0; | |
109 String16 dataString = toProtocolString(data.As<v8::String>()); | |
110 if (dataString.isEmpty()) return 0; | |
111 size_t commaPos = dataString.find(","); | |
112 if (commaPos == String16::kNotFound) return 0; | |
113 return dataString.substring(0, commaPos).toInteger(); | |
114 } | |
115 | |
116 void V8Debugger::getCompiledScripts( | 89 void V8Debugger::getCompiledScripts( |
117 int contextGroupId, | 90 int contextGroupId, |
118 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { | 91 std::vector<std::unique_ptr<V8DebuggerScript>>& result) { |
119 v8::HandleScope scope(m_isolate); | 92 v8::HandleScope scope(m_isolate); |
120 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); | 93 v8::PersistentValueVector<v8::debug::Script> scripts(m_isolate); |
121 v8::debug::GetLoadedScripts(m_isolate, scripts); | 94 v8::debug::GetLoadedScripts(m_isolate, scripts); |
122 String16 contextPrefix = String16::fromInteger(contextGroupId) + ","; | |
123 for (size_t i = 0; i < scripts.Size(); ++i) { | 95 for (size_t i = 0; i < scripts.Size(); ++i) { |
124 v8::Local<v8::debug::Script> script = scripts.Get(i); | 96 v8::Local<v8::debug::Script> script = scripts.Get(i); |
125 if (!script->WasCompiled()) continue; | 97 if (!script->WasCompiled()) continue; |
126 v8::Local<v8::String> v8ContextData; | 98 v8::Local<v8::Value> contextData; |
127 if (!script->ContextData().ToLocal(&v8ContextData)) continue; | 99 if (!script->ContextData().ToLocal(&contextData) || !contextData->IsInt32()) |
128 String16 contextData = toProtocolString(v8ContextData); | 100 continue; |
129 if (contextData.find(contextPrefix) != 0) continue; | 101 int contextId = static_cast<int>(contextData.As<v8::Int32>()->Value()); |
| 102 if (m_inspector->contextGroupId(contextId) != contextGroupId) continue; |
130 result.push_back(V8DebuggerScript::Create(m_isolate, script, false)); | 103 result.push_back(V8DebuggerScript::Create(m_isolate, script, false)); |
131 } | 104 } |
132 } | 105 } |
133 | 106 |
134 String16 V8Debugger::setBreakpoint(const ScriptBreakpoint& breakpoint, | 107 String16 V8Debugger::setBreakpoint(const ScriptBreakpoint& breakpoint, |
135 int* actualLineNumber, | 108 int* actualLineNumber, |
136 int* actualColumnNumber) { | 109 int* actualColumnNumber) { |
137 v8::HandleScope scope(m_isolate); | 110 v8::HandleScope scope(m_isolate); |
138 v8::Local<v8::Context> context = debuggerContext(); | 111 v8::Local<v8::Context> context = debuggerContext(); |
139 v8::Context::Scope contextScope(context); | 112 v8::Context::Scope contextScope(context); |
(...skipping 336 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
476 } | 449 } |
477 | 450 |
478 void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, | 451 void V8Debugger::handleProgramBreak(v8::Local<v8::Context> pausedContext, |
479 v8::Local<v8::Object> executionState, | 452 v8::Local<v8::Object> executionState, |
480 v8::Local<v8::Value> exception, | 453 v8::Local<v8::Value> exception, |
481 v8::Local<v8::Array> hitBreakpointNumbers, | 454 v8::Local<v8::Array> hitBreakpointNumbers, |
482 bool isPromiseRejection, bool isUncaught) { | 455 bool isPromiseRejection, bool isUncaught) { |
483 // Don't allow nested breaks. | 456 // Don't allow nested breaks. |
484 if (m_runningNestedMessageLoop) return; | 457 if (m_runningNestedMessageLoop) return; |
485 | 458 |
486 V8DebuggerAgentImpl* agent = | 459 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( |
487 m_inspector->enabledDebuggerAgentForGroup(getGroupId(pausedContext)); | 460 m_inspector->contextGroupId(pausedContext)); |
488 if (!agent) return; | 461 if (!agent) return; |
489 | 462 |
490 std::vector<String16> breakpointIds; | 463 std::vector<String16> breakpointIds; |
491 if (!hitBreakpointNumbers.IsEmpty()) { | 464 if (!hitBreakpointNumbers.IsEmpty()) { |
492 breakpointIds.reserve(hitBreakpointNumbers->Length()); | 465 breakpointIds.reserve(hitBreakpointNumbers->Length()); |
493 for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) { | 466 for (uint32_t i = 0; i < hitBreakpointNumbers->Length(); i++) { |
494 v8::Local<v8::Value> hitBreakpointNumber = | 467 v8::Local<v8::Value> hitBreakpointNumber = |
495 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); | 468 hitBreakpointNumbers->Get(debuggerContext(), i).ToLocalChecked(); |
496 DCHECK(hitBreakpointNumber->IsInt32()); | 469 DCHECK(hitBreakpointNumber->IsInt32()); |
497 breakpointIds.push_back(String16::fromInteger( | 470 breakpointIds.push_back(String16::fromInteger( |
498 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); | 471 hitBreakpointNumber->Int32Value(debuggerContext()).FromJust())); |
499 } | 472 } |
500 } | 473 } |
501 | 474 |
502 m_pausedContext = pausedContext; | 475 m_pausedContext = pausedContext; |
503 m_executionState = executionState; | 476 m_executionState = executionState; |
504 V8DebuggerAgentImpl::SkipPauseRequest result = agent->didPause( | 477 V8DebuggerAgentImpl::SkipPauseRequest result = agent->didPause( |
505 pausedContext, exception, breakpointIds, isPromiseRejection, isUncaught); | 478 pausedContext, exception, breakpointIds, isPromiseRejection, isUncaught); |
506 if (result == V8DebuggerAgentImpl::RequestNoSkip) { | 479 if (result == V8DebuggerAgentImpl::RequestNoSkip) { |
507 m_runningNestedMessageLoop = true; | 480 m_runningNestedMessageLoop = true; |
508 int groupId = getGroupId(pausedContext); | 481 int groupId = m_inspector->contextGroupId(pausedContext); |
509 DCHECK(groupId); | 482 DCHECK(groupId); |
510 m_inspector->client()->runMessageLoopOnPause(groupId); | 483 m_inspector->client()->runMessageLoopOnPause(groupId); |
511 // The agent may have been removed in the nested loop. | 484 // The agent may have been removed in the nested loop. |
512 agent = | 485 agent = m_inspector->enabledDebuggerAgentForGroup( |
513 m_inspector->enabledDebuggerAgentForGroup(getGroupId(pausedContext)); | 486 m_inspector->contextGroupId(pausedContext)); |
514 if (agent) agent->didContinue(); | 487 if (agent) agent->didContinue(); |
515 m_runningNestedMessageLoop = false; | 488 m_runningNestedMessageLoop = false; |
516 } | 489 } |
517 m_pausedContext.Clear(); | 490 m_pausedContext.Clear(); |
518 m_executionState.Clear(); | 491 m_executionState.Clear(); |
519 | 492 |
520 if (result == V8DebuggerAgentImpl::RequestStepFrame) { | 493 if (result == V8DebuggerAgentImpl::RequestStepFrame) { |
521 v8::debug::PrepareStep(m_isolate, v8::debug::StepFrame); | 494 v8::debug::PrepareStep(m_isolate, v8::debug::StepFrame); |
522 } else if (result == V8DebuggerAgentImpl::RequestStepInto) { | 495 } else if (result == V8DebuggerAgentImpl::RequestStepInto) { |
523 v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); | 496 v8::debug::PrepareStep(m_isolate, v8::debug::StepIn); |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
559 v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); | 532 v8::Local<v8::Context> eventContext = eventDetails.GetEventContext(); |
560 DCHECK(!eventContext.IsEmpty()); | 533 DCHECK(!eventContext.IsEmpty()); |
561 | 534 |
562 if (event == v8::AsyncTaskEvent) { | 535 if (event == v8::AsyncTaskEvent) { |
563 v8::HandleScope scope(m_isolate); | 536 v8::HandleScope scope(m_isolate); |
564 handleV8AsyncTaskEvent(eventContext, eventDetails.GetExecutionState(), | 537 handleV8AsyncTaskEvent(eventContext, eventDetails.GetExecutionState(), |
565 eventDetails.GetEventData()); | 538 eventDetails.GetEventData()); |
566 return; | 539 return; |
567 } | 540 } |
568 | 541 |
569 V8DebuggerAgentImpl* agent = | 542 V8DebuggerAgentImpl* agent = m_inspector->enabledDebuggerAgentForGroup( |
570 m_inspector->enabledDebuggerAgentForGroup(getGroupId(eventContext)); | 543 m_inspector->contextGroupId(eventContext)); |
571 if (!agent) return; | 544 if (!agent) return; |
572 | 545 |
573 v8::HandleScope scope(m_isolate); | 546 v8::HandleScope scope(m_isolate); |
574 if (event == v8::AfterCompile || event == v8::CompileError) { | 547 if (event == v8::AfterCompile || event == v8::CompileError) { |
575 v8::Context::Scope contextScope(debuggerContext()); | 548 v8::Context::Scope contextScope(debuggerContext()); |
576 // Determine if the script is a wasm script. | 549 // Determine if the script is a wasm script. |
577 v8::Local<v8::Value> scriptMirror = | 550 v8::Local<v8::Value> scriptMirror = |
578 callInternalGetterFunction(eventDetails.GetEventData(), "script"); | 551 callInternalGetterFunction(eventDetails.GetEventData(), "script"); |
579 DCHECK(scriptMirror->IsObject()); | 552 DCHECK(scriptMirror->IsObject()); |
580 v8::Local<v8::Value> scriptWrapper = | 553 v8::Local<v8::Value> scriptWrapper = |
(...skipping 296 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
877 if (!markAsInternal(context, location, V8InternalValueType::kLocation)) | 850 if (!markAsInternal(context, location, V8InternalValueType::kLocation)) |
878 return v8::Null(m_isolate); | 851 return v8::Null(m_isolate); |
879 return location; | 852 return location; |
880 } | 853 } |
881 | 854 |
882 bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } | 855 bool V8Debugger::isPaused() { return !m_pausedContext.IsEmpty(); } |
883 | 856 |
884 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( | 857 std::unique_ptr<V8StackTraceImpl> V8Debugger::createStackTrace( |
885 v8::Local<v8::StackTrace> stackTrace) { | 858 v8::Local<v8::StackTrace> stackTrace) { |
886 int contextGroupId = | 859 int contextGroupId = |
887 m_isolate->InContext() ? getGroupId(m_isolate->GetCurrentContext()) : 0; | 860 m_isolate->InContext() |
| 861 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) |
| 862 : 0; |
888 return V8StackTraceImpl::create(this, contextGroupId, stackTrace, | 863 return V8StackTraceImpl::create(this, contextGroupId, stackTrace, |
889 V8StackTraceImpl::maxCallStackSizeToCapture); | 864 V8StackTraceImpl::maxCallStackSizeToCapture); |
890 } | 865 } |
891 | 866 |
892 int V8Debugger::markContext(const V8ContextInfo& info) { | |
893 DCHECK(info.context->GetIsolate() == m_isolate); | |
894 int contextId = ++m_lastContextId; | |
895 String16 debugData = String16::fromInteger(info.contextGroupId) + "," + | |
896 String16::fromInteger(contextId) + "," + | |
897 toString16(info.auxData); | |
898 v8::Context::Scope contextScope(info.context); | |
899 info.context->SetEmbedderData(static_cast<int>(v8::Context::kDebugIdIndex), | |
900 toV8String(m_isolate, debugData)); | |
901 return contextId; | |
902 } | |
903 | |
904 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { | 867 void V8Debugger::setAsyncCallStackDepth(V8DebuggerAgentImpl* agent, int depth) { |
905 if (depth <= 0) | 868 if (depth <= 0) |
906 m_maxAsyncCallStackDepthMap.erase(agent); | 869 m_maxAsyncCallStackDepthMap.erase(agent); |
907 else | 870 else |
908 m_maxAsyncCallStackDepthMap[agent] = depth; | 871 m_maxAsyncCallStackDepthMap[agent] = depth; |
909 | 872 |
910 int maxAsyncCallStackDepth = 0; | 873 int maxAsyncCallStackDepth = 0; |
911 for (const auto& pair : m_maxAsyncCallStackDepthMap) { | 874 for (const auto& pair : m_maxAsyncCallStackDepthMap) { |
912 if (pair.second > maxAsyncCallStackDepth) | 875 if (pair.second > maxAsyncCallStackDepth) |
913 maxAsyncCallStackDepth = pair.second; | 876 maxAsyncCallStackDepth = pair.second; |
914 } | 877 } |
915 | 878 |
916 if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return; | 879 if (m_maxAsyncCallStackDepth == maxAsyncCallStackDepth) return; |
917 m_maxAsyncCallStackDepth = maxAsyncCallStackDepth; | 880 m_maxAsyncCallStackDepth = maxAsyncCallStackDepth; |
918 if (!maxAsyncCallStackDepth) allAsyncTasksCanceled(); | 881 if (!maxAsyncCallStackDepth) allAsyncTasksCanceled(); |
919 } | 882 } |
920 | 883 |
921 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, | 884 void V8Debugger::asyncTaskScheduled(const StringView& taskName, void* task, |
922 bool recurring) { | 885 bool recurring) { |
923 if (!m_maxAsyncCallStackDepth) return; | 886 if (!m_maxAsyncCallStackDepth) return; |
924 asyncTaskScheduled(toString16(taskName), task, recurring); | 887 asyncTaskScheduled(toString16(taskName), task, recurring); |
925 } | 888 } |
926 | 889 |
927 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, | 890 void V8Debugger::asyncTaskScheduled(const String16& taskName, void* task, |
928 bool recurring) { | 891 bool recurring) { |
929 if (!m_maxAsyncCallStackDepth) return; | 892 if (!m_maxAsyncCallStackDepth) return; |
930 v8::HandleScope scope(m_isolate); | 893 v8::HandleScope scope(m_isolate); |
931 int contextGroupId = | 894 int contextGroupId = |
932 m_isolate->InContext() ? getGroupId(m_isolate->GetCurrentContext()) : 0; | 895 m_isolate->InContext() |
| 896 ? m_inspector->contextGroupId(m_isolate->GetCurrentContext()) |
| 897 : 0; |
933 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( | 898 std::unique_ptr<V8StackTraceImpl> chain = V8StackTraceImpl::capture( |
934 this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, | 899 this, contextGroupId, V8StackTraceImpl::maxCallStackSizeToCapture, |
935 taskName); | 900 taskName); |
936 if (chain) { | 901 if (chain) { |
937 m_asyncTaskStacks[task] = std::move(chain); | 902 m_asyncTaskStacks[task] = std::move(chain); |
938 if (recurring) m_recurringTasks.insert(task); | 903 if (recurring) m_recurringTasks.insert(task); |
939 } | 904 } |
940 } | 905 } |
941 | 906 |
942 void V8Debugger::asyncTaskCanceled(void* task) { | 907 void V8Debugger::asyncTaskCanceled(void* task) { |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
989 void V8Debugger::unmuteScriptParsedEvents() { | 954 void V8Debugger::unmuteScriptParsedEvents() { |
990 --m_ignoreScriptParsedEventsCounter; | 955 --m_ignoreScriptParsedEventsCounter; |
991 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); | 956 DCHECK_GE(m_ignoreScriptParsedEventsCounter, 0); |
992 } | 957 } |
993 | 958 |
994 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( | 959 std::unique_ptr<V8StackTraceImpl> V8Debugger::captureStackTrace( |
995 bool fullStack) { | 960 bool fullStack) { |
996 if (!m_isolate->InContext()) return nullptr; | 961 if (!m_isolate->InContext()) return nullptr; |
997 | 962 |
998 v8::HandleScope handles(m_isolate); | 963 v8::HandleScope handles(m_isolate); |
999 int contextGroupId = getGroupId(m_isolate->GetCurrentContext()); | 964 int contextGroupId = |
| 965 m_inspector->contextGroupId(m_isolate->GetCurrentContext()); |
1000 if (!contextGroupId) return nullptr; | 966 if (!contextGroupId) return nullptr; |
1001 | 967 |
1002 size_t stackSize = | 968 size_t stackSize = |
1003 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; | 969 fullStack ? V8StackTraceImpl::maxCallStackSizeToCapture : 1; |
1004 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) | 970 if (m_inspector->enabledRuntimeAgentForGroup(contextGroupId)) |
1005 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; | 971 stackSize = V8StackTraceImpl::maxCallStackSizeToCapture; |
1006 | 972 |
1007 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); | 973 return V8StackTraceImpl::capture(this, contextGroupId, stackSize); |
1008 } | 974 } |
1009 | 975 |
1010 } // namespace v8_inspector | 976 } // namespace v8_inspector |
OLD | NEW |