wasm-idle 0.7.2 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +760 -81
- package/dist/index.d.ts +4 -9
- package/dist/index.js +2 -4
- package/dist/playground/applicationAssets.d.ts +4 -0
- package/dist/playground/applicationAssets.js +277 -0
- package/dist/playground/assemblyscript.d.ts +41 -0
- package/dist/playground/assemblyscript.js +630 -0
- package/dist/playground/assetBridge.d.ts +18 -7
- package/dist/playground/assetBridge.js +824 -100
- package/dist/playground/assets.d.ts +813 -19
- package/dist/playground/assets.js +2096 -156
- package/dist/playground/awk.d.ts +5 -0
- package/dist/playground/awk.js +60 -0
- package/dist/playground/bash.d.ts +53 -0
- package/dist/playground/bash.js +1096 -0
- package/dist/playground/bashWorkerProtocol.d.ts +88 -0
- package/dist/playground/bashWorkerProtocol.js +135 -0
- package/dist/playground/bqn.d.ts +5 -0
- package/dist/playground/bqn.js +57 -0
- package/dist/playground/bqnPreflight.d.ts +26 -0
- package/dist/playground/bqnPreflight.js +399 -0
- package/dist/playground/c3.d.ts +15 -0
- package/dist/playground/c3.js +154 -0
- package/dist/playground/clang.d.ts +35 -19
- package/dist/playground/clang.js +241 -52
- package/dist/playground/clangAssetIntegrity.d.ts +32 -0
- package/dist/playground/clangAssetIntegrity.js +8 -0
- package/dist/playground/clojurescript.d.ts +5 -0
- package/dist/playground/clojurescript.js +59 -0
- package/dist/playground/clojurescriptPreflight.d.ts +26 -0
- package/dist/playground/clojurescriptPreflight.js +383 -0
- package/dist/playground/cobol.d.ts +46 -0
- package/dist/playground/cobol.js +703 -0
- package/dist/playground/d.d.ts +47 -0
- package/dist/playground/d.js +644 -0
- package/dist/playground/dOuterAssets.d.ts +16 -0
- package/dist/playground/dOuterAssets.js +163 -0
- package/dist/playground/dotnet.d.ts +99 -0
- package/dist/playground/dotnet.js +1131 -0
- package/dist/playground/duckdb.d.ts +36 -0
- package/dist/playground/duckdb.js +542 -0
- package/dist/playground/elixir.d.ts +18 -10
- package/dist/playground/elixir.js +630 -96
- package/dist/playground/elixirAssets.d.ts +6 -0
- package/dist/playground/elixirAssets.js +33 -0
- package/dist/playground/executionObservation.d.ts +22 -0
- package/dist/playground/executionObservation.js +65 -0
- package/dist/playground/forth.d.ts +5 -0
- package/dist/playground/forth.js +53 -0
- package/dist/playground/forthPreflight.d.ts +24 -0
- package/dist/playground/forthPreflight.js +198 -0
- package/dist/playground/fortran.d.ts +47 -0
- package/dist/playground/fortran.js +651 -0
- package/dist/playground/fortranAssets.d.ts +6 -0
- package/dist/playground/fortranAssets.js +27 -0
- package/dist/playground/gleam.d.ts +6 -0
- package/dist/playground/gleam.js +33 -0
- package/dist/playground/go.d.ts +17 -11
- package/dist/playground/go.js +376 -72
- package/dist/playground/goDebugInstrumentation.d.ts +1 -0
- package/dist/playground/goDebugInstrumentation.js +229 -0
- package/dist/playground/haskell.d.ts +44 -0
- package/dist/playground/haskell.js +678 -0
- package/dist/playground/haskellAssets.d.ts +24 -0
- package/dist/playground/haskellAssets.js +93 -0
- package/dist/playground/index.d.ts +1 -1
- package/dist/playground/index.js +360 -111
- package/dist/playground/j.d.ts +5 -0
- package/dist/playground/j.js +60 -0
- package/dist/playground/jPreflight.d.ts +26 -0
- package/dist/playground/jPreflight.js +372 -0
- package/dist/playground/janet.d.ts +5 -0
- package/dist/playground/janet.js +64 -0
- package/dist/playground/java.d.ts +24 -10
- package/dist/playground/java.js +706 -84
- package/dist/playground/javaSource.d.ts +5 -0
- package/dist/playground/javaSource.js +16 -0
- package/dist/playground/javaStdin.d.ts +1 -1
- package/dist/playground/javaStdin.js +13 -4
- package/dist/playground/julia.d.ts +5 -0
- package/dist/playground/julia.js +64 -0
- package/dist/playground/lfortran.d.ts +8 -0
- package/dist/playground/lfortran.js +30 -0
- package/dist/playground/lfortranAssets.d.ts +21 -0
- package/dist/playground/lfortranAssets.js +118 -0
- package/dist/playground/lisp.d.ts +45 -0
- package/dist/playground/lisp.js +640 -0
- package/dist/playground/lispAssets.d.ts +9 -0
- package/dist/playground/lispAssets.js +74 -0
- package/dist/playground/lldbManifest.d.ts +3 -0
- package/dist/playground/lldbManifest.js +155 -0
- package/dist/playground/lldbSession.d.ts +115 -0
- package/dist/playground/lldbSession.js +1347 -0
- package/dist/playground/loadingProgress.d.ts +16 -0
- package/dist/playground/loadingProgress.js +166 -0
- package/dist/playground/lua.d.ts +44 -0
- package/dist/playground/lua.js +630 -0
- package/dist/playground/nim.d.ts +5 -0
- package/dist/playground/nim.js +76 -0
- package/dist/playground/objectivec.d.ts +39 -0
- package/dist/playground/objectivec.js +288 -0
- package/dist/playground/ocaml.d.ts +28 -10
- package/dist/playground/ocaml.js +815 -253
- package/dist/playground/octave.d.ts +43 -0
- package/dist/playground/octave.js +783 -0
- package/dist/playground/options.d.ts +19 -40
- package/dist/playground/options.js +2 -1
- package/dist/playground/pascal.d.ts +5 -0
- package/dist/playground/pascal.js +60 -0
- package/dist/playground/perl.d.ts +5 -0
- package/dist/playground/perl.js +61 -0
- package/dist/playground/php.d.ts +44 -0
- package/dist/playground/php.js +665 -0
- package/dist/playground/prolog.d.ts +6 -0
- package/dist/playground/prolog.js +75 -0
- package/dist/playground/python.d.ts +20 -14
- package/dist/playground/python.js +445 -101
- package/dist/playground/pythonPackageLock.d.ts +6 -0
- package/dist/playground/pythonPackageLock.js +56 -0
- package/dist/playground/r.d.ts +44 -0
- package/dist/playground/r.js +637 -0
- package/dist/playground/ruby.d.ts +46 -0
- package/dist/playground/ruby.js +732 -0
- package/dist/playground/rubyAssets.d.ts +23 -0
- package/dist/playground/rubyAssets.js +68 -0
- package/dist/playground/rubyTestPreflight.d.ts +2 -0
- package/dist/playground/rubyTestPreflight.js +18 -0
- package/dist/playground/runtimeModule.d.ts +1 -0
- package/dist/playground/runtimeModule.js +5 -0
- package/dist/playground/rust.d.ts +44 -13
- package/dist/playground/rust.js +714 -76
- package/dist/playground/rustExecutableGraph.d.ts +85 -0
- package/dist/playground/rustExecutableGraph.js +946 -0
- package/dist/playground/rustWorkerLimits.d.ts +17 -0
- package/dist/playground/rustWorkerLimits.js +34 -0
- package/dist/playground/sandbox.d.ts +16 -10
- package/dist/playground/sharedBuffer.d.ts +6 -0
- package/dist/playground/sharedBuffer.js +12 -0
- package/dist/playground/sqlite.d.ts +38 -0
- package/dist/playground/sqlite.js +550 -0
- package/dist/playground/staticRuntimeModuleVersion.d.ts +1 -0
- package/dist/playground/staticRuntimeModuleVersion.js +2 -0
- package/dist/playground/staticRuntimePreflight.d.ts +13 -0
- package/dist/playground/staticRuntimePreflight.js +231 -0
- package/dist/playground/staticRuntimePreflightExecute.d.ts +8 -0
- package/dist/playground/staticRuntimePreflightExecute.js +66 -0
- package/dist/playground/staticRuntimePreflightProtocol.d.ts +68 -0
- package/dist/playground/staticRuntimePreflightProtocol.js +339 -0
- package/dist/playground/staticStdinRing.d.ts +45 -0
- package/dist/playground/staticStdinRing.js +158 -0
- package/dist/playground/staticWorkerRuntime.d.ts +154 -0
- package/dist/playground/staticWorkerRuntime.js +1917 -0
- package/dist/playground/stdinBuffer.d.ts +9 -7
- package/dist/playground/stdinBuffer.js +9 -18
- package/dist/playground/swift.d.ts +5 -0
- package/dist/playground/swift.js +17 -0
- package/dist/playground/tcl.d.ts +5 -0
- package/dist/playground/tcl.js +62 -0
- package/dist/playground/teavmConfig.d.ts +1 -1
- package/dist/playground/teavmConfig.js +2 -2
- package/dist/playground/tinygo.d.ts +48 -18
- package/dist/playground/tinygo.js +1202 -329
- package/dist/playground/tinygoExecutableGraph.d.ts +44 -0
- package/dist/playground/tinygoExecutableGraph.js +449 -0
- package/dist/playground/typescript.d.ts +55 -0
- package/dist/playground/typescript.js +924 -0
- package/dist/playground/wasm.d.ts +43 -0
- package/dist/playground/wasm.js +608 -0
- package/dist/playground/wasmAwkVersion.d.ts +59 -0
- package/dist/playground/wasmAwkVersion.js +31 -0
- package/dist/playground/wasmBashVersion.d.ts +63 -0
- package/dist/playground/wasmBashVersion.js +36 -0
- package/dist/playground/wasmBqnVersion.d.ts +24 -0
- package/dist/playground/wasmBqnVersion.js +24 -0
- package/dist/playground/wasmC3Version.d.ts +20 -0
- package/dist/playground/wasmC3Version.js +21 -0
- package/dist/playground/wasmClojureScriptVersion.d.ts +21 -0
- package/dist/playground/wasmClojureScriptVersion.js +21 -0
- package/dist/playground/wasmDIntegrity.d.ts +15 -0
- package/dist/playground/wasmDIntegrity.js +15 -0
- package/dist/playground/wasmDVersion.d.ts +1 -0
- package/dist/playground/wasmDVersion.js +1 -0
- package/dist/playground/wasmDebugVersion.d.ts +6 -0
- package/dist/playground/wasmDebugVersion.js +6 -0
- package/dist/playground/wasmDotnetVersion.d.ts +1 -0
- package/dist/playground/wasmDotnetVersion.js +1 -0
- package/dist/playground/wasmElixirVersion.d.ts +21 -1
- package/dist/playground/wasmElixirVersion.js +21 -1
- package/dist/playground/wasmForthVersion.d.ts +18 -0
- package/dist/playground/wasmForthVersion.js +18 -0
- package/dist/playground/wasmFortranExecutionAssets.d.ts +15 -0
- package/dist/playground/wasmFortranExecutionAssets.js +15 -0
- package/dist/playground/wasmFortranVersion.d.ts +1 -0
- package/dist/playground/wasmFortranVersion.js +1 -0
- package/dist/playground/wasmGleamVersion.d.ts +5 -0
- package/dist/playground/wasmGleamVersion.js +5 -0
- package/dist/playground/wasmGoVersion.d.ts +1 -1
- package/dist/playground/wasmGoVersion.js +1 -1
- package/dist/playground/wasmHaskellVersion.d.ts +1 -0
- package/dist/playground/wasmHaskellVersion.js +1 -0
- package/dist/playground/wasmJVersion.d.ts +24 -0
- package/dist/playground/wasmJVersion.js +24 -0
- package/dist/playground/wasmJanetVersion.d.ts +53 -0
- package/dist/playground/wasmJanetVersion.js +30 -0
- package/dist/playground/wasmJuliaVersion.d.ts +71 -0
- package/dist/playground/wasmJuliaVersion.js +39 -0
- package/dist/playground/wasmLfortranVersion.d.ts +28 -0
- package/dist/playground/wasmLfortranVersion.js +29 -0
- package/dist/playground/wasmLispVersion.d.ts +1 -0
- package/dist/playground/wasmLispVersion.js +1 -0
- package/dist/playground/wasmLuaVersion.d.ts +1 -0
- package/dist/playground/wasmLuaVersion.js +1 -0
- package/dist/playground/wasmNimVersion.d.ts +125 -0
- package/dist/playground/wasmNimVersion.js +66 -0
- package/dist/playground/wasmObjectiveCVersion.d.ts +27 -0
- package/dist/playground/wasmObjectiveCVersion.js +27 -0
- package/dist/playground/wasmOcamlVersion.d.ts +12 -1
- package/dist/playground/wasmOcamlVersion.js +12 -1
- package/dist/playground/wasmOctaveVersion.d.ts +1 -0
- package/dist/playground/wasmOctaveVersion.js +1 -0
- package/dist/playground/wasmPascalVersion.d.ts +61 -0
- package/dist/playground/wasmPascalVersion.js +34 -0
- package/dist/playground/wasmPerlVersion.d.ts +71 -0
- package/dist/playground/wasmPerlVersion.js +39 -0
- package/dist/playground/wasmPrologVersion.d.ts +31 -0
- package/dist/playground/wasmPrologVersion.js +31 -0
- package/dist/playground/wasmRVersion.d.ts +1 -0
- package/dist/playground/wasmRVersion.js +1 -0
- package/dist/playground/wasmRustVersion.d.ts +1306 -1
- package/dist/playground/wasmRustVersion.js +1458 -1
- package/dist/playground/wasmSwiftVersion.d.ts +1 -0
- package/dist/playground/wasmSwiftVersion.js +1 -0
- package/dist/playground/wasmTclVersion.d.ts +85 -0
- package/dist/playground/wasmTclVersion.js +46 -0
- package/dist/playground/wasmTinyGoVersion.d.ts +98 -1
- package/dist/playground/wasmTinyGoVersion.js +107 -1
- package/dist/playground/wasmTypeScriptVersion.d.ts +5 -0
- package/dist/playground/wasmTypeScriptVersion.js +5 -0
- package/dist/playground/wasmWatVersion.d.ts +1 -0
- package/dist/playground/wasmWatVersion.js +1 -0
- package/dist/playground/wasmZigVersion.d.ts +13 -0
- package/dist/playground/wasmZigVersion.js +13 -0
- package/dist/playground/wat.d.ts +44 -0
- package/dist/playground/wat.js +622 -0
- package/dist/playground/worker/assemblyscript.js +339 -0
- package/dist/playground/worker/assets.d.ts +7 -0
- package/dist/playground/worker/assets.js +288 -39
- package/dist/playground/worker/bash.js +338 -0
- package/dist/playground/worker/bashNestedBootstrap.d.ts +6 -0
- package/dist/playground/worker/bashNestedBootstrap.js +59 -0
- package/dist/playground/worker/bashRuntime.d.ts +89 -0
- package/dist/playground/worker/bashRuntime.js +982 -0
- package/dist/playground/worker/clang.js +92 -13
- package/dist/playground/worker/cobol.js +107 -0
- package/dist/playground/worker/d.js +199 -0
- package/dist/playground/worker/dotnet.js +141 -0
- package/dist/playground/worker/duckdb.d.ts +1 -0
- package/dist/playground/worker/duckdb.js +136 -0
- package/dist/playground/worker/elixir.js +307 -41
- package/dist/playground/worker/fortran.d.ts +1 -0
- package/dist/playground/worker/fortran.js +295 -0
- package/dist/playground/worker/go.js +246 -40
- package/dist/playground/worker/haskell.d.ts +7 -0
- package/dist/playground/worker/haskell.js +465 -0
- package/dist/playground/worker/java.js +59 -20
- package/dist/playground/worker/lisp.d.ts +1 -0
- package/dist/playground/worker/lisp.js +195 -0
- package/dist/playground/worker/lua.d.ts +1 -0
- package/dist/playground/worker/lua.js +163 -0
- package/dist/playground/worker/objectivec.d.ts +1 -0
- package/dist/playground/worker/objectivec.js +10 -0
- package/dist/playground/worker/ocaml.js +206 -58
- package/dist/playground/worker/php.d.ts +1 -0
- package/dist/playground/worker/php.js +261 -0
- package/dist/playground/worker/python.js +201 -44
- package/dist/playground/worker/r.d.ts +1 -0
- package/dist/playground/worker/r.js +192 -0
- package/dist/playground/worker/ruby.d.ts +1 -0
- package/dist/playground/worker/ruby.js +248 -0
- package/dist/playground/worker/runtimeAssetFetch.d.ts +15 -0
- package/dist/playground/worker/runtimeAssetFetch.js +375 -0
- package/dist/playground/worker/rust.js +546 -20
- package/dist/playground/worker/sqlite.d.ts +1 -0
- package/dist/playground/worker/sqlite.js +112 -0
- package/dist/playground/worker/staticRuntimePreflight.d.ts +1 -0
- package/dist/playground/worker/staticRuntimePreflight.js +56 -0
- package/dist/playground/worker/tinygo.js +34 -9
- package/dist/playground/worker/typescript.d.ts +1 -0
- package/dist/playground/worker/typescript.js +251 -0
- package/dist/playground/worker/wasm.d.ts +1 -0
- package/dist/playground/worker/wasm.js +273 -0
- package/dist/playground/worker/wat.d.ts +1 -0
- package/dist/playground/worker/wat.js +188 -0
- package/dist/playground/worker/zig.d.ts +8 -0
- package/dist/playground/worker/zig.js +578 -0
- package/dist/playground/workerProgress.d.ts +15 -0
- package/dist/playground/workerProgress.js +72 -0
- package/dist/playground/workerSession.d.ts +28 -0
- package/dist/playground/workerSession.js +164 -0
- package/dist/playground/zig.d.ts +46 -0
- package/dist/playground/zig.js +690 -0
- package/dist/playground/zigAssets.d.ts +6 -0
- package/dist/playground/zigAssets.js +49 -0
- package/package.json +234 -105
- package/dist/clang/app.d.ts +0 -75
- package/dist/clang/app.js +0 -744
- package/dist/clang/apply.d.ts +0 -2
- package/dist/clang/apply.js +0 -11
- package/dist/clang/color.d.ts +0 -3
- package/dist/clang/color.js +0 -3
- package/dist/clang/encode.d.ts +0 -4
- package/dist/clang/encode.js +0 -20
- package/dist/clang/error.d.ts +0 -14
- package/dist/clang/error.js +0 -27
- package/dist/clang/gccCompat.d.ts +0 -15
- package/dist/clang/gccCompat.js +0 -767
- package/dist/clang/index.d.ts +0 -85
- package/dist/clang/index.js +0 -1077
- package/dist/clang/memory/index.d.ts +0 -4
- package/dist/clang/memory/index.js +0 -4
- package/dist/clang/memory/memFs.d.ts +0 -35
- package/dist/clang/memory/memFs.js +0 -132
- package/dist/clang/memory/memory.d.ts +0 -22
- package/dist/clang/memory/memory.js +0 -73
- package/dist/clang/memory/tar.d.ts +0 -2
- package/dist/clang/memory/tar.js +0 -59
- package/dist/clang/url.d.ts +0 -4
- package/dist/clang/url.js +0 -5
- package/dist/clang/wasm.d.ts +0 -4
- package/dist/clang/wasm.js +0 -50
- package/dist/clangd/config.d.ts +0 -18
- package/dist/clangd/config.js +0 -14
- package/dist/clangd/jsonStream.d.ts +0 -9
- package/dist/clangd/jsonStream.js +0 -48
- package/dist/clangd/session.d.ts +0 -18
- package/dist/clangd/session.js +0 -112
- package/dist/clangd/worker.js +0 -131
- package/dist/debug/controller.svelte.d.ts +0 -43
- package/dist/debug/controller.svelte.js +0 -268
- package/dist/debug/editor/index.d.ts +0 -2
- package/dist/debug/editor/index.js +0 -1
- package/dist/debug/editor/monaco.d.ts +0 -26
- package/dist/debug/editor/monaco.js +0 -128
- package/dist/debug/expression.d.ts +0 -26
- package/dist/debug/expression.js +0 -547
- package/dist/debug/index.d.ts +0 -8
- package/dist/debug/index.js +0 -5
- package/dist/debug/language/cpp.d.ts +0 -2
- package/dist/debug/language/cpp.js +0 -7
- package/dist/debug/language/index.d.ts +0 -3
- package/dist/debug/language/index.js +0 -2
- package/dist/debug/language/python.d.ts +0 -2
- package/dist/debug/language/python.js +0 -14
- package/dist/debug/language/types.d.ts +0 -6
- package/dist/debug/locals.d.ts +0 -2
- package/dist/debug/locals.js +0 -8
- package/dist/lsp/cpp/server.d.ts +0 -2
- package/dist/lsp/cpp/server.js +0 -68
- package/dist/lsp/index.d.ts +0 -5
- package/dist/lsp/index.js +0 -4
- package/dist/lsp/python/main.worker.js +0 -92
- package/dist/lsp/python/package/arcturus_python_lsp/__init__.py +0 -3
- package/dist/lsp/python/package/arcturus_python_lsp/server.py +0 -462
- package/dist/lsp/python/server.d.ts +0 -2
- package/dist/lsp/python/server.js +0 -54
- package/dist/lsp/registry.d.ts +0 -2
- package/dist/lsp/registry.js +0 -12
- package/dist/lsp/runtime.d.ts +0 -5
- package/dist/lsp/runtime.js +0 -31
- package/dist/lsp/types.d.ts +0 -17
- package/dist/terminal/Terminal.svelte +0 -422
- package/dist/terminal/Terminal.svelte.d.ts +0 -26
- package/dist/terminal/index.d.ts +0 -7
- package/dist/terminal/index.js +0 -5
- package/dist/terminal/plugin/index.d.ts +0 -9
- package/dist/terminal/plugin/index.js +0 -19
- package/dist/terminal/theme.d.ts +0 -49
- package/dist/terminal/theme.js +0 -49
- package/dist/terminal/types.d.ts +0 -18
- package/dist/utils/vscodeJsonrpcBrowser.d.ts +0 -5
- package/dist/utils/vscodeJsonrpcBrowser.js +0 -4
- /package/dist/{clangd/worker.d.ts → playground/worker/assemblyscript.d.ts} +0 -0
- /package/dist/{debug/language/types.js → playground/worker/bash.d.ts} +0 -0
- /package/dist/{lsp/python/main.worker.d.ts → playground/worker/cobol.d.ts} +0 -0
- /package/dist/{lsp/types.js → playground/worker/d.d.ts} +0 -0
- /package/dist/{terminal/types.js → playground/worker/dotnet.d.ts} +0 -0
|
@@ -0,0 +1,1347 @@
|
|
|
1
|
+
import { ProtocolError } from '@wasm-idle/core';
|
|
2
|
+
import { createBrowserLldbSession, DapProtocolError } from '@wasm-idle/llvm-core/debug';
|
|
3
|
+
import { loadVerifiedDebugRuntimeManifest } from './lldbManifest';
|
|
4
|
+
const MAX_DEBUG_MEMORY_BYTES = 256;
|
|
5
|
+
const MAX_DEBUG_IDENTIFIER_CODE_UNITS = 4096;
|
|
6
|
+
const MAX_DEBUG_DATA_BREAKPOINTS = 256;
|
|
7
|
+
function pauseReason(reason, command) {
|
|
8
|
+
if (reason === 'breakpoint')
|
|
9
|
+
return 'breakpoint';
|
|
10
|
+
if (reason === 'data breakpoint')
|
|
11
|
+
return 'dataBreakpoint';
|
|
12
|
+
if (reason === 'entry')
|
|
13
|
+
return 'entry';
|
|
14
|
+
if (reason === 'pause')
|
|
15
|
+
return 'pause';
|
|
16
|
+
if (command === 'nextLine')
|
|
17
|
+
return 'nextLine';
|
|
18
|
+
if (command === 'stepOut')
|
|
19
|
+
return 'stepOut';
|
|
20
|
+
return 'step';
|
|
21
|
+
}
|
|
22
|
+
function invalidDapPayload(subject, path, expectation) {
|
|
23
|
+
throw new ProtocolError(`Invalid LLDB DAP ${subject} at ${path}: ${expectation}.`);
|
|
24
|
+
}
|
|
25
|
+
function invalidDapResponse(command, path, expectation) {
|
|
26
|
+
invalidDapPayload(`${command} response`, path, expectation);
|
|
27
|
+
}
|
|
28
|
+
function assertDapRecord(value, command, path) {
|
|
29
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
30
|
+
invalidDapResponse(command, path, 'expected an object');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function assertDapString(value, command, path) {
|
|
34
|
+
if (typeof value !== 'string')
|
|
35
|
+
invalidDapResponse(command, path, 'expected a string');
|
|
36
|
+
}
|
|
37
|
+
function assertDapBoolean(value, command, path) {
|
|
38
|
+
if (typeof value !== 'boolean')
|
|
39
|
+
invalidDapResponse(command, path, 'expected a boolean');
|
|
40
|
+
}
|
|
41
|
+
function assertDapPositiveSafeInteger(value, subject, path) {
|
|
42
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 1) {
|
|
43
|
+
invalidDapPayload(subject, path, 'expected a positive safe integer');
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
function assertDapNonNegativeSafeInteger(value, command, path) {
|
|
47
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0) {
|
|
48
|
+
invalidDapResponse(command, path, 'expected a non-negative safe integer');
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function dapResponseCollection(response, command, path) {
|
|
52
|
+
assertDapRecord(response, command, 'body');
|
|
53
|
+
const collection = response[path];
|
|
54
|
+
if (!Array.isArray(collection))
|
|
55
|
+
invalidDapResponse(command, path, 'expected an array');
|
|
56
|
+
return collection;
|
|
57
|
+
}
|
|
58
|
+
function dapOptionalNonNegativeSafeInteger(record, property, command, path) {
|
|
59
|
+
const value = record[property];
|
|
60
|
+
if (value === undefined)
|
|
61
|
+
return undefined;
|
|
62
|
+
assertDapNonNegativeSafeInteger(value, command, `${path}.${property}`);
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
function snapshotBreakpointLines(lines) {
|
|
66
|
+
if (lines.some((line) => !Number.isSafeInteger(line) || line < 1)) {
|
|
67
|
+
throw new RangeError('LLDB breakpoint lines must be positive safe integers.');
|
|
68
|
+
}
|
|
69
|
+
return [...lines];
|
|
70
|
+
}
|
|
71
|
+
function assertPositiveSafeIntegerArgument(value, name) {
|
|
72
|
+
if (!Number.isSafeInteger(value) || value < 1) {
|
|
73
|
+
throw new RangeError(`${name} must be a positive safe integer.`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function assertNonNegativeSafeIntegerArgument(value, name) {
|
|
77
|
+
if (!Number.isSafeInteger(value) || value < 0) {
|
|
78
|
+
throw new RangeError(`${name} must be a non-negative safe integer.`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function assertBoundedNonEmptyStringArgument(value, name) {
|
|
82
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
83
|
+
throw new TypeError(`${name} must be a non-empty string.`);
|
|
84
|
+
}
|
|
85
|
+
if (value.length > MAX_DEBUG_IDENTIFIER_CODE_UNITS) {
|
|
86
|
+
throw new RangeError(`${name} must not exceed ${MAX_DEBUG_IDENTIFIER_CODE_UNITS} UTF-16 code units.`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
function assertOptionalBooleanArgument(value, name) {
|
|
90
|
+
if (value !== undefined && typeof value !== 'boolean') {
|
|
91
|
+
throw new TypeError(`${name} must be a boolean.`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
export class LldbSandboxSession {
|
|
95
|
+
options;
|
|
96
|
+
session;
|
|
97
|
+
startupAbortController;
|
|
98
|
+
activeThreadId = 1;
|
|
99
|
+
activeFrameId;
|
|
100
|
+
stoppedFrames = [];
|
|
101
|
+
supportsValueFormatting = false;
|
|
102
|
+
command = null;
|
|
103
|
+
pauseRequested = false;
|
|
104
|
+
pauseRequestVersion = 0;
|
|
105
|
+
targetStopped = false;
|
|
106
|
+
entryPhase = 'done';
|
|
107
|
+
entrySetup;
|
|
108
|
+
stopped = false;
|
|
109
|
+
stateVersion = 0;
|
|
110
|
+
completionResolve;
|
|
111
|
+
completionReject;
|
|
112
|
+
sessionDisposal;
|
|
113
|
+
pendingInput = [];
|
|
114
|
+
pendingEof = false;
|
|
115
|
+
inputReady = false;
|
|
116
|
+
lifecycleVersion = 0;
|
|
117
|
+
initialized = false;
|
|
118
|
+
supportsEvaluateExpressions = false;
|
|
119
|
+
supportsReadMemory = false;
|
|
120
|
+
supportsWriteMemory = false;
|
|
121
|
+
supportsDataBreakpoints = false;
|
|
122
|
+
breakpointVersion = 0;
|
|
123
|
+
scopeRequestVersion = 0;
|
|
124
|
+
dapExitCode = null;
|
|
125
|
+
breakpointsBySource = new Map();
|
|
126
|
+
breakpointRequestVersions = new Map();
|
|
127
|
+
sourceContentSha256ByPath = new Map();
|
|
128
|
+
constructor(options) {
|
|
129
|
+
this.options = options;
|
|
130
|
+
const sourceBreakpoints = options.sourceBreakpoints?.length
|
|
131
|
+
? options.sourceBreakpoints
|
|
132
|
+
: [{ sourcePath: options.sourcePath, lines: options.breakpoints }];
|
|
133
|
+
for (const { sourcePath, lines } of sourceBreakpoints) {
|
|
134
|
+
this.breakpointsBySource.set(sourcePath, snapshotBreakpointLines(lines));
|
|
135
|
+
}
|
|
136
|
+
for (const source of options.artifact.sources) {
|
|
137
|
+
if (source.contentSha256) {
|
|
138
|
+
this.sourceContentSha256ByPath.set(source.path, source.contentSha256);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async start() {
|
|
143
|
+
if (this.session || this.startupAbortController) {
|
|
144
|
+
throw new Error('LLDB sandbox session is already running.');
|
|
145
|
+
}
|
|
146
|
+
const previousDisposal = this.sessionDisposal;
|
|
147
|
+
const lifecycleVersion = ++this.lifecycleVersion;
|
|
148
|
+
const startupAbortController = new AbortController();
|
|
149
|
+
this.startupAbortController = startupAbortController;
|
|
150
|
+
this.targetStopped = false;
|
|
151
|
+
this.stopped = false;
|
|
152
|
+
this.entryPhase =
|
|
153
|
+
this.options.pauseOnEntry && this.options.pauseAtMain ? 'initial' : 'done';
|
|
154
|
+
this.pauseRequested = false;
|
|
155
|
+
this.initialized = false;
|
|
156
|
+
this.dapExitCode = null;
|
|
157
|
+
let rejectCompletion;
|
|
158
|
+
const completion = new Promise((resolve, reject) => {
|
|
159
|
+
this.completionResolve = resolve;
|
|
160
|
+
this.completionReject = reject;
|
|
161
|
+
rejectCompletion = reject;
|
|
162
|
+
});
|
|
163
|
+
void completion.catch(() => undefined);
|
|
164
|
+
if (previousDisposal) {
|
|
165
|
+
try {
|
|
166
|
+
await previousDisposal;
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
if (lifecycleVersion !== this.lifecycleVersion)
|
|
170
|
+
return completion;
|
|
171
|
+
if (this.startupAbortController === startupAbortController) {
|
|
172
|
+
this.startupAbortController = undefined;
|
|
173
|
+
}
|
|
174
|
+
this.stopped = true;
|
|
175
|
+
rejectCompletion(error instanceof Error
|
|
176
|
+
? error
|
|
177
|
+
: new Error('Unable to dispose the previous LLDB debug session.'));
|
|
178
|
+
return completion;
|
|
179
|
+
}
|
|
180
|
+
if (lifecycleVersion !== this.lifecycleVersion ||
|
|
181
|
+
startupAbortController.signal.aborted) {
|
|
182
|
+
return completion;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
let manifest;
|
|
186
|
+
try {
|
|
187
|
+
manifest = await loadVerifiedDebugRuntimeManifest(this.options.manifestUrl, this.options.manifestReceipt, this.options.fetchImpl ?? fetch, startupAbortController.signal);
|
|
188
|
+
}
|
|
189
|
+
catch (error) {
|
|
190
|
+
if (lifecycleVersion !== this.lifecycleVersion)
|
|
191
|
+
return completion;
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
194
|
+
finally {
|
|
195
|
+
if (this.startupAbortController === startupAbortController) {
|
|
196
|
+
this.startupAbortController = undefined;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
this.supportsEvaluateExpressions =
|
|
200
|
+
manifest.debugger?.capabilities?.evaluateExpressions === true;
|
|
201
|
+
const manifestSupportsReadMemory = manifest.debugger?.capabilities?.readMemory === true;
|
|
202
|
+
const manifestSupportsWriteMemory = manifest.debugger?.capabilities?.writeMemory === true;
|
|
203
|
+
this.supportsReadMemory = false;
|
|
204
|
+
this.supportsWriteMemory = false;
|
|
205
|
+
const manifestSupportsDataBreakpoints = manifest.debugger?.capabilities?.dataBreakpoints === true;
|
|
206
|
+
if (lifecycleVersion !== this.lifecycleVersion)
|
|
207
|
+
return completion;
|
|
208
|
+
const artifactCompiler = this.options.artifact.descriptor?.compiler;
|
|
209
|
+
if (artifactCompiler?.name === 'clang' &&
|
|
210
|
+
artifactCompiler.revision &&
|
|
211
|
+
artifactCompiler.revision !== manifest.debugger.lldb.llvmRevision) {
|
|
212
|
+
throw new Error(`Compiler/LLDB revision mismatch: artifact ${artifactCompiler.revision}, runtime ${manifest.debugger.lldb.llvmRevision}.`);
|
|
213
|
+
}
|
|
214
|
+
if (artifactCompiler?.name === 'rustc' &&
|
|
215
|
+
artifactCompiler.llvmVersion &&
|
|
216
|
+
artifactCompiler.llvmVersion !== manifest.debugger.lldb.llvmVersion) {
|
|
217
|
+
throw new Error(`Rust LLVM/LLDB version mismatch: artifact ${artifactCompiler.llvmVersion}, runtime ${manifest.debugger.lldb.llvmVersion}.`);
|
|
218
|
+
}
|
|
219
|
+
let session;
|
|
220
|
+
const sourceBreakpoints = Array.from(this.breakpointsBySource, ([sourcePath, lines]) => ({
|
|
221
|
+
sourcePath,
|
|
222
|
+
lines: [...lines]
|
|
223
|
+
}));
|
|
224
|
+
const configuredBreakpointVersion = this.breakpointVersion;
|
|
225
|
+
session = createBrowserLldbSession({
|
|
226
|
+
manifest,
|
|
227
|
+
runtimeBaseUrl: this.options.runtimeBaseUrl,
|
|
228
|
+
module: this.options.artifact.bytes,
|
|
229
|
+
moduleSha256: this.options.artifact.descriptor?.moduleSha256,
|
|
230
|
+
sources: this.options.artifact.sources,
|
|
231
|
+
breakpoints: sourceBreakpoints.map(({ sourcePath, lines }) => ({
|
|
232
|
+
source: { path: sourcePath },
|
|
233
|
+
lines
|
|
234
|
+
})),
|
|
235
|
+
launch: {
|
|
236
|
+
program: '/workspace/program.wasm',
|
|
237
|
+
stopOnEntry: this.options.pauseOnEntry,
|
|
238
|
+
args: this.options.programArgs
|
|
239
|
+
},
|
|
240
|
+
fetchImpl: this.options.fetchImpl,
|
|
241
|
+
onOutput: (_channel, output) => this.options.onOutput(output),
|
|
242
|
+
onLifecycle: (event) => {
|
|
243
|
+
if (lifecycleVersion !== this.lifecycleVersion || this.session !== session) {
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (event.type === 'worker-error') {
|
|
247
|
+
this.fail(new Error(`${event.worker} debug worker failed: ${event.message}`));
|
|
248
|
+
}
|
|
249
|
+
else {
|
|
250
|
+
this.finish(event.exitCode ?? this.dapExitCode);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
if (lifecycleVersion !== this.lifecycleVersion) {
|
|
255
|
+
await session.dispose();
|
|
256
|
+
return completion;
|
|
257
|
+
}
|
|
258
|
+
this.session = session;
|
|
259
|
+
let resolveEntrySetup;
|
|
260
|
+
this.entrySetup = {
|
|
261
|
+
ready: new Promise((resolve) => {
|
|
262
|
+
resolveEntrySetup = resolve;
|
|
263
|
+
}),
|
|
264
|
+
resolve: () => resolveEntrySetup()
|
|
265
|
+
};
|
|
266
|
+
session.onEvent((event) => {
|
|
267
|
+
if (lifecycleVersion === this.lifecycleVersion && this.session === session) {
|
|
268
|
+
try {
|
|
269
|
+
this.handleDapEvent(event);
|
|
270
|
+
}
|
|
271
|
+
catch (error) {
|
|
272
|
+
if (!(error instanceof ProtocolError))
|
|
273
|
+
throw error;
|
|
274
|
+
this.fail(error);
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
});
|
|
278
|
+
try {
|
|
279
|
+
const capabilities = await session.initialize();
|
|
280
|
+
if (lifecycleVersion !== this.lifecycleVersion || this.session !== session) {
|
|
281
|
+
await session.dispose();
|
|
282
|
+
return completion;
|
|
283
|
+
}
|
|
284
|
+
this.supportsReadMemory =
|
|
285
|
+
manifestSupportsReadMemory && capabilities.supportsReadMemoryRequest === true;
|
|
286
|
+
this.supportsWriteMemory =
|
|
287
|
+
manifestSupportsWriteMemory && capabilities.supportsWriteMemoryRequest === true;
|
|
288
|
+
this.supportsDataBreakpoints =
|
|
289
|
+
manifestSupportsDataBreakpoints && capabilities.supportsDataBreakpoints === true;
|
|
290
|
+
this.supportsValueFormatting = capabilities.supportsValueFormattingOptions === true;
|
|
291
|
+
this.initialized = true;
|
|
292
|
+
if (configuredBreakpointVersion === this.breakpointVersion) {
|
|
293
|
+
for (const { sourcePath, lines } of sourceBreakpoints) {
|
|
294
|
+
this.publishResolvedBreakpoints(session.getResolvedBreakpoints(sourcePath), lines, sourcePath);
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
else {
|
|
298
|
+
for (const [sourcePath, lines] of this.breakpointsBySource) {
|
|
299
|
+
await this.setBreakpoints(lines, sourcePath);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// Startup breakpoint edits must reach LLDB before automatic source entry. Do not
|
|
303
|
+
// wait for stdin to drain: a full input queue needs the guest to run first.
|
|
304
|
+
resolveEntrySetup();
|
|
305
|
+
this.inputReady = true;
|
|
306
|
+
if (this.options.stdin !== undefined) {
|
|
307
|
+
this.pendingInput.push(this.options.stdin);
|
|
308
|
+
this.pendingEof = true;
|
|
309
|
+
}
|
|
310
|
+
await this.flushInput(session, lifecycleVersion);
|
|
311
|
+
}
|
|
312
|
+
catch (error) {
|
|
313
|
+
if (lifecycleVersion === this.lifecycleVersion &&
|
|
314
|
+
this.stopped &&
|
|
315
|
+
this.session !== session) {
|
|
316
|
+
return completion;
|
|
317
|
+
}
|
|
318
|
+
if (lifecycleVersion !== this.lifecycleVersion) {
|
|
319
|
+
await session.dispose();
|
|
320
|
+
return completion;
|
|
321
|
+
}
|
|
322
|
+
if (this.session === session) {
|
|
323
|
+
this.fail(this.asProtocolError(error) ??
|
|
324
|
+
(error instanceof Error
|
|
325
|
+
? error
|
|
326
|
+
: new Error('Unable to initialize the LLDB debug session.')));
|
|
327
|
+
return completion;
|
|
328
|
+
}
|
|
329
|
+
await session.dispose();
|
|
330
|
+
throw error;
|
|
331
|
+
}
|
|
332
|
+
finally {
|
|
333
|
+
resolveEntrySetup();
|
|
334
|
+
}
|
|
335
|
+
return completion;
|
|
336
|
+
}
|
|
337
|
+
write(input) {
|
|
338
|
+
this.pendingInput.push(input);
|
|
339
|
+
this.pendingEof = false;
|
|
340
|
+
const session = this.session;
|
|
341
|
+
const lifecycleVersion = this.lifecycleVersion;
|
|
342
|
+
return this.observeInputFlush(this.flushInput(session, lifecycleVersion), session, lifecycleVersion);
|
|
343
|
+
}
|
|
344
|
+
eof() {
|
|
345
|
+
this.pendingEof = true;
|
|
346
|
+
const session = this.session;
|
|
347
|
+
const lifecycleVersion = this.lifecycleVersion;
|
|
348
|
+
return this.observeInputFlush(this.flushInput(session, lifecycleVersion), session, lifecycleVersion);
|
|
349
|
+
}
|
|
350
|
+
async debugCommand(command) {
|
|
351
|
+
const session = this.requireSession();
|
|
352
|
+
this.targetStopped = false;
|
|
353
|
+
this.command = command;
|
|
354
|
+
this.pauseRequested = false;
|
|
355
|
+
const dapCommand = command === 'stepInto'
|
|
356
|
+
? 'stepIn'
|
|
357
|
+
: command === 'nextLine'
|
|
358
|
+
? 'next'
|
|
359
|
+
: command === 'stepOut'
|
|
360
|
+
? 'stepOut'
|
|
361
|
+
: 'continue';
|
|
362
|
+
const stateVersion = ++this.stateVersion;
|
|
363
|
+
const request = session.request(dapCommand, { threadId: this.activeThreadId }, { responseTimeoutMs: null });
|
|
364
|
+
this.publishActiveDebugEvent({ type: 'resume', command });
|
|
365
|
+
void request.catch((error) => {
|
|
366
|
+
if (this.session !== session || this.stateVersion !== stateVersion)
|
|
367
|
+
return;
|
|
368
|
+
this.fail(error instanceof Error
|
|
369
|
+
? error
|
|
370
|
+
: new Error(`Unable to send the LLDB ${dapCommand} request.`));
|
|
371
|
+
});
|
|
372
|
+
}
|
|
373
|
+
async pause() {
|
|
374
|
+
const session = this.requireSession();
|
|
375
|
+
const requestVersion = ++this.pauseRequestVersion;
|
|
376
|
+
this.pauseRequested = true;
|
|
377
|
+
try {
|
|
378
|
+
await session.request('pause', {
|
|
379
|
+
threadId: this.activeThreadId
|
|
380
|
+
});
|
|
381
|
+
}
|
|
382
|
+
catch (error) {
|
|
383
|
+
if (this.session !== session ||
|
|
384
|
+
this.pauseRequestVersion !== requestVersion ||
|
|
385
|
+
!this.pauseRequested) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
this.pauseRequested = false;
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
async setBreakpoints(lines, sourcePath = this.options.sourcePath) {
|
|
393
|
+
const requestedLines = snapshotBreakpointLines(lines);
|
|
394
|
+
this.breakpointsBySource.set(sourcePath, requestedLines);
|
|
395
|
+
this.breakpointVersion += 1;
|
|
396
|
+
const requestVersion = (this.breakpointRequestVersions.get(sourcePath) ?? 0) + 1;
|
|
397
|
+
this.breakpointRequestVersions.set(sourcePath, requestVersion);
|
|
398
|
+
if (!this.session || !this.initialized)
|
|
399
|
+
return;
|
|
400
|
+
const session = this.requireSession();
|
|
401
|
+
let breakpoints;
|
|
402
|
+
try {
|
|
403
|
+
breakpoints = await session.setBreakpoints({ path: sourcePath }, requestedLines);
|
|
404
|
+
}
|
|
405
|
+
catch (error) {
|
|
406
|
+
if (this.session !== session ||
|
|
407
|
+
this.breakpointRequestVersions.get(sourcePath) !== requestVersion) {
|
|
408
|
+
return;
|
|
409
|
+
}
|
|
410
|
+
this.rethrowProtocolError(error);
|
|
411
|
+
throw error;
|
|
412
|
+
}
|
|
413
|
+
if (this.session !== session ||
|
|
414
|
+
this.breakpointRequestVersions.get(sourcePath) !== requestVersion) {
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
this.publishResolvedBreakpoints(breakpoints, requestedLines, sourcePath);
|
|
418
|
+
}
|
|
419
|
+
async evaluate(expression) {
|
|
420
|
+
if (!this.supportsEvaluateExpressions || !this.activeFrameId)
|
|
421
|
+
return '?';
|
|
422
|
+
const session = this.requireSession();
|
|
423
|
+
const stateVersion = this.stateVersion;
|
|
424
|
+
const scopeRequestVersion = this.scopeRequestVersion;
|
|
425
|
+
const frameId = this.activeFrameId;
|
|
426
|
+
try {
|
|
427
|
+
const response = await session.request('evaluate', {
|
|
428
|
+
expression,
|
|
429
|
+
frameId,
|
|
430
|
+
context: 'watch'
|
|
431
|
+
});
|
|
432
|
+
if (!this.isCurrentValueRequest(session, stateVersion, scopeRequestVersion)) {
|
|
433
|
+
return '?';
|
|
434
|
+
}
|
|
435
|
+
assertDapRecord(response, 'evaluate', 'body');
|
|
436
|
+
assertDapString(response.result, 'evaluate', 'result');
|
|
437
|
+
assertDapNonNegativeSafeInteger(response.variablesReference, 'evaluate', 'variablesReference');
|
|
438
|
+
return response.result;
|
|
439
|
+
}
|
|
440
|
+
catch (error) {
|
|
441
|
+
if (!this.isCurrentValueRequest(session, stateVersion, scopeRequestVersion)) {
|
|
442
|
+
return '?';
|
|
443
|
+
}
|
|
444
|
+
this.rethrowProtocolError(error);
|
|
445
|
+
return '?';
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
async variables(variablesReference, start, count) {
|
|
449
|
+
assertPositiveSafeIntegerArgument(variablesReference, 'variablesReference');
|
|
450
|
+
if (start !== undefined)
|
|
451
|
+
assertNonNegativeSafeIntegerArgument(start, 'start');
|
|
452
|
+
if (count !== undefined)
|
|
453
|
+
assertNonNegativeSafeIntegerArgument(count, 'count');
|
|
454
|
+
const session = this.requireSession();
|
|
455
|
+
const stateVersion = this.stateVersion;
|
|
456
|
+
const scopeRequestVersion = this.scopeRequestVersion;
|
|
457
|
+
try {
|
|
458
|
+
const response = await session.request('variables', {
|
|
459
|
+
variablesReference,
|
|
460
|
+
...(start === undefined ? {} : { start }),
|
|
461
|
+
...(count === undefined ? {} : { count })
|
|
462
|
+
});
|
|
463
|
+
if (!this.isCurrentValueRequest(session, stateVersion, scopeRequestVersion)) {
|
|
464
|
+
return [];
|
|
465
|
+
}
|
|
466
|
+
return dapResponseCollection(response, 'variables', 'variables').map((variable, index) => {
|
|
467
|
+
const path = `variables[${index}]`;
|
|
468
|
+
assertDapRecord(variable, 'variables', path);
|
|
469
|
+
assertDapString(variable.name, 'variables', `${path}.name`);
|
|
470
|
+
assertDapString(variable.value, 'variables', `${path}.value`);
|
|
471
|
+
assertDapNonNegativeSafeInteger(variable.variablesReference, 'variables', `${path}.variablesReference`);
|
|
472
|
+
const type = variable.type;
|
|
473
|
+
if (type !== undefined)
|
|
474
|
+
assertDapString(type, 'variables', `${path}.type`);
|
|
475
|
+
const evaluateName = variable.evaluateName;
|
|
476
|
+
if (evaluateName !== undefined) {
|
|
477
|
+
assertDapString(evaluateName, 'variables', `${path}.evaluateName`);
|
|
478
|
+
}
|
|
479
|
+
const memoryReference = variable.memoryReference;
|
|
480
|
+
if (memoryReference !== undefined) {
|
|
481
|
+
assertDapString(memoryReference, 'variables', `${path}.memoryReference`);
|
|
482
|
+
}
|
|
483
|
+
const namedVariables = dapOptionalNonNegativeSafeInteger(variable, 'namedVariables', 'variables', path);
|
|
484
|
+
const indexedVariables = dapOptionalNonNegativeSafeInteger(variable, 'indexedVariables', 'variables', path);
|
|
485
|
+
return {
|
|
486
|
+
name: variable.name,
|
|
487
|
+
value: variable.value,
|
|
488
|
+
type,
|
|
489
|
+
...(evaluateName === undefined ? {} : { evaluateName }),
|
|
490
|
+
variablesReference: variable.variablesReference,
|
|
491
|
+
memoryReference,
|
|
492
|
+
...(namedVariables === undefined ? {} : { namedVariables }),
|
|
493
|
+
...(indexedVariables === undefined ? {} : { indexedVariables })
|
|
494
|
+
};
|
|
495
|
+
});
|
|
496
|
+
}
|
|
497
|
+
catch (error) {
|
|
498
|
+
if (!this.isCurrentValueRequest(session, stateVersion, scopeRequestVersion)) {
|
|
499
|
+
return [];
|
|
500
|
+
}
|
|
501
|
+
this.rethrowProtocolError(error);
|
|
502
|
+
throw error;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
/** Ask the adapter to format one stopped frame, without changing evaluation selection. */
|
|
506
|
+
async formattedFrameName(frameId) {
|
|
507
|
+
assertPositiveSafeIntegerArgument(frameId, 'frameId');
|
|
508
|
+
if (!this.targetStopped || !this.supportsValueFormatting || !this.activeThreadId)
|
|
509
|
+
return null;
|
|
510
|
+
const index = this.stoppedFrames.findIndex((frame) => frame.id === frameId);
|
|
511
|
+
if (index < 0)
|
|
512
|
+
return null;
|
|
513
|
+
const session = this.requireSession();
|
|
514
|
+
const version = this.stateVersion;
|
|
515
|
+
try {
|
|
516
|
+
const response = await session.request('stackTrace', {
|
|
517
|
+
threadId: this.activeThreadId,
|
|
518
|
+
startFrame: index,
|
|
519
|
+
levels: 1,
|
|
520
|
+
format: {
|
|
521
|
+
parameters: true,
|
|
522
|
+
parameterNames: true,
|
|
523
|
+
parameterValues: true,
|
|
524
|
+
parameterTypes: false,
|
|
525
|
+
line: false,
|
|
526
|
+
module: false
|
|
527
|
+
}
|
|
528
|
+
});
|
|
529
|
+
if (!this.isCurrentValueRequest(session, version))
|
|
530
|
+
return null;
|
|
531
|
+
const frames = dapResponseCollection(response, 'stackTrace', 'stackFrames');
|
|
532
|
+
if (!frames.length)
|
|
533
|
+
return null;
|
|
534
|
+
const frame = frames[0];
|
|
535
|
+
assertDapRecord(frame, 'stackTrace', 'stackFrames[0]');
|
|
536
|
+
assertDapPositiveSafeInteger(frame.id, 'stackTrace', 'stackFrames[0].id');
|
|
537
|
+
assertDapString(frame.name, 'stackTrace', 'stackFrames[0].name');
|
|
538
|
+
if (frame.id !== frameId || frame.name === this.stoppedFrames[index]?.name)
|
|
539
|
+
return null;
|
|
540
|
+
return frame.name.length > 512 ? frame.name.slice(0, 511) + '…' : frame.name;
|
|
541
|
+
}
|
|
542
|
+
catch (error) {
|
|
543
|
+
if (!this.isCurrentValueRequest(session, version))
|
|
544
|
+
return null;
|
|
545
|
+
this.rethrowProtocolError(error);
|
|
546
|
+
throw error;
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
/** Scope metadata lookup does not select a frame or retire other value requests. */
|
|
550
|
+
async frameScopes(frameId) {
|
|
551
|
+
assertPositiveSafeIntegerArgument(frameId, 'frameId');
|
|
552
|
+
const session = this.requireSession();
|
|
553
|
+
const stateVersion = this.stateVersion;
|
|
554
|
+
try {
|
|
555
|
+
const scopes = await this.requestScopes(session, frameId);
|
|
556
|
+
return this.isCurrentValueRequest(session, stateVersion) ? scopes : [];
|
|
557
|
+
}
|
|
558
|
+
catch (error) {
|
|
559
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
560
|
+
return [];
|
|
561
|
+
this.rethrowProtocolError(error);
|
|
562
|
+
throw error;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
/** Select the evaluation frame, keeping the existing public debugScopes contract. */
|
|
566
|
+
async scopes(frameId) {
|
|
567
|
+
assertPositiveSafeIntegerArgument(frameId, 'frameId');
|
|
568
|
+
const session = this.requireSession();
|
|
569
|
+
const stateVersion = this.stateVersion;
|
|
570
|
+
const requestVersion = ++this.scopeRequestVersion;
|
|
571
|
+
try {
|
|
572
|
+
const scopes = await this.requestScopes(session, frameId);
|
|
573
|
+
if (this.session === session &&
|
|
574
|
+
this.stateVersion === stateVersion &&
|
|
575
|
+
this.scopeRequestVersion === requestVersion) {
|
|
576
|
+
this.activeFrameId = frameId;
|
|
577
|
+
}
|
|
578
|
+
return scopes;
|
|
579
|
+
}
|
|
580
|
+
catch (error) {
|
|
581
|
+
if (this.session !== session ||
|
|
582
|
+
this.stateVersion !== stateVersion ||
|
|
583
|
+
this.scopeRequestVersion !== requestVersion) {
|
|
584
|
+
throw error;
|
|
585
|
+
}
|
|
586
|
+
this.rethrowProtocolError(error);
|
|
587
|
+
throw error;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
async readMemory(memoryReference, offset, count) {
|
|
591
|
+
if (!this.targetStopped || !this.supportsReadMemory)
|
|
592
|
+
return null;
|
|
593
|
+
assertBoundedNonEmptyStringArgument(memoryReference, 'memoryReference');
|
|
594
|
+
if (!Number.isSafeInteger(offset)) {
|
|
595
|
+
throw new RangeError('offset must be a safe integer.');
|
|
596
|
+
}
|
|
597
|
+
assertNonNegativeSafeIntegerArgument(count, 'count');
|
|
598
|
+
if (count > MAX_DEBUG_MEMORY_BYTES) {
|
|
599
|
+
throw new RangeError(`count must not exceed ${MAX_DEBUG_MEMORY_BYTES}.`);
|
|
600
|
+
}
|
|
601
|
+
const session = this.requireSession();
|
|
602
|
+
const stateVersion = this.stateVersion;
|
|
603
|
+
try {
|
|
604
|
+
const response = await session.request('readMemory', {
|
|
605
|
+
memoryReference,
|
|
606
|
+
offset,
|
|
607
|
+
count
|
|
608
|
+
});
|
|
609
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
610
|
+
return null;
|
|
611
|
+
assertDapRecord(response, 'readMemory', 'body');
|
|
612
|
+
assertDapString(response.address, 'readMemory', 'address');
|
|
613
|
+
const encodedData = response.data;
|
|
614
|
+
if (encodedData !== undefined)
|
|
615
|
+
assertDapString(encodedData, 'readMemory', 'data');
|
|
616
|
+
const unreadableBytes = response.unreadableBytes;
|
|
617
|
+
if (unreadableBytes !== undefined) {
|
|
618
|
+
assertDapNonNegativeSafeInteger(unreadableBytes, 'readMemory', 'unreadableBytes');
|
|
619
|
+
}
|
|
620
|
+
const maximumEncodedDataLength = Math.ceil(count / 3) * 4;
|
|
621
|
+
if (encodedData !== undefined && encodedData.length > maximumEncodedDataLength) {
|
|
622
|
+
invalidDapResponse('readMemory', 'data', `encoded data exceeds the ${maximumEncodedDataLength}-character limit for a ${count}-byte request`);
|
|
623
|
+
}
|
|
624
|
+
let binary;
|
|
625
|
+
try {
|
|
626
|
+
binary = globalThis.atob(encodedData ?? '');
|
|
627
|
+
}
|
|
628
|
+
catch {
|
|
629
|
+
invalidDapResponse('readMemory', 'data', 'expected valid Base64');
|
|
630
|
+
}
|
|
631
|
+
if (binary.length > count) {
|
|
632
|
+
invalidDapResponse('readMemory', 'data', `decoded ${binary.length} bytes for a ${count}-byte request`);
|
|
633
|
+
}
|
|
634
|
+
if (binary.length + (unreadableBytes ?? 0) > count) {
|
|
635
|
+
invalidDapResponse('readMemory', 'unreadableBytes', `reported ${binary.length} readable and ${unreadableBytes ?? 0} unreadable bytes for a ${count}-byte request`);
|
|
636
|
+
}
|
|
637
|
+
const data = new Uint8Array(binary.length);
|
|
638
|
+
for (let index = 0; index < binary.length; index += 1) {
|
|
639
|
+
data[index] = binary.charCodeAt(index);
|
|
640
|
+
}
|
|
641
|
+
return {
|
|
642
|
+
address: response.address,
|
|
643
|
+
data,
|
|
644
|
+
unreadableBytes: unreadableBytes ?? 0
|
|
645
|
+
};
|
|
646
|
+
}
|
|
647
|
+
catch (error) {
|
|
648
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
649
|
+
return null;
|
|
650
|
+
this.rethrowProtocolError(error);
|
|
651
|
+
throw error;
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
async writeMemory(memoryReference, offset, data, allowPartial = false) {
|
|
655
|
+
if (!this.targetStopped || !this.supportsWriteMemory)
|
|
656
|
+
return null;
|
|
657
|
+
assertBoundedNonEmptyStringArgument(memoryReference, 'memoryReference');
|
|
658
|
+
if (!Number.isSafeInteger(offset)) {
|
|
659
|
+
throw new RangeError('offset must be a safe integer.');
|
|
660
|
+
}
|
|
661
|
+
if (!(data instanceof Uint8Array)) {
|
|
662
|
+
throw new TypeError('data must be a Uint8Array.');
|
|
663
|
+
}
|
|
664
|
+
if (data.byteLength > MAX_DEBUG_MEMORY_BYTES) {
|
|
665
|
+
throw new RangeError(`data must not exceed ${MAX_DEBUG_MEMORY_BYTES} bytes.`);
|
|
666
|
+
}
|
|
667
|
+
assertOptionalBooleanArgument(allowPartial, 'allowPartial');
|
|
668
|
+
const chunks = [];
|
|
669
|
+
for (let start = 0; start < data.byteLength; start += 0x8000) {
|
|
670
|
+
chunks.push(String.fromCharCode(...data.subarray(start, start + 0x8000)));
|
|
671
|
+
}
|
|
672
|
+
const session = this.requireSession();
|
|
673
|
+
const stateVersion = this.stateVersion;
|
|
674
|
+
try {
|
|
675
|
+
const response = await session.request('writeMemory', {
|
|
676
|
+
memoryReference,
|
|
677
|
+
offset,
|
|
678
|
+
allowPartial,
|
|
679
|
+
data: globalThis.btoa(chunks.join(''))
|
|
680
|
+
});
|
|
681
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
682
|
+
return null;
|
|
683
|
+
if (response !== undefined)
|
|
684
|
+
assertDapRecord(response, 'writeMemory', 'body');
|
|
685
|
+
const responseBody = response ?? {};
|
|
686
|
+
const responseBytesWritten = responseBody.bytesWritten;
|
|
687
|
+
if (responseBytesWritten !== undefined) {
|
|
688
|
+
assertDapNonNegativeSafeInteger(responseBytesWritten, 'writeMemory', 'bytesWritten');
|
|
689
|
+
}
|
|
690
|
+
const bytesWritten = responseBytesWritten ?? data.byteLength;
|
|
691
|
+
if (bytesWritten > data.byteLength) {
|
|
692
|
+
invalidDapResponse('writeMemory', 'bytesWritten', `reported ${bytesWritten} bytes written for ${data.byteLength} input bytes`);
|
|
693
|
+
}
|
|
694
|
+
if (!allowPartial && bytesWritten !== data.byteLength) {
|
|
695
|
+
invalidDapResponse('writeMemory', 'bytesWritten', `reported a partial write of ${bytesWritten} bytes for a required ${data.byteLength}-byte write`);
|
|
696
|
+
}
|
|
697
|
+
const responseOffset = responseBody.offset;
|
|
698
|
+
if (responseOffset !== undefined &&
|
|
699
|
+
(typeof responseOffset !== 'number' || !Number.isSafeInteger(responseOffset))) {
|
|
700
|
+
invalidDapResponse('writeMemory', 'offset', 'expected a safe integer');
|
|
701
|
+
}
|
|
702
|
+
return {
|
|
703
|
+
...(responseOffset === undefined ? {} : { offset: responseOffset }),
|
|
704
|
+
bytesWritten
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
catch (error) {
|
|
708
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
709
|
+
return null;
|
|
710
|
+
this.rethrowProtocolError(error);
|
|
711
|
+
throw error;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
async dataBreakpointInfo(arguments_) {
|
|
715
|
+
if (!this.targetStopped || !this.supportsDataBreakpoints)
|
|
716
|
+
return null;
|
|
717
|
+
if (typeof arguments_ !== 'object' || arguments_ === null || Array.isArray(arguments_)) {
|
|
718
|
+
throw new TypeError('arguments must be an object.');
|
|
719
|
+
}
|
|
720
|
+
assertBoundedNonEmptyStringArgument(arguments_.name, 'name');
|
|
721
|
+
if (arguments_.variablesReference !== undefined) {
|
|
722
|
+
assertNonNegativeSafeIntegerArgument(arguments_.variablesReference, 'variablesReference');
|
|
723
|
+
}
|
|
724
|
+
if (arguments_.frameId !== undefined) {
|
|
725
|
+
assertPositiveSafeIntegerArgument(arguments_.frameId, 'frameId');
|
|
726
|
+
}
|
|
727
|
+
if (arguments_.bytes !== undefined) {
|
|
728
|
+
assertPositiveSafeIntegerArgument(arguments_.bytes, 'bytes');
|
|
729
|
+
if (arguments_.bytes > MAX_DEBUG_MEMORY_BYTES) {
|
|
730
|
+
throw new RangeError(`bytes must not exceed ${MAX_DEBUG_MEMORY_BYTES}.`);
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
assertOptionalBooleanArgument(arguments_.asAddress, 'asAddress');
|
|
734
|
+
const session = this.requireSession();
|
|
735
|
+
const stateVersion = this.stateVersion;
|
|
736
|
+
try {
|
|
737
|
+
const response = await session.request('dataBreakpointInfo', {
|
|
738
|
+
name: arguments_.name,
|
|
739
|
+
...(arguments_.variablesReference === undefined
|
|
740
|
+
? {}
|
|
741
|
+
: { variablesReference: arguments_.variablesReference }),
|
|
742
|
+
...(arguments_.frameId === undefined ? {} : { frameId: arguments_.frameId }),
|
|
743
|
+
...(arguments_.asAddress === undefined ? {} : { asAddress: arguments_.asAddress }),
|
|
744
|
+
...(arguments_.bytes === undefined ? {} : { bytes: arguments_.bytes })
|
|
745
|
+
});
|
|
746
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
747
|
+
return null;
|
|
748
|
+
assertDapRecord(response, 'dataBreakpointInfo', 'body');
|
|
749
|
+
assertDapString(response.description, 'dataBreakpointInfo', 'description');
|
|
750
|
+
let dataId;
|
|
751
|
+
if (response.dataId !== undefined && response.dataId !== null) {
|
|
752
|
+
assertDapString(response.dataId, 'dataBreakpointInfo', 'dataId');
|
|
753
|
+
if (response.dataId.length === 0) {
|
|
754
|
+
invalidDapResponse('dataBreakpointInfo', 'dataId', 'expected a non-empty string');
|
|
755
|
+
}
|
|
756
|
+
if (response.dataId.length > MAX_DEBUG_IDENTIFIER_CODE_UNITS) {
|
|
757
|
+
invalidDapResponse('dataBreakpointInfo', 'dataId', `expected at most ${MAX_DEBUG_IDENTIFIER_CODE_UNITS} UTF-16 code units`);
|
|
758
|
+
}
|
|
759
|
+
dataId = response.dataId;
|
|
760
|
+
}
|
|
761
|
+
let accessTypes;
|
|
762
|
+
if (response.accessTypes !== undefined) {
|
|
763
|
+
if (!Array.isArray(response.accessTypes)) {
|
|
764
|
+
invalidDapResponse('dataBreakpointInfo', 'accessTypes', 'expected an array');
|
|
765
|
+
}
|
|
766
|
+
if (response.accessTypes.length > 3) {
|
|
767
|
+
invalidDapResponse('dataBreakpointInfo', 'accessTypes', 'expected at most 3 entries');
|
|
768
|
+
}
|
|
769
|
+
const seenAccessTypes = new Set();
|
|
770
|
+
accessTypes = response.accessTypes.map((accessType, index) => {
|
|
771
|
+
if (accessType !== 'read' &&
|
|
772
|
+
accessType !== 'write' &&
|
|
773
|
+
accessType !== 'readWrite') {
|
|
774
|
+
invalidDapResponse('dataBreakpointInfo', `accessTypes[${index}]`, 'expected read, write, or readWrite');
|
|
775
|
+
}
|
|
776
|
+
if (seenAccessTypes.has(accessType)) {
|
|
777
|
+
invalidDapResponse('dataBreakpointInfo', `accessTypes[${index}]`, 'expected a unique access type');
|
|
778
|
+
}
|
|
779
|
+
seenAccessTypes.add(accessType);
|
|
780
|
+
return accessType;
|
|
781
|
+
});
|
|
782
|
+
}
|
|
783
|
+
let canPersist;
|
|
784
|
+
if (response.canPersist !== undefined) {
|
|
785
|
+
assertDapBoolean(response.canPersist, 'dataBreakpointInfo', 'canPersist');
|
|
786
|
+
canPersist = response.canPersist;
|
|
787
|
+
}
|
|
788
|
+
return {
|
|
789
|
+
...(dataId === undefined ? {} : { dataId }),
|
|
790
|
+
description: response.description,
|
|
791
|
+
...(accessTypes === undefined ? {} : { accessTypes }),
|
|
792
|
+
...(canPersist === undefined ? {} : { canPersist })
|
|
793
|
+
};
|
|
794
|
+
}
|
|
795
|
+
catch (error) {
|
|
796
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
797
|
+
return null;
|
|
798
|
+
this.rethrowProtocolError(error);
|
|
799
|
+
throw error;
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
async setDataBreakpoints(breakpoints) {
|
|
803
|
+
if (!this.targetStopped || !this.supportsDataBreakpoints)
|
|
804
|
+
return [];
|
|
805
|
+
if (!Array.isArray(breakpoints)) {
|
|
806
|
+
throw new TypeError('breakpoints must be an array.');
|
|
807
|
+
}
|
|
808
|
+
if (breakpoints.length > MAX_DEBUG_DATA_BREAKPOINTS) {
|
|
809
|
+
throw new RangeError(`breakpoints must not contain more than ${MAX_DEBUG_DATA_BREAKPOINTS} entries.`);
|
|
810
|
+
}
|
|
811
|
+
for (let index = 0; index < breakpoints.length; index += 1) {
|
|
812
|
+
const breakpoint = breakpoints[index];
|
|
813
|
+
if (typeof breakpoint !== 'object' ||
|
|
814
|
+
breakpoint === null ||
|
|
815
|
+
Array.isArray(breakpoint)) {
|
|
816
|
+
throw new TypeError(`breakpoints[${index}] must be an object.`);
|
|
817
|
+
}
|
|
818
|
+
if (typeof breakpoint.dataId !== 'string' || breakpoint.dataId.length === 0) {
|
|
819
|
+
throw new TypeError(`breakpoints[${index}].dataId must be a non-empty string.`);
|
|
820
|
+
}
|
|
821
|
+
if (breakpoint.dataId.length > MAX_DEBUG_IDENTIFIER_CODE_UNITS) {
|
|
822
|
+
throw new RangeError(`breakpoints[${index}].dataId must not exceed ${MAX_DEBUG_IDENTIFIER_CODE_UNITS} UTF-16 code units.`);
|
|
823
|
+
}
|
|
824
|
+
if (breakpoint.accessType !== undefined &&
|
|
825
|
+
breakpoint.accessType !== 'read' &&
|
|
826
|
+
breakpoint.accessType !== 'write' &&
|
|
827
|
+
breakpoint.accessType !== 'readWrite') {
|
|
828
|
+
throw new TypeError(`breakpoints[${index}].accessType must be read, write, or readWrite.`);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
const requestBreakpoints = breakpoints.map((breakpoint) => {
|
|
832
|
+
return {
|
|
833
|
+
dataId: breakpoint.dataId,
|
|
834
|
+
...(breakpoint.accessType === undefined
|
|
835
|
+
? {}
|
|
836
|
+
: { accessType: breakpoint.accessType })
|
|
837
|
+
};
|
|
838
|
+
});
|
|
839
|
+
const session = this.requireSession();
|
|
840
|
+
const stateVersion = this.stateVersion;
|
|
841
|
+
try {
|
|
842
|
+
const response = await session.request('setDataBreakpoints', {
|
|
843
|
+
breakpoints: requestBreakpoints
|
|
844
|
+
});
|
|
845
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
846
|
+
return [];
|
|
847
|
+
const responseBreakpoints = dapResponseCollection(response, 'setDataBreakpoints', 'breakpoints');
|
|
848
|
+
if (responseBreakpoints.length !== requestBreakpoints.length) {
|
|
849
|
+
invalidDapResponse('setDataBreakpoints', 'breakpoints', `expected ${requestBreakpoints.length} entries`);
|
|
850
|
+
}
|
|
851
|
+
return responseBreakpoints.map((breakpoint, index) => {
|
|
852
|
+
const path = `breakpoints[${index}]`;
|
|
853
|
+
assertDapRecord(breakpoint, 'setDataBreakpoints', path);
|
|
854
|
+
assertDapBoolean(breakpoint.verified, 'setDataBreakpoints', `${path}.verified`);
|
|
855
|
+
const id = dapOptionalNonNegativeSafeInteger(breakpoint, 'id', 'setDataBreakpoints', path);
|
|
856
|
+
let message;
|
|
857
|
+
if (breakpoint.message !== undefined) {
|
|
858
|
+
assertDapString(breakpoint.message, 'setDataBreakpoints', `${path}.message`);
|
|
859
|
+
message = breakpoint.message;
|
|
860
|
+
}
|
|
861
|
+
return {
|
|
862
|
+
...(id === undefined ? {} : { id }),
|
|
863
|
+
verified: breakpoint.verified,
|
|
864
|
+
...(message === undefined ? {} : { message })
|
|
865
|
+
};
|
|
866
|
+
});
|
|
867
|
+
}
|
|
868
|
+
catch (error) {
|
|
869
|
+
if (!this.isCurrentValueRequest(session, stateVersion))
|
|
870
|
+
return [];
|
|
871
|
+
const failure = this.asProtocolError(error) ??
|
|
872
|
+
(error instanceof Error
|
|
873
|
+
? error
|
|
874
|
+
: new Error('Unable to replace the LLDB data breakpoints.'));
|
|
875
|
+
this.fail(failure);
|
|
876
|
+
throw failure;
|
|
877
|
+
}
|
|
878
|
+
}
|
|
879
|
+
async disconnect() {
|
|
880
|
+
const completionResolve = this.completionResolve;
|
|
881
|
+
const completionReject = this.completionReject;
|
|
882
|
+
this.lifecycleVersion += 1;
|
|
883
|
+
this.entrySetup?.resolve();
|
|
884
|
+
this.entrySetup = undefined;
|
|
885
|
+
const startupAbortController = this.startupAbortController;
|
|
886
|
+
this.startupAbortController = undefined;
|
|
887
|
+
startupAbortController?.abort(new Error('LLDB sandbox session disconnected during startup.'));
|
|
888
|
+
this.stateVersion += 1;
|
|
889
|
+
this.targetStopped = false;
|
|
890
|
+
this.retireInput();
|
|
891
|
+
this.initialized = false;
|
|
892
|
+
this.supportsEvaluateExpressions = false;
|
|
893
|
+
this.supportsReadMemory = false;
|
|
894
|
+
this.supportsWriteMemory = false;
|
|
895
|
+
this.supportsDataBreakpoints = false;
|
|
896
|
+
this.dapExitCode = null;
|
|
897
|
+
const session = this.session;
|
|
898
|
+
this.session = undefined;
|
|
899
|
+
const shouldPublishStop = !this.stopped;
|
|
900
|
+
this.stopped = true;
|
|
901
|
+
const disposal = session
|
|
902
|
+
? this.trackSessionDisposal(session.disconnect({ terminateTarget: true }))
|
|
903
|
+
: this.sessionDisposal;
|
|
904
|
+
let disposalFailure;
|
|
905
|
+
try {
|
|
906
|
+
await disposal;
|
|
907
|
+
}
|
|
908
|
+
catch (error) {
|
|
909
|
+
disposalFailure =
|
|
910
|
+
error instanceof Error
|
|
911
|
+
? error
|
|
912
|
+
: new Error('Unable to disconnect the LLDB debug session.');
|
|
913
|
+
}
|
|
914
|
+
if (disposalFailure) {
|
|
915
|
+
completionReject?.(disposalFailure);
|
|
916
|
+
if (shouldPublishStop)
|
|
917
|
+
this.publishStop();
|
|
918
|
+
throw disposalFailure;
|
|
919
|
+
}
|
|
920
|
+
completionResolve?.(true);
|
|
921
|
+
if (shouldPublishStop)
|
|
922
|
+
this.publishStop();
|
|
923
|
+
}
|
|
924
|
+
handleDapEvent(event) {
|
|
925
|
+
if (event.event === 'output') {
|
|
926
|
+
const body = event.body;
|
|
927
|
+
if (typeof body?.output === 'string')
|
|
928
|
+
this.options.onOutput(body.output);
|
|
929
|
+
return;
|
|
930
|
+
}
|
|
931
|
+
if (event.event === 'stopped') {
|
|
932
|
+
this.targetStopped = false;
|
|
933
|
+
if (typeof event.body !== 'object' ||
|
|
934
|
+
event.body === null ||
|
|
935
|
+
Array.isArray(event.body)) {
|
|
936
|
+
invalidDapPayload('stopped event', 'body', 'expected an object');
|
|
937
|
+
}
|
|
938
|
+
const body = event.body;
|
|
939
|
+
if (typeof body.reason !== 'string') {
|
|
940
|
+
invalidDapPayload('stopped event', 'reason', 'expected a string');
|
|
941
|
+
}
|
|
942
|
+
const threadId = body.threadId;
|
|
943
|
+
if (threadId !== undefined) {
|
|
944
|
+
assertDapPositiveSafeInteger(threadId, 'stopped event', 'threadId');
|
|
945
|
+
}
|
|
946
|
+
if (body.allThreadsStopped !== undefined &&
|
|
947
|
+
typeof body.allThreadsStopped !== 'boolean') {
|
|
948
|
+
invalidDapPayload('stopped event', 'allThreadsStopped', 'expected a boolean');
|
|
949
|
+
}
|
|
950
|
+
const reason = this.pauseRequested && body.reason === 'exception' ? 'pause' : body.reason;
|
|
951
|
+
this.pauseRequested = false;
|
|
952
|
+
const session = this.requireSession();
|
|
953
|
+
const version = ++this.stateVersion;
|
|
954
|
+
void this.resolveStoppedState(threadId, reason, version).catch((error) => {
|
|
955
|
+
if (version !== this.stateVersion || this.session !== session)
|
|
956
|
+
return;
|
|
957
|
+
this.fail(error instanceof Error ? error : new Error('Unable to read LLDB stopped state.'));
|
|
958
|
+
});
|
|
959
|
+
return;
|
|
960
|
+
}
|
|
961
|
+
if (event.event === 'continued') {
|
|
962
|
+
this.targetStopped = false;
|
|
963
|
+
if (typeof event.body !== 'object' ||
|
|
964
|
+
event.body === null ||
|
|
965
|
+
Array.isArray(event.body)) {
|
|
966
|
+
invalidDapPayload('continued event', 'body', 'expected an object');
|
|
967
|
+
}
|
|
968
|
+
const body = event.body;
|
|
969
|
+
assertDapPositiveSafeInteger(body.threadId, 'continued event', 'threadId');
|
|
970
|
+
if (body.allThreadsContinued !== undefined &&
|
|
971
|
+
typeof body.allThreadsContinued !== 'boolean') {
|
|
972
|
+
invalidDapPayload('continued event', 'allThreadsContinued', 'expected a boolean');
|
|
973
|
+
}
|
|
974
|
+
this.stateVersion += 1;
|
|
975
|
+
return;
|
|
976
|
+
}
|
|
977
|
+
if (event.event === 'breakpoint') {
|
|
978
|
+
const body = event.body;
|
|
979
|
+
const breakpointId = body?.breakpoint?.id;
|
|
980
|
+
const sourcePath = body?.breakpoint?.source?.path;
|
|
981
|
+
for (const [trackedSourcePath, requestedLines] of this.breakpointsBySource) {
|
|
982
|
+
const resolved = this.requireSession().getResolvedBreakpoints(trackedSourcePath);
|
|
983
|
+
if (breakpointId !== undefined) {
|
|
984
|
+
if (!resolved.some((breakpoint) => breakpoint.id === breakpointId))
|
|
985
|
+
continue;
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
if (sourcePath && sourcePath !== trackedSourcePath)
|
|
989
|
+
continue;
|
|
990
|
+
}
|
|
991
|
+
this.publishResolvedBreakpoints(resolved, requestedLines, trackedSourcePath);
|
|
992
|
+
}
|
|
993
|
+
return;
|
|
994
|
+
}
|
|
995
|
+
if (event.event === 'exited') {
|
|
996
|
+
if (typeof event.body !== 'object' ||
|
|
997
|
+
event.body === null ||
|
|
998
|
+
Array.isArray(event.body)) {
|
|
999
|
+
invalidDapPayload('exited event', 'body', 'expected an object');
|
|
1000
|
+
}
|
|
1001
|
+
const exitCode = event.body.exitCode;
|
|
1002
|
+
if (typeof exitCode !== 'number' || !Number.isSafeInteger(exitCode)) {
|
|
1003
|
+
invalidDapPayload('exited event', 'exitCode', 'expected a safe integer');
|
|
1004
|
+
}
|
|
1005
|
+
this.dapExitCode = exitCode;
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (event.event === 'terminated')
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
1011
|
+
async resolveStoppedState(requestedThreadId, reason, version) {
|
|
1012
|
+
const session = this.requireSession();
|
|
1013
|
+
let threadId = requestedThreadId;
|
|
1014
|
+
if (threadId === undefined) {
|
|
1015
|
+
const response = await session.request('threads');
|
|
1016
|
+
const threads = dapResponseCollection(response, 'threads', 'threads').map((thread, index) => {
|
|
1017
|
+
const path = `threads[${index}]`;
|
|
1018
|
+
assertDapRecord(thread, 'threads', path);
|
|
1019
|
+
assertDapPositiveSafeInteger(thread.id, 'threads response', `${path}.id`);
|
|
1020
|
+
assertDapString(thread.name, 'threads', `${path}.name`);
|
|
1021
|
+
return { id: thread.id, name: thread.name };
|
|
1022
|
+
});
|
|
1023
|
+
threadId = threads[0]?.id;
|
|
1024
|
+
}
|
|
1025
|
+
if (!threadId)
|
|
1026
|
+
throw new Error('LLDB stopped without a WebAssembly thread.');
|
|
1027
|
+
const response = await session.request('stackTrace', {
|
|
1028
|
+
threadId,
|
|
1029
|
+
startFrame: 0,
|
|
1030
|
+
levels: 100
|
|
1031
|
+
});
|
|
1032
|
+
const frames = dapResponseCollection(response, 'stackTrace', 'stackFrames').map((frame, index) => {
|
|
1033
|
+
const path = `stackFrames[${index}]`;
|
|
1034
|
+
assertDapRecord(frame, 'stackTrace', path);
|
|
1035
|
+
assertDapPositiveSafeInteger(frame.id, 'stackTrace response', `${path}.id`);
|
|
1036
|
+
assertDapString(frame.name, 'stackTrace', `${path}.name`);
|
|
1037
|
+
assertDapNonNegativeSafeInteger(frame.line, 'stackTrace', `${path}.line`);
|
|
1038
|
+
assertDapNonNegativeSafeInteger(frame.column, 'stackTrace', `${path}.column`);
|
|
1039
|
+
let source;
|
|
1040
|
+
if (frame.source !== undefined) {
|
|
1041
|
+
assertDapRecord(frame.source, 'stackTrace', `${path}.source`);
|
|
1042
|
+
const sourcePath = frame.source.path;
|
|
1043
|
+
if (sourcePath !== undefined) {
|
|
1044
|
+
assertDapString(sourcePath, 'stackTrace', `${path}.source.path`);
|
|
1045
|
+
}
|
|
1046
|
+
source = sourcePath === undefined ? {} : { path: sourcePath };
|
|
1047
|
+
}
|
|
1048
|
+
return {
|
|
1049
|
+
id: frame.id,
|
|
1050
|
+
name: frame.name,
|
|
1051
|
+
source,
|
|
1052
|
+
line: frame.line,
|
|
1053
|
+
column: frame.column
|
|
1054
|
+
};
|
|
1055
|
+
});
|
|
1056
|
+
const selectedFrame = frames[0];
|
|
1057
|
+
if (!selectedFrame)
|
|
1058
|
+
throw new Error('LLDB stopped without a stack frame.');
|
|
1059
|
+
const isWorkspaceFrame = this.options.artifact.sources.some((source) => source.path === selectedFrame.source?.path);
|
|
1060
|
+
if (!this.isCurrentValueRequest(session, version))
|
|
1061
|
+
return;
|
|
1062
|
+
if (this.entryPhase === 'initial') {
|
|
1063
|
+
await this.entrySetup?.ready;
|
|
1064
|
+
if (!this.isCurrentValueRequest(session, version))
|
|
1065
|
+
return;
|
|
1066
|
+
this.entryPhase = 'done';
|
|
1067
|
+
if (reason === 'entry' && selectedFrame.name === '_start' && !isWorkspaceFrame) {
|
|
1068
|
+
// configurationDone has already installed all user source breakpoints. Function
|
|
1069
|
+
// breakpoints occupy a separate DAP registry owned by this product session.
|
|
1070
|
+
this.entryPhase = 'seeking-main';
|
|
1071
|
+
const verified = await this.setMainEntryBreakpoint(session, true);
|
|
1072
|
+
if (!this.isCurrentValueRequest(session, version))
|
|
1073
|
+
return;
|
|
1074
|
+
if (verified && !this.pauseRequested) {
|
|
1075
|
+
this.activeThreadId = threadId;
|
|
1076
|
+
await this.debugCommand('continue');
|
|
1077
|
+
return;
|
|
1078
|
+
}
|
|
1079
|
+
await this.setMainEntryBreakpoint(session, false);
|
|
1080
|
+
if (!this.isCurrentValueRequest(session, version))
|
|
1081
|
+
return;
|
|
1082
|
+
this.entryPhase = 'done';
|
|
1083
|
+
if (this.pauseRequested) {
|
|
1084
|
+
this.pauseRequested = false;
|
|
1085
|
+
reason = 'pause';
|
|
1086
|
+
}
|
|
1087
|
+
else {
|
|
1088
|
+
this.options.onOutput('LLDB could not resolve main; paused at runtime entry.\n');
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
else if (this.entryPhase === 'seeking-main') {
|
|
1093
|
+
// Honor any earlier user breakpoint, trap, or Pause, and never leave a hidden
|
|
1094
|
+
// main breakpoint behind for a later Continue.
|
|
1095
|
+
this.entryPhase = 'done';
|
|
1096
|
+
await this.setMainEntryBreakpoint(session, false);
|
|
1097
|
+
if (!this.isCurrentValueRequest(session, version))
|
|
1098
|
+
return;
|
|
1099
|
+
if (reason === 'breakpoint' && selectedFrame.name === 'main' && isWorkspaceFrame) {
|
|
1100
|
+
reason = 'entry';
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
const scopes = isWorkspaceFrame ? await this.requestScopes(session, selectedFrame.id) : [];
|
|
1104
|
+
if (version !== this.stateVersion || this.session !== session)
|
|
1105
|
+
return;
|
|
1106
|
+
this.activeThreadId = threadId;
|
|
1107
|
+
this.activeFrameId = selectedFrame.id;
|
|
1108
|
+
this.stoppedFrames = frames;
|
|
1109
|
+
this.targetStopped = true;
|
|
1110
|
+
const callStack = frames.map((frame) => {
|
|
1111
|
+
const sourcePath = frame.source?.path;
|
|
1112
|
+
const sourceContentSha256 = this.sourceContentSha256ByPath.get(sourcePath || '');
|
|
1113
|
+
return {
|
|
1114
|
+
id: frame.id,
|
|
1115
|
+
functionName: frame.name,
|
|
1116
|
+
line: frame.line,
|
|
1117
|
+
column: frame.column,
|
|
1118
|
+
sourcePath,
|
|
1119
|
+
...(sourceContentSha256 ? { sourceContentSha256 } : {})
|
|
1120
|
+
};
|
|
1121
|
+
});
|
|
1122
|
+
const sourceContentSha256 = this.sourceContentSha256ByPath.get(selectedFrame.source?.path || '');
|
|
1123
|
+
this.options.onDebugEvent({
|
|
1124
|
+
type: 'pause',
|
|
1125
|
+
capabilities: {
|
|
1126
|
+
readMemory: this.supportsReadMemory,
|
|
1127
|
+
writeMemory: this.supportsWriteMemory,
|
|
1128
|
+
dataBreakpoints: this.supportsDataBreakpoints
|
|
1129
|
+
},
|
|
1130
|
+
line: selectedFrame.line,
|
|
1131
|
+
sourcePath: selectedFrame.source?.path,
|
|
1132
|
+
...(sourceContentSha256 ? { sourceContentSha256 } : {}),
|
|
1133
|
+
reason: pauseReason(reason, this.command),
|
|
1134
|
+
stoppedReason: reason,
|
|
1135
|
+
threadId,
|
|
1136
|
+
frameId: selectedFrame.id,
|
|
1137
|
+
locals: [],
|
|
1138
|
+
callStack,
|
|
1139
|
+
scopes
|
|
1140
|
+
});
|
|
1141
|
+
this.command = null;
|
|
1142
|
+
}
|
|
1143
|
+
async setMainEntryBreakpoint(session, enabled) {
|
|
1144
|
+
const response = await session.request('setFunctionBreakpoints', {
|
|
1145
|
+
breakpoints: enabled ? [{ name: 'main' }] : []
|
|
1146
|
+
});
|
|
1147
|
+
const breakpoints = dapResponseCollection(response, 'setFunctionBreakpoints', 'breakpoints');
|
|
1148
|
+
if (breakpoints.length !== (enabled ? 1 : 0)) {
|
|
1149
|
+
invalidDapResponse('setFunctionBreakpoints', 'breakpoints', 'unexpected breakpoint count');
|
|
1150
|
+
}
|
|
1151
|
+
if (!enabled)
|
|
1152
|
+
return false;
|
|
1153
|
+
const breakpoint = breakpoints[0];
|
|
1154
|
+
assertDapRecord(breakpoint, 'setFunctionBreakpoints', 'breakpoints[0]');
|
|
1155
|
+
assertDapBoolean(breakpoint.verified, 'setFunctionBreakpoints', 'breakpoints[0].verified');
|
|
1156
|
+
return breakpoint.verified;
|
|
1157
|
+
}
|
|
1158
|
+
async requestScopes(session, frameId) {
|
|
1159
|
+
const response = await session.request('scopes', { frameId });
|
|
1160
|
+
return dapResponseCollection(response, 'scopes', 'scopes').map((scope, index) => {
|
|
1161
|
+
const path = `scopes[${index}]`;
|
|
1162
|
+
assertDapRecord(scope, 'scopes', path);
|
|
1163
|
+
assertDapString(scope.name, 'scopes', `${path}.name`);
|
|
1164
|
+
assertDapNonNegativeSafeInteger(scope.variablesReference, 'scopes', `${path}.variablesReference`);
|
|
1165
|
+
assertDapBoolean(scope.expensive, 'scopes', `${path}.expensive`);
|
|
1166
|
+
const presentationHint = scope.presentationHint;
|
|
1167
|
+
if (presentationHint !== undefined) {
|
|
1168
|
+
assertDapString(presentationHint, 'scopes', `${path}.presentationHint`);
|
|
1169
|
+
}
|
|
1170
|
+
const namedVariables = dapOptionalNonNegativeSafeInteger(scope, 'namedVariables', 'scopes', path);
|
|
1171
|
+
const indexedVariables = dapOptionalNonNegativeSafeInteger(scope, 'indexedVariables', 'scopes', path);
|
|
1172
|
+
return {
|
|
1173
|
+
name: scope.name,
|
|
1174
|
+
...(presentationHint === undefined ? {} : { presentationHint }),
|
|
1175
|
+
variablesReference: scope.variablesReference,
|
|
1176
|
+
...(namedVariables === undefined ? {} : { namedVariables }),
|
|
1177
|
+
...(indexedVariables === undefined ? {} : { indexedVariables }),
|
|
1178
|
+
expensive: scope.expensive,
|
|
1179
|
+
variables: []
|
|
1180
|
+
};
|
|
1181
|
+
});
|
|
1182
|
+
}
|
|
1183
|
+
isCurrentValueRequest(session, stateVersion, scopeRequestVersion) {
|
|
1184
|
+
return (this.session === session &&
|
|
1185
|
+
this.stateVersion === stateVersion &&
|
|
1186
|
+
(scopeRequestVersion === undefined || this.scopeRequestVersion === scopeRequestVersion));
|
|
1187
|
+
}
|
|
1188
|
+
rethrowProtocolError(error) {
|
|
1189
|
+
const protocolError = this.asProtocolError(error);
|
|
1190
|
+
if (!protocolError)
|
|
1191
|
+
return;
|
|
1192
|
+
this.fail(protocolError);
|
|
1193
|
+
throw protocolError;
|
|
1194
|
+
}
|
|
1195
|
+
asProtocolError(error) {
|
|
1196
|
+
if (error instanceof ProtocolError)
|
|
1197
|
+
return error;
|
|
1198
|
+
if (error instanceof DapProtocolError) {
|
|
1199
|
+
return new ProtocolError(error.message, { cause: error });
|
|
1200
|
+
}
|
|
1201
|
+
return null;
|
|
1202
|
+
}
|
|
1203
|
+
finish(exitCode) {
|
|
1204
|
+
if (this.stopped)
|
|
1205
|
+
return;
|
|
1206
|
+
this.entrySetup?.resolve();
|
|
1207
|
+
this.entrySetup = undefined;
|
|
1208
|
+
this.stopped = true;
|
|
1209
|
+
this.stateVersion += 1;
|
|
1210
|
+
this.targetStopped = false;
|
|
1211
|
+
this.retireInput();
|
|
1212
|
+
this.initialized = false;
|
|
1213
|
+
this.supportsEvaluateExpressions = false;
|
|
1214
|
+
this.supportsReadMemory = false;
|
|
1215
|
+
this.supportsWriteMemory = false;
|
|
1216
|
+
this.supportsDataBreakpoints = false;
|
|
1217
|
+
this.dapExitCode = null;
|
|
1218
|
+
const session = this.session;
|
|
1219
|
+
this.session = undefined;
|
|
1220
|
+
const completionResolve = this.completionResolve;
|
|
1221
|
+
const completionReject = this.completionReject;
|
|
1222
|
+
const disposal = session
|
|
1223
|
+
? this.trackSessionDisposal(session.dispose())
|
|
1224
|
+
: (this.sessionDisposal ?? Promise.resolve());
|
|
1225
|
+
void disposal.then(() => {
|
|
1226
|
+
if (exitCode !== null && exitCode !== 0) {
|
|
1227
|
+
completionReject?.(new Error(`Debug target exited with code ${exitCode}.`));
|
|
1228
|
+
}
|
|
1229
|
+
else {
|
|
1230
|
+
completionResolve?.(true);
|
|
1231
|
+
}
|
|
1232
|
+
}, (error) => completionReject?.(error instanceof Error
|
|
1233
|
+
? error
|
|
1234
|
+
: new Error('Unable to dispose the LLDB debug session.')));
|
|
1235
|
+
this.publishStop();
|
|
1236
|
+
}
|
|
1237
|
+
fail(error) {
|
|
1238
|
+
if (this.stopped)
|
|
1239
|
+
return;
|
|
1240
|
+
this.entrySetup?.resolve();
|
|
1241
|
+
this.entrySetup = undefined;
|
|
1242
|
+
this.stopped = true;
|
|
1243
|
+
this.stateVersion += 1;
|
|
1244
|
+
this.targetStopped = false;
|
|
1245
|
+
this.retireInput();
|
|
1246
|
+
this.initialized = false;
|
|
1247
|
+
this.supportsEvaluateExpressions = false;
|
|
1248
|
+
this.supportsReadMemory = false;
|
|
1249
|
+
this.supportsWriteMemory = false;
|
|
1250
|
+
this.supportsDataBreakpoints = false;
|
|
1251
|
+
this.dapExitCode = null;
|
|
1252
|
+
const session = this.session;
|
|
1253
|
+
this.session = undefined;
|
|
1254
|
+
const completionReject = this.completionReject;
|
|
1255
|
+
const disposal = session
|
|
1256
|
+
? this.trackSessionDisposal(session.dispose())
|
|
1257
|
+
: (this.sessionDisposal ?? Promise.resolve());
|
|
1258
|
+
void disposal.then(() => completionReject?.(error), () => completionReject?.(error));
|
|
1259
|
+
this.publishStop();
|
|
1260
|
+
}
|
|
1261
|
+
publishStop() {
|
|
1262
|
+
try {
|
|
1263
|
+
this.options.onDebugEvent({ type: 'stop' });
|
|
1264
|
+
}
|
|
1265
|
+
catch {
|
|
1266
|
+
// Consumer callbacks cannot interrupt target teardown or completion settlement.
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
publishActiveDebugEvent(event) {
|
|
1270
|
+
try {
|
|
1271
|
+
this.options.onDebugEvent(event);
|
|
1272
|
+
}
|
|
1273
|
+
catch (error) {
|
|
1274
|
+
const failure = error instanceof Error
|
|
1275
|
+
? error
|
|
1276
|
+
: new Error('Unable to publish the LLDB debug session state.');
|
|
1277
|
+
this.fail(failure);
|
|
1278
|
+
throw failure;
|
|
1279
|
+
}
|
|
1280
|
+
}
|
|
1281
|
+
trackSessionDisposal(disposal) {
|
|
1282
|
+
this.sessionDisposal = disposal;
|
|
1283
|
+
void disposal.then(() => {
|
|
1284
|
+
if (this.sessionDisposal === disposal)
|
|
1285
|
+
this.sessionDisposal = undefined;
|
|
1286
|
+
}, () => {
|
|
1287
|
+
if (this.sessionDisposal === disposal)
|
|
1288
|
+
this.sessionDisposal = undefined;
|
|
1289
|
+
});
|
|
1290
|
+
return disposal;
|
|
1291
|
+
}
|
|
1292
|
+
requireSession() {
|
|
1293
|
+
if (!this.session)
|
|
1294
|
+
throw new Error('LLDB sandbox session is not running.');
|
|
1295
|
+
return this.session;
|
|
1296
|
+
}
|
|
1297
|
+
publishResolvedBreakpoints(breakpoints, requestedLines, sourcePath = this.options.sourcePath) {
|
|
1298
|
+
const sourceContentSha256 = this.sourceContentSha256ByPath.get(sourcePath);
|
|
1299
|
+
this.publishActiveDebugEvent({
|
|
1300
|
+
type: 'breakpoints',
|
|
1301
|
+
sourcePath,
|
|
1302
|
+
...(sourceContentSha256 ? { sourceContentSha256 } : {}),
|
|
1303
|
+
breakpoints: requestedLines.map((requestedLine, index) => ({
|
|
1304
|
+
requestedLine,
|
|
1305
|
+
line: breakpoints[index]?.line ?? requestedLine,
|
|
1306
|
+
verified: breakpoints[index]?.verified === true,
|
|
1307
|
+
message: breakpoints[index]?.message
|
|
1308
|
+
}))
|
|
1309
|
+
});
|
|
1310
|
+
}
|
|
1311
|
+
observeInputFlush(flush, session, lifecycleVersion) {
|
|
1312
|
+
void flush.catch((error) => {
|
|
1313
|
+
if (this.stopped ||
|
|
1314
|
+
this.lifecycleVersion !== lifecycleVersion ||
|
|
1315
|
+
this.session !== session) {
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
this.fail(error instanceof Error ? error : new Error('Unable to write LLDB target input.'));
|
|
1319
|
+
});
|
|
1320
|
+
return flush;
|
|
1321
|
+
}
|
|
1322
|
+
retireInput() {
|
|
1323
|
+
this.inputReady = false;
|
|
1324
|
+
this.pendingInput.length = 0;
|
|
1325
|
+
this.pendingEof = false;
|
|
1326
|
+
}
|
|
1327
|
+
async flushInput(session, lifecycleVersion) {
|
|
1328
|
+
if (!this.inputReady ||
|
|
1329
|
+
!session ||
|
|
1330
|
+
this.lifecycleVersion !== lifecycleVersion ||
|
|
1331
|
+
this.session !== session) {
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
while (this.pendingInput.length > 0) {
|
|
1335
|
+
await session.writeStdin(this.pendingInput.shift() || '');
|
|
1336
|
+
if (!this.inputReady ||
|
|
1337
|
+
this.lifecycleVersion !== lifecycleVersion ||
|
|
1338
|
+
this.session !== session) {
|
|
1339
|
+
return;
|
|
1340
|
+
}
|
|
1341
|
+
}
|
|
1342
|
+
if (this.pendingEof) {
|
|
1343
|
+
this.pendingEof = false;
|
|
1344
|
+
await session.closeStdin();
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
}
|