From dfb3279dee609718e6db1428920d5b9f443dacb7 Mon Sep 17 00:00:00 2001 From: "chenwei.sun" Date: Tue, 21 Oct 2025 11:19:15 +0800 Subject: [PATCH] [SYCLomatic][NFC] Remove dependecy of brace-expansion pacakge Signed-off-by: chenwei.sun --- lldb/tools/lldb-dap/.editorconfig | 10 - lldb/tools/lldb-dap/.gitignore | 5 - lldb/tools/lldb-dap/.prettierrc.json | 7 - lldb/tools/lldb-dap/.vscode/launch.json | 24 - lldb/tools/lldb-dap/.vscode/tasks.json | 33 - lldb/tools/lldb-dap/.vscodeignore | 10 - lldb/tools/lldb-dap/Breakpoint.cpp | 107 - lldb/tools/lldb-dap/Breakpoint.h | 40 - lldb/tools/lldb-dap/BreakpointBase.cpp | 28 - lldb/tools/lldb-dap/BreakpointBase.h | 61 - lldb/tools/lldb-dap/CMakeLists.txt | 90 - lldb/tools/lldb-dap/CommandPlugins.cpp | 163 - lldb/tools/lldb-dap/CommandPlugins.h | 40 - lldb/tools/lldb-dap/DAP.cpp | 1492 ------- lldb/tools/lldb-dap/DAP.h | 426 -- lldb/tools/lldb-dap/DAPError.cpp | 38 - lldb/tools/lldb-dap/DAPError.h | 52 - lldb/tools/lldb-dap/DAPForward.h | 62 - lldb/tools/lldb-dap/DAPLog.cpp | 30 - lldb/tools/lldb-dap/DAPLog.h | 67 - lldb/tools/lldb-dap/EventHelper.cpp | 264 -- lldb/tools/lldb-dap/EventHelper.h | 35 - lldb/tools/lldb-dap/ExceptionBreakpoint.cpp | 38 - lldb/tools/lldb-dap/ExceptionBreakpoint.h | 47 - lldb/tools/lldb-dap/FifoFiles.cpp | 101 - lldb/tools/lldb-dap/FifoFiles.h | 85 - lldb/tools/lldb-dap/FunctionBreakpoint.cpp | 31 - lldb/tools/lldb-dap/FunctionBreakpoint.h | 33 - .../lldb-dap/Handler/AttachRequestHandler.cpp | 146 - .../Handler/BreakpointLocationsHandler.cpp | 129 - .../lldb-dap/Handler/CancelRequestHandler.cpp | 55 - .../Handler/CompileUnitsRequestHandler.cpp | 82 - .../lldb-dap/Handler/CompletionsHandler.cpp | 224 -- .../ConfigurationDoneRequestHandler.cpp | 62 - .../Handler/ContinueRequestHandler.cpp | 50 - .../DataBreakpointInfoRequestHandler.cpp | 95 - .../Handler/DisassembleRequestHandler.cpp | 259 -- .../Handler/DisconnectRequestHandler.cpp | 33 - .../Handler/EvaluateRequestHandler.cpp | 234 -- .../Handler/ExceptionInfoRequestHandler.cpp | 174 - .../Handler/InitializeRequestHandler.cpp | 81 - .../lldb-dap/Handler/LaunchRequestHandler.cpp | 73 - .../Handler/LocationsRequestHandler.cpp | 166 - .../Handler/ModulesRequestHandler.cpp | 70 - .../lldb-dap/Handler/NextRequestHandler.cpp | 51 - .../lldb-dap/Handler/PauseRequestHandler.cpp | 60 - .../Handler/ReadMemoryRequestHandler.cpp | 142 - .../tools/lldb-dap/Handler/RequestHandler.cpp | 239 -- lldb/tools/lldb-dap/Handler/RequestHandler.h | 609 --- .../lldb-dap/Handler/ResponseHandler.cpp | 35 - lldb/tools/lldb-dap/Handler/ResponseHandler.h | 56 - .../Handler/RestartRequestHandler.cpp | 156 - .../lldb-dap/Handler/ScopesRequestHandler.cpp | 98 - .../Handler/SetBreakpointsRequestHandler.cpp | 28 - .../SetDataBreakpointsRequestHandler.cpp | 50 - .../SetExceptionBreakpointsRequestHandler.cpp | 93 - .../SetFunctionBreakpointsRequestHandler.cpp | 56 - ...etInstructionBreakpointsRequestHandler.cpp | 57 - .../Handler/SetVariableRequestHandler.cpp | 86 - .../lldb-dap/Handler/SourceRequestHandler.cpp | 62 - .../Handler/StackTraceRequestHandler.cpp | 242 -- .../lldb-dap/Handler/StepInRequestHandler.cpp | 63 - .../Handler/StepInTargetsRequestHandler.cpp | 91 - .../Handler/StepOutRequestHandler.cpp | 49 - ...TestGetTargetBreakpointsRequestHandler.cpp | 31 - .../Handler/ThreadsRequestHandler.cpp | 79 - .../Handler/VariablesRequestHandler.cpp | 242 -- lldb/tools/lldb-dap/InstructionBreakpoint.cpp | 34 - lldb/tools/lldb-dap/InstructionBreakpoint.h | 41 - lldb/tools/lldb-dap/JSONUtils.cpp | 1353 ------- lldb/tools/lldb-dap/JSONUtils.h | 496 --- lldb/tools/lldb-dap/LICENSE.TXT | 234 -- lldb/tools/lldb-dap/LLDBUtils.cpp | 262 -- lldb/tools/lldb-dap/LLDBUtils.h | 253 -- lldb/tools/lldb-dap/Options.td | 63 - lldb/tools/lldb-dap/OutputRedirector.cpp | 125 - lldb/tools/lldb-dap/OutputRedirector.h | 58 - lldb/tools/lldb-dap/ProgressEvent.cpp | 237 -- lldb/tools/lldb-dap/ProgressEvent.h | 158 - lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp | 298 -- lldb/tools/lldb-dap/Protocol/ProtocolBase.h | 164 - .../lldb-dap/Protocol/ProtocolRequests.cpp | 490 --- .../lldb-dap/Protocol/ProtocolRequests.h | 784 ---- .../tools/lldb-dap/Protocol/ProtocolTypes.cpp | 902 ----- lldb/tools/lldb-dap/Protocol/ProtocolTypes.h | 721 ---- lldb/tools/lldb-dap/ProtocolUtils.cpp | 113 - lldb/tools/lldb-dap/ProtocolUtils.h | 53 - lldb/tools/lldb-dap/README.md | 381 -- lldb/tools/lldb-dap/RunInTerminal.cpp | 170 - lldb/tools/lldb-dap/RunInTerminal.h | 131 - lldb/tools/lldb-dap/SourceBreakpoint.cpp | 379 -- lldb/tools/lldb-dap/SourceBreakpoint.h | 72 - lldb/tools/lldb-dap/Transport.cpp | 159 - lldb/tools/lldb-dap/Transport.h | 96 - lldb/tools/lldb-dap/Variables.cpp | 105 - lldb/tools/lldb-dap/Variables.h | 71 - lldb/tools/lldb-dap/Watchpoint.cpp | 61 - lldb/tools/lldb-dap/Watchpoint.h | 47 - lldb/tools/lldb-dap/llvm-logo.png | Bin 261036 -> 0 bytes lldb/tools/lldb-dap/package-lock.json | 2936 -------------- lldb/tools/lldb-dap/package.json | 799 ---- .../lldb-dap/src-ts/debug-adapter-factory.ts | 224 -- .../src-ts/debug-configuration-provider.ts | 199 - .../lldb-dap/src-ts/debug-session-tracker.ts | 139 - .../lldb-dap/src-ts/disposable-context.ts | 27 - lldb/tools/lldb-dap/src-ts/extension.ts | 59 - lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts | 132 - .../src-ts/ui/error-with-notification.ts | 68 - .../src-ts/ui/modules-data-provider.ts | 84 - .../lldb-dap/src-ts/ui/show-error-message.ts | 98 - .../lldb-dap/src-ts/uri-launch-handler.ts | 102 - lldb/tools/lldb-dap/syntaxes/arm.disasm | 45 - lldb/tools/lldb-dap/syntaxes/arm64.disasm | 91 - lldb/tools/lldb-dap/syntaxes/disassembly.json | 64 - lldb/tools/lldb-dap/syntaxes/x86.disasm | 28 - lldb/tools/lldb-dap/tool/CMakeLists.txt | 28 - .../lldb-dap/tool/lldb-dap-Info.plist.in | 21 - lldb/tools/lldb-dap/tool/lldb-dap.cpp | 568 --- lldb/tools/lldb-dap/tsconfig.json | 16 - mlir/utils/vscode/.gitignore | 8 - mlir/utils/vscode/.vscode/launch.json | 24 - mlir/utils/vscode/.vscode/tasks.json | 33 - mlir/utils/vscode/.vscodeignore | 4 - mlir/utils/vscode/cpp-grammar.json | 44 - mlir/utils/vscode/language-configuration.json | 22 - mlir/utils/vscode/markdown-grammar.json | 117 - mlir/utils/vscode/package-lock.json | 3559 ----------------- mlir/utils/vscode/package.json | 230 -- mlir/utils/vscode/pdll-grammar.json | 524 --- .../vscode/pdll-language-configuration.json | 67 - .../utils/vscode/src/MLIR/bytecodeProvider.ts | 194 - mlir/utils/vscode/src/MLIR/mlir.ts | 12 - .../vscode/src/PDLL/commands/viewOutput.ts | 65 - mlir/utils/vscode/src/PDLL/pdll.ts | 12 - mlir/utils/vscode/src/command.ts | 25 - mlir/utils/vscode/src/config.ts | 19 - mlir/utils/vscode/src/configWatcher.ts | 85 - mlir/utils/vscode/src/extension.ts | 29 - mlir/utils/vscode/src/mlirContext.ts | 392 -- .../tablegen-language-configuration.json | 89 - mlir/utils/vscode/tsconfig.json | 16 - 141 files changed, 27836 deletions(-) delete mode 100644 lldb/tools/lldb-dap/.editorconfig delete mode 100644 lldb/tools/lldb-dap/.gitignore delete mode 100644 lldb/tools/lldb-dap/.prettierrc.json delete mode 100644 lldb/tools/lldb-dap/.vscode/launch.json delete mode 100644 lldb/tools/lldb-dap/.vscode/tasks.json delete mode 100644 lldb/tools/lldb-dap/.vscodeignore delete mode 100644 lldb/tools/lldb-dap/Breakpoint.cpp delete mode 100644 lldb/tools/lldb-dap/Breakpoint.h delete mode 100644 lldb/tools/lldb-dap/BreakpointBase.cpp delete mode 100644 lldb/tools/lldb-dap/BreakpointBase.h delete mode 100644 lldb/tools/lldb-dap/CMakeLists.txt delete mode 100644 lldb/tools/lldb-dap/CommandPlugins.cpp delete mode 100644 lldb/tools/lldb-dap/CommandPlugins.h delete mode 100644 lldb/tools/lldb-dap/DAP.cpp delete mode 100644 lldb/tools/lldb-dap/DAP.h delete mode 100644 lldb/tools/lldb-dap/DAPError.cpp delete mode 100644 lldb/tools/lldb-dap/DAPError.h delete mode 100644 lldb/tools/lldb-dap/DAPForward.h delete mode 100644 lldb/tools/lldb-dap/DAPLog.cpp delete mode 100644 lldb/tools/lldb-dap/DAPLog.h delete mode 100644 lldb/tools/lldb-dap/EventHelper.cpp delete mode 100644 lldb/tools/lldb-dap/EventHelper.h delete mode 100644 lldb/tools/lldb-dap/ExceptionBreakpoint.cpp delete mode 100644 lldb/tools/lldb-dap/ExceptionBreakpoint.h delete mode 100644 lldb/tools/lldb-dap/FifoFiles.cpp delete mode 100644 lldb/tools/lldb-dap/FifoFiles.h delete mode 100644 lldb/tools/lldb-dap/FunctionBreakpoint.cpp delete mode 100644 lldb/tools/lldb-dap/FunctionBreakpoint.h delete mode 100644 lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/CancelRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/InitializeRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ModulesRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/PauseRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ReadMemoryRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/RequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/RequestHandler.h delete mode 100644 lldb/tools/lldb-dap/Handler/ResponseHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ResponseHandler.h delete mode 100644 lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/ThreadsRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp delete mode 100644 lldb/tools/lldb-dap/InstructionBreakpoint.cpp delete mode 100644 lldb/tools/lldb-dap/InstructionBreakpoint.h delete mode 100644 lldb/tools/lldb-dap/JSONUtils.cpp delete mode 100644 lldb/tools/lldb-dap/JSONUtils.h delete mode 100644 lldb/tools/lldb-dap/LICENSE.TXT delete mode 100644 lldb/tools/lldb-dap/LLDBUtils.cpp delete mode 100644 lldb/tools/lldb-dap/LLDBUtils.h delete mode 100644 lldb/tools/lldb-dap/Options.td delete mode 100644 lldb/tools/lldb-dap/OutputRedirector.cpp delete mode 100644 lldb/tools/lldb-dap/OutputRedirector.h delete mode 100644 lldb/tools/lldb-dap/ProgressEvent.cpp delete mode 100644 lldb/tools/lldb-dap/ProgressEvent.h delete mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp delete mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolBase.h delete mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp delete mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolRequests.h delete mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp delete mode 100644 lldb/tools/lldb-dap/Protocol/ProtocolTypes.h delete mode 100644 lldb/tools/lldb-dap/ProtocolUtils.cpp delete mode 100644 lldb/tools/lldb-dap/ProtocolUtils.h delete mode 100644 lldb/tools/lldb-dap/README.md delete mode 100644 lldb/tools/lldb-dap/RunInTerminal.cpp delete mode 100644 lldb/tools/lldb-dap/RunInTerminal.h delete mode 100644 lldb/tools/lldb-dap/SourceBreakpoint.cpp delete mode 100644 lldb/tools/lldb-dap/SourceBreakpoint.h delete mode 100644 lldb/tools/lldb-dap/Transport.cpp delete mode 100644 lldb/tools/lldb-dap/Transport.h delete mode 100644 lldb/tools/lldb-dap/Variables.cpp delete mode 100644 lldb/tools/lldb-dap/Variables.h delete mode 100644 lldb/tools/lldb-dap/Watchpoint.cpp delete mode 100644 lldb/tools/lldb-dap/Watchpoint.h delete mode 100644 lldb/tools/lldb-dap/llvm-logo.png delete mode 100644 lldb/tools/lldb-dap/package-lock.json delete mode 100644 lldb/tools/lldb-dap/package.json delete mode 100644 lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/debug-session-tracker.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/disposable-context.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/extension.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/ui/error-with-notification.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/ui/show-error-message.ts delete mode 100644 lldb/tools/lldb-dap/src-ts/uri-launch-handler.ts delete mode 100644 lldb/tools/lldb-dap/syntaxes/arm.disasm delete mode 100644 lldb/tools/lldb-dap/syntaxes/arm64.disasm delete mode 100644 lldb/tools/lldb-dap/syntaxes/disassembly.json delete mode 100644 lldb/tools/lldb-dap/syntaxes/x86.disasm delete mode 100644 lldb/tools/lldb-dap/tool/CMakeLists.txt delete mode 100644 lldb/tools/lldb-dap/tool/lldb-dap-Info.plist.in delete mode 100644 lldb/tools/lldb-dap/tool/lldb-dap.cpp delete mode 100644 lldb/tools/lldb-dap/tsconfig.json delete mode 100644 mlir/utils/vscode/.gitignore delete mode 100644 mlir/utils/vscode/.vscode/launch.json delete mode 100644 mlir/utils/vscode/.vscode/tasks.json delete mode 100644 mlir/utils/vscode/.vscodeignore delete mode 100644 mlir/utils/vscode/cpp-grammar.json delete mode 100644 mlir/utils/vscode/language-configuration.json delete mode 100644 mlir/utils/vscode/markdown-grammar.json delete mode 100644 mlir/utils/vscode/package-lock.json delete mode 100644 mlir/utils/vscode/package.json delete mode 100644 mlir/utils/vscode/pdll-grammar.json delete mode 100644 mlir/utils/vscode/pdll-language-configuration.json delete mode 100644 mlir/utils/vscode/src/MLIR/bytecodeProvider.ts delete mode 100644 mlir/utils/vscode/src/MLIR/mlir.ts delete mode 100644 mlir/utils/vscode/src/PDLL/commands/viewOutput.ts delete mode 100644 mlir/utils/vscode/src/PDLL/pdll.ts delete mode 100644 mlir/utils/vscode/src/command.ts delete mode 100644 mlir/utils/vscode/src/config.ts delete mode 100644 mlir/utils/vscode/src/configWatcher.ts delete mode 100644 mlir/utils/vscode/src/extension.ts delete mode 100644 mlir/utils/vscode/src/mlirContext.ts delete mode 100644 mlir/utils/vscode/tablegen-language-configuration.json delete mode 100644 mlir/utils/vscode/tsconfig.json diff --git a/lldb/tools/lldb-dap/.editorconfig b/lldb/tools/lldb-dap/.editorconfig deleted file mode 100644 index c97930f849a1..000000000000 --- a/lldb/tools/lldb-dap/.editorconfig +++ /dev/null @@ -1,10 +0,0 @@ -[{*.ts}] -# Non-configurable Prettier behaviors -charset = utf-8 -insert_final_newline = true -trim_trailing_whitespace = true - -end_of_line = lf -indent_style = space -indent_size = 2 -max_line_length = 100 diff --git a/lldb/tools/lldb-dap/.gitignore b/lldb/tools/lldb-dap/.gitignore deleted file mode 100644 index f4e1656d5a5d..000000000000 --- a/lldb/tools/lldb-dap/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -out -bin -node_modules -*.vsix -!.vscode diff --git a/lldb/tools/lldb-dap/.prettierrc.json b/lldb/tools/lldb-dap/.prettierrc.json deleted file mode 100644 index a28c70b90a4e..000000000000 --- a/lldb/tools/lldb-dap/.prettierrc.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "trailingComma": "all", - "tabWidth": 2, - "semi": true, - "singleQuote": false, - "plugins": ["prettier-plugin-curly"] -} diff --git a/lldb/tools/lldb-dap/.vscode/launch.json b/lldb/tools/lldb-dap/.vscode/launch.json deleted file mode 100644 index 8241a5aca035..000000000000 --- a/lldb/tools/lldb-dap/.vscode/launch.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "extensionHost", - "request": "launch", - "name": "Run Extension", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceFolder}" - ], - "outFiles": [ - "${workspaceFolder}/out/**/*.js" - ], - "preLaunchTask": { - "type": "npm", - "script": "watch" - } - } - ] -} diff --git a/lldb/tools/lldb-dap/.vscode/tasks.json b/lldb/tools/lldb-dap/.vscode/tasks.json deleted file mode 100644 index f82fc4134e78..000000000000 --- a/lldb/tools/lldb-dap/.vscode/tasks.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "compile", - "group": "build", - "presentation": { - "panel": "dedicated", - "reveal": "never" - }, - "problemMatcher": [ - "$tsc" - ] - }, - { - "type": "npm", - "script": "watch", - "isBackground": true, - "group": { - "kind": "build", - "isDefault": true - }, - "presentation": { - "panel": "dedicated", - "reveal": "never" - }, - "problemMatcher": [ - "$tsc-watch" - ] - } - ] -} diff --git a/lldb/tools/lldb-dap/.vscodeignore b/lldb/tools/lldb-dap/.vscodeignore deleted file mode 100644 index 511bbf3d0839..000000000000 --- a/lldb/tools/lldb-dap/.vscodeignore +++ /dev/null @@ -1,10 +0,0 @@ -// Ignore everything by default -**/* - -// Only include specific files and directories -!LICENSE.TXT -!package.json -!README.md -!llvm-logo.png -!out/** -!syntaxes/** \ No newline at end of file diff --git a/lldb/tools/lldb-dap/Breakpoint.cpp b/lldb/tools/lldb-dap/Breakpoint.cpp deleted file mode 100644 index ef5646c4c3d1..000000000000 --- a/lldb/tools/lldb-dap/Breakpoint.cpp +++ /dev/null @@ -1,107 +0,0 @@ -//===-- Breakpoint.cpp ----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Breakpoint.h" -#include "DAP.h" -#include "ProtocolUtils.h" -#include "lldb/API/SBAddress.h" -#include "lldb/API/SBBreakpointLocation.h" -#include "lldb/API/SBLineEntry.h" -#include "lldb/API/SBMutex.h" -#include "llvm/ADT/StringExtras.h" -#include -#include -#include -#include - -using namespace lldb_dap; - -void Breakpoint::SetCondition() { m_bp.SetCondition(m_condition.c_str()); } - -void Breakpoint::SetHitCondition() { - uint64_t hitCount = 0; - if (llvm::to_integer(m_hit_condition, hitCount)) - m_bp.SetIgnoreCount(hitCount - 1); -} - -protocol::Breakpoint Breakpoint::ToProtocolBreakpoint() { - protocol::Breakpoint breakpoint; - - // Each breakpoint location is treated as a separate breakpoint for VS code. - // They don't have the notion of a single breakpoint with multiple locations. - if (!m_bp.IsValid()) - return breakpoint; - - breakpoint.verified = m_bp.GetNumResolvedLocations() > 0; - breakpoint.id = m_bp.GetID(); - // VS Code DAP doesn't currently allow one breakpoint to have multiple - // locations so we just report the first one. If we report all locations - // then the IDE starts showing the wrong line numbers and locations for - // other source file and line breakpoints in the same file. - - // Below we search for the first resolved location in a breakpoint and report - // this as the breakpoint location since it will have a complete location - // that is at least loaded in the current process. - lldb::SBBreakpointLocation bp_loc; - const auto num_locs = m_bp.GetNumLocations(); - for (size_t i = 0; i < num_locs; ++i) { - bp_loc = m_bp.GetLocationAtIndex(i); - if (bp_loc.IsResolved()) - break; - } - // If not locations are resolved, use the first location. - if (!bp_loc.IsResolved()) - bp_loc = m_bp.GetLocationAtIndex(0); - auto bp_addr = bp_loc.GetAddress(); - - if (bp_addr.IsValid()) { - std::string formatted_addr = - "0x" + llvm::utohexstr(bp_addr.GetLoadAddress(m_bp.GetTarget())); - breakpoint.instructionReference = formatted_addr; - - auto source = CreateSource(bp_addr, m_dap.target); - if (!IsAssemblySource(source)) { - auto line_entry = bp_addr.GetLineEntry(); - const auto line = line_entry.GetLine(); - if (line != LLDB_INVALID_LINE_NUMBER) - breakpoint.line = line; - const auto column = line_entry.GetColumn(); - if (column != LLDB_INVALID_COLUMN_NUMBER) - breakpoint.column = column; - } else { - // Assembly breakpoint. - auto symbol = bp_addr.GetSymbol(); - if (symbol.IsValid()) { - breakpoint.line = - m_bp.GetTarget() - .ReadInstructions(symbol.GetStartAddress(), bp_addr, nullptr) - .GetSize() + - 1; - } - } - - breakpoint.source = std::move(source); - } - - return breakpoint; -} - -bool Breakpoint::MatchesName(const char *name) { - return m_bp.MatchesName(name); -} - -void Breakpoint::SetBreakpoint() { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - m_bp.AddName(kDAPBreakpointLabel); - if (!m_condition.empty()) - SetCondition(); - if (!m_hit_condition.empty()) - SetHitCondition(); -} diff --git a/lldb/tools/lldb-dap/Breakpoint.h b/lldb/tools/lldb-dap/Breakpoint.h deleted file mode 100644 index c4f1fa291f18..000000000000 --- a/lldb/tools/lldb-dap/Breakpoint.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- Breakpoint.h --------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_BREAKPOINT_H -#define LLDB_TOOLS_LLDB_DAP_BREAKPOINT_H - -#include "BreakpointBase.h" -#include "DAPForward.h" -#include "lldb/API/SBBreakpoint.h" - -namespace lldb_dap { - -class Breakpoint : public BreakpointBase { -public: - Breakpoint(DAP &d, const std::optional &condition, - const std::optional &hit_condition) - : BreakpointBase(d, condition, hit_condition) {} - Breakpoint(DAP &d, lldb::SBBreakpoint bp) : BreakpointBase(d), m_bp(bp) {} - - lldb::break_id_t GetID() const { return m_bp.GetID(); } - - void SetCondition() override; - void SetHitCondition() override; - protocol::Breakpoint ToProtocolBreakpoint() override; - - bool MatchesName(const char *name); - void SetBreakpoint(); - -protected: - /// The LLDB breakpoint associated wit this source breakpoint. - lldb::SBBreakpoint m_bp; -}; -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/BreakpointBase.cpp b/lldb/tools/lldb-dap/BreakpointBase.cpp deleted file mode 100644 index 1a4da92e44d3..000000000000 --- a/lldb/tools/lldb-dap/BreakpointBase.cpp +++ /dev/null @@ -1,28 +0,0 @@ -//===-- BreakpointBase.cpp --------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "BreakpointBase.h" - -using namespace lldb_dap; - -BreakpointBase::BreakpointBase(DAP &d, - const std::optional &condition, - const std::optional &hit_condition) - : m_dap(d), m_condition(condition.value_or("")), - m_hit_condition(hit_condition.value_or("")) {} - -void BreakpointBase::UpdateBreakpoint(const BreakpointBase &request_bp) { - if (m_condition != request_bp.m_condition) { - m_condition = request_bp.m_condition; - SetCondition(); - } - if (m_hit_condition != request_bp.m_hit_condition) { - m_hit_condition = request_bp.m_hit_condition; - SetHitCondition(); - } -} diff --git a/lldb/tools/lldb-dap/BreakpointBase.h b/lldb/tools/lldb-dap/BreakpointBase.h deleted file mode 100644 index e9cfc112675c..000000000000 --- a/lldb/tools/lldb-dap/BreakpointBase.h +++ /dev/null @@ -1,61 +0,0 @@ -//===-- BreakpointBase.h ----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_BREAKPOINTBASE_H -#define LLDB_TOOLS_LLDB_DAP_BREAKPOINTBASE_H - -#include "DAPForward.h" -#include "Protocol/ProtocolTypes.h" -#include -#include - -namespace lldb_dap { - -class BreakpointBase { -public: - explicit BreakpointBase(DAP &d) : m_dap(d) {} - BreakpointBase(DAP &d, const std::optional &condition, - const std::optional &hit_condition); - virtual ~BreakpointBase() = default; - - virtual void SetCondition() = 0; - virtual void SetHitCondition() = 0; - virtual protocol::Breakpoint ToProtocolBreakpoint() = 0; - - void UpdateBreakpoint(const BreakpointBase &request_bp); - - /// Breakpoints in LLDB can have names added to them which are kind of like - /// labels or categories. All breakpoints that are set through DAP get sent - /// through the various DAP set*Breakpoint packets, and these breakpoints will - /// be labeled with this name so if breakpoint update events come in for - /// breakpoints that the client doesn't know about, like if a breakpoint is - /// set manually using the debugger console, we won't report any updates on - /// them and confused the client. This label gets added by all of the - /// breakpoint classes after they set breakpoints to mark a breakpoint as a - /// DAP breakpoint. We can later check a lldb::SBBreakpoint object that comes - /// in via LLDB breakpoint changed events and check the breakpoint by calling - /// "bool lldb::SBBreakpoint::MatchesName(const char *)" to check if a - /// breakpoint in one of the DAP breakpoints that we should report changes - /// for. - static constexpr const char *kDAPBreakpointLabel = "dap"; - -protected: - /// Associated DAP session. - DAP &m_dap; - - /// An optional expression for conditional breakpoints. - std::string m_condition; - - /// An optional expression that controls how many hits of the breakpoint are - /// ignored. The backend is expected to interpret the expression as needed - std::string m_hit_condition; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/CMakeLists.txt b/lldb/tools/lldb-dap/CMakeLists.txt deleted file mode 100644 index f65c987d4c9c..000000000000 --- a/lldb/tools/lldb-dap/CMakeLists.txt +++ /dev/null @@ -1,90 +0,0 @@ -# We need to include the llvm components we depend on manually, as liblldb does -# not re-export those. -set(LLVM_LINK_COMPONENTS Support) -set(LLVM_TARGET_DEFINITIONS Options.td) -tablegen(LLVM Options.inc -gen-opt-parser-defs) -add_public_tablegen_target(LLDBDAPOptionsTableGen) - -add_lldb_library(lldbDAP - Breakpoint.cpp - BreakpointBase.cpp - CommandPlugins.cpp - DAP.cpp - DAPError.cpp - DAPLog.cpp - EventHelper.cpp - ExceptionBreakpoint.cpp - FifoFiles.cpp - FunctionBreakpoint.cpp - InstructionBreakpoint.cpp - JSONUtils.cpp - LLDBUtils.cpp - OutputRedirector.cpp - ProgressEvent.cpp - ProtocolUtils.cpp - RunInTerminal.cpp - SourceBreakpoint.cpp - Transport.cpp - Variables.cpp - Watchpoint.cpp - - Handler/ResponseHandler.cpp - Handler/AttachRequestHandler.cpp - Handler/BreakpointLocationsHandler.cpp - Handler/CancelRequestHandler.cpp - Handler/CompileUnitsRequestHandler.cpp - Handler/CompletionsHandler.cpp - Handler/ConfigurationDoneRequestHandler.cpp - Handler/ContinueRequestHandler.cpp - Handler/DataBreakpointInfoRequestHandler.cpp - Handler/DisassembleRequestHandler.cpp - Handler/DisconnectRequestHandler.cpp - Handler/EvaluateRequestHandler.cpp - Handler/ExceptionInfoRequestHandler.cpp - Handler/InitializeRequestHandler.cpp - Handler/LaunchRequestHandler.cpp - Handler/LocationsRequestHandler.cpp - Handler/ModulesRequestHandler.cpp - Handler/NextRequestHandler.cpp - Handler/PauseRequestHandler.cpp - Handler/ReadMemoryRequestHandler.cpp - Handler/RequestHandler.cpp - Handler/RestartRequestHandler.cpp - Handler/ScopesRequestHandler.cpp - Handler/SetBreakpointsRequestHandler.cpp - Handler/SetDataBreakpointsRequestHandler.cpp - Handler/SetExceptionBreakpointsRequestHandler.cpp - Handler/SetFunctionBreakpointsRequestHandler.cpp - Handler/SetInstructionBreakpointsRequestHandler.cpp - Handler/SetVariableRequestHandler.cpp - Handler/SourceRequestHandler.cpp - Handler/StackTraceRequestHandler.cpp - Handler/StepInRequestHandler.cpp - Handler/StepInTargetsRequestHandler.cpp - Handler/StepOutRequestHandler.cpp - Handler/TestGetTargetBreakpointsRequestHandler.cpp - Handler/ThreadsRequestHandler.cpp - Handler/VariablesRequestHandler.cpp - - Protocol/ProtocolBase.cpp - Protocol/ProtocolTypes.cpp - Protocol/ProtocolRequests.cpp - - LINK_COMPONENTS - Option - Support - LINK_LIBS - liblldb - lldbHost - ) - -target_include_directories(lldbDAP - PUBLIC ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR}) - -if(LLDB_DAP_WELCOME_MESSAGE) - target_compile_definitions(lldbDAP - PRIVATE - -DLLDB_DAP_WELCOME_MESSAGE=\"${LLDB_DAP_WELCOME_MESSAGE}\") -endif() - -add_subdirectory(tool) diff --git a/lldb/tools/lldb-dap/CommandPlugins.cpp b/lldb/tools/lldb-dap/CommandPlugins.cpp deleted file mode 100644 index 4e7aa029e0f2..000000000000 --- a/lldb/tools/lldb-dap/CommandPlugins.cpp +++ /dev/null @@ -1,163 +0,0 @@ -//===-- CommandPlugins.cpp ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "CommandPlugins.h" -#include "Handler/ResponseHandler.h" -#include "JSONUtils.h" -#include "lldb/API/SBStream.h" - -using namespace lldb_dap; - -bool StartDebuggingCommand::DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `start-debugging ` - if (!command) { - result.SetError("Invalid use of start-debugging, expected format " - "`start-debugging `."); - return false; - } - - if (!command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("start-debugging request type missing."); - return false; - } - - if (!command[1] || llvm::StringRef(command[1]).empty()) { - result.SetError("start-debugging debug configuration missing."); - return false; - } - - llvm::StringRef request{command[0]}; - std::string raw_configuration{command[1]}; - - llvm::Expected configuration = - llvm::json::parse(raw_configuration); - - if (!configuration) { - llvm::Error err = configuration.takeError(); - std::string msg = "Failed to parse json configuration: " + - llvm::toString(std::move(err)) + "\n\n" + - raw_configuration; - result.SetError(msg.c_str()); - return false; - } - - dap.SendReverseRequest( - "startDebugging", - llvm::json::Object{{"request", request}, - {"configuration", std::move(*configuration)}}); - - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - - return true; -} - -bool ReplModeCommand::DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `repl-mode ?` - // If a new mode is not specified report the current mode. - if (!command || llvm::StringRef(command[0]).empty()) { - std::string mode; - switch (dap.repl_mode) { - case ReplMode::Variable: - mode = "variable"; - break; - case ReplMode::Command: - mode = "command"; - break; - case ReplMode::Auto: - mode = "auto"; - break; - } - - result.Printf("lldb-dap repl-mode %s.\n", mode.c_str()); - result.SetStatus(lldb::eReturnStatusSuccessFinishResult); - - return true; - } - - llvm::StringRef new_mode{command[0]}; - - if (new_mode == "variable") { - dap.repl_mode = ReplMode::Variable; - } else if (new_mode == "command") { - dap.repl_mode = ReplMode::Command; - } else if (new_mode == "auto") { - dap.repl_mode = ReplMode::Auto; - } else { - lldb::SBStream error_message; - error_message.Printf("Invalid repl-mode '%s'. Expected one of 'variable', " - "'command' or 'auto'.\n", - new_mode.data()); - result.SetError(error_message.GetData()); - return false; - } - - result.Printf("lldb-dap repl-mode %s set.\n", new_mode.data()); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} - -/// Sends a DAP event with an optional body. -/// -/// https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent -bool SendEventCommand::DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) { - // Command format like: `send-event ?` - if (!command || !command[0] || llvm::StringRef(command[0]).empty()) { - result.SetError("Not enough arguments found, expected format " - "`lldb-dap send-event ?`."); - return false; - } - - llvm::StringRef name{command[0]}; - // Events that are stateful and should be handled by lldb-dap internally. - const std::array internal_events{"breakpoint", "capabilities", "continued", - "exited", "initialize", "loadedSource", - "module", "process", "stopped", - "terminated", "thread"}; - if (llvm::is_contained(internal_events, name)) { - std::string msg = - llvm::formatv("Invalid use of lldb-dap send-event, event \"{0}\" " - "should be handled by lldb-dap internally.", - name) - .str(); - result.SetError(msg.c_str()); - return false; - } - - llvm::json::Object event(CreateEventObject(name)); - - if (command[1] && !llvm::StringRef(command[1]).empty()) { - // See if we have unused arguments. - if (command[2]) { - result.SetError( - "Additional arguments found, expected `lldb-dap send-event " - " ?`."); - return false; - } - - llvm::StringRef raw_body{command[1]}; - - llvm::Expected body = llvm::json::parse(raw_body); - - if (!body) { - llvm::Error err = body.takeError(); - std::string msg = "Failed to parse custom event body: " + - llvm::toString(std::move(err)); - result.SetError(msg.c_str()); - return false; - } - - event.try_emplace("body", std::move(*body)); - } - - dap.SendJSON(llvm::json::Value(std::move(event))); - result.SetStatus(lldb::eReturnStatusSuccessFinishNoResult); - return true; -} diff --git a/lldb/tools/lldb-dap/CommandPlugins.h b/lldb/tools/lldb-dap/CommandPlugins.h deleted file mode 100644 index 011c7fd2da2a..000000000000 --- a/lldb/tools/lldb-dap/CommandPlugins.h +++ /dev/null @@ -1,40 +0,0 @@ -//===-- CommandPlugins.h --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H -#define LLDB_TOOLS_LLDB_DAP_COMMANDPLUGINS_H - -#include "DAP.h" -#include "lldb/API/SBCommandInterpreter.h" - -namespace lldb_dap { - -struct StartDebuggingCommand : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit StartDebuggingCommand(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct ReplModeCommand : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit ReplModeCommand(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -struct SendEventCommand : public lldb::SBCommandPluginInterface { - DAP &dap; - explicit SendEventCommand(DAP &d) : dap(d) {}; - bool DoExecute(lldb::SBDebugger debugger, char **command, - lldb::SBCommandReturnObject &result) override; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/DAP.cpp b/lldb/tools/lldb-dap/DAP.cpp deleted file mode 100644 index 2537e007d691..000000000000 --- a/lldb/tools/lldb-dap/DAP.cpp +++ /dev/null @@ -1,1492 +0,0 @@ -//===-- DAP.cpp -------------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "DAPLog.h" -#include "EventHelper.h" -#include "Handler/RequestHandler.h" -#include "Handler/ResponseHandler.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "OutputRedirector.h" -#include "Protocol/ProtocolBase.h" -#include "Protocol/ProtocolRequests.h" -#include "Protocol/ProtocolTypes.h" -#include "Transport.h" -#include "lldb/API/SBBreakpoint.h" -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBCommandReturnObject.h" -#include "lldb/API/SBEvent.h" -#include "lldb/API/SBLanguageRuntime.h" -#include "lldb/API/SBListener.h" -#include "lldb/API/SBProcess.h" -#include "lldb/API/SBStream.h" -#include "lldb/Utility/IOObject.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-defines.h" -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/STLExtras.h" -#include "llvm/ADT/ScopeExit.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Support/Chrono.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -#define NOMINMAX -#include -#include -#include -#else -#include -#endif - -using namespace lldb_dap; -using namespace lldb_dap::protocol; - -namespace { -#ifdef _WIN32 -const char DEV_NULL[] = "nul"; -#else -const char DEV_NULL[] = "/dev/null"; -#endif -} // namespace - -namespace lldb_dap { - -static std::string GetStringFromStructuredData(lldb::SBStructuredData &data, - const char *key) { - lldb::SBStructuredData keyValue = data.GetValueForKey(key); - if (!keyValue) - return std::string(); - - const size_t length = keyValue.GetStringValue(nullptr, 0); - - if (length == 0) - return std::string(); - - std::string str(length + 1, 0); - keyValue.GetStringValue(&str[0], length + 1); - return str; -} - -static uint64_t GetUintFromStructuredData(lldb::SBStructuredData &data, - const char *key) { - lldb::SBStructuredData keyValue = data.GetValueForKey(key); - - if (!keyValue.IsValid()) - return 0; - return keyValue.GetUnsignedIntegerValue(); -} - -/// Return string with first character capitalized. -static std::string capitalize(llvm::StringRef str) { - if (str.empty()) - return ""; - return ((llvm::Twine)llvm::toUpper(str[0]) + str.drop_front()).str(); -} - -llvm::StringRef DAP::debug_adapter_path = ""; - -DAP::DAP(Log *log, const ReplMode default_repl_mode, - std::vector pre_init_commands, Transport &transport) - : log(log), transport(transport), broadcaster("lldb-dap"), - progress_event_reporter( - [&](const ProgressEvent &event) { SendJSON(event.ToJSON()); }), - repl_mode(default_repl_mode) { - configuration.preInitCommands = std::move(pre_init_commands); - RegisterRequests(); -} - -DAP::~DAP() = default; - -void DAP::PopulateExceptionBreakpoints() { - llvm::call_once(init_exception_breakpoints_flag, [this]() { - exception_breakpoints = std::vector{}; - - if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeC_plus_plus)) { - exception_breakpoints->emplace_back(*this, "cpp_catch", "C++ Catch", - lldb::eLanguageTypeC_plus_plus); - exception_breakpoints->emplace_back(*this, "cpp_throw", "C++ Throw", - lldb::eLanguageTypeC_plus_plus); - } - if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeObjC)) { - exception_breakpoints->emplace_back( - *this, "objc_catch", "Objective-C Catch", lldb::eLanguageTypeObjC); - exception_breakpoints->emplace_back( - *this, "objc_throw", "Objective-C Throw", lldb::eLanguageTypeObjC); - } - if (lldb::SBDebugger::SupportsLanguage(lldb::eLanguageTypeSwift)) { - exception_breakpoints->emplace_back(*this, "swift_catch", "Swift Catch", - lldb::eLanguageTypeSwift); - exception_breakpoints->emplace_back(*this, "swift_throw", "Swift Throw", - lldb::eLanguageTypeSwift); - } - // Besides handling the hardcoded list of languages from above, we try to - // find any other languages that support exception breakpoints using the - // SB API. - for (int raw_lang = lldb::eLanguageTypeUnknown; - raw_lang < lldb::eNumLanguageTypes; ++raw_lang) { - lldb::LanguageType lang = static_cast(raw_lang); - - // We first discard any languages already handled above. - if (lldb::SBLanguageRuntime::LanguageIsCFamily(lang) || - lang == lldb::eLanguageTypeSwift) - continue; - - if (!lldb::SBDebugger::SupportsLanguage(lang)) - continue; - - const char *name = lldb::SBLanguageRuntime::GetNameForLanguageType(lang); - if (!name) - continue; - std::string raw_lang_name = name; - std::string capitalized_lang_name = capitalize(name); - - if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnThrow(lang)) { - const char *raw_throw_keyword = - lldb::SBLanguageRuntime::GetThrowKeywordForLanguage(lang); - std::string throw_keyword = - raw_throw_keyword ? raw_throw_keyword : "throw"; - - exception_breakpoints->emplace_back( - *this, raw_lang_name + "_" + throw_keyword, - capitalized_lang_name + " " + capitalize(throw_keyword), lang); - } - - if (lldb::SBLanguageRuntime::SupportsExceptionBreakpointsOnCatch(lang)) { - const char *raw_catch_keyword = - lldb::SBLanguageRuntime::GetCatchKeywordForLanguage(lang); - std::string catch_keyword = - raw_catch_keyword ? raw_catch_keyword : "catch"; - - exception_breakpoints->emplace_back( - *this, raw_lang_name + "_" + catch_keyword, - capitalized_lang_name + " " + capitalize(catch_keyword), lang); - } - } - assert(!exception_breakpoints->empty() && "should not be empty"); - }); -} - -ExceptionBreakpoint *DAP::GetExceptionBreakpoint(llvm::StringRef filter) { - // PopulateExceptionBreakpoints() is called after g_dap.debugger is created - // in a request-initialize. - // - // But this GetExceptionBreakpoint() method may be called before attaching, in - // which case, we may not have populated the filter yet. - // - // We also cannot call PopulateExceptionBreakpoints() in DAP::DAP() because - // we need SBDebugger::Initialize() to have been called before this. - // - // So just calling PopulateExceptionBreakoints(),which does lazy-populating - // seems easiest. Two other options include: - // + call g_dap.PopulateExceptionBreakpoints() in lldb-dap.cpp::main() - // right after the call to SBDebugger::Initialize() - // + Just call PopulateExceptionBreakpoints() to get a fresh list everytime - // we query (a bit overkill since it's not likely to change?) - PopulateExceptionBreakpoints(); - - for (auto &bp : *exception_breakpoints) { - if (bp.GetFilter() == filter) - return &bp; - } - return nullptr; -} - -ExceptionBreakpoint *DAP::GetExceptionBreakpoint(const lldb::break_id_t bp_id) { - // See comment in the other GetExceptionBreakpoint(). - PopulateExceptionBreakpoints(); - - for (auto &bp : *exception_breakpoints) { - if (bp.GetID() == bp_id) - return &bp; - } - return nullptr; -} - -llvm::Error DAP::ConfigureIO(std::FILE *overrideOut, std::FILE *overrideErr) { - in = lldb::SBFile(std::fopen(DEV_NULL, "r"), /*transfer_ownership=*/true); - - if (auto Error = out.RedirectTo(overrideOut, [this](llvm::StringRef output) { - SendOutput(OutputType::Console, output); - })) - return Error; - - if (auto Error = err.RedirectTo(overrideErr, [this](llvm::StringRef output) { - SendOutput(OutputType::Console, output); - })) - return Error; - - return llvm::Error::success(); -} - -void DAP::StopEventHandlers() { - if (event_thread.joinable()) { - broadcaster.BroadcastEventByType(eBroadcastBitStopEventThread); - event_thread.join(); - } - if (progress_event_thread.joinable()) { - broadcaster.BroadcastEventByType(eBroadcastBitStopProgressThread); - progress_event_thread.join(); - } -} - -// Serialize the JSON value into a string and send the JSON packet to -// the "out" stream. -void DAP::SendJSON(const llvm::json::Value &json) { - // FIXME: Instead of parsing the output message from JSON, pass the `Message` - // as parameter to `SendJSON`. - Message message; - llvm::json::Path::Root root; - if (!fromJSON(json, message, root)) { - DAP_LOG_ERROR(log, root.getError(), "({1}) encoding failed: {0}", - transport.GetClientName()); - return; - } - Send(message); -} - -void DAP::Send(const Message &message) { - // FIXME: After all the requests have migrated from LegacyRequestHandler > - // RequestHandler<> this should be handled in RequestHandler<>::operator(). - if (auto *resp = std::get_if(&message); - resp && debugger.InterruptRequested()) { - // Clear the interrupt request. - debugger.CancelInterruptRequest(); - - // If the debugger was interrupted, convert this response into a 'cancelled' - // response because we might have a partial result. - Response cancelled{/*request_seq=*/resp->request_seq, - /*command=*/resp->command, - /*success=*/false, - /*message=*/eResponseMessageCancelled, - /*body=*/std::nullopt}; - if (llvm::Error err = transport.Write(cancelled)) - DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}", - transport.GetClientName()); - return; - } - - if (llvm::Error err = transport.Write(message)) - DAP_LOG_ERROR(log, std::move(err), "({1}) write failed: {0}", - transport.GetClientName()); -} - -// "OutputEvent": { -// "allOf": [ { "$ref": "#/definitions/Event" }, { -// "type": "object", -// "description": "Event message for 'output' event type. The event -// indicates that the target has produced some output.", -// "properties": { -// "event": { -// "type": "string", -// "enum": [ "output" ] -// }, -// "body": { -// "type": "object", -// "properties": { -// "category": { -// "type": "string", -// "description": "The output category. If not specified, -// 'console' is assumed.", -// "_enum": [ "console", "stdout", "stderr", "telemetry" ] -// }, -// "output": { -// "type": "string", -// "description": "The output to report." -// }, -// "variablesReference": { -// "type": "number", -// "description": "If an attribute 'variablesReference' exists -// and its value is > 0, the output contains -// objects which can be retrieved by passing -// variablesReference to the VariablesRequest." -// }, -// "source": { -// "$ref": "#/definitions/Source", -// "description": "An optional source location where the output -// was produced." -// }, -// "line": { -// "type": "integer", -// "description": "An optional source location line where the -// output was produced." -// }, -// "column": { -// "type": "integer", -// "description": "An optional source location column where the -// output was produced." -// }, -// "data": { -// "type":["array","boolean","integer","null","number","object", -// "string"], -// "description": "Optional data to report. For the 'telemetry' -// category the data will be sent to telemetry, for -// the other categories the data is shown in JSON -// format." -// } -// }, -// "required": ["output"] -// } -// }, -// "required": [ "event", "body" ] -// }] -// } -void DAP::SendOutput(OutputType o, const llvm::StringRef output) { - if (output.empty()) - return; - - const char *category = nullptr; - switch (o) { - case OutputType::Console: - category = "console"; - break; - case OutputType::Important: - category = "important"; - break; - case OutputType::Stdout: - category = "stdout"; - break; - case OutputType::Stderr: - category = "stderr"; - break; - case OutputType::Telemetry: - category = "telemetry"; - break; - } - - // Send each line of output as an individual event, including the newline if - // present. - ::size_t idx = 0; - do { - ::size_t end = output.find('\n', idx); - if (end == llvm::StringRef::npos) - end = output.size() - 1; - llvm::json::Object event(CreateEventObject("output")); - llvm::json::Object body; - body.try_emplace("category", category); - EmplaceSafeString(body, "output", output.slice(idx, end + 1).str()); - event.try_emplace("body", std::move(body)); - SendJSON(llvm::json::Value(std::move(event))); - idx = end + 1; - } while (idx < output.size()); -} - -// interface ProgressStartEvent extends Event { -// event: 'progressStart'; -// -// body: { -// /** -// * An ID that must be used in subsequent 'progressUpdate' and -// 'progressEnd' -// * events to make them refer to the same progress reporting. -// * IDs must be unique within a debug session. -// */ -// progressId: string; -// -// /** -// * Mandatory (short) title of the progress reporting. Shown in the UI to -// * describe the long running operation. -// */ -// title: string; -// -// /** -// * The request ID that this progress report is related to. If specified a -// * debug adapter is expected to emit -// * progress events for the long running request until the request has -// been -// * either completed or cancelled. -// * If the request ID is omitted, the progress report is assumed to be -// * related to some general activity of the debug adapter. -// */ -// requestId?: number; -// -// /** -// * If true, the request that reports progress may be canceled with a -// * 'cancel' request. -// * So this property basically controls whether the client should use UX -// that -// * supports cancellation. -// * Clients that don't support cancellation are allowed to ignore the -// * setting. -// */ -// cancellable?: boolean; -// -// /** -// * Optional, more detailed progress message. -// */ -// message?: string; -// -// /** -// * Optional progress percentage to display (value range: 0 to 100). If -// * omitted no percentage will be shown. -// */ -// percentage?: number; -// }; -// } -// -// interface ProgressUpdateEvent extends Event { -// event: 'progressUpdate'; -// -// body: { -// /** -// * The ID that was introduced in the initial 'progressStart' event. -// */ -// progressId: string; -// -// /** -// * Optional, more detailed progress message. If omitted, the previous -// * message (if any) is used. -// */ -// message?: string; -// -// /** -// * Optional progress percentage to display (value range: 0 to 100). If -// * omitted no percentage will be shown. -// */ -// percentage?: number; -// }; -// } -// -// interface ProgressEndEvent extends Event { -// event: 'progressEnd'; -// -// body: { -// /** -// * The ID that was introduced in the initial 'ProgressStartEvent'. -// */ -// progressId: string; -// -// /** -// * Optional, more detailed progress message. If omitted, the previous -// * message (if any) is used. -// */ -// message?: string; -// }; -// } - -void DAP::SendProgressEvent(uint64_t progress_id, const char *message, - uint64_t completed, uint64_t total) { - progress_event_reporter.Push(progress_id, message, completed, total); -} - -void __attribute__((format(printf, 3, 4))) -DAP::SendFormattedOutput(OutputType o, const char *format, ...) { - char buffer[1024]; - va_list args; - va_start(args, format); - int actual_length = vsnprintf(buffer, sizeof(buffer), format, args); - va_end(args); - SendOutput( - o, llvm::StringRef(buffer, std::min(actual_length, sizeof(buffer)))); -} - -ExceptionBreakpoint *DAP::GetExceptionBPFromStopReason(lldb::SBThread &thread) { - const auto num = thread.GetStopReasonDataCount(); - // Check to see if have hit an exception breakpoint and change the - // reason to "exception", but only do so if all breakpoints that were - // hit are exception breakpoints. - ExceptionBreakpoint *exc_bp = nullptr; - for (size_t i = 0; i < num; i += 2) { - // thread.GetStopReasonDataAtIndex(i) will return the bp ID and - // thread.GetStopReasonDataAtIndex(i+1) will return the location - // within that breakpoint. We only care about the bp ID so we can - // see if this is an exception breakpoint that is getting hit. - lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i); - exc_bp = GetExceptionBreakpoint(bp_id); - // If any breakpoint is not an exception breakpoint, then stop and - // report this as a normal breakpoint - if (exc_bp == nullptr) - return nullptr; - } - return exc_bp; -} - -lldb::SBThread DAP::GetLLDBThread(lldb::tid_t tid) { - return target.GetProcess().GetThreadByID(tid); -} - -lldb::SBThread DAP::GetLLDBThread(const llvm::json::Object &arguments) { - auto tid = GetInteger(arguments, "threadId") - .value_or(LLDB_INVALID_THREAD_ID); - return target.GetProcess().GetThreadByID(tid); -} - -lldb::SBFrame DAP::GetLLDBFrame(uint64_t frame_id) { - lldb::SBProcess process = target.GetProcess(); - // Upper 32 bits is the thread index ID - lldb::SBThread thread = - process.GetThreadByIndexID(GetLLDBThreadIndexID(frame_id)); - // Lower 32 bits is the frame index - return thread.GetFrameAtIndex(GetLLDBFrameID(frame_id)); -} - -lldb::SBFrame DAP::GetLLDBFrame(const llvm::json::Object &arguments) { - const auto frame_id = - GetInteger(arguments, "frameId").value_or(UINT64_MAX); - return GetLLDBFrame(frame_id); -} - -ReplMode DAP::DetectReplMode(lldb::SBFrame frame, std::string &expression, - bool partial_expression) { - // Check for the escape hatch prefix. - if (!expression.empty() && - llvm::StringRef(expression) - .starts_with(configuration.commandEscapePrefix)) { - expression = expression.substr(configuration.commandEscapePrefix.size()); - return ReplMode::Command; - } - - switch (repl_mode) { - case ReplMode::Variable: - return ReplMode::Variable; - case ReplMode::Command: - return ReplMode::Command; - case ReplMode::Auto: - // To determine if the expression is a command or not, check if the first - // term is a variable or command. If it's a variable in scope we will prefer - // that behavior and give a warning to the user if they meant to invoke the - // operation as a command. - // - // Example use case: - // int p and expression "p + 1" > variable - // int i and expression "i" > variable - // int var and expression "va" > command - std::pair token = - llvm::getToken(expression); - - // If the first token is not fully finished yet, we can't - // determine whether this will be a variable or a lldb command. - if (partial_expression && token.second.empty()) - return ReplMode::Auto; - - std::string term = token.first.str(); - lldb::SBCommandInterpreter interpreter = debugger.GetCommandInterpreter(); - bool term_is_command = interpreter.CommandExists(term.c_str()) || - interpreter.UserCommandExists(term.c_str()) || - interpreter.AliasExists(term.c_str()); - bool term_is_variable = frame.FindVariable(term.c_str()).IsValid(); - - // If we have both a variable and command, warn the user about the conflict. - if (term_is_command && term_is_variable) { - llvm::errs() - << "Warning: Expression '" << term - << "' is both an LLDB command and variable. It will be evaluated as " - "a variable. To evaluate the expression as an LLDB command, use '" - << configuration.commandEscapePrefix << "' as a prefix.\n"; - } - - // Variables take preference to commands in auto, since commands can always - // be called using the command_escape_prefix - return term_is_variable ? ReplMode::Variable - : term_is_command ? ReplMode::Command - : ReplMode::Variable; - } - - llvm_unreachable("enum cases exhausted."); -} - -bool DAP::RunLLDBCommands(llvm::StringRef prefix, - llvm::ArrayRef commands) { - bool required_command_failed = false; - std::string output = ::RunLLDBCommands( - debugger, prefix, commands, required_command_failed, - /*parse_command_directives*/ true, /*echo_commands*/ true); - SendOutput(OutputType::Console, output); - return !required_command_failed; -} - -static llvm::Error createRunLLDBCommandsErrorMessage(llvm::StringRef category) { - return llvm::createStringError( - llvm::inconvertibleErrorCode(), - llvm::formatv( - "Failed to run {0} commands. See the Debug Console for more details.", - category) - .str() - .c_str()); -} - -llvm::Error -DAP::RunAttachCommands(llvm::ArrayRef attach_commands) { - if (!RunLLDBCommands("Running attachCommands:", attach_commands)) - return createRunLLDBCommandsErrorMessage("attach"); - return llvm::Error::success(); -} - -llvm::Error -DAP::RunLaunchCommands(llvm::ArrayRef launch_commands) { - if (!RunLLDBCommands("Running launchCommands:", launch_commands)) - return createRunLLDBCommandsErrorMessage("launch"); - return llvm::Error::success(); -} - -llvm::Error DAP::RunInitCommands() { - if (!RunLLDBCommands("Running initCommands:", configuration.initCommands)) - return createRunLLDBCommandsErrorMessage("initCommands"); - return llvm::Error::success(); -} - -llvm::Error DAP::RunPreInitCommands() { - if (!RunLLDBCommands("Running preInitCommands:", - configuration.preInitCommands)) - return createRunLLDBCommandsErrorMessage("preInitCommands"); - return llvm::Error::success(); -} - -llvm::Error DAP::RunPreRunCommands() { - if (!RunLLDBCommands("Running preRunCommands:", configuration.preRunCommands)) - return createRunLLDBCommandsErrorMessage("preRunCommands"); - return llvm::Error::success(); -} - -void DAP::RunPostRunCommands() { - RunLLDBCommands("Running postRunCommands:", configuration.postRunCommands); -} -void DAP::RunStopCommands() { - RunLLDBCommands("Running stopCommands:", configuration.stopCommands); -} - -void DAP::RunExitCommands() { - RunLLDBCommands("Running exitCommands:", configuration.exitCommands); -} - -void DAP::RunTerminateCommands() { - RunLLDBCommands("Running terminateCommands:", - configuration.terminateCommands); -} - -lldb::SBTarget DAP::CreateTarget(lldb::SBError &error) { - // Grab the name of the program we need to debug and create a target using - // the given program as an argument. Executable file can be a source of target - // architecture and platform, if they differ from the host. Setting exe path - // in launch info is useless because Target.Launch() will not change - // architecture and platform, therefore they should be known at the target - // creation. We also use target triple and platform from the launch - // configuration, if given, since in some cases ELF file doesn't contain - // enough information to determine correct arch and platform (or ELF can be - // omitted at all), so it is good to leave the user an opportunity to specify - // those. Any of those three can be left empty. - auto target = this->debugger.CreateTarget( - /*filename=*/configuration.program.data(), - /*target_triple=*/configuration.targetTriple.data(), - /*platform_name=*/configuration.platformName.data(), - /*add_dependent_modules=*/true, // Add dependent modules. - error); - - return target; -} - -void DAP::SetTarget(const lldb::SBTarget target) { - this->target = target; - - if (target.IsValid()) { - // Configure breakpoint event listeners for the target. - lldb::SBListener listener = this->debugger.GetListener(); - listener.StartListeningForEvents( - this->target.GetBroadcaster(), - lldb::SBTarget::eBroadcastBitBreakpointChanged | - lldb::SBTarget::eBroadcastBitModulesLoaded | - lldb::SBTarget::eBroadcastBitModulesUnloaded | - lldb::SBTarget::eBroadcastBitSymbolsLoaded | - lldb::SBTarget::eBroadcastBitSymbolsChanged); - listener.StartListeningForEvents(this->broadcaster, - eBroadcastBitStopEventThread); - } -} - -bool DAP::HandleObject(const Message &M) { - TelemetryDispatcher dispatcher(&debugger); - dispatcher.Set("client_name", transport.GetClientName().str()); - if (const auto *req = std::get_if(&M)) { - { - std::lock_guard guard(m_active_request_mutex); - m_active_request = req; - - // Clear the interrupt request prior to invoking a handler. - if (debugger.InterruptRequested()) - debugger.CancelInterruptRequest(); - } - - auto cleanup = llvm::make_scope_exit([&]() { - std::scoped_lock active_request_lock(m_active_request_mutex); - m_active_request = nullptr; - }); - - auto handler_pos = request_handlers.find(req->command); - dispatcher.Set("client_data", - llvm::Twine("request_command:", req->command).str()); - if (handler_pos != request_handlers.end()) { - handler_pos->second->Run(*req); - return true; // Success - } - - dispatcher.Set("error", - llvm::Twine("unhandled-command:" + req->command).str()); - DAP_LOG(log, "({0}) error: unhandled command '{1}'", - transport.GetClientName(), req->command); - return false; // Fail - } - - if (const auto *resp = std::get_if(&M)) { - std::unique_ptr response_handler; - { - std::lock_guard guard(call_mutex); - auto inflight = inflight_reverse_requests.find(resp->request_seq); - if (inflight != inflight_reverse_requests.end()) { - response_handler = std::move(inflight->second); - inflight_reverse_requests.erase(inflight); - } - } - - if (!response_handler) - response_handler = - std::make_unique("", resp->request_seq); - - // Result should be given, use null if not. - if (resp->success) { - (*response_handler)(resp->body); - dispatcher.Set("client_data", - llvm::Twine("response_command:", resp->command).str()); - } else { - llvm::StringRef message = "Unknown error, response failed"; - if (resp->message) { - message = - std::visit(llvm::makeVisitor( - [](const std::string &message) -> llvm::StringRef { - return message; - }, - [](const protocol::ResponseMessage &message) - -> llvm::StringRef { - switch (message) { - case protocol::eResponseMessageCancelled: - return "cancelled"; - case protocol::eResponseMessageNotStopped: - return "notStopped"; - } - llvm_unreachable("unknown response message kind."); - }), - *resp->message); - } - dispatcher.Set("error", message.str()); - - (*response_handler)(llvm::createStringError( - std::error_code(-1, std::generic_category()), message)); - } - - return true; - } - - dispatcher.Set("error", "Unsupported protocol message"); - DAP_LOG(log, "Unsupported protocol message"); - - return false; -} - -void DAP::SendTerminatedEvent() { - // Prevent races if the process exits while we're being asked to disconnect. - llvm::call_once(terminated_event_flag, [&] { - RunTerminateCommands(); - // Send a "terminated" event - llvm::json::Object event(CreateTerminatedEventObject(target)); - SendJSON(llvm::json::Value(std::move(event))); - }); -} - -llvm::Error DAP::Disconnect() { return Disconnect(!is_attach); } - -llvm::Error DAP::Disconnect(bool terminateDebuggee) { - lldb::SBError error; - lldb::SBProcess process = target.GetProcess(); - auto state = process.GetState(); - switch (state) { - case lldb::eStateInvalid: - case lldb::eStateUnloaded: - case lldb::eStateDetached: - case lldb::eStateExited: - break; - case lldb::eStateConnected: - case lldb::eStateAttaching: - case lldb::eStateLaunching: - case lldb::eStateStepping: - case lldb::eStateCrashed: - case lldb::eStateSuspended: - case lldb::eStateStopped: - case lldb::eStateRunning: { - ScopeSyncMode scope_sync_mode(debugger); - error = terminateDebuggee ? process.Kill() : process.Detach(); - break; - } - } - - SendTerminatedEvent(); - - disconnecting = true; - - return ToError(error); -} - -bool DAP::IsCancelled(const protocol::Request &req) { - std::lock_guard guard(m_cancelled_requests_mutex); - return m_cancelled_requests.contains(req.seq); -} - -void DAP::ClearCancelRequest(const CancelArguments &args) { - std::lock_guard guard(m_cancelled_requests_mutex); - if (args.requestId) - m_cancelled_requests.erase(*args.requestId); -} - -template -static std::optional getArgumentsIfRequest(const Message &pm, - llvm::StringLiteral command) { - auto *const req = std::get_if(&pm); - if (!req || req->command != command) - return std::nullopt; - - T args; - llvm::json::Path::Root root; - if (!fromJSON(req->arguments, args, root)) - return std::nullopt; - - return args; -} - -llvm::Error DAP::Loop() { - // Can't use \a std::future because it doesn't compile on - // Windows. - std::future queue_reader = - std::async(std::launch::async, [&]() -> lldb::SBError { - llvm::set_thread_name(transport.GetClientName() + ".transport_handler"); - auto cleanup = llvm::make_scope_exit([&]() { - // Ensure we're marked as disconnecting when the reader exits. - disconnecting = true; - m_queue_cv.notify_all(); - }); - - while (!disconnecting) { - llvm::Expected next = - transport.Read(std::chrono::seconds(1)); - if (next.errorIsA()) { - consumeError(next.takeError()); - break; - } - - // If the read timed out, continue to check if we should disconnect. - if (next.errorIsA()) { - consumeError(next.takeError()); - continue; - } - - if (llvm::Error err = next.takeError()) { - lldb::SBError errWrapper; - errWrapper.SetErrorString(llvm::toString(std::move(err)).c_str()); - return errWrapper; - } - - if (const protocol::Request *req = - std::get_if(&*next); - req && req->arguments == "disconnect") - disconnecting = true; - - const std::optional cancel_args = - getArgumentsIfRequest(*next, "cancel"); - if (cancel_args) { - { - std::lock_guard guard(m_cancelled_requests_mutex); - if (cancel_args->requestId) - m_cancelled_requests.insert(*cancel_args->requestId); - } - - // If a cancel is requested for the active request, make a best - // effort attempt to interrupt. - std::lock_guard guard(m_active_request_mutex); - if (m_active_request && - cancel_args->requestId == m_active_request->seq) { - DAP_LOG( - log, - "({0}) interrupting inflight request (command={1} seq={2})", - transport.GetClientName(), m_active_request->command, - m_active_request->seq); - debugger.RequestInterrupt(); - } - } - - { - std::lock_guard guard(m_queue_mutex); - m_queue.push_back(std::move(*next)); - } - m_queue_cv.notify_one(); - } - - return lldb::SBError(); - }); - - auto cleanup = llvm::make_scope_exit([&]() { - out.Stop(); - err.Stop(); - StopEventHandlers(); - }); - - while (true) { - std::unique_lock lock(m_queue_mutex); - m_queue_cv.wait(lock, [&] { return disconnecting || !m_queue.empty(); }); - - if (disconnecting && m_queue.empty()) - break; - - Message next = m_queue.front(); - m_queue.pop_front(); - - // Unlock while we're processing the event. - lock.unlock(); - - if (!HandleObject(next)) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "unhandled packet"); - } - - return ToError(queue_reader.get()); -} - -lldb::SBError DAP::WaitForProcessToStop(std::chrono::seconds seconds) { - lldb::SBError error; - lldb::SBProcess process = target.GetProcess(); - if (!process.IsValid()) { - error.SetErrorString("invalid process"); - return error; - } - auto timeout_time = - std::chrono::steady_clock::now() + std::chrono::seconds(seconds); - while (std::chrono::steady_clock::now() < timeout_time) { - const auto state = process.GetState(); - switch (state) { - case lldb::eStateUnloaded: - case lldb::eStateAttaching: - case lldb::eStateConnected: - case lldb::eStateInvalid: - case lldb::eStateLaunching: - case lldb::eStateRunning: - case lldb::eStateStepping: - case lldb::eStateSuspended: - break; - case lldb::eStateDetached: - error.SetErrorString("process detached during launch or attach"); - return error; - case lldb::eStateExited: - error.SetErrorString("process exited during launch or attach"); - return error; - case lldb::eStateCrashed: - case lldb::eStateStopped: - return lldb::SBError(); // Success! - } - std::this_thread::sleep_for(std::chrono::microseconds(250)); - } - error.SetErrorString( - llvm::formatv("process failed to stop within {0}", seconds) - .str() - .c_str()); - return error; -} - -void DAP::ConfigureSourceMaps() { - if (configuration.sourceMap.empty() && configuration.sourcePath.empty()) - return; - - std::string sourceMapCommand; - llvm::raw_string_ostream strm(sourceMapCommand); - strm << "settings set target.source-map "; - - if (!configuration.sourceMap.empty()) { - for (const auto &kv : configuration.sourceMap) { - strm << "\"" << kv.first << "\" \"" << kv.second << "\" "; - } - } else if (!configuration.sourcePath.empty()) { - strm << "\".\" \"" << configuration.sourcePath << "\""; - } - - RunLLDBCommands("Setting source map:", {sourceMapCommand}); -} - -void DAP::SetConfiguration(const protocol::Configuration &config, - bool is_attach) { - configuration = config; - stop_at_entry = config.stopOnEntry; - this->is_attach = is_attach; - - if (configuration.customFrameFormat) - SetFrameFormat(*configuration.customFrameFormat); - if (configuration.customThreadFormat) - SetThreadFormat(*configuration.customThreadFormat); -} - -void DAP::SetFrameFormat(llvm::StringRef format) { - lldb::SBError error; - frame_format = lldb::SBFormat(format.str().c_str(), error); - if (error.Fail()) { - SendOutput(OutputType::Console, - llvm::formatv( - "The provided frame format '{0}' couldn't be parsed: {1}\n", - format, error.GetCString()) - .str()); - } -} - -void DAP::SetThreadFormat(llvm::StringRef format) { - lldb::SBError error; - thread_format = lldb::SBFormat(format.str().c_str(), error); - if (error.Fail()) { - SendOutput(OutputType::Console, - llvm::formatv( - "The provided thread format '{0}' couldn't be parsed: {1}\n", - format, error.GetCString()) - .str()); - } -} - -InstructionBreakpoint * -DAP::GetInstructionBreakpoint(const lldb::break_id_t bp_id) { - for (auto &bp : instruction_breakpoints) { - if (bp.second.GetID() == bp_id) - return &bp.second; - } - return nullptr; -} - -InstructionBreakpoint * -DAP::GetInstructionBPFromStopReason(lldb::SBThread &thread) { - const auto num = thread.GetStopReasonDataCount(); - InstructionBreakpoint *inst_bp = nullptr; - for (size_t i = 0; i < num; i += 2) { - // thread.GetStopReasonDataAtIndex(i) will return the bp ID and - // thread.GetStopReasonDataAtIndex(i+1) will return the location - // within that breakpoint. We only care about the bp ID so we can - // see if this is an instruction breakpoint that is getting hit. - lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(i); - inst_bp = GetInstructionBreakpoint(bp_id); - // If any breakpoint is not an instruction breakpoint, then stop and - // report this as a normal breakpoint - if (inst_bp == nullptr) - return nullptr; - } - return inst_bp; -} - -protocol::Capabilities DAP::GetCapabilities() { - protocol::Capabilities capabilities; - - // Supported capabilities that are not specific to a single request. - capabilities.supportedFeatures = { - protocol::eAdapterFeatureLogPoints, - protocol::eAdapterFeatureSteppingGranularity, - protocol::eAdapterFeatureValueFormattingOptions, - }; - - // Capabilities associated with specific requests. - for (auto &kv : request_handlers) { - llvm::SmallDenseSet features = - kv.second->GetSupportedFeatures(); - capabilities.supportedFeatures.insert(features.begin(), features.end()); - } - - // Available filters or options for the setExceptionBreakpoints request. - std::vector filters; - for (const auto &exc_bp : *exception_breakpoints) - filters.emplace_back(CreateExceptionBreakpointFilter(exc_bp)); - capabilities.exceptionBreakpointFilters = std::move(filters); - - // FIXME: This should be registered based on the supported languages? - std::vector completion_characters; - completion_characters.emplace_back("."); - // FIXME: I wonder if we should remove this key... its very aggressive - // triggering and accepting completions. - completion_characters.emplace_back(" "); - completion_characters.emplace_back("\t"); - capabilities.completionTriggerCharacters = std::move(completion_characters); - - // Put in non-DAP specification lldb specific information. - capabilities.lldbExtVersion = debugger.GetVersionString(); - - return capabilities; -} - -void DAP::StartEventThread() { - event_thread = std::thread(&DAP::EventThread, this); -} - -void DAP::StartProgressEventThread() { - progress_event_thread = std::thread(&DAP::ProgressEventThread, this); -} - -void DAP::ProgressEventThread() { - lldb::SBListener listener("lldb-dap.progress.listener"); - debugger.GetBroadcaster().AddListener( - listener, lldb::SBDebugger::eBroadcastBitProgress | - lldb::SBDebugger::eBroadcastBitExternalProgress); - broadcaster.AddListener(listener, eBroadcastBitStopProgressThread); - lldb::SBEvent event; - bool done = false; - while (!done) { - if (listener.WaitForEvent(1, event)) { - const auto event_mask = event.GetType(); - if (event.BroadcasterMatchesRef(broadcaster)) { - if (event_mask & eBroadcastBitStopProgressThread) { - done = true; - } - } else { - lldb::SBStructuredData data = - lldb::SBDebugger::GetProgressDataFromEvent(event); - - const uint64_t progress_id = - GetUintFromStructuredData(data, "progress_id"); - const uint64_t completed = GetUintFromStructuredData(data, "completed"); - const uint64_t total = GetUintFromStructuredData(data, "total"); - const std::string details = - GetStringFromStructuredData(data, "details"); - - if (completed == 0) { - if (total == UINT64_MAX) { - // This progress is non deterministic and won't get updated until it - // is completed. Send the "message" which will be the combined title - // and detail. The only other progress event for thus - // non-deterministic progress will be the completed event So there - // will be no need to update the detail. - const std::string message = - GetStringFromStructuredData(data, "message"); - SendProgressEvent(progress_id, message.c_str(), completed, total); - } else { - // This progress is deterministic and will receive updates, - // on the progress creation event VSCode will save the message in - // the create packet and use that as the title, so we send just the - // title in the progressCreate packet followed immediately by a - // detail packet, if there is any detail. - const std::string title = - GetStringFromStructuredData(data, "title"); - SendProgressEvent(progress_id, title.c_str(), completed, total); - if (!details.empty()) - SendProgressEvent(progress_id, details.c_str(), completed, total); - } - } else { - // This progress event is either the end of the progress dialog, or an - // update with possible detail. The "detail" string we send to VS Code - // will be appended to the progress dialog's initial text from when it - // was created. - SendProgressEvent(progress_id, details.c_str(), completed, total); - } - } - } - } -} - -// All events from the debugger, target, process, thread and frames are -// received in this function that runs in its own thread. We are using a -// "FILE *" to output packets back to VS Code and they have mutexes in them -// them prevent multiple threads from writing simultaneously so no locking -// is required. -void DAP::EventThread() { - llvm::set_thread_name(transport.GetClientName() + ".event_handler"); - lldb::SBEvent event; - lldb::SBListener listener = debugger.GetListener(); - broadcaster.AddListener(listener, eBroadcastBitStopEventThread); - debugger.GetBroadcaster().AddListener( - listener, lldb::eBroadcastBitError | lldb::eBroadcastBitWarning); - bool done = false; - while (!done) { - if (listener.WaitForEvent(1, event)) { - const auto event_mask = event.GetType(); - if (lldb::SBProcess::EventIsProcessEvent(event)) { - lldb::SBProcess process = lldb::SBProcess::GetProcessFromEvent(event); - if (event_mask & lldb::SBProcess::eBroadcastBitStateChanged) { - auto state = lldb::SBProcess::GetStateFromEvent(event); - switch (state) { - case lldb::eStateConnected: - case lldb::eStateDetached: - case lldb::eStateInvalid: - case lldb::eStateUnloaded: - break; - case lldb::eStateAttaching: - case lldb::eStateCrashed: - case lldb::eStateLaunching: - case lldb::eStateStopped: - case lldb::eStateSuspended: - // Only report a stopped event if the process was not - // automatically restarted. - if (!lldb::SBProcess::GetRestartedFromEvent(event)) { - SendStdOutStdErr(*this, process); - SendThreadStoppedEvent(*this); - } - break; - case lldb::eStateRunning: - case lldb::eStateStepping: - WillContinue(); - SendContinuedEvent(*this); - break; - case lldb::eStateExited: - lldb::SBStream stream; - process.GetStatus(stream); - SendOutput(OutputType::Console, stream.GetData()); - - // When restarting, we can get an "exited" event for the process we - // just killed with the old PID, or even with no PID. In that case - // we don't have to terminate the session. - if (process.GetProcessID() == LLDB_INVALID_PROCESS_ID || - process.GetProcessID() == restarting_process_id) { - restarting_process_id = LLDB_INVALID_PROCESS_ID; - } else { - // Run any exit LLDB commands the user specified in the - // launch.json - RunExitCommands(); - SendProcessExitedEvent(*this, process); - SendTerminatedEvent(); - done = true; - } - break; - } - } else if ((event_mask & lldb::SBProcess::eBroadcastBitSTDOUT) || - (event_mask & lldb::SBProcess::eBroadcastBitSTDERR)) { - SendStdOutStdErr(*this, process); - } - } else if (lldb::SBTarget::EventIsTargetEvent(event)) { - if (event_mask & lldb::SBTarget::eBroadcastBitModulesLoaded || - event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded || - event_mask & lldb::SBTarget::eBroadcastBitSymbolsLoaded || - event_mask & lldb::SBTarget::eBroadcastBitSymbolsChanged) { - const uint32_t num_modules = - lldb::SBTarget::GetNumModulesFromEvent(event); - std::lock_guard guard(modules_mutex); - for (uint32_t i = 0; i < num_modules; ++i) { - lldb::SBModule module = - lldb::SBTarget::GetModuleAtIndexFromEvent(i, event); - if (!module.IsValid()) - continue; - llvm::StringRef module_id = module.GetUUIDString(); - if (module_id.empty()) - continue; - - llvm::StringRef reason; - bool id_only = false; - if (modules.contains(module_id)) { - if (event_mask & lldb::SBTarget::eBroadcastBitModulesUnloaded) { - modules.erase(module_id); - reason = "removed"; - id_only = true; - } else { - reason = "changed"; - } - } else { - modules.insert(module_id); - reason = "new"; - } - - llvm::json::Object body; - body.try_emplace("reason", reason); - body.try_emplace("module", CreateModule(target, module, id_only)); - llvm::json::Object module_event = CreateEventObject("module"); - module_event.try_emplace("body", std::move(body)); - SendJSON(llvm::json::Value(std::move(module_event))); - } - } - } else if (lldb::SBBreakpoint::EventIsBreakpointEvent(event)) { - if (event_mask & lldb::SBTarget::eBroadcastBitBreakpointChanged) { - auto event_type = - lldb::SBBreakpoint::GetBreakpointEventTypeFromEvent(event); - auto bp = Breakpoint( - *this, lldb::SBBreakpoint::GetBreakpointFromEvent(event)); - // If the breakpoint was set through DAP, it will have the - // BreakpointBase::kDAPBreakpointLabel. Regardless of whether - // locations were added, removed, or resolved, the breakpoint isn't - // going away and the reason is always "changed". - if ((event_type & lldb::eBreakpointEventTypeLocationsAdded || - event_type & lldb::eBreakpointEventTypeLocationsRemoved || - event_type & lldb::eBreakpointEventTypeLocationsResolved) && - bp.MatchesName(BreakpointBase::kDAPBreakpointLabel)) { - // As the DAP client already knows the path of this breakpoint, we - // don't need to send it back as part of the "changed" event. This - // avoids sending paths that should be source mapped. Note that - // CreateBreakpoint doesn't apply source mapping and certain - // implementation ignore the source part of this event anyway. - llvm::json::Value source_bp = bp.ToProtocolBreakpoint(); - source_bp.getAsObject()->erase("source"); - - llvm::json::Object body; - body.try_emplace("breakpoint", source_bp); - body.try_emplace("reason", "changed"); - - llvm::json::Object bp_event = CreateEventObject("breakpoint"); - bp_event.try_emplace("body", std::move(body)); - - SendJSON(llvm::json::Value(std::move(bp_event))); - } - } - } else if (event_mask & lldb::eBroadcastBitError || - event_mask & lldb::eBroadcastBitWarning) { - lldb::SBStructuredData data = - lldb::SBDebugger::GetDiagnosticFromEvent(event); - if (!data.IsValid()) - continue; - std::string type = GetStringValue(data.GetValueForKey("type")); - std::string message = GetStringValue(data.GetValueForKey("message")); - SendOutput(OutputType::Important, - llvm::formatv("{0}: {1}", type, message).str()); - } else if (event.BroadcasterMatchesRef(broadcaster)) { - if (event_mask & eBroadcastBitStopEventThread) { - done = true; - } - } - } - } -} - -std::vector DAP::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints) { - std::vector response_breakpoints; - if (source.sourceReference) { - // Breakpoint set by assembly source. - auto &existing_breakpoints = - m_source_assembly_breakpoints[*source.sourceReference]; - response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints); - } else { - // Breakpoint set by a regular source file. - const auto path = source.path.value_or(""); - auto &existing_breakpoints = m_source_breakpoints[path]; - response_breakpoints = - SetSourceBreakpoints(source, breakpoints, existing_breakpoints); - } - - return response_breakpoints; -} - -std::vector DAP::SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints, - SourceBreakpointMap &existing_breakpoints) { - std::vector response_breakpoints; - - SourceBreakpointMap request_breakpoints; - if (breakpoints) { - for (const auto &bp : *breakpoints) { - SourceBreakpoint src_bp(*this, bp); - std::pair bp_pos(src_bp.GetLine(), - src_bp.GetColumn()); - request_breakpoints.try_emplace(bp_pos, src_bp); - - const auto [iv, inserted] = - existing_breakpoints.try_emplace(bp_pos, src_bp); - // We check if this breakpoint already exists to update it. - if (inserted) { - if (llvm::Error error = iv->second.SetBreakpoint(source)) { - protocol::Breakpoint invalid_breakpoint; - invalid_breakpoint.message = llvm::toString(std::move(error)); - invalid_breakpoint.verified = false; - response_breakpoints.push_back(std::move(invalid_breakpoint)); - existing_breakpoints.erase(iv); - continue; - } - } else { - iv->second.UpdateBreakpoint(src_bp); - } - - protocol::Breakpoint response_breakpoint = - iv->second.ToProtocolBreakpoint(); - response_breakpoint.source = source; - - if (!response_breakpoint.line && - src_bp.GetLine() != LLDB_INVALID_LINE_NUMBER) - response_breakpoint.line = src_bp.GetLine(); - if (!response_breakpoint.column && - src_bp.GetColumn() != LLDB_INVALID_COLUMN_NUMBER) - response_breakpoint.column = src_bp.GetColumn(); - response_breakpoints.push_back(std::move(response_breakpoint)); - } - } - - // Delete any breakpoints in this source file that aren't in the - // request_bps set. There is no call to remove breakpoints other than - // calling this function with a smaller or empty "breakpoints" list. - for (auto it = existing_breakpoints.begin(); - it != existing_breakpoints.end();) { - auto request_pos = request_breakpoints.find(it->first); - if (request_pos == request_breakpoints.end()) { - // This breakpoint no longer exists in this source file, delete it - target.BreakpointDelete(it->second.GetID()); - it = existing_breakpoints.erase(it); - } else { - ++it; - } - } - - return response_breakpoints; -} - -void DAP::RegisterRequests() { - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - RegisterRequest(); - - // Custom requests - RegisterRequest(); - RegisterRequest(); - - // Testing requests - RegisterRequest(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/DAP.h b/lldb/tools/lldb-dap/DAP.h deleted file mode 100644 index 1bd94fab402c..000000000000 --- a/lldb/tools/lldb-dap/DAP.h +++ /dev/null @@ -1,426 +0,0 @@ -//===-- DAP.h ---------------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_DAP_H -#define LLDB_TOOLS_LLDB_DAP_DAP_H - -#include "DAPForward.h" -#include "ExceptionBreakpoint.h" -#include "FunctionBreakpoint.h" -#include "InstructionBreakpoint.h" -#include "OutputRedirector.h" -#include "ProgressEvent.h" -#include "Protocol/ProtocolBase.h" -#include "Protocol/ProtocolRequests.h" -#include "Protocol/ProtocolTypes.h" -#include "SourceBreakpoint.h" -#include "Transport.h" -#include "Variables.h" -#include "lldb/API/SBBroadcaster.h" -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBFile.h" -#include "lldb/API/SBFormat.h" -#include "lldb/API/SBFrame.h" -#include "lldb/API/SBMutex.h" -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBThread.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/FunctionExtras.h" -#include "llvm/ADT/SmallSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSet.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/JSON.h" -#include "llvm/Support/Threading.h" -#include -#include -#include -#include -#include -#include -#include -#include - -#define NO_TYPENAME "" - -namespace lldb_dap { - -typedef std::map, SourceBreakpoint> - SourceBreakpointMap; -typedef llvm::StringMap FunctionBreakpointMap; -typedef llvm::DenseMap - InstructionBreakpointMap; - -using AdapterFeature = protocol::AdapterFeature; -using ClientFeature = protocol::ClientFeature; - -enum class OutputType { Console, Important, Stdout, Stderr, Telemetry }; - -/// Buffer size for handling output events. -constexpr uint64_t OutputBufferSize = (1u << 12); - -enum DAPBroadcasterBits { - eBroadcastBitStopEventThread = 1u << 0, - eBroadcastBitStopProgressThread = 1u << 1 -}; - -enum class ReplMode { Variable = 0, Command, Auto }; - -struct DAP { - /// Path to the lldb-dap binary itself. - static llvm::StringRef debug_adapter_path; - - Log *log; - Transport &transport; - lldb::SBFile in; - OutputRedirector out; - OutputRedirector err; - - /// Configuration specified by the launch or attach commands. - protocol::Configuration configuration; - - /// The debugger instance for this DAP session. - lldb::SBDebugger debugger; - - /// The target instance for this DAP session. - lldb::SBTarget target; - - Variables variables; - lldb::SBBroadcaster broadcaster; - FunctionBreakpointMap function_breakpoints; - InstructionBreakpointMap instruction_breakpoints; - std::optional> exception_breakpoints; - llvm::once_flag init_exception_breakpoints_flag; - - /// Map step in target id to list of function targets that user can choose. - llvm::DenseMap step_in_targets; - - /// A copy of the last LaunchRequest so we can reuse its arguments if we get a - /// RestartRequest. Restarting an AttachRequest is not supported. - std::optional last_launch_request; - - /// The focused thread for this DAP session. - lldb::tid_t focus_tid = LLDB_INVALID_THREAD_ID; - - bool disconnecting = false; - llvm::once_flag terminated_event_flag; - bool stop_at_entry = false; - bool is_attach = false; - - /// The process event thread normally responds to process exited events by - /// shutting down the entire adapter. When we're restarting, we keep the id of - /// the old process here so we can detect this case and keep running. - lldb::pid_t restarting_process_id = LLDB_INVALID_PROCESS_ID; - - /// Whether we have received the ConfigurationDone request, indicating that - /// the client has finished initialization of the debug adapter. - bool configuration_done; - - bool waiting_for_run_in_terminal = false; - ProgressEventReporter progress_event_reporter; - - /// Keep track of the last stop thread index IDs as threads won't go away - /// unless we send a "thread" event to indicate the thread exited. - llvm::DenseSet thread_ids; - - uint32_t reverse_request_seq = 0; - std::mutex call_mutex; - llvm::SmallDenseMap> - inflight_reverse_requests; - ReplMode repl_mode; - lldb::SBFormat frame_format; - lldb::SBFormat thread_format; - - /// This is used to allow request_evaluate to handle empty expressions - /// (ie the user pressed 'return' and expects the previous expression to - /// repeat). If the previous expression was a command, this string will be - /// empty; if the previous expression was a variable expression, this string - /// will contain that expression. - std::string last_nonempty_var_expression; - - /// The set of features supported by the connected client. - llvm::DenseSet clientFeatures; - - /// The initial thread list upon attaching. - std::optional initial_thread_list; - - /// Keep track of all the modules our client knows about: either through the - /// modules request or the module events. - /// @{ - std::mutex modules_mutex; - llvm::StringSet<> modules; - /// @} - - /// Number of lines of assembly code to show when no debug info is available. - static constexpr uint32_t k_number_of_assembly_lines_for_nodebug = 32; - - /// Creates a new DAP sessions. - /// - /// \param[in] log - /// Log stream, if configured. - /// \param[in] default_repl_mode - /// Default repl mode behavior, as configured by the binary. - /// \param[in] pre_init_commands - /// LLDB commands to execute as soon as the debugger instance is - /// allocated. - /// \param[in] transport - /// Transport for this debug session. - DAP(Log *log, const ReplMode default_repl_mode, - std::vector pre_init_commands, Transport &transport); - - ~DAP(); - - /// DAP is not copyable. - /// @{ - DAP(const DAP &rhs) = delete; - void operator=(const DAP &rhs) = delete; - /// @} - - ExceptionBreakpoint *GetExceptionBreakpoint(llvm::StringRef filter); - ExceptionBreakpoint *GetExceptionBreakpoint(const lldb::break_id_t bp_id); - - /// Redirect stdout and stderr fo the IDE's console output. - /// - /// Errors in this operation will be printed to the log file and the IDE's - /// console output as well. - llvm::Error ConfigureIO(std::FILE *overrideOut = nullptr, - std::FILE *overrideErr = nullptr); - - /// Stop event handler threads. - void StopEventHandlers(); - - /// Configures the debug adapter for launching/attaching. - void SetConfiguration(const protocol::Configuration &confing, bool is_attach); - - /// Configure source maps based on the current `DAPConfiguration`. - void ConfigureSourceMaps(); - - /// Serialize the JSON value into a string and send the JSON packet to the - /// "out" stream. - void SendJSON(const llvm::json::Value &json); - /// Send the given message to the client - void Send(const protocol::Message &message); - - void SendOutput(OutputType o, const llvm::StringRef output); - - void SendProgressEvent(uint64_t progress_id, const char *message, - uint64_t completed, uint64_t total); - - void __attribute__((format(printf, 3, 4))) - SendFormattedOutput(OutputType o, const char *format, ...); - - static int64_t GetNextSourceReference(); - - ExceptionBreakpoint *GetExceptionBPFromStopReason(lldb::SBThread &thread); - - lldb::SBThread GetLLDBThread(lldb::tid_t id); - lldb::SBThread GetLLDBThread(const llvm::json::Object &arguments); - - lldb::SBFrame GetLLDBFrame(uint64_t frame_id); - /// TODO: remove this function when we finish migrating to the - /// new protocol types. - lldb::SBFrame GetLLDBFrame(const llvm::json::Object &arguments); - - void PopulateExceptionBreakpoints(); - - /// Attempt to determine if an expression is a variable expression or - /// lldb command using a heuristic based on the first term of the - /// expression. - /// - /// \param[in] frame - /// The frame, used as context to detect local variable names - /// \param[inout] expression - /// The expression string. Might be modified by this function to - /// remove the leading escape character. - /// \param[in] partial_expression - /// Whether the provided `expression` is only a prefix of the - /// final expression. If `true`, this function might return - /// `ReplMode::Auto` to indicate that the expression could be - /// either an expression or a statement, depending on the rest of - /// the expression. - /// \return the expression mode - ReplMode DetectReplMode(lldb::SBFrame frame, std::string &expression, - bool partial_expression); - - /// \return - /// \b false if a fatal error was found while executing these commands, - /// according to the rules of \a LLDBUtils::RunLLDBCommands. - bool RunLLDBCommands(llvm::StringRef prefix, - llvm::ArrayRef commands); - - llvm::Error RunAttachCommands(llvm::ArrayRef attach_commands); - llvm::Error RunLaunchCommands(llvm::ArrayRef launch_commands); - llvm::Error RunPreInitCommands(); - llvm::Error RunInitCommands(); - llvm::Error RunPreRunCommands(); - void RunPostRunCommands(); - void RunStopCommands(); - void RunExitCommands(); - void RunTerminateCommands(); - - /// Create a new SBTarget object from the given request arguments. - /// - /// \param[out] error - /// An SBError object that will contain an error description if - /// function failed to create the target. - /// - /// \return - /// An SBTarget object. - lldb::SBTarget CreateTarget(lldb::SBError &error); - - /// Set given target object as a current target for lldb-dap and start - /// listeing for its breakpoint events. - void SetTarget(const lldb::SBTarget target); - - bool HandleObject(const protocol::Message &M); - - /// Disconnect the DAP session. - llvm::Error Disconnect(); - - /// Disconnect the DAP session and optionally terminate the debuggee. - llvm::Error Disconnect(bool terminateDebuggee); - - /// Send a "terminated" event to indicate the process is done being debugged. - void SendTerminatedEvent(); - - llvm::Error Loop(); - - /// Send a Debug Adapter Protocol reverse request to the IDE. - /// - /// \param[in] command - /// The reverse request command. - /// - /// \param[in] arguments - /// The reverse request arguments. - template - void SendReverseRequest(llvm::StringRef command, - llvm::json::Value arguments) { - int64_t id; - { - std::lock_guard locker(call_mutex); - id = ++reverse_request_seq; - inflight_reverse_requests[id] = std::make_unique(command, id); - } - - SendJSON(llvm::json::Object{ - {"type", "request"}, - {"seq", id}, - {"command", command}, - {"arguments", std::move(arguments)}, - }); - } - - /// The set of capablities supported by this adapter. - protocol::Capabilities GetCapabilities(); - - /// Debuggee will continue from stopped state. - void WillContinue() { variables.Clear(); } - - /// Poll the process to wait for it to reach the eStateStopped state. - /// - /// Wait for the process hit a stopped state. When running a launch with - /// "launchCommands", or attach with "attachCommands", the calls might take - /// some time to stop at the entry point since the command is asynchronous. We - /// need to sync up with the process and make sure it is stopped before we - /// proceed to do anything else as we will soon be asked to set breakpoints - /// and other things that require the process to be stopped. We must use - /// polling because "attachCommands" or "launchCommands" may or may not send - /// process state change events depending on if the user modifies the async - /// setting in the debugger. Since both "attachCommands" and "launchCommands" - /// could end up using any combination of LLDB commands, we must ensure we can - /// also catch when the process stops, so we must poll the process to make - /// sure we handle all cases. - /// - /// \param[in] seconds - /// The number of seconds to poll the process to wait until it is stopped. - /// - /// \return Error if waiting for the process fails, no error if succeeds. - lldb::SBError WaitForProcessToStop(std::chrono::seconds seconds); - - void SetFrameFormat(llvm::StringRef format); - - void SetThreadFormat(llvm::StringRef format); - - InstructionBreakpoint *GetInstructionBreakpoint(const lldb::break_id_t bp_id); - - InstructionBreakpoint *GetInstructionBPFromStopReason(lldb::SBThread &thread); - - /// Checks if the request is cancelled. - bool IsCancelled(const protocol::Request &); - - /// Clears the cancel request from the set of tracked cancel requests. - void ClearCancelRequest(const protocol::CancelArguments &); - - lldb::SBMutex GetAPIMutex() const { return target.GetAPIMutex(); } - - void StartEventThread(); - void StartProgressEventThread(); - - /// Sets the given protocol `breakpoints` in the given `source`, while - /// removing any existing breakpoints in the given source if they are not in - /// `breakpoint`. - /// - /// \param[in] source - /// The relevant source of the breakpoints. - /// - /// \param[in] breakpoints - /// The breakpoints to set. - /// - /// \return a vector of the breakpoints that were set. - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> - &breakpoints); - -private: - std::vector SetSourceBreakpoints( - const protocol::Source &source, - const std::optional> &breakpoints, - SourceBreakpointMap &existing_breakpoints); - - /// Registration of request handler. - /// @{ - void RegisterRequests(); - template void RegisterRequest() { - request_handlers[Handler::GetCommand()] = std::make_unique(*this); - } - llvm::StringMap> request_handlers; - /// @} - - /// Event threads. - /// @{ - void EventThread(); - void ProgressEventThread(); - - std::thread event_thread; - std::thread progress_event_thread; - /// @} - - /// Queue for all incoming messages. - std::deque m_queue; - std::mutex m_queue_mutex; - std::condition_variable m_queue_cv; - - std::mutex m_cancelled_requests_mutex; - llvm::SmallSet m_cancelled_requests; - - std::mutex m_active_request_mutex; - const protocol::Request *m_active_request; - - llvm::StringMap m_source_breakpoints; - llvm::DenseMap m_source_assembly_breakpoints; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/DAPError.cpp b/lldb/tools/lldb-dap/DAPError.cpp deleted file mode 100644 index 60347d577f82..000000000000 --- a/lldb/tools/lldb-dap/DAPError.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===-- DAPError.cpp ------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAPError.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" -#include - -namespace lldb_dap { - -char DAPError::ID; - -DAPError::DAPError(std::string message, std::error_code EC, bool show_user, - std::optional url, - std::optional url_label) - : m_message(message), m_ec(EC), m_show_user(show_user), m_url(url), - m_url_label(url_label) {} - -void DAPError::log(llvm::raw_ostream &OS) const { OS << m_message; } - -std::error_code DAPError::convertToErrorCode() const { - return llvm::inconvertibleErrorCode(); -} - -char NotStoppedError::ID; - -void NotStoppedError::log(llvm::raw_ostream &OS) const { OS << "not stopped"; } - -std::error_code NotStoppedError::convertToErrorCode() const { - return llvm::inconvertibleErrorCode(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/DAPError.h b/lldb/tools/lldb-dap/DAPError.h deleted file mode 100644 index 4c94bdd6ac3d..000000000000 --- a/lldb/tools/lldb-dap/DAPError.h +++ /dev/null @@ -1,52 +0,0 @@ -//===-- DAPError.h --------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Error.h" -#include -#include -#include - -namespace lldb_dap { - -/// An error that is reported as a DAP Error Message, which may be presented to -/// the user. -class DAPError : public llvm::ErrorInfo { -public: - static char ID; - - DAPError(std::string message, - std::error_code EC = llvm::inconvertibleErrorCode(), - bool show_user = true, std::optional url = std::nullopt, - std::optional url_label = std::nullopt); - - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; - - const std::string &getMessage() const { return m_message; } - bool getShowUser() const { return m_show_user; } - const std::optional &getURL() const { return m_url; } - const std::optional &getURLLabel() const { return m_url; } - -private: - std::string m_message; - std::error_code m_ec; - bool m_show_user; - std::optional m_url; - std::optional m_url_label; -}; - -/// An error that indicates the current request handler cannot execute because -/// the process is not stopped. -class NotStoppedError : public llvm::ErrorInfo { -public: - static char ID; - void log(llvm::raw_ostream &OS) const override; - std::error_code convertToErrorCode() const override; -}; - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/DAPForward.h b/lldb/tools/lldb-dap/DAPForward.h deleted file mode 100644 index 6620d5fd3364..000000000000 --- a/lldb/tools/lldb-dap/DAPForward.h +++ /dev/null @@ -1,62 +0,0 @@ -//===-- DAPForward.h --------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_DAPFORWARD_H -#define LLDB_TOOLS_LLDB_DAP_DAPFORWARD_H - -// IWYU pragma: begin_exports - -namespace lldb_dap { -class BaseRequestHandler; -class BreakpointBase; -class ExceptionBreakpoint; -class FunctionBreakpoint; -class InstructionBreakpoint; -class Log; -class ResponseHandler; -class SourceBreakpoint; -class Watchpoint; -struct DAP; -} // namespace lldb_dap - -namespace lldb { -class SBAttachInfo; -class SBBreakpoint; -class SBBreakpointLocation; -class SBCommandInterpreter; -class SBCommandReturnObject; -class SBCommunication; -class SBDebugger; -class SBEvent; -class SBFrame; -class SBHostOS; -class SBInstruction; -class SBInstructionList; -class SBLanguageRuntime; -class SBLaunchInfo; -class SBLineEntry; -class SBListener; -class SBModule; -class SBProcess; -class SBStream; -class SBStringList; -class SBTarget; -class SBThread; -class SBValue; -class SBWatchpoint; -} // namespace lldb - -namespace llvm { -namespace json { -class Object; -} // namespace json -} // namespace llvm - -// IWYU pragma: end_exports - -#endif diff --git a/lldb/tools/lldb-dap/DAPLog.cpp b/lldb/tools/lldb-dap/DAPLog.cpp deleted file mode 100644 index f66784e19751..000000000000 --- a/lldb/tools/lldb-dap/DAPLog.cpp +++ /dev/null @@ -1,30 +0,0 @@ -//===-- DAPLog.cpp --------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAPLog.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include - -using namespace llvm; - -namespace lldb_dap { - -Log::Log(StringRef filename, std::error_code &EC) : m_stream(filename, EC) {} - -void Log::WriteMessage(StringRef message) { - std::lock_guard lock(m_mutex); - std::chrono::duration now{ - std::chrono::system_clock::now().time_since_epoch()}; - m_stream << formatv("{0:f9} ", now.count()).str() << message << "\n"; - m_stream.flush(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/DAPLog.h b/lldb/tools/lldb-dap/DAPLog.h deleted file mode 100644 index 484001a9b162..000000000000 --- a/lldb/tools/lldb-dap/DAPLog.h +++ /dev/null @@ -1,67 +0,0 @@ -//===-- DAPLog.h ----------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_DAPLOG_H -#define LLDB_TOOLS_LLDB_DAP_DAPLOG_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FormatAdapters.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include - -// Write a message to log, if logging is enabled. -#define DAP_LOG(log, ...) \ - do { \ - ::lldb_dap::Log *log_private = (log); \ - if (log_private) { \ - log_private->WriteMessage(::llvm::formatv(__VA_ARGS__).str()); \ - } \ - } while (0) - -// Write message to log, if error is set. In the log message refer to the error -// with {0}. Error is cleared regardless of whether logging is enabled. -#define DAP_LOG_ERROR(log, error, ...) \ - do { \ - ::lldb_dap::Log *log_private = (log); \ - ::llvm::Error error_private = (error); \ - if (log_private && error_private) { \ - log_private->WriteMessage( \ - ::lldb_dap::FormatError(::std::move(error_private), __VA_ARGS__)); \ - } else \ - ::llvm::consumeError(::std::move(error_private)); \ - } while (0) - -namespace lldb_dap { - -/// Log manages the lldb-dap log file, used with the corresponding `DAP_LOG` and -/// `DAP_LOG_ERROR` helpers. -class Log final { -public: - /// Creates a log file with the given filename. - Log(llvm::StringRef filename, std::error_code &EC); - - void WriteMessage(llvm::StringRef message); - -private: - std::mutex m_mutex; - llvm::raw_fd_ostream m_stream; -}; - -template -inline auto FormatError(llvm::Error error, const char *format, Args &&...args) { - return llvm::formatv(format, llvm::toString(std::move(error)), - std::forward(args)...) - .str(); -} -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/EventHelper.cpp b/lldb/tools/lldb-dap/EventHelper.cpp deleted file mode 100644 index 33bc7c2cbef1..000000000000 --- a/lldb/tools/lldb-dap/EventHelper.cpp +++ /dev/null @@ -1,264 +0,0 @@ -//===-- EventHelper.h -----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "EventHelper.h" -#include "DAP.h" -#include "DAPLog.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "lldb/API/SBFileSpec.h" - -#if defined(_WIN32) -#define NOMINMAX -#include - -#ifndef PATH_MAX -#define PATH_MAX MAX_PATH -#endif -#endif - -namespace lldb_dap { - -static void SendThreadExitedEvent(DAP &dap, lldb::tid_t tid) { - llvm::json::Object event(CreateEventObject("thread")); - llvm::json::Object body; - body.try_emplace("reason", "exited"); - body.try_emplace("threadId", (int64_t)tid); - event.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(event))); -} - -void SendTargetBasedCapabilities(DAP &dap) { - if (!dap.target.IsValid()) - return; - - // FIXME: stepInTargets request is only supported by the x86 - // architecture remove when `lldb::InstructionControlFlowKind` is - // supported by other architectures - const llvm::StringRef target_triple = dap.target.GetTriple(); - if (target_triple.starts_with("x86")) - return; - - protocol::Event event; - event.event = "capabilities"; - event.body = llvm::json::Object{ - {"capabilities", - llvm::json::Object{{"supportsStepInTargetsRequest", false}}}}; - dap.Send(event); -} -// "ProcessEvent": { -// "allOf": [ -// { "$ref": "#/definitions/Event" }, -// { -// "type": "object", -// "description": "Event message for 'process' event type. The event -// indicates that the debugger has begun debugging a -// new process. Either one that it has launched, or one -// that it has attached to.", -// "properties": { -// "event": { -// "type": "string", -// "enum": [ "process" ] -// }, -// "body": { -// "type": "object", -// "properties": { -// "name": { -// "type": "string", -// "description": "The logical name of the process. This is -// usually the full path to process's executable -// file. Example: /home/myproj/program.js." -// }, -// "systemProcessId": { -// "type": "integer", -// "description": "The system process id of the debugged process. -// This property will be missing for non-system -// processes." -// }, -// "isLocalProcess": { -// "type": "boolean", -// "description": "If true, the process is running on the same -// computer as the debug adapter." -// }, -// "startMethod": { -// "type": "string", -// "enum": [ "launch", "attach", "attachForSuspendedLaunch" ], -// "description": "Describes how the debug engine started -// debugging this process.", -// "enumDescriptions": [ -// "Process was launched under the debugger.", -// "Debugger attached to an existing process.", -// "A project launcher component has launched a new process in -// a suspended state and then asked the debugger to attach." -// ] -// } -// }, -// "required": [ "name" ] -// } -// }, -// "required": [ "event", "body" ] -// } -// ] -// } -void SendProcessEvent(DAP &dap, LaunchMethod launch_method) { - lldb::SBFileSpec exe_fspec = dap.target.GetExecutable(); - char exe_path[PATH_MAX]; - exe_fspec.GetPath(exe_path, sizeof(exe_path)); - llvm::json::Object event(CreateEventObject("process")); - llvm::json::Object body; - EmplaceSafeString(body, "name", exe_path); - const auto pid = dap.target.GetProcess().GetProcessID(); - body.try_emplace("systemProcessId", (int64_t)pid); - body.try_emplace("isLocalProcess", true); - const char *startMethod = nullptr; - switch (launch_method) { - case Launch: - startMethod = "launch"; - break; - case Attach: - startMethod = "attach"; - break; - case AttachForSuspendedLaunch: - startMethod = "attachForSuspendedLaunch"; - break; - } - body.try_emplace("startMethod", startMethod); - event.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(event))); -} - -// Send a thread stopped event for all threads as long as the process -// is stopped. -void SendThreadStoppedEvent(DAP &dap) { - lldb::SBProcess process = dap.target.GetProcess(); - if (process.IsValid()) { - auto state = process.GetState(); - if (state == lldb::eStateStopped) { - llvm::DenseSet old_thread_ids; - old_thread_ids.swap(dap.thread_ids); - uint32_t stop_id = process.GetStopID(); - const uint32_t num_threads = process.GetNumThreads(); - - // First make a pass through the threads to see if the focused thread - // has a stop reason. In case the focus thread doesn't have a stop - // reason, remember the first thread that has a stop reason so we can - // set it as the focus thread if below if needed. - lldb::tid_t first_tid_with_reason = LLDB_INVALID_THREAD_ID; - uint32_t num_threads_with_reason = 0; - bool focus_thread_exists = false; - for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { - lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); - const lldb::tid_t tid = thread.GetThreadID(); - const bool has_reason = ThreadHasStopReason(thread); - // If the focus thread doesn't have a stop reason, clear the thread ID - if (tid == dap.focus_tid) { - focus_thread_exists = true; - if (!has_reason) - dap.focus_tid = LLDB_INVALID_THREAD_ID; - } - if (has_reason) { - ++num_threads_with_reason; - if (first_tid_with_reason == LLDB_INVALID_THREAD_ID) - first_tid_with_reason = tid; - } - } - - // We will have cleared dap.focus_tid if the focus thread doesn't have - // a stop reason, so if it was cleared, or wasn't set, or doesn't exist, - // then set the focus thread to the first thread with a stop reason. - if (!focus_thread_exists || dap.focus_tid == LLDB_INVALID_THREAD_ID) - dap.focus_tid = first_tid_with_reason; - - // If no threads stopped with a reason, then report the first one so - // we at least let the UI know we stopped. - if (num_threads_with_reason == 0) { - lldb::SBThread thread = process.GetThreadAtIndex(0); - dap.focus_tid = thread.GetThreadID(); - dap.SendJSON(CreateThreadStopped(dap, thread, stop_id)); - } else { - for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { - lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); - dap.thread_ids.insert(thread.GetThreadID()); - if (ThreadHasStopReason(thread)) { - dap.SendJSON(CreateThreadStopped(dap, thread, stop_id)); - } - } - } - - for (auto tid : old_thread_ids) { - auto end = dap.thread_ids.end(); - auto pos = dap.thread_ids.find(tid); - if (pos == end) - SendThreadExitedEvent(dap, tid); - } - } else { - DAP_LOG( - dap.log, - "error: SendThreadStoppedEvent() when process isn't stopped ({0})", - lldb::SBDebugger::StateAsCString(state)); - } - } else { - DAP_LOG(dap.log, "error: SendThreadStoppedEvent() invalid process"); - } - dap.RunStopCommands(); -} - -// Send a "terminated" event to indicate the process is done being -// debugged. -void SendTerminatedEvent(DAP &dap) { - // Prevent races if the process exits while we're being asked to disconnect. - llvm::call_once(dap.terminated_event_flag, [&] { - dap.RunTerminateCommands(); - // Send a "terminated" event - llvm::json::Object event(CreateTerminatedEventObject(dap.target)); - dap.SendJSON(llvm::json::Value(std::move(event))); - }); -} - -// Grab any STDOUT and STDERR from the process and send it up to VS Code -// via an "output" event to the "stdout" and "stderr" categories. -void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process) { - char buffer[OutputBufferSize]; - size_t count; - while ((count = process.GetSTDOUT(buffer, sizeof(buffer))) > 0) - dap.SendOutput(OutputType::Stdout, llvm::StringRef(buffer, count)); - while ((count = process.GetSTDERR(buffer, sizeof(buffer))) > 0) - dap.SendOutput(OutputType::Stderr, llvm::StringRef(buffer, count)); -} - -// Send a "continued" event to indicate the process is in the running state. -void SendContinuedEvent(DAP &dap) { - lldb::SBProcess process = dap.target.GetProcess(); - if (!process.IsValid()) { - return; - } - - // If the focus thread is not set then we haven't reported any thread status - // to the client, so nothing to report. - if (!dap.configuration_done || dap.focus_tid == LLDB_INVALID_THREAD_ID) { - return; - } - - llvm::json::Object event(CreateEventObject("continued")); - llvm::json::Object body; - body.try_emplace("threadId", (int64_t)dap.focus_tid); - body.try_emplace("allThreadsContinued", true); - event.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(event))); -} - -// Send a "exited" event to indicate the process has exited. -void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process) { - llvm::json::Object event(CreateEventObject("exited")); - llvm::json::Object body; - body.try_emplace("exitCode", (int64_t)process.GetExitStatus()); - event.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(event))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/EventHelper.h b/lldb/tools/lldb-dap/EventHelper.h deleted file mode 100644 index e648afbf67e5..000000000000 --- a/lldb/tools/lldb-dap/EventHelper.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- EventHelper.h -----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_EVENTHELPER_H -#define LLDB_TOOLS_LLDB_DAP_EVENTHELPER_H - -#include "DAPForward.h" - -namespace lldb_dap { -struct DAP; - -enum LaunchMethod { Launch, Attach, AttachForSuspendedLaunch }; - -void SendTargetBasedCapabilities(DAP &dap); - -void SendProcessEvent(DAP &dap, LaunchMethod launch_method); - -void SendThreadStoppedEvent(DAP &dap); - -void SendTerminatedEvent(DAP &dap); - -void SendStdOutStdErr(DAP &dap, lldb::SBProcess &process); - -void SendContinuedEvent(DAP &dap); - -void SendProcessExitedEvent(DAP &dap, lldb::SBProcess &process); - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp b/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp deleted file mode 100644 index 9772e7344ced..000000000000 --- a/lldb/tools/lldb-dap/ExceptionBreakpoint.cpp +++ /dev/null @@ -1,38 +0,0 @@ -//===-- ExceptionBreakpoint.cpp ---------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "ExceptionBreakpoint.h" -#include "BreakpointBase.h" -#include "DAP.h" -#include "lldb/API/SBMutex.h" -#include "lldb/API/SBTarget.h" -#include - -namespace lldb_dap { - -void ExceptionBreakpoint::SetBreakpoint() { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - if (m_bp.IsValid()) - return; - bool catch_value = m_filter.find("_catch") != std::string::npos; - bool throw_value = m_filter.find("_throw") != std::string::npos; - m_bp = m_dap.target.BreakpointCreateForException(m_language, catch_value, - throw_value); - m_bp.AddName(BreakpointBase::kDAPBreakpointLabel); -} - -void ExceptionBreakpoint::ClearBreakpoint() { - if (!m_bp.IsValid()) - return; - m_dap.target.BreakpointDelete(m_bp.GetID()); - m_bp = lldb::SBBreakpoint(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/ExceptionBreakpoint.h b/lldb/tools/lldb-dap/ExceptionBreakpoint.h deleted file mode 100644 index 319b472a89a3..000000000000 --- a/lldb/tools/lldb-dap/ExceptionBreakpoint.h +++ /dev/null @@ -1,47 +0,0 @@ -//===-- ExceptionBreakpoint.h -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_EXCEPTIONBREAKPOINT_H -#define LLDB_TOOLS_LLDB_DAP_EXCEPTIONBREAKPOINT_H - -#include "DAPForward.h" -#include "lldb/API/SBBreakpoint.h" -#include "lldb/lldb-enumerations.h" -#include "llvm/ADT/StringRef.h" -#include -#include - -namespace lldb_dap { - -class ExceptionBreakpoint { -public: - ExceptionBreakpoint(DAP &d, std::string f, std::string l, - lldb::LanguageType lang) - : m_dap(d), m_filter(std::move(f)), m_label(std::move(l)), - m_language(lang), m_bp() {} - - void SetBreakpoint(); - void ClearBreakpoint(); - - lldb::break_id_t GetID() const { return m_bp.GetID(); } - llvm::StringRef GetFilter() const { return m_filter; } - llvm::StringRef GetLabel() const { return m_label; } - - static constexpr bool kDefaultValue = false; - -protected: - DAP &m_dap; - std::string m_filter; - std::string m_label; - lldb::LanguageType m_language; - lldb::SBBreakpoint m_bp; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/FifoFiles.cpp b/lldb/tools/lldb-dap/FifoFiles.cpp deleted file mode 100644 index 1f1bba80bd3b..000000000000 --- a/lldb/tools/lldb-dap/FifoFiles.cpp +++ /dev/null @@ -1,101 +0,0 @@ -//===-- FifoFiles.cpp -------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "FifoFiles.h" -#include "JSONUtils.h" - -#if !defined(_WIN32) -#include -#include -#include -#endif - -#include -#include -#include -#include - -using namespace llvm; - -namespace lldb_dap { - -FifoFile::FifoFile(StringRef path) : m_path(path) {} - -FifoFile::~FifoFile() { -#if !defined(_WIN32) - unlink(m_path.c_str()); -#endif -} - -Expected> CreateFifoFile(StringRef path) { -#if defined(_WIN32) - return createStringError(inconvertibleErrorCode(), "Unimplemented"); -#else - if (int err = mkfifo(path.data(), 0600)) - return createStringError(std::error_code(err, std::generic_category()), - "Couldn't create fifo file: %s", path.data()); - return std::make_shared(path); -#endif -} - -FifoFileIO::FifoFileIO(StringRef fifo_file, StringRef other_endpoint_name) - : m_fifo_file(fifo_file), m_other_endpoint_name(other_endpoint_name) {} - -Expected FifoFileIO::ReadJSON(std::chrono::milliseconds timeout) { - // We use a pointer for this future, because otherwise its normal destructor - // would wait for the getline to end, rendering the timeout useless. - std::optional line; - std::future *future = - new std::future(std::async(std::launch::async, [&]() { - std::ifstream reader(m_fifo_file, std::ifstream::in); - std::string buffer; - std::getline(reader, buffer); - if (!buffer.empty()) - line = buffer; - })); - if (future->wait_for(timeout) == std::future_status::timeout || !line) - // Indeed this is a leak, but it's intentional. "future" obj destructor - // will block on waiting for the worker thread to join. And the worker - // thread might be stuck in blocking I/O. Intentionally leaking the obj - // as a hack to avoid blocking main thread, and adding annotation to - // supress static code inspection warnings - - // coverity[leaked_storage] - return createStringError(inconvertibleErrorCode(), - "Timed out trying to get messages from the " + - m_other_endpoint_name); - delete future; - return json::parse(*line); -} - -Error FifoFileIO::SendJSON(const json::Value &json, - std::chrono::milliseconds timeout) { - bool done = false; - std::future *future = - new std::future(std::async(std::launch::async, [&]() { - std::ofstream writer(m_fifo_file, std::ofstream::out); - writer << JSONToString(json) << std::endl; - done = true; - })); - if (future->wait_for(timeout) == std::future_status::timeout || !done) { - // Indeed this is a leak, but it's intentional. "future" obj destructor will - // block on waiting for the worker thread to join. And the worker thread - // might be stuck in blocking I/O. Intentionally leaking the obj as a hack - // to avoid blocking main thread, and adding annotation to supress static - // code inspection warnings" - - // coverity[leaked_storage] - return createStringError(inconvertibleErrorCode(), - "Timed out trying to send messages to the " + - m_other_endpoint_name); - } - delete future; - return Error::success(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/FifoFiles.h b/lldb/tools/lldb-dap/FifoFiles.h deleted file mode 100644 index 633ebeb2aedd..000000000000 --- a/lldb/tools/lldb-dap/FifoFiles.h +++ /dev/null @@ -1,85 +0,0 @@ -//===-- FifoFiles.h ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_FIFOFILES_H -#define LLDB_TOOLS_LLDB_DAP_FIFOFILES_H - -#include "llvm/Support/Error.h" -#include "llvm/Support/JSON.h" - -#include - -namespace lldb_dap { - -/// Struct that controls the life of a fifo file in the filesystem. -/// -/// The file is destroyed when the destructor is invoked. -struct FifoFile { - FifoFile(llvm::StringRef path); - - ~FifoFile(); - - std::string m_path; -}; - -/// Create a fifo file in the filesystem. -/// -/// \param[in] path -/// The path for the fifo file. -/// -/// \return -/// A \a std::shared_ptr if the file could be created, or an -/// \a llvm::Error in case of failures. -llvm::Expected> CreateFifoFile(llvm::StringRef path); - -class FifoFileIO { -public: - /// \param[in] fifo_file - /// The path to an input fifo file that exists in the file system. - /// - /// \param[in] other_endpoint_name - /// A human readable name for the other endpoint that will communicate - /// using this file. This is used for error messages. - FifoFileIO(llvm::StringRef fifo_file, llvm::StringRef other_endpoint_name); - - /// Read the next JSON object from the underlying input fifo file. - /// - /// The JSON object is expected to be a single line delimited with \a - /// std::endl. - /// - /// \return - /// An \a llvm::Error object indicating the success or failure of this - /// operation. Failures arise if the timeout is hit, the next line of text - /// from the fifo file is not a valid JSON object, or is it impossible to - /// read from the file. - llvm::Expected ReadJSON(std::chrono::milliseconds timeout); - - /// Serialize a JSON object and write it to the underlying output fifo file. - /// - /// \param[in] json - /// The JSON object to send. It will be printed as a single line delimited - /// with \a std::endl. - /// - /// \param[in] timeout - /// A timeout for how long we should until for the data to be consumed. - /// - /// \return - /// An \a llvm::Error object indicating whether the data was consumed by - /// a reader or not. - llvm::Error SendJSON( - const llvm::json::Value &json, - std::chrono::milliseconds timeout = std::chrono::milliseconds(20000)); - -private: - std::string m_fifo_file; - std::string m_other_endpoint_name; -}; - -} // namespace lldb_dap - -#endif // LLDB_TOOLS_LLDB_DAP_FIFOFILES_H diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp b/lldb/tools/lldb-dap/FunctionBreakpoint.cpp deleted file mode 100644 index 1ea9cddb9f68..000000000000 --- a/lldb/tools/lldb-dap/FunctionBreakpoint.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//===-- FunctionBreakpoint.cpp ----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "FunctionBreakpoint.h" -#include "DAP.h" -#include "lldb/API/SBMutex.h" -#include - -namespace lldb_dap { - -FunctionBreakpoint::FunctionBreakpoint( - DAP &d, const protocol::FunctionBreakpoint &breakpoint) - : Breakpoint(d, breakpoint.condition, breakpoint.hitCondition), - m_function_name(breakpoint.name) {} - -void FunctionBreakpoint::SetBreakpoint() { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - if (m_function_name.empty()) - return; - m_bp = m_dap.target.BreakpointCreateByName(m_function_name.c_str()); - Breakpoint::SetBreakpoint(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/FunctionBreakpoint.h b/lldb/tools/lldb-dap/FunctionBreakpoint.h deleted file mode 100644 index 76fbdb3e886a..000000000000 --- a/lldb/tools/lldb-dap/FunctionBreakpoint.h +++ /dev/null @@ -1,33 +0,0 @@ -//===-- FunctionBreakpoint.h ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_FUNCTIONBREAKPOINT_H -#define LLDB_TOOLS_LLDB_DAP_FUNCTIONBREAKPOINT_H - -#include "Breakpoint.h" -#include "DAPForward.h" -#include "Protocol/ProtocolTypes.h" - -namespace lldb_dap { - -class FunctionBreakpoint : public Breakpoint { -public: - FunctionBreakpoint(DAP &dap, const protocol::FunctionBreakpoint &breakpoint); - - /// Set this breakpoint in LLDB as a new breakpoint. - void SetBreakpoint(); - - llvm::StringRef GetFunctionName() const { return m_function_name; } - -protected: - std::string m_function_name; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp deleted file mode 100644 index 371349a26866..000000000000 --- a/lldb/tools/lldb-dap/Handler/AttachRequestHandler.cpp +++ /dev/null @@ -1,146 +0,0 @@ -//===-- AttachRequestHandler.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "lldb/API/SBAttachInfo.h" -#include "lldb/API/SBListener.h" -#include "lldb/lldb-defines.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" - -using namespace llvm; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// The `attach` request is sent from the client to the debug adapter to attach -/// to a debuggee that is already running. -/// -/// Since attaching is debugger/runtime specific, the arguments for this request -/// are not part of this specification. -Error AttachRequestHandler::Run(const AttachRequestArguments &args) const { - // Validate that we have a well formed attach request. - if (args.attachCommands.empty() && args.coreFile.empty() && - args.configuration.program.empty() && - args.pid == LLDB_INVALID_PROCESS_ID && - args.gdbRemotePort == LLDB_DAP_INVALID_PORT) - return make_error( - "expected one of 'pid', 'program', 'attachCommands', " - "'coreFile' or 'gdb-remote-port' to be specified"); - - // Check if we have mutually exclusive arguments. - if ((args.pid != LLDB_INVALID_PROCESS_ID) && - (args.gdbRemotePort != LLDB_DAP_INVALID_PORT)) - return make_error( - "'pid' and 'gdb-remote-port' are mutually exclusive"); - - dap.SetConfiguration(args.configuration, /*is_attach=*/true); - if (!args.coreFile.empty()) - dap.stop_at_entry = true; - - PrintWelcomeMessage(); - - // This is a hack for loading DWARF in .o files on Mac where the .o files - // in the debug map of the main executable have relative paths which - // require the lldb-dap binary to have its working directory set to that - // relative root for the .o files in order to be able to load debug info. - if (!dap.configuration.debuggerRoot.empty()) - sys::fs::set_current_path(dap.configuration.debuggerRoot); - - // Run any initialize LLDB commands the user specified in the launch.json - if (llvm::Error err = dap.RunInitCommands()) - return err; - - dap.ConfigureSourceMaps(); - - lldb::SBError error; - lldb::SBTarget target = dap.CreateTarget(error); - if (error.Fail()) - return ToError(error); - - dap.SetTarget(target); - - // Run any pre run LLDB commands the user specified in the launch.json - if (Error err = dap.RunPreRunCommands()) - return err; - - if ((args.pid == LLDB_INVALID_PROCESS_ID || - args.gdbRemotePort == LLDB_DAP_INVALID_PORT) && - args.waitFor) { - dap.SendOutput(OutputType::Console, - llvm::formatv("Waiting to attach to \"{0}\"...", - dap.target.GetExecutable().GetFilename()) - .str()); - } - - { - // Perform the launch in synchronous mode so that we don't have to worry - // about process state changes during the launch. - ScopeSyncMode scope_sync_mode(dap.debugger); - - if (!args.attachCommands.empty()) { - // Run the attach commands, after which we expect the debugger's selected - // target to contain a valid and stopped process. Otherwise inform the - // user that their command failed or the debugger is in an unexpected - // state. - if (llvm::Error err = dap.RunAttachCommands(args.attachCommands)) - return err; - - dap.target = dap.debugger.GetSelectedTarget(); - - // Validate the attachCommand results. - if (!dap.target.GetProcess().IsValid()) - return make_error( - "attachCommands failed to attach to a process"); - } else if (!args.coreFile.empty()) { - dap.target.LoadCore(args.coreFile.data(), error); - } else if (args.gdbRemotePort != LLDB_DAP_INVALID_PORT) { - lldb::SBListener listener = dap.debugger.GetListener(); - - // If the user hasn't provided the hostname property, default - // localhost being used. - std::string connect_url = - llvm::formatv("connect://{0}:", args.gdbRemoteHostname); - connect_url += std::to_string(args.gdbRemotePort); - dap.target.ConnectRemote(listener, connect_url.c_str(), "gdb-remote", - error); - } else { - // Attach by pid or process name. - lldb::SBAttachInfo attach_info; - if (args.pid != LLDB_INVALID_PROCESS_ID) - attach_info.SetProcessID(args.pid); - else if (!dap.configuration.program.empty()) - attach_info.SetExecutable(dap.configuration.program.data()); - attach_info.SetWaitForLaunch(args.waitFor, /*async=*/false); - dap.target.Attach(attach_info, error); - } - } - - // Make sure the process is attached and stopped. - error = dap.WaitForProcessToStop(args.configuration.timeout); - if (error.Fail()) - return ToError(error); - - if (args.coreFile.empty() && !dap.target.GetProcess().IsValid()) - return make_error("failed to attach to process"); - - dap.RunPostRunCommands(); - - return Error::success(); -} - -void AttachRequestHandler::PostRun() const { - dap.SendJSON(CreateEventObject("initialized")); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp b/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp deleted file mode 100644 index 8a026f81b432..000000000000 --- a/lldb/tools/lldb-dap/Handler/BreakpointLocationsHandler.cpp +++ /dev/null @@ -1,129 +0,0 @@ -//===-- BreakpointLocationsHandler..cpp -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "RequestHandler.h" -#include -#include - -namespace lldb_dap { - -/// The `breakpointLocations` request returns all possible locations for source -/// breakpoints in a given range. Clients should only call this request if the -/// corresponding capability `supportsBreakpointLocationsRequest` is true. -llvm::Expected -BreakpointLocationsRequestHandler::Run( - const protocol::BreakpointLocationsArguments &args) const { - uint32_t start_line = args.line; - uint32_t start_column = args.column.value_or(LLDB_INVALID_COLUMN_NUMBER); - uint32_t end_line = args.endLine.value_or(start_line); - uint32_t end_column = - args.endColumn.value_or(std::numeric_limits::max()); - - // Find all relevant lines & columns. - std::vector> locations; - if (args.source.sourceReference) { - locations = GetAssemblyBreakpointLocations(*args.source.sourceReference, - start_line, end_line); - } else { - std::string path = args.source.path.value_or(""); - locations = GetSourceBreakpointLocations( - std::move(path), start_line, start_column, end_line, end_column); - } - - // The line entries are sorted by addresses, but we must return the list - // ordered by line / column position. - std::sort(locations.begin(), locations.end()); - locations.erase(llvm::unique(locations), locations.end()); - - std::vector breakpoint_locations; - for (auto &l : locations) - breakpoint_locations.push_back( - {l.first, l.second, std::nullopt, std::nullopt}); - - return protocol::BreakpointLocationsResponseBody{ - /*breakpoints=*/std::move(breakpoint_locations)}; -} - -std::vector> -BreakpointLocationsRequestHandler::GetSourceBreakpointLocations( - std::string path, uint32_t start_line, uint32_t start_column, - uint32_t end_line, uint32_t end_column) const { - std::vector> locations; - lldb::SBFileSpec file_spec(path.c_str(), true); - lldb::SBSymbolContextList compile_units = - dap.target.FindCompileUnits(file_spec); - - for (uint32_t c_idx = 0, c_limit = compile_units.GetSize(); c_idx < c_limit; - ++c_idx) { - const lldb::SBCompileUnit &compile_unit = - compile_units.GetContextAtIndex(c_idx).GetCompileUnit(); - if (!compile_unit.IsValid()) - continue; - lldb::SBFileSpec primary_file_spec = compile_unit.GetFileSpec(); - - // Go through the line table and find all matching lines / columns - for (uint32_t l_idx = 0, l_limit = compile_unit.GetNumLineEntries(); - l_idx < l_limit; ++l_idx) { - lldb::SBLineEntry line_entry = compile_unit.GetLineEntryAtIndex(l_idx); - - // Filter by line / column - uint32_t line = line_entry.GetLine(); - if (line < start_line || line > end_line) - continue; - uint32_t column = line_entry.GetColumn(); - if (column == LLDB_INVALID_COLUMN_NUMBER) - continue; - if (line == start_line && column < start_column) - continue; - if (line == end_line && column > end_column) - continue; - - // Make sure we are in the right file. - // We might have a match on line & column range and still - // be in the wrong file, e.g. for included files. - // Given that the involved pointers point into LLDB's string pool, - // we can directly compare the `const char*` pointers. - if (line_entry.GetFileSpec().GetFilename() != - primary_file_spec.GetFilename() || - line_entry.GetFileSpec().GetDirectory() != - primary_file_spec.GetDirectory()) - continue; - - locations.emplace_back(line, column); - } - } - - return locations; -} - -std::vector> -BreakpointLocationsRequestHandler::GetAssemblyBreakpointLocations( - int64_t source_reference, uint32_t start_line, uint32_t end_line) const { - std::vector> locations; - lldb::SBAddress address(source_reference, dap.target); - if (!address.IsValid()) - return locations; - - lldb::SBSymbol symbol = address.GetSymbol(); - if (!symbol.IsValid()) - return locations; - - // start_line is relative to the symbol's start address. - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - if (insts.GetSize() > (start_line - 1)) - locations.reserve(insts.GetSize() - (start_line - 1)); - for (uint32_t i = start_line - 1; i < insts.GetSize() && i <= (end_line - 1); - ++i) { - locations.emplace_back(i, 1); - } - - return locations; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/CancelRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/CancelRequestHandler.cpp deleted file mode 100644 index 995fe38362f6..000000000000 --- a/lldb/tools/lldb-dap/Handler/CancelRequestHandler.cpp +++ /dev/null @@ -1,55 +0,0 @@ -//===-- CancelRequestHandler.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Handler/RequestHandler.h" -#include "Protocol/ProtocolRequests.h" -#include "llvm/Support/Error.h" - -using namespace llvm; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// The `cancel` request is used by the client in two situations: -/// -/// - to indicate that it is no longer interested in the result produced by a -/// specific request issued earlier -/// - to cancel a progress sequence. -/// -/// Clients should only call this request if the corresponding capability -/// `supportsCancelRequest` is true. -/// -/// This request has a hint characteristic: a debug adapter can only be -/// expected to make a 'best effort' in honoring this request but there are no -/// guarantees. -/// -/// The `cancel` request may return an error if it could not cancel -/// an operation but a client should refrain from presenting this error to end -/// users. -/// -/// The request that got cancelled still needs to send a response back. -/// This can either be a normal result (`success` attribute true) or an error -/// response (`success` attribute false and the `message` set to `cancelled`). -/// -/// Returning partial results from a cancelled request is possible but please -/// note that a client has no generic way for detecting that a response is -/// partial or not. -/// -/// The progress that got cancelled still needs to send a `progressEnd` event -/// back. -/// -/// A client cannot assume that progress just got cancelled after sending -/// the `cancel` request. -Error CancelRequestHandler::Run(const CancelArguments &arguments) const { - // Cancel support is built into the DAP::Loop handler for detecting - // cancellations of pending or inflight requests. - dap.ClearCancelRequest(arguments); - return Error::success(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp deleted file mode 100644 index cd937116f738..000000000000 --- a/lldb/tools/lldb-dap/Handler/CompileUnitsRequestHandler.cpp +++ /dev/null @@ -1,82 +0,0 @@ -//===-- CompileUnitsRequestHandler.cpp ------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -// "compileUnitsRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Compile Unit request; value of command field is -// 'compileUnits'.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "compileUnits" ] -// }, -// "arguments": { -// "$ref": "#/definitions/compileUnitRequestArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "compileUnitsRequestArguments": { -// "type": "object", -// "description": "Arguments for 'compileUnits' request.", -// "properties": { -// "moduleId": { -// "type": "string", -// "description": "The ID of the module." -// } -// }, -// "required": [ "moduleId" ] -// }, -// "compileUnitsResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'compileUnits' request.", -// "properties": { -// "body": { -// "description": "Response to 'compileUnits' request. Array of -// paths of compile units." -// } -// } -// }] -// } -void CompileUnitsRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - llvm::json::Array units; - const auto *arguments = request.getObject("arguments"); - const std::string module_id = - GetString(arguments, "moduleId").value_or("").str(); - int num_modules = dap.target.GetNumModules(); - for (int i = 0; i < num_modules; i++) { - auto curr_module = dap.target.GetModuleAtIndex(i); - if (module_id == curr_module.GetUUIDString()) { - int num_units = curr_module.GetNumCompileUnits(); - for (int j = 0; j < num_units; j++) { - auto curr_unit = curr_module.GetCompileUnitAtIndex(j); - units.emplace_back(CreateCompileUnit(curr_unit)); - } - body.try_emplace("compileUnits", std::move(units)); - break; - } - } - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp b/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp deleted file mode 100644 index c72fc5686cd5..000000000000 --- a/lldb/tools/lldb-dap/Handler/CompletionsHandler.cpp +++ /dev/null @@ -1,224 +0,0 @@ -//===-- CompletionsHandler.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "JSONUtils.h" -#include "RequestHandler.h" -#include "lldb/API/SBStringList.h" - -namespace lldb_dap { - -// "CompletionsRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Returns a list of possible completions for a given caret -// position and text.\nThe CompletionsRequest may only be called if the -// 'supportsCompletionsRequest' capability exists and is true.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "completions" ] -// }, -// "arguments": { -// "$ref": "#/definitions/CompletionsArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "CompletionsArguments": { -// "type": "object", -// "description": "Arguments for 'completions' request.", -// "properties": { -// "frameId": { -// "type": "integer", -// "description": "Returns completions in the scope of this stack frame. -// If not specified, the completions are returned for the global scope." -// }, -// "text": { -// "type": "string", -// "description": "One or more source lines. Typically this is the text a -// user has typed into the debug console before he asked for completion." -// }, -// "column": { -// "type": "integer", -// "description": "The character position for which to determine the -// completion proposals." -// }, -// "line": { -// "type": "integer", -// "description": "An optional line for which to determine the completion -// proposals. If missing the first line of the text is assumed." -// } -// }, -// "required": [ "text", "column" ] -// }, -// "CompletionsResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'completions' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "targets": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/CompletionItem" -// }, -// "description": "The possible completions for ." -// } -// }, -// "required": [ "targets" ] -// } -// }, -// "required": [ "body" ] -// }] -// }, -// "CompletionItem": { -// "type": "object", -// "description": "CompletionItems are the suggestions returned from the -// CompletionsRequest.", "properties": { -// "label": { -// "type": "string", -// "description": "The label of this completion item. By default this is -// also the text that is inserted when selecting this completion." -// }, -// "text": { -// "type": "string", -// "description": "If text is not falsy then it is inserted instead of the -// label." -// }, -// "sortText": { -// "type": "string", -// "description": "A string that should be used when comparing this item -// with other items. When `falsy` the label is used." -// }, -// "type": { -// "$ref": "#/definitions/CompletionItemType", -// "description": "The item's type. Typically the client uses this -// information to render the item in the UI with an icon." -// }, -// "start": { -// "type": "integer", -// "description": "This value determines the location (in the -// CompletionsRequest's 'text' attribute) where the completion text is -// added.\nIf missing the text is added at the location specified by the -// CompletionsRequest's 'column' attribute." -// }, -// "length": { -// "type": "integer", -// "description": "This value determines how many characters are -// overwritten by the completion text.\nIf missing the value 0 is assumed -// which results in the completion text being inserted." -// } -// }, -// "required": [ "label" ] -// }, -// "CompletionItemType": { -// "type": "string", -// "description": "Some predefined types for the CompletionItem. Please note -// that not all clients have specific icons for all of them.", "enum": [ -// "method", "function", "constructor", "field", "variable", "class", -// "interface", "module", "property", "unit", "value", "enum", "keyword", -// "snippet", "text", "color", "file", "reference", "customcolor" ] -// } -void CompletionsRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - const auto *arguments = request.getObject("arguments"); - - // If we have a frame, try to set the context for variable completions. - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); - if (frame.IsValid()) { - frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); - frame.GetThread().SetSelectedFrame(frame.GetFrameID()); - } - - std::string text = GetString(arguments, "text").value_or("").str(); - auto original_column = - GetInteger(arguments, "column").value_or(text.size()); - auto original_line = GetInteger(arguments, "line").value_or(1); - auto offset = original_column - 1; - if (original_line > 1) { - llvm::SmallVector<::llvm::StringRef, 2> lines; - llvm::StringRef(text).split(lines, '\n'); - for (int i = 0; i < original_line - 1; i++) { - offset += lines[i].size(); - } - } - llvm::json::Array targets; - - bool had_escape_prefix = - llvm::StringRef(text).starts_with(dap.configuration.commandEscapePrefix); - ReplMode completion_mode = dap.DetectReplMode(frame, text, true); - - // Handle the offset change introduced by stripping out the - // `command_escape_prefix`. - if (had_escape_prefix) { - if (offset < - static_cast(dap.configuration.commandEscapePrefix.size())) { - body.try_emplace("targets", std::move(targets)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - offset -= dap.configuration.commandEscapePrefix.size(); - } - - // While the user is typing then we likely have an incomplete input and cannot - // reliably determine the precise intent (command vs variable), try completing - // the text as both a command and variable expression, if applicable. - const std::string expr_prefix = "expression -- "; - std::array, 2> exprs = { - {std::make_tuple(ReplMode::Command, text, offset), - std::make_tuple(ReplMode::Variable, expr_prefix + text, - offset + expr_prefix.size())}}; - for (const auto &[mode, line, cursor] : exprs) { - if (completion_mode != ReplMode::Auto && completion_mode != mode) - continue; - - lldb::SBStringList matches; - lldb::SBStringList descriptions; - if (!dap.debugger.GetCommandInterpreter().HandleCompletionWithDescriptions( - line.c_str(), cursor, 0, 100, matches, descriptions)) - continue; - - // The first element is the common substring after the cursor position for - // all the matches. The rest of the elements are the matches so ignore the - // first result. - for (size_t i = 1; i < matches.GetSize(); i++) { - std::string match = matches.GetStringAtIndex(i); - std::string description = descriptions.GetStringAtIndex(i); - - llvm::json::Object item; - llvm::StringRef match_ref = match; - for (llvm::StringRef commit_point : {".", "->"}) { - if (match_ref.contains(commit_point)) { - match_ref = match_ref.rsplit(commit_point).second; - } - } - EmplaceSafeString(item, "text", match_ref); - - if (description.empty()) - EmplaceSafeString(item, "label", match); - else - EmplaceSafeString(item, "label", match + " -- " + description); - - targets.emplace_back(std::move(item)); - } - } - - body.try_emplace("targets", std::move(targets)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp deleted file mode 100644 index 7cbbbd798246..000000000000 --- a/lldb/tools/lldb-dap/Handler/ConfigurationDoneRequestHandler.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===-- ConfigurationDoneRequestHandler..cpp ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "lldb/API/SBDebugger.h" - -using namespace llvm; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// This request indicates that the client has finished initialization of the -/// debug adapter. -/// -/// So it is the last request in the sequence of configuration requests (which -/// was started by the `initialized` event). -/// -/// Clients should only call this request if the corresponding capability -/// `supportsConfigurationDoneRequest` is true. -llvm::Error -ConfigurationDoneRequestHandler::Run(const ConfigurationDoneArguments &) const { - dap.configuration_done = true; - - SendTargetBasedCapabilities(dap); - // Ensure any command scripts did not leave us in an unexpected state. - lldb::SBProcess process = dap.target.GetProcess(); - if (!process.IsValid() || - !lldb::SBDebugger::StateIsStoppedState(process.GetState())) - return make_error( - "Expected process to be stopped.\r\n\r\nProcess is in an unexpected " - "state and may have missed an initial configuration. Please check that " - "any debugger command scripts are not resuming the process during the " - "launch sequence."); - - // Clients can request a baseline of currently existing threads after - // we acknowledge the configurationDone request. - // Client requests the baseline of currently existing threads after - // a successful or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // Obtain the list of threads before we resume the process - dap.initial_thread_list = GetThreads(process, dap.thread_format); - - SendProcessEvent(dap, dap.is_attach ? Attach : Launch); - - if (dap.stop_at_entry) - SendThreadStoppedEvent(dap); - else - process.Continue(); - - return Error::success(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp deleted file mode 100644 index 361c86421cf1..000000000000 --- a/lldb/tools/lldb-dap/Handler/ContinueRequestHandler.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//===-- ContinueRequestHandler.cpp ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "Handler/RequestHandler.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBProcess.h" -#include "llvm/Support/Error.h" - -using namespace llvm; -using namespace lldb; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// The request resumes execution of all threads. If the debug adapter supports -/// single thread execution (see capability -/// `supportsSingleThreadExecutionRequests`), setting the `singleThread` -/// argument to true resumes only the specified thread. If not all threads were -/// resumed, the `allThreadsContinued` attribute of the response should be set -/// to false. -Expected -ContinueRequestHandler::Run(const ContinueArguments &args) const { - SBProcess process = dap.target.GetProcess(); - SBError error; - - if (!SBDebugger::StateIsStoppedState(process.GetState())) - return make_error(); - - if (args.singleThread) - dap.GetLLDBThread(args.threadId).Resume(error); - else - error = process.Continue(); - - if (error.Fail()) - return ToError(error); - - ContinueResponseBody body; - body.allThreadsContinued = !args.singleThread; - return body; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp deleted file mode 100644 index 8cb25d060344..000000000000 --- a/lldb/tools/lldb-dap/Handler/DataBreakpointInfoRequestHandler.cpp +++ /dev/null @@ -1,95 +0,0 @@ -//===-- DataBreakpointInfoRequestHandler.cpp ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "Protocol/ProtocolTypes.h" -#include "RequestHandler.h" -#include "lldb/API/SBMemoryRegionInfo.h" -#include "llvm/ADT/StringExtras.h" -#include - -namespace lldb_dap { - -/// Obtains information on a possible data breakpoint that could be set on an -/// expression or variable. Clients should only call this request if the -/// corresponding capability supportsDataBreakpoints is true. -llvm::Expected -DataBreakpointInfoRequestHandler::Run( - const protocol::DataBreakpointInfoArguments &args) const { - protocol::DataBreakpointInfoResponseBody response; - lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId.value_or(UINT64_MAX)); - lldb::SBValue variable = dap.variables.FindVariable( - args.variablesReference.value_or(0), args.name); - std::string addr, size; - - bool is_data_ok = true; - if (variable.IsValid()) { - lldb::addr_t load_addr = variable.GetLoadAddress(); - size_t byte_size = variable.GetByteSize(); - if (load_addr == LLDB_INVALID_ADDRESS) { - is_data_ok = false; - response.description = "does not exist in memory, its location is " + - std::string(variable.GetLocation()); - } else if (byte_size == 0) { - is_data_ok = false; - response.description = "variable size is 0"; - } else { - addr = llvm::utohexstr(load_addr); - size = llvm::utostr(byte_size); - } - } else if (args.variablesReference.value_or(0) == 0 && frame.IsValid()) { - lldb::SBValue value = frame.EvaluateExpression(args.name.c_str()); - if (value.GetError().Fail()) { - lldb::SBError error = value.GetError(); - const char *error_cstr = error.GetCString(); - is_data_ok = false; - response.description = error_cstr && error_cstr[0] - ? std::string(error_cstr) - : "evaluation failed"; - } else { - uint64_t load_addr = value.GetValueAsUnsigned(); - lldb::SBData data = value.GetPointeeData(); - if (data.IsValid()) { - size = llvm::utostr(data.GetByteSize()); - addr = llvm::utohexstr(load_addr); - lldb::SBMemoryRegionInfo region; - lldb::SBError err = - dap.target.GetProcess().GetMemoryRegionInfo(load_addr, region); - // Only lldb-server supports "qMemoryRegionInfo". So, don't fail this - // request if SBProcess::GetMemoryRegionInfo returns error. - if (err.Success()) { - if (!(region.IsReadable() || region.IsWritable())) { - is_data_ok = false; - response.description = "memory region for address " + addr + - " has no read or write permissions"; - } - } - } else { - is_data_ok = false; - response.description = - "unable to get byte size for expression: " + args.name; - } - } - } else { - is_data_ok = false; - response.description = "variable not found: " + args.name; - } - - if (is_data_ok) { - response.dataId = addr + "/" + size; - response.accessTypes = {protocol::eDataBreakpointAccessTypeRead, - protocol::eDataBreakpointAccessTypeWrite, - protocol::eDataBreakpointAccessTypeReadWrite}; - response.description = size + " bytes at " + addr + " " + args.name; - } - - return response; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp deleted file mode 100644 index d5878d18289d..000000000000 --- a/lldb/tools/lldb-dap/Handler/DisassembleRequestHandler.cpp +++ /dev/null @@ -1,259 +0,0 @@ -//===-- DisassembleRequestHandler.cpp -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "Protocol/ProtocolTypes.h" -#include "ProtocolUtils.h" -#include "RequestHandler.h" -#include "lldb/API/SBAddress.h" -#include "lldb/API/SBInstruction.h" -#include "lldb/API/SBLineEntry.h" -#include "lldb/API/SBTarget.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Error.h" -#include -#include - -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -static protocol::DisassembledInstruction GetInvalidInstruction() { - DisassembledInstruction invalid_inst; - invalid_inst.address = LLDB_INVALID_ADDRESS; - invalid_inst.presentationHint = - DisassembledInstruction::eDisassembledInstructionPresentationHintInvalid; - return invalid_inst; -} - -static lldb::SBAddress GetDisassembleStartAddress(lldb::SBTarget target, - lldb::SBAddress addr, - int64_t instruction_offset) { - if (instruction_offset == 0) - return addr; - - if (target.GetMinimumOpcodeByteSize() == target.GetMaximumOpcodeByteSize()) { - // We have fixed opcode size, so we can calculate the address directly, - // negative or positive. - lldb::addr_t load_addr = addr.GetLoadAddress(target); - load_addr += instruction_offset * target.GetMinimumOpcodeByteSize(); - return lldb::SBAddress(load_addr, target); - } - - if (instruction_offset > 0) { - lldb::SBInstructionList forward_insts = - target.ReadInstructions(addr, instruction_offset + 1); - return forward_insts.GetInstructionAtIndex(forward_insts.GetSize() - 1) - .GetAddress(); - } - - // We have a negative instruction offset, so we need to disassemble backwards. - // The opcode size is not fixed, so we have no idea where to start from. - // Let's try from the start of the current symbol if available. - auto symbol = addr.GetSymbol(); - if (!symbol.IsValid()) - return addr; - - // Add valid instructions before the current instruction using the symbol. - lldb::SBInstructionList symbol_insts = - target.ReadInstructions(symbol.GetStartAddress(), addr, nullptr); - if (!symbol_insts.IsValid() || symbol_insts.GetSize() == 0) - return addr; - - const auto backwards_instructions_count = - static_cast(std::abs(instruction_offset)); - if (symbol_insts.GetSize() < backwards_instructions_count) { - // We don't have enough instructions to disassemble backwards, so just - // return the start address of the symbol. - return symbol_insts.GetInstructionAtIndex(0).GetAddress(); - } - - return symbol_insts - .GetInstructionAtIndex(symbol_insts.GetSize() - - backwards_instructions_count) - .GetAddress(); -} - -static DisassembledInstruction ConvertSBInstructionToDisassembledInstruction( - lldb::SBTarget &target, lldb::SBInstruction &inst, bool resolve_symbols) { - if (!inst.IsValid()) - return GetInvalidInstruction(); - - auto addr = inst.GetAddress(); - const auto inst_addr = addr.GetLoadAddress(target); - - // FIXME: This is a workaround - this address might come from - // disassembly that started in a different section, and thus - // comparisons between this object and other address objects with the - // same load address will return false. - addr = lldb::SBAddress(inst_addr, target); - - const char *m = inst.GetMnemonic(target); - const char *o = inst.GetOperands(target); - const char *c = inst.GetComment(target); - auto d = inst.GetData(target); - - std::string bytes; - llvm::raw_string_ostream sb(bytes); - for (unsigned i = 0; i < inst.GetByteSize(); i++) { - lldb::SBError error; - uint8_t b = d.GetUnsignedInt8(error, i); - if (error.Success()) - sb << llvm::format("%2.2x ", b); - } - - DisassembledInstruction disassembled_inst; - disassembled_inst.address = inst_addr; - disassembled_inst.instructionBytes = - bytes.size() > 0 ? bytes.substr(0, bytes.size() - 1) : ""; - - std::string instruction; - llvm::raw_string_ostream si(instruction); - - lldb::SBSymbol symbol = addr.GetSymbol(); - // Only add the symbol on the first line of the function. - if (symbol.IsValid() && symbol.GetStartAddress() == addr) { - // If we have a valid symbol, append it as a label prefix for the first - // instruction. This is so you can see the start of a function/callsite - // in the assembly, at the moment VS Code (1.80) does not visualize the - // symbol associated with the assembly instruction. - si << (symbol.GetMangledName() != nullptr ? symbol.GetMangledName() - : symbol.GetName()) - << ": "; - - if (resolve_symbols) - disassembled_inst.symbol = symbol.GetDisplayName(); - } - - si << llvm::formatv("{0,7} {1,12}", m, o); - if (c && c[0]) { - si << " ; " << c; - } - - disassembled_inst.instruction = std::move(instruction); - - protocol::Source source = CreateSource(addr, target); - lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, addr); - - // If the line number is 0 then the entry represents a compiler generated - // location. - if (!IsAssemblySource(source) && line_entry.GetStartAddress() == addr && - line_entry.IsValid() && line_entry.GetFileSpec().IsValid() && - line_entry.GetLine() != 0) { - - disassembled_inst.location = std::move(source); - const auto line = line_entry.GetLine(); - if (line != 0 && line != LLDB_INVALID_LINE_NUMBER) - disassembled_inst.line = line; - - const auto column = line_entry.GetColumn(); - if (column != 0 && column != LLDB_INVALID_COLUMN_NUMBER) - disassembled_inst.column = column; - - lldb::SBAddress end_addr = line_entry.GetEndAddress(); - auto end_line_entry = GetLineEntryForAddress(target, end_addr); - if (end_line_entry.IsValid() && - end_line_entry.GetFileSpec() == line_entry.GetFileSpec()) { - const auto end_line = end_line_entry.GetLine(); - if (end_line != 0 && end_line != LLDB_INVALID_LINE_NUMBER && - end_line != line) { - disassembled_inst.endLine = end_line; - - const auto end_column = end_line_entry.GetColumn(); - if (end_column != 0 && end_column != LLDB_INVALID_COLUMN_NUMBER && - end_column != column) - disassembled_inst.endColumn = end_column - 1; - } - } - } - - return disassembled_inst; -} - -/// Disassembles code stored at the provided location. -/// Clients should only call this request if the corresponding capability -/// `supportsDisassembleRequest` is true. -llvm::Expected -DisassembleRequestHandler::Run(const DisassembleArguments &args) const { - std::optional addr_opt = - DecodeMemoryReference(args.memoryReference); - if (!addr_opt.has_value()) - return llvm::make_error("Malformed memory reference: " + - args.memoryReference); - - lldb::addr_t addr_ptr = *addr_opt; - addr_ptr += args.offset.value_or(0); - lldb::SBAddress addr(addr_ptr, dap.target); - if (!addr.IsValid()) - return llvm::make_error( - "Memory reference not found in the current binary."); - - // Offset (in instructions) to be applied after the byte offset (if any) - // before disassembling. Can be negative. - int64_t instruction_offset = args.instructionOffset.value_or(0); - - // Calculate a sufficient address to start disassembling from. - lldb::SBAddress disassemble_start_addr = - GetDisassembleStartAddress(dap.target, addr, instruction_offset); - if (!disassemble_start_addr.IsValid()) - return llvm::make_error( - "Unexpected error while disassembling instructions."); - - lldb::SBInstructionList insts = dap.target.ReadInstructions( - disassemble_start_addr, args.instructionCount); - if (!insts.IsValid()) - return llvm::make_error( - "Unexpected error while disassembling instructions."); - - // Conver the found instructions to the DAP format. - const bool resolve_symbols = args.resolveSymbols.value_or(false); - std::vector instructions; - size_t original_address_index = args.instructionCount; - for (size_t i = 0; i < insts.GetSize(); ++i) { - lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); - if (inst.GetAddress() == addr) - original_address_index = i; - - instructions.push_back(ConvertSBInstructionToDisassembledInstruction( - dap.target, inst, resolve_symbols)); - } - - // Check if we miss instructions at the beginning. - if (instruction_offset < 0) { - const auto backwards_instructions_count = - static_cast(std::abs(instruction_offset)); - if (original_address_index < backwards_instructions_count) { - // We don't have enough instructions before the main address as was - // requested. Let's pad the start of the instructions with invalid - // instructions. - std::vector invalid_instructions( - backwards_instructions_count - original_address_index, - GetInvalidInstruction()); - instructions.insert(instructions.begin(), invalid_instructions.begin(), - invalid_instructions.end()); - - // Trim excess instructions if needed. - if (instructions.size() > args.instructionCount) - instructions.resize(args.instructionCount); - } - } - - // Pad the instructions with invalid instructions if needed. - while (instructions.size() < args.instructionCount) { - instructions.push_back(GetInvalidInstruction()); - } - - return DisassembleResponseBody{std::move(instructions)}; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp deleted file mode 100644 index 8314a1011a57..000000000000 --- a/lldb/tools/lldb-dap/Handler/DisconnectRequestHandler.cpp +++ /dev/null @@ -1,33 +0,0 @@ -//===-- DisconnectRequestHandler.cpp --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "llvm/Support/Error.h" -#include - -using namespace llvm; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// Disconnect request; value of command field is 'disconnect'. -Error DisconnectRequestHandler::Run( - const std::optional &arguments) const { - bool terminateDebuggee = !dap.is_attach; - - if (arguments && arguments->terminateDebuggee) - terminateDebuggee = *arguments->terminateDebuggee; - - if (Error error = dap.Disconnect(terminateDebuggee)) - return error; - - return Error::success(); -} -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp deleted file mode 100644 index e1556846dff1..000000000000 --- a/lldb/tools/lldb-dap/Handler/EvaluateRequestHandler.cpp +++ /dev/null @@ -1,234 +0,0 @@ -//===-- EvaluateRequestHandler.cpp ----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -// "EvaluateRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Evaluate request; value of command field is 'evaluate'. -// Evaluates the given expression in the context of the -// top most stack frame. The expression has access to any -// variables and arguments that are in scope.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "evaluate" ] -// }, -// "arguments": { -// "$ref": "#/definitions/EvaluateArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "EvaluateArguments": { -// "type": "object", -// "description": "Arguments for 'evaluate' request.", -// "properties": { -// "expression": { -// "type": "string", -// "description": "The expression to evaluate." -// }, -// "frameId": { -// "type": "integer", -// "description": "Evaluate the expression in the scope of this stack -// frame. If not specified, the expression is evaluated -// in the global scope." -// }, -// "context": { -// "type": "string", -// "_enum": [ "watch", "repl", "hover" ], -// "enumDescriptions": [ -// "evaluate is run in a watch.", -// "evaluate is run from REPL console.", -// "evaluate is run from a data hover." -// ], -// "description": "The context in which the evaluate request is run." -// }, -// "format": { -// "$ref": "#/definitions/ValueFormat", -// "description": "Specifies details on how to format the Evaluate -// result." -// } -// }, -// "required": [ "expression" ] -// }, -// "EvaluateResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'evaluate' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "result": { -// "type": "string", -// "description": "The result of the evaluate request." -// }, -// "type": { -// "type": "string", -// "description": "The optional type of the evaluate result." -// }, -// "presentationHint": { -// "$ref": "#/definitions/VariablePresentationHint", -// "description": "Properties of a evaluate result that can be -// used to determine how to render the result in -// the UI." -// }, -// "variablesReference": { -// "type": "number", -// "description": "If variablesReference is > 0, the evaluate -// result is structured and its children can be -// retrieved by passing variablesReference to the -// VariablesRequest." -// }, -// "namedVariables": { -// "type": "number", -// "description": "The number of named child variables. The -// client can use this optional information to -// present the variables in a paged UI and fetch -// them in chunks." -// }, -// "indexedVariables": { -// "type": "number", -// "description": "The number of indexed child variables. The -// client can use this optional information to -// present the variables in a paged UI and fetch -// them in chunks." -// }, -// "valueLocationReference": { -// "type": "integer", -// "description": "A reference that allows the client to request -// the location where the returned value is -// declared. For example, if a function pointer is -// returned, the adapter may be able to look up the -// function's location. This should be present only -// if the adapter is likely to be able to resolve -// the location.\n\nThis reference shares the same -// lifetime as the `variablesReference`. See -// 'Lifetime of Object References' in the -// Overview section for details." -// } -// "memoryReference": { -// "type": "string", -// "description": "A memory reference to a location appropriate -// for this result. For pointer type eval -// results, this is generally a reference to the -// memory address contained in the pointer. This -// attribute may be returned by a debug adapter -// if corresponding capability -// `supportsMemoryReferences` is true." -// }, -// }, -// "required": [ "result", "variablesReference" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void EvaluateRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Object body; - const auto *arguments = request.getObject("arguments"); - lldb::SBFrame frame = dap.GetLLDBFrame(*arguments); - std::string expression = - GetString(arguments, "expression").value_or("").str(); - const llvm::StringRef context = GetString(arguments, "context").value_or(""); - bool repeat_last_command = - expression.empty() && dap.last_nonempty_var_expression.empty(); - - if (context == "repl" && - (repeat_last_command || - (!expression.empty() && - dap.DetectReplMode(frame, expression, false) == ReplMode::Command))) { - // Since the current expression is not for a variable, clear the - // last_nonempty_var_expression field. - dap.last_nonempty_var_expression.clear(); - // If we're evaluating a command relative to the current frame, set the - // focus_tid to the current frame for any thread related events. - if (frame.IsValid()) { - dap.focus_tid = frame.GetThread().GetThreadID(); - } - - bool required_command_failed = false; - std::string result = RunLLDBCommands( - dap.debugger, llvm::StringRef(), {expression}, required_command_failed, - /*parse_command_directives=*/false, /*echo_commands=*/false); - - EmplaceSafeString(body, "result", result); - body.try_emplace("variablesReference", (int64_t)0); - } else { - if (context == "repl") { - // If the expression is empty and the last expression was for a - // variable, set the expression to the previous expression (repeat the - // evaluation); otherwise save the current non-empty expression for the - // next (possibly empty) variable expression. - if (expression.empty()) - expression = dap.last_nonempty_var_expression; - else - dap.last_nonempty_var_expression = expression; - } - // Always try to get the answer from the local variables if possible. If - // this fails, then if the context is not "hover", actually evaluate an - // expression using the expression parser. - // - // "frame variable" is more reliable than the expression parser in - // many cases and it is faster. - lldb::SBValue value = frame.GetValueForVariablePath( - expression.data(), lldb::eDynamicDontRunTarget); - - // Freeze dry the value in case users expand it later in the debug console - if (value.GetError().Success() && context == "repl") - value = value.Persist(); - - if (value.GetError().Fail() && context != "hover") - value = frame.EvaluateExpression(expression.data()); - - if (value.GetError().Fail()) { - response["success"] = llvm::json::Value(false); - // This error object must live until we're done with the pointer returned - // by GetCString(). - lldb::SBError error = value.GetError(); - const char *error_cstr = error.GetCString(); - if (error_cstr && error_cstr[0]) - EmplaceSafeString(response, "message", error_cstr); - else - EmplaceSafeString(response, "message", "evaluate failed"); - } else { - VariableDescription desc(value, - dap.configuration.enableAutoVariableSummaries); - EmplaceSafeString(body, "result", desc.GetResult(context)); - EmplaceSafeString(body, "type", desc.display_type_name); - int64_t var_ref = 0; - if (value.MightHaveChildren() || ValuePointsToCode(value)) - var_ref = dap.variables.InsertVariable( - value, /*is_permanent=*/context == "repl"); - if (value.MightHaveChildren()) - body.try_emplace("variablesReference", var_ref); - else - body.try_emplace("variablesReference", (int64_t)0); - if (lldb::addr_t addr = value.GetLoadAddress(); - addr != LLDB_INVALID_ADDRESS) - body.try_emplace("memoryReference", EncodeMemoryReference(addr)); - if (ValuePointsToCode(value)) - body.try_emplace("valueLocationReference", var_ref); - } - } - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp deleted file mode 100644 index c1c2adb32a51..000000000000 --- a/lldb/tools/lldb-dap/Handler/ExceptionInfoRequestHandler.cpp +++ /dev/null @@ -1,174 +0,0 @@ -//===-- ExceptionInfoRequestHandler.cpp -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" -#include "lldb/API/SBStream.h" - -namespace lldb_dap { - -// "ExceptionInfoRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Retrieves the details of the exception that -// caused this event to be raised. Clients should only call this request if -// the corresponding capability `supportsExceptionInfoRequest` is true.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "exceptionInfo" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ExceptionInfoArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "ExceptionInfoArguments": { -// "type": "object", -// "description": "Arguments for `exceptionInfo` request.", -// "properties": { -// "threadId": { -// "type": "integer", -// "description": "Thread for which exception information should be -// retrieved." -// } -// }, -// "required": [ "threadId" ] -// }, -// "ExceptionInfoResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `exceptionInfo` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "exceptionId": { -// "type": "string", -// "description": "ID of the exception that was thrown." -// }, -// "description": { -// "type": "string", -// "description": "Descriptive text for the exception." -// }, -// "breakMode": { -// "$ref": "#/definitions/ExceptionBreakMode", -// "description": "Mode that caused the exception notification to -// be raised." -// }, -// "details": { -// "$ref": "#/definitions/ExceptionDetails", -// "description": "Detailed information about the exception." -// } -// }, -// "required": [ "exceptionId", "breakMode" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -// "ExceptionDetails": { -// "type": "object", -// "description": "Detailed information about an exception that has -// occurred.", "properties": { -// "message": { -// "type": "string", -// "description": "Message contained in the exception." -// }, -// "typeName": { -// "type": "string", -// "description": "Short type name of the exception object." -// }, -// "fullTypeName": { -// "type": "string", -// "description": "Fully-qualified type name of the exception object." -// }, -// "evaluateName": { -// "type": "string", -// "description": "An expression that can be evaluated in the current -// scope to obtain the exception object." -// }, -// "stackTrace": { -// "type": "string", -// "description": "Stack trace at the time the exception was thrown." -// }, -// "innerException": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/ExceptionDetails" -// }, -// "description": "Details of the exception contained by this exception, -// if any." -// } -// } -// }, -void ExceptionInfoRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - const auto *arguments = request.getObject("arguments"); - llvm::json::Object body; - lldb::SBThread thread = dap.GetLLDBThread(*arguments); - if (thread.IsValid()) { - auto stopReason = thread.GetStopReason(); - if (stopReason == lldb::eStopReasonSignal) - body.try_emplace("exceptionId", "signal"); - else if (stopReason == lldb::eStopReasonBreakpoint) { - ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread); - if (exc_bp) { - EmplaceSafeString(body, "exceptionId", exc_bp->GetFilter()); - EmplaceSafeString(body, "description", exc_bp->GetLabel()); - } else { - body.try_emplace("exceptionId", "exception"); - } - } else { - body.try_emplace("exceptionId", "exception"); - } - if (!ObjectContainsKey(body, "description")) { - char description[1024]; - if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", description); - } - } - body.try_emplace("breakMode", "always"); - auto exception = thread.GetCurrentException(); - if (exception.IsValid()) { - llvm::json::Object details; - lldb::SBStream stream; - if (exception.GetDescription(stream)) { - EmplaceSafeString(details, "message", stream.GetData()); - } - - auto exceptionBacktrace = thread.GetCurrentExceptionBacktrace(); - if (exceptionBacktrace.IsValid()) { - lldb::SBStream stream; - exceptionBacktrace.GetDescription(stream); - for (uint32_t i = 0; i < exceptionBacktrace.GetNumFrames(); i++) { - lldb::SBFrame frame = exceptionBacktrace.GetFrameAtIndex(i); - frame.GetDescription(stream); - } - EmplaceSafeString(details, "stackTrace", stream.GetData()); - } - - body.try_emplace("details", std::move(details)); - } - // auto excInfoCount = thread.GetStopReasonDataCount(); - // for (auto i=0; i InitializeRequestHandler::Run( - const InitializeRequestArguments &arguments) const { - dap.clientFeatures = arguments.supportedFeatures; - - // Do not source init files until in/out/err are configured. - dap.debugger = lldb::SBDebugger::Create(false); - dap.debugger.SetInputFile(dap.in); - dap.target = dap.debugger.GetDummyTarget(); - - llvm::Expected out_fd = dap.out.GetWriteFileDescriptor(); - if (!out_fd) - return out_fd.takeError(); - dap.debugger.SetOutputFile(lldb::SBFile(*out_fd, "w", false)); - - llvm::Expected err_fd = dap.err.GetWriteFileDescriptor(); - if (!err_fd) - return err_fd.takeError(); - dap.debugger.SetErrorFile(lldb::SBFile(*err_fd, "w", false)); - - auto interp = dap.debugger.GetCommandInterpreter(); - - // The sourceInitFile option is not part of the DAP specification. It is an - // extension used by the test suite to prevent sourcing `.lldbinit` and - // changing its behavior. - if (arguments.lldbExtSourceInitFile.value_or(true)) { - dap.debugger.SkipLLDBInitFiles(false); - dap.debugger.SkipAppInitFiles(false); - lldb::SBCommandReturnObject init; - interp.SourceInitFileInGlobalDirectory(init); - interp.SourceInitFileInHomeDirectory(init); - } - - if (llvm::Error err = dap.RunPreInitCommands()) - return err; - - dap.PopulateExceptionBreakpoints(); - auto cmd = dap.debugger.GetCommandInterpreter().AddMultiwordCommand( - "lldb-dap", "Commands for managing lldb-dap."); - if (arguments.supportedFeatures.contains( - eClientFeatureStartDebuggingRequest)) { - cmd.AddCommand( - "start-debugging", new StartDebuggingCommand(dap), - "Sends a startDebugging request from the debug adapter to the client " - "to start a child debug session of the same type as the caller."); - } - cmd.AddCommand( - "repl-mode", new ReplModeCommand(dap), - "Get or set the repl behavior of lldb-dap evaluation requests."); - cmd.AddCommand("send-event", new SendEventCommand(dap), - "Sends an DAP event to the client."); - - if (arguments.supportedFeatures.contains(eClientFeatureProgressReporting)) - dap.StartProgressEventThread(); - - // Start our event thread so we can receive events from the debugger, target, - // process and more. - dap.StartEventThread(); - - return dap.GetCapabilities(); -} diff --git a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp deleted file mode 100644 index 1d7b4b700946..000000000000 --- a/lldb/tools/lldb-dap/Handler/LaunchRequestHandler.cpp +++ /dev/null @@ -1,73 +0,0 @@ -//===-- LaunchRequestHandler.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" - -using namespace llvm; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// Launch request; value of command field is 'launch'. -Error LaunchRequestHandler::Run(const LaunchRequestArguments &arguments) const { - // Validate that we have a well formed launch request. - if (!arguments.launchCommands.empty() && arguments.runInTerminal) - return make_error( - "'launchCommands' and 'runInTerminal' are mutually exclusive"); - - dap.SetConfiguration(arguments.configuration, /*is_attach=*/false); - dap.last_launch_request = arguments; - - PrintWelcomeMessage(); - - // This is a hack for loading DWARF in .o files on Mac where the .o files - // in the debug map of the main executable have relative paths which - // require the lldb-dap binary to have its working directory set to that - // relative root for the .o files in order to be able to load debug info. - if (!dap.configuration.debuggerRoot.empty()) - sys::fs::set_current_path(dap.configuration.debuggerRoot); - - // Run any initialize LLDB commands the user specified in the launch.json. - // This is run before target is created, so commands can't do anything with - // the targets - preRunCommands are run with the target. - if (Error err = dap.RunInitCommands()) - return err; - - dap.ConfigureSourceMaps(); - - lldb::SBError error; - lldb::SBTarget target = dap.CreateTarget(error); - if (error.Fail()) - return ToError(error); - - dap.SetTarget(target); - - // Run any pre run LLDB commands the user specified in the launch.json - if (Error err = dap.RunPreRunCommands()) - return err; - - if (Error err = LaunchProcess(arguments)) - return err; - - dap.RunPostRunCommands(); - - return Error::success(); -} - -void LaunchRequestHandler::PostRun() const { - dap.SendJSON(CreateEventObject("initialized")); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp deleted file mode 100644 index 804bdcd622a2..000000000000 --- a/lldb/tools/lldb-dap/Handler/LocationsRequestHandler.cpp +++ /dev/null @@ -1,166 +0,0 @@ -//===-- LocationsRequestHandler.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "ProtocolUtils.h" -#include "RequestHandler.h" -#include "lldb/API/SBAddress.h" -#include "lldb/API/SBDeclaration.h" -#include "lldb/API/SBLineEntry.h" - -namespace lldb_dap { - -// "LocationsRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Looks up information about a location reference -// previously returned by the debug adapter.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "locations" ] -// }, -// "arguments": { -// "$ref": "#/definitions/LocationsArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "LocationsArguments": { -// "type": "object", -// "description": "Arguments for `locations` request.", -// "properties": { -// "locationReference": { -// "type": "integer", -// "description": "Location reference to resolve." -// } -// }, -// "required": [ "locationReference" ] -// }, -// "LocationsResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `locations` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "source": { -// "$ref": "#/definitions/Source", -// "description": "The source containing the location; either -// `source.path` or `source.sourceReference` must be -// specified." -// }, -// "line": { -// "type": "integer", -// "description": "The line number of the location. The client -// capability `linesStartAt1` determines whether it -// is 0- or 1-based." -// }, -// "column": { -// "type": "integer", -// "description": "Position of the location within the `line`. It is -// measured in UTF-16 code units and the client -// capability `columnsStartAt1` determines whether -// it is 0- or 1-based. If no column is given, the -// first position in the start line is assumed." -// }, -// "endLine": { -// "type": "integer", -// "description": "End line of the location, present if the location -// refers to a range. The client capability -// `linesStartAt1` determines whether it is 0- or -// 1-based." -// }, -// "endColumn": { -// "type": "integer", -// "description": "End position of the location within `endLine`, -// present if the location refers to a range. It is -// measured in UTF-16 code units and the client -// capability `columnsStartAt1` determines whether -// it is 0- or 1-based." -// } -// }, -// "required": [ "source", "line" ] -// } -// } -// }] -// }, -void LocationsRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - auto *arguments = request.getObject("arguments"); - - const auto location_id = - GetInteger(arguments, "locationReference").value_or(0); - // We use the lowest bit to distinguish between value location and declaration - // location - auto [var_ref, is_value_location] = UnpackLocation(location_id); - lldb::SBValue variable = dap.variables.GetVariable(var_ref); - if (!variable.IsValid()) { - response["success"] = false; - response["message"] = "Invalid variable reference"; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - llvm::json::Object body; - if (is_value_location) { - // Get the value location - if (!variable.GetType().IsPointerType() && - !variable.GetType().IsReferenceType()) { - response["success"] = false; - response["message"] = - "Value locations are only available for pointers and references"; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - lldb::addr_t raw_addr = variable.GetValueAsAddress(); - lldb::SBAddress addr = dap.target.ResolveLoadAddress(raw_addr); - lldb::SBLineEntry line_entry = GetLineEntryForAddress(dap.target, addr); - - if (!line_entry.IsValid()) { - response["success"] = false; - response["message"] = "Failed to resolve line entry for location"; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - body.try_emplace("source", CreateSource(line_entry.GetFileSpec())); - if (int line = line_entry.GetLine()) - body.try_emplace("line", line); - if (int column = line_entry.GetColumn()) - body.try_emplace("column", column); - } else { - // Get the declaration location - lldb::SBDeclaration decl = variable.GetDeclaration(); - if (!decl.IsValid()) { - response["success"] = false; - response["message"] = "No declaration location available"; - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - body.try_emplace("source", CreateSource(decl.GetFileSpec())); - if (int line = decl.GetLine()) - body.try_emplace("line", line); - if (int column = decl.GetColumn()) - body.try_emplace("column", column); - } - - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ModulesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ModulesRequestHandler.cpp deleted file mode 100644 index d37f302b0695..000000000000 --- a/lldb/tools/lldb-dap/Handler/ModulesRequestHandler.cpp +++ /dev/null @@ -1,70 +0,0 @@ -//===-- ModulesRequestHandler.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -// "modulesRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Modules request; value of command field is -// 'modules'.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "modules" ] -// }, -// }, -// "required": [ "command" ] -// }] -// }, -// "modulesResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'modules' request.", -// "properties": { -// "body": { -// "description": "Response to 'modules' request. Array of -// module objects." -// } -// } -// }] -// } -void ModulesRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - - llvm::json::Array modules; - - { - std::lock_guard guard(dap.modules_mutex); - for (size_t i = 0; i < dap.target.GetNumModules(); i++) { - lldb::SBModule module = dap.target.GetModuleAtIndex(i); - if (!module.IsValid()) - continue; - - llvm::StringRef module_id = module.GetUUIDString(); - if (!module_id.empty()) - dap.modules.insert(module_id); - - modules.emplace_back(CreateModule(dap.target, module)); - } - } - - llvm::json::Object body; - body.try_emplace("modules", std::move(modules)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp deleted file mode 100644 index 2b48350dfba1..000000000000 --- a/lldb/tools/lldb-dap/Handler/NextRequestHandler.cpp +++ /dev/null @@ -1,51 +0,0 @@ -//===-- NextRequestHandler.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolTypes.h" -#include "RequestHandler.h" -#include "llvm/Support/Error.h" - -using namespace llvm; -using namespace lldb; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// The request executes one step (in the given granularity) for the specified -/// thread and allows all other threads to run freely by resuming them. If the -/// debug adapter supports single thread execution (see capability -/// `supportsSingleThreadExecutionRequests`), setting the `singleThread` -/// argument to true prevents other suspended threads from resuming. The debug -/// adapter first sends the response and then a `stopped` event (with reason -/// `step`) after the step has completed. -Error NextRequestHandler::Run(const NextArguments &args) const { - lldb::SBThread thread = dap.GetLLDBThread(args.threadId); - if (!thread.IsValid()) - return make_error("invalid thread"); - - if (!SBDebugger::StateIsStoppedState(dap.target.GetProcess().GetState())) - return make_error(); - - // Remember the thread ID that caused the resume so we can set the - // "threadCausedFocus" boolean value in the "stopped" events. - dap.focus_tid = thread.GetThreadID(); - lldb::SBError error; - if (args.granularity == eSteppingGranularityInstruction) { - thread.StepInstruction(/*step_over=*/true, error); - } else { - thread.StepOver(args.singleThread ? eOnlyThisThread : eOnlyDuringStepping, - error); - } - - return ToError(error); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/PauseRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/PauseRequestHandler.cpp deleted file mode 100644 index 99917b2e2822..000000000000 --- a/lldb/tools/lldb-dap/Handler/PauseRequestHandler.cpp +++ /dev/null @@ -1,60 +0,0 @@ -//===-- PauseRequestHandler.cpp -------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -// "PauseRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Pause request; value of command field is 'pause'. The -// request suspenses the debuggee. The debug adapter first sends the -// PauseResponse and then a StoppedEvent (event type 'pause') after the -// thread has been paused successfully.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "pause" ] -// }, -// "arguments": { -// "$ref": "#/definitions/PauseArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "PauseArguments": { -// "type": "object", -// "description": "Arguments for 'pause' request.", -// "properties": { -// "threadId": { -// "type": "integer", -// "description": "Pause execution for this thread." -// } -// }, -// "required": [ "threadId" ] -// }, -// "PauseResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'pause' request. This is just an -// acknowledgement, so no body field is required." -// }] -// } -void PauseRequestHandler::operator()(const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - lldb::SBProcess process = dap.target.GetProcess(); - lldb::SBError error = process.Stop(); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ReadMemoryRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ReadMemoryRequestHandler.cpp deleted file mode 100644 index 891c2af4f2f2..000000000000 --- a/lldb/tools/lldb-dap/Handler/ReadMemoryRequestHandler.cpp +++ /dev/null @@ -1,142 +0,0 @@ -//===-- ReadMemoryRequestHandler.cpp --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/Support/Base64.h" - -namespace lldb_dap { - -// "ReadMemoryRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Reads bytes from memory at the provided location. Clients -// should only call this request if the corresponding -// capability `supportsReadMemoryRequest` is true.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "readMemory" ] -// }, -// "arguments": { -// "$ref": "#/definitions/ReadMemoryArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "ReadMemoryArguments": { -// "type": "object", -// "description": "Arguments for `readMemory` request.", -// "properties": { -// "memoryReference": { -// "type": "string", -// "description": "Memory reference to the base location from which data -// should be read." -// }, -// "offset": { -// "type": "integer", -// "description": "Offset (in bytes) to be applied to the reference -// location before reading data. Can be negative." -// }, -// "count": { -// "type": "integer", -// "description": "Number of bytes to read at the specified location and -// offset." -// } -// }, -// "required": [ "memoryReference", "count" ] -// }, -// "ReadMemoryResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `readMemory` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "address": { -// "type": "string", -// "description": "The address of the first byte of data returned. -// Treated as a hex value if prefixed with `0x`, or -// as a decimal value otherwise." -// }, -// "unreadableBytes": { -// "type": "integer", -// "description": "The number of unreadable bytes encountered after -// the last successfully read byte.\nThis can be -// used to determine the number of bytes that should -// be skipped before a subsequent -// `readMemory` request succeeds." -// }, -// "data": { -// "type": "string", -// "description": "The bytes read from memory, encoded using base64. -// If the decoded length of `data` is less than the -// requested `count` in the original `readMemory` -// request, and `unreadableBytes` is zero or -// omitted, then the client should assume it's -// reached the end of readable memory." -// } -// }, -// "required": [ "address" ] -// } -// } -// }] -// }, -void ReadMemoryRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - auto *arguments = request.getObject("arguments"); - - llvm::StringRef memoryReference = - GetString(arguments, "memoryReference").value_or(""); - auto addr_opt = DecodeMemoryReference(memoryReference); - if (!addr_opt.has_value()) { - response["success"] = false; - response["message"] = - "Malformed memory reference: " + memoryReference.str(); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - lldb::addr_t addr_int = *addr_opt; - addr_int += GetInteger(arguments, "offset").value_or(0); - const uint64_t count_requested = - GetInteger(arguments, "count").value_or(0); - - // We also need support reading 0 bytes - // VS Code sends those requests to check if a `memoryReference` - // can be dereferenced. - const uint64_t count_read = std::max(count_requested, 1); - std::vector buf; - buf.resize(count_read); - lldb::SBError error; - lldb::SBAddress addr{addr_int, dap.target}; - size_t count_result = - dap.target.ReadMemory(addr, buf.data(), count_read, error); - if (count_result == 0) { - response["success"] = false; - EmplaceSafeString(response, "message", error.GetCString()); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - buf.resize(std::min(count_result, count_requested)); - - llvm::json::Object body; - std::string formatted_addr = "0x" + llvm::utohexstr(addr_int); - body.try_emplace("address", formatted_addr); - body.try_emplace("data", llvm::encodeBase64(buf)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RequestHandler.cpp deleted file mode 100644 index 93bc80a38e29..000000000000 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.cpp +++ /dev/null @@ -1,239 +0,0 @@ -//===-- RequestHandler.cpp ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Handler/RequestHandler.h" -#include "DAP.h" -#include "EventHelper.h" -#include "Handler/ResponseHandler.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolBase.h" -#include "Protocol/ProtocolRequests.h" -#include "RunInTerminal.h" -#include "lldb/API/SBDefines.h" -#include "lldb/API/SBEnvironment.h" -#include "llvm/Support/Error.h" -#include - -#if !defined(_WIN32) -#include -#endif - -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -static std::vector -MakeArgv(const llvm::ArrayRef &strs) { - // Create and return an array of "const char *", one for each C string in - // "strs" and terminate the list with a NULL. This can be used for argument - // vectors (argv) or environment vectors (envp) like those passed to the - // "main" function in C programs. - std::vector argv; - for (const auto &s : strs) - argv.push_back(s.c_str()); - argv.push_back(nullptr); - return argv; -} - -static uint32_t SetLaunchFlag(uint32_t flags, bool flag, - lldb::LaunchFlags mask) { - if (flag) - flags |= mask; - else - flags &= ~mask; - - return flags; -} - -static llvm::Error -RunInTerminal(DAP &dap, const protocol::LaunchRequestArguments &arguments) { - if (!dap.clientFeatures.contains( - protocol::eClientFeatureRunInTerminalRequest)) - return llvm::make_error("Cannot use runInTerminal, feature is " - "not supported by the connected client"); - - if (arguments.configuration.program.empty()) - return llvm::make_error( - "program must be set to when using runInTerminal"); - - dap.is_attach = true; - lldb::SBAttachInfo attach_info; - - llvm::Expected> comm_file_or_err = - CreateRunInTerminalCommFile(); - if (!comm_file_or_err) - return comm_file_or_err.takeError(); - FifoFile &comm_file = *comm_file_or_err.get(); - - RunInTerminalDebugAdapterCommChannel comm_channel(comm_file.m_path); - - lldb::pid_t debugger_pid = LLDB_INVALID_PROCESS_ID; -#if !defined(_WIN32) - debugger_pid = getpid(); -#endif - - llvm::json::Object reverse_request = CreateRunInTerminalReverseRequest( - arguments.configuration.program, arguments.args, arguments.env, - arguments.cwd, comm_file.m_path, debugger_pid); - dap.SendReverseRequest("runInTerminal", - std::move(reverse_request)); - - if (llvm::Expected pid = comm_channel.GetLauncherPid()) - attach_info.SetProcessID(*pid); - else - return pid.takeError(); - - std::optional scope_sync_mode(dap.debugger); - lldb::SBError error; - dap.target.Attach(attach_info, error); - - if (error.Fail()) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Failed to attach to the target process. %s", - comm_channel.GetLauncherError().c_str()); - // This will notify the runInTerminal launcher that we attached. - // We have to make this async, as the function won't return until the launcher - // resumes and reads the data. - std::future did_attach_message_success = - comm_channel.NotifyDidAttach(); - - // We just attached to the runInTerminal launcher, which was waiting to be - // attached. We now resume it, so it can receive the didAttach notification - // and then perform the exec. Upon continuing, the debugger will stop the - // process right in the middle of the exec. To the user, what we are doing is - // transparent, as they will only be able to see the process since the exec, - // completely unaware of the preparatory work. - dap.target.GetProcess().Continue(); - - // Now that the actual target is just starting (i.e. exec was just invoked), - // we return the debugger to its sync state. - scope_sync_mode.reset(); - - // If sending the notification failed, the launcher should be dead by now and - // the async didAttach notification should have an error message, so we - // return it. Otherwise, everything was a success. - did_attach_message_success.wait(); - error = did_attach_message_success.get(); - if (error.Success()) - return llvm::Error::success(); - return llvm::createStringError(llvm::inconvertibleErrorCode(), - error.GetCString()); -} - -void BaseRequestHandler::Run(const Request &request) { - // If this request was cancelled, send a cancelled response. - if (dap.IsCancelled(request)) { - Response cancelled{/*request_seq=*/request.seq, - /*command=*/request.command, - /*success=*/false, - /*message=*/eResponseMessageCancelled, - /*body=*/std::nullopt}; - dap.Send(cancelled); - return; - } - - lldb::SBMutex lock = dap.GetAPIMutex(); - std::lock_guard guard(lock); - - // FIXME: After all the requests have migrated from LegacyRequestHandler > - // RequestHandler<> we should be able to move this into - // RequestHandler<>::operator(). - operator()(request); - - // FIXME: After all the requests have migrated from LegacyRequestHandler > - // RequestHandler<> we should be able to check `debugger.InterruptRequest` and - // mark the response as cancelled. -} - -llvm::Error BaseRequestHandler::LaunchProcess( - const protocol::LaunchRequestArguments &arguments) const { - auto launchCommands = arguments.launchCommands; - - // Instantiate a launch info instance for the target. - auto launch_info = dap.target.GetLaunchInfo(); - - // Grab the current working directory if there is one and set it in the - // launch info. - if (!arguments.cwd.empty()) - launch_info.SetWorkingDirectory(arguments.cwd.data()); - - // Extract any extra arguments and append them to our program arguments for - // when we launch - if (!arguments.args.empty()) - launch_info.SetArguments(MakeArgv(arguments.args).data(), true); - - // Pass any environment variables along that the user specified. - if (!arguments.env.empty()) { - lldb::SBEnvironment env; - for (const auto &kv : arguments.env) - env.Set(kv.first().data(), kv.second.c_str(), true); - launch_info.SetEnvironment(env, true); - } - - launch_info.SetDetachOnError(arguments.detachOnError); - launch_info.SetShellExpandArguments(arguments.shellExpandArguments); - - auto flags = launch_info.GetLaunchFlags(); - flags = - SetLaunchFlag(flags, arguments.disableASLR, lldb::eLaunchFlagDisableASLR); - flags = SetLaunchFlag(flags, arguments.disableSTDIO, - lldb::eLaunchFlagDisableSTDIO); - launch_info.SetLaunchFlags(flags | lldb::eLaunchFlagDebug | - lldb::eLaunchFlagStopAtEntry); - - { - // Perform the launch in synchronous mode so that we don't have to worry - // about process state changes during the launch. - ScopeSyncMode scope_sync_mode(dap.debugger); - - if (arguments.runInTerminal) { - if (llvm::Error err = RunInTerminal(dap, arguments)) - return err; - } else if (launchCommands.empty()) { - lldb::SBError error; - dap.target.Launch(launch_info, error); - if (error.Fail()) - return ToError(error); - } else { - // Set the launch info so that run commands can access the configured - // launch details. - dap.target.SetLaunchInfo(launch_info); - if (llvm::Error err = dap.RunLaunchCommands(launchCommands)) - return err; - - // The custom commands might have created a new target so we should use - // the selected target after these commands are run. - dap.target = dap.debugger.GetSelectedTarget(); - } - } - - // Make sure the process is launched and stopped at the entry point before - // proceeding. - lldb::SBError error = - dap.WaitForProcessToStop(arguments.configuration.timeout); - if (error.Fail()) - return ToError(error); - - return llvm::Error::success(); -} - -void BaseRequestHandler::PrintWelcomeMessage() const { -#ifdef LLDB_DAP_WELCOME_MESSAGE - dap.SendOutput(OutputType::Console, LLDB_DAP_WELCOME_MESSAGE); -#endif -} - -bool BaseRequestHandler::HasInstructionGranularity( - const llvm::json::Object &arguments) const { - if (std::optional value = arguments.getString("granularity")) - return value == "instruction"; - return false; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/RequestHandler.h b/lldb/tools/lldb-dap/Handler/RequestHandler.h deleted file mode 100644 index 559929ffb21e..000000000000 --- a/lldb/tools/lldb-dap/Handler/RequestHandler.h +++ /dev/null @@ -1,609 +0,0 @@ -//===-- Request.h ---------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H -#define LLDB_TOOLS_LLDB_DAP_HANDLER_HANDLER_H - -#include "DAP.h" -#include "DAPError.h" -#include "DAPLog.h" -#include "Protocol/ProtocolBase.h" -#include "Protocol/ProtocolRequests.h" -#include "Protocol/ProtocolTypes.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/JSON.h" -#include -#include -#include -#include - -template struct is_optional : std::false_type {}; - -template struct is_optional> : std::true_type {}; - -template -inline constexpr bool is_optional_v = is_optional::value; - -namespace lldb_dap { -struct DAP; - -/// Base class for request handlers. Do not extend this directly: Extend -/// the RequestHandler template subclass instead. -class BaseRequestHandler { -public: - BaseRequestHandler(DAP &dap) : dap(dap) {} - - /// BaseRequestHandler are not copyable. - /// @{ - BaseRequestHandler(const BaseRequestHandler &) = delete; - BaseRequestHandler &operator=(const BaseRequestHandler &) = delete; - /// @} - - virtual ~BaseRequestHandler() = default; - - void Run(const protocol::Request &); - - virtual void operator()(const protocol::Request &request) const = 0; - - using FeatureSet = llvm::SmallDenseSet; - virtual FeatureSet GetSupportedFeatures() const { return {}; } - -protected: - /// Helpers used by multiple request handlers. - /// FIXME: Move these into the DAP class? - /// @{ - - /// Prints a welcome message on the editor if the preprocessor variable - /// LLDB_DAP_WELCOME_MESSAGE is defined. - void PrintWelcomeMessage() const; - - // Takes a LaunchRequest object and launches the process, also handling - // runInTerminal if applicable. It doesn't do any of the additional - // initialization and bookkeeping stuff that is needed for `request_launch`. - // This way we can reuse the process launching logic for RestartRequest too. - llvm::Error - LaunchProcess(const protocol::LaunchRequestArguments &request) const; - - // Check if the step-granularity is `instruction`. - bool HasInstructionGranularity(const llvm::json::Object &request) const; - - /// @} - - DAP &dap; -}; - -/// FIXME: Migrate callers to typed RequestHandler for improved type handling. -class LegacyRequestHandler : public BaseRequestHandler { - using BaseRequestHandler::BaseRequestHandler; - virtual void operator()(const llvm::json::Object &request) const = 0; - void operator()(const protocol::Request &request) const override { - auto req = toJSON(request); - (*this)(*req.getAsObject()); - } -}; - -template -llvm::Expected parseArgs(const protocol::Request &request) { - if (!is_optional_v && !request.arguments) - return llvm::make_error( - llvm::formatv("arguments required for command '{0}' " - "but none received", - request.command) - .str()); - - Args arguments; - llvm::json::Path::Root root("arguments"); - if (request.arguments && !fromJSON(*request.arguments, arguments, root)) { - std::string parse_failure; - llvm::raw_string_ostream OS(parse_failure); - OS << "invalid arguments for request '" << request.command - << "': " << llvm::toString(root.getError()) << "\n"; - root.printErrorContext(*request.arguments, OS); - return llvm::make_error(parse_failure); - } - - return arguments; -} -template <> -inline llvm::Expected -parseArgs(const protocol::Request &request) { - return std::nullopt; -} - -/// Base class for handling DAP requests. Handlers should declare their -/// arguments and response body types like: -/// -/// class MyRequestHandler : public RequestHandler { -/// .... -/// }; -template -class RequestHandler : public BaseRequestHandler { - using BaseRequestHandler::BaseRequestHandler; - - void operator()(const protocol::Request &request) const override { - protocol::Response response; - response.request_seq = request.seq; - response.command = request.command; - - llvm::Expected arguments = parseArgs(request); - if (llvm::Error err = arguments.takeError()) { - HandleErrorResponse(std::move(err), response); - dap.Send(response); - return; - } - - if constexpr (std::is_same_v) { - if (llvm::Error err = Run(*arguments)) { - HandleErrorResponse(std::move(err), response); - } else { - response.success = true; - } - } else { - Resp body = Run(*arguments); - if (llvm::Error err = body.takeError()) { - HandleErrorResponse(std::move(err), response); - } else { - response.success = true; - response.body = std::move(*body); - } - } - - // Mark the request as 'cancelled' if the debugger was interrupted while - // evaluating this handler. - if (dap.debugger.InterruptRequested()) { - dap.debugger.CancelInterruptRequest(); - response.success = false; - response.message = protocol::eResponseMessageCancelled; - response.body = std::nullopt; - } - - dap.Send(response); - - PostRun(); - }; - - virtual Resp Run(const Args &) const = 0; - - /// A hook for a request handler to run additional operations after the - /// request response is sent but before the next request handler. - /// - /// *NOTE*: PostRun will be invoked even if the `Run` operation returned an - /// error. - virtual void PostRun() const {}; - - void HandleErrorResponse(llvm::Error err, - protocol::Response &response) const { - response.success = false; - llvm::handleAllErrors( - std::move(err), - [&](const NotStoppedError &err) { - response.message = lldb_dap::protocol::eResponseMessageNotStopped; - }, - [&](const DAPError &err) { - protocol::ErrorMessage error_message; - error_message.sendTelemetry = false; - error_message.format = err.getMessage(); - error_message.showUser = err.getShowUser(); - error_message.id = err.convertToErrorCode().value(); - error_message.url = err.getURL(); - error_message.urlLabel = err.getURLLabel(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }, - [&](const llvm::ErrorInfoBase &err) { - protocol::ErrorMessage error_message; - error_message.showUser = true; - error_message.sendTelemetry = false; - error_message.format = err.message(); - error_message.id = err.convertToErrorCode().value(); - protocol::ErrorResponseBody body; - body.error = error_message; - response.body = body; - }); - } -}; - -class AttachRequestHandler - : public RequestHandler { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "attach"; } - llvm::Error Run(const protocol::AttachRequestArguments &args) const override; - void PostRun() const override; -}; - -class BreakpointLocationsRequestHandler - : public RequestHandler< - protocol::BreakpointLocationsArguments, - llvm::Expected> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "breakpointLocations"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureBreakpointLocationsRequest}; - } - llvm::Expected - Run(const protocol::BreakpointLocationsArguments &args) const override; - - std::vector> - GetSourceBreakpointLocations(std::string path, uint32_t start_line, - uint32_t start_column, uint32_t end_line, - uint32_t end_column) const; - std::vector> - GetAssemblyBreakpointLocations(int64_t source_reference, uint32_t start_line, - uint32_t end_line) const; -}; - -class CompletionsRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "completions"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureCompletionsRequest}; - } - void operator()(const llvm::json::Object &request) const override; -}; - -class ContinueRequestHandler - : public RequestHandler> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "continue"; } - llvm::Expected - Run(const protocol::ContinueArguments &args) const override; -}; - -class ConfigurationDoneRequestHandler - : public RequestHandler { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "configurationDone"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureConfigurationDoneRequest}; - } - protocol::ConfigurationDoneResponse - Run(const protocol::ConfigurationDoneArguments &) const override; -}; - -class DisconnectRequestHandler - : public RequestHandler, - protocol::DisconnectResponse> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "disconnect"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureTerminateDebuggee}; - } - llvm::Error - Run(const std::optional &args) const override; -}; - -class EvaluateRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "evaluate"; } - void operator()(const llvm::json::Object &request) const override; - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureEvaluateForHovers}; - } -}; - -class ExceptionInfoRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "exceptionInfo"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureExceptionInfoRequest}; - } - void operator()(const llvm::json::Object &request) const override; -}; - -class InitializeRequestHandler - : public RequestHandler> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "initialize"; } - llvm::Expected - Run(const protocol::InitializeRequestArguments &args) const override; -}; - -class LaunchRequestHandler - : public RequestHandler { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "launch"; } - llvm::Error - Run(const protocol::LaunchRequestArguments &arguments) const override; - void PostRun() const override; -}; - -class RestartRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "restart"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureRestartRequest}; - } - void operator()(const llvm::json::Object &request) const override; -}; - -class NextRequestHandler - : public RequestHandler { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "next"; } - llvm::Error Run(const protocol::NextArguments &args) const override; -}; - -class StepInRequestHandler : public RequestHandler { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "stepIn"; } - llvm::Error Run(const protocol::StepInArguments &args) const override; -}; - -class StepInTargetsRequestHandler - : public RequestHandler< - protocol::StepInTargetsArguments, - llvm::Expected> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "stepInTargets"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureStepInTargetsRequest}; - } - llvm::Expected - Run(const protocol::StepInTargetsArguments &args) const override; -}; - -class StepInTargetsRequestHandler2 : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "stepInTargets"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureStepInTargetsRequest}; - } - void operator()(const llvm::json::Object &request) const override; -}; - -class StepOutRequestHandler : public RequestHandler { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "stepOut"; } - llvm::Error Run(const protocol::StepOutArguments &args) const override; -}; - -class SetBreakpointsRequestHandler - : public RequestHandler< - protocol::SetBreakpointsArguments, - llvm::Expected> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "setBreakpoints"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureConditionalBreakpoints, - protocol::eAdapterFeatureHitConditionalBreakpoints}; - } - llvm::Expected - Run(const protocol::SetBreakpointsArguments &args) const override; -}; - -class SetExceptionBreakpointsRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "setExceptionBreakpoints"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureExceptionOptions}; - } - void operator()(const llvm::json::Object &request) const override; -}; - -class SetFunctionBreakpointsRequestHandler - : public RequestHandler< - protocol::SetFunctionBreakpointsArguments, - llvm::Expected> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "setFunctionBreakpoints"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureFunctionBreakpoints}; - } - llvm::Expected - Run(const protocol::SetFunctionBreakpointsArguments &args) const override; -}; - -class DataBreakpointInfoRequestHandler - : public RequestHandler< - protocol::DataBreakpointInfoArguments, - llvm::Expected> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "dataBreakpointInfo"; } - llvm::Expected - Run(const protocol::DataBreakpointInfoArguments &args) const override; -}; - -class SetDataBreakpointsRequestHandler - : public RequestHandler< - protocol::SetDataBreakpointsArguments, - llvm::Expected> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "setDataBreakpoints"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureDataBreakpoints}; - } - llvm::Expected - Run(const protocol::SetDataBreakpointsArguments &args) const override; -}; - -class SetInstructionBreakpointsRequestHandler - : public RequestHandler< - protocol::SetInstructionBreakpointsArguments, - llvm::Expected> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { - return "setInstructionBreakpoints"; - } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureInstructionBreakpoints}; - } - llvm::Expected - Run(const protocol::SetInstructionBreakpointsArguments &args) const override; -}; - -class CompileUnitsRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "compileUnits"; } - void operator()(const llvm::json::Object &request) const override; -}; - -class ModulesRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "modules"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureModulesRequest}; - } - void operator()(const llvm::json::Object &request) const override; -}; - -class PauseRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "pause"; } - void operator()(const llvm::json::Object &request) const override; -}; - -class ScopesRequestHandler final - : public RequestHandler> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "scopes"; } - - llvm::Expected - Run(const protocol::ScopesArguments &args) const override; -}; - -class SetVariableRequestHandler final - : public RequestHandler> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "setVariable"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureSetVariable}; - } - llvm::Expected - Run(const protocol::SetVariableArguments &args) const override; -}; - -class SourceRequestHandler final - : public RequestHandler> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "source"; } - llvm::Expected - Run(const protocol::SourceArguments &args) const override; -}; - -class StackTraceRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "stackTrace"; } - void operator()(const llvm::json::Object &request) const override; - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureDelayedStackTraceLoading}; - } -}; - -class ThreadsRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "threads"; } - void operator()(const llvm::json::Object &request) const override; -}; - -class VariablesRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "variables"; } - void operator()(const llvm::json::Object &request) const override; -}; - -class LocationsRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "locations"; } - void operator()(const llvm::json::Object &request) const override; -}; - -class DisassembleRequestHandler final - : public RequestHandler> { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "disassemble"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureDisassembleRequest}; - } - llvm::Expected - Run(const protocol::DisassembleArguments &args) const override; -}; - -class ReadMemoryRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { return "readMemory"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureReadMemoryRequest}; - } - void operator()(const llvm::json::Object &request) const override; -}; - -class CancelRequestHandler : public RequestHandler { -public: - using RequestHandler::RequestHandler; - static llvm::StringLiteral GetCommand() { return "cancel"; } - FeatureSet GetSupportedFeatures() const override { - return {protocol::eAdapterFeatureCancelRequest}; - } - llvm::Error Run(const protocol::CancelArguments &args) const override; -}; - -/// A request used in testing to get the details on all breakpoints that are -/// currently set in the target. This helps us to test "setBreakpoints" and -/// "setFunctionBreakpoints" requests to verify we have the correct set of -/// breakpoints currently set in LLDB. -class TestGetTargetBreakpointsRequestHandler : public LegacyRequestHandler { -public: - using LegacyRequestHandler::LegacyRequestHandler; - static llvm::StringLiteral GetCommand() { - return "_testGetTargetBreakpoints"; - } - void operator()(const llvm::json::Object &request) const override; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/Handler/ResponseHandler.cpp b/lldb/tools/lldb-dap/Handler/ResponseHandler.cpp deleted file mode 100644 index 27a1437de550..000000000000 --- a/lldb/tools/lldb-dap/Handler/ResponseHandler.cpp +++ /dev/null @@ -1,35 +0,0 @@ -//===-- ResponseHandler.cpp -----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "ResponseHandler.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" - -namespace lldb_dap { - -void UnknownResponseHandler::operator()( - llvm::Expected value) const { - llvm::errs() << "unexpected response: "; - if (value) { - if (std::optional str = value->getAsString()) - llvm::errs() << *str; - } else { - llvm::errs() << "error: " << llvm::toString(value.takeError()); - } - llvm::errs() << '\n'; -} - -void LogFailureResponseHandler::operator()( - llvm::Expected value) const { - if (!value) - llvm::errs() << "reverse request \"" << m_command << "\" (" << m_id - << ") failed: " << llvm::toString(value.takeError()) << '\n'; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ResponseHandler.h b/lldb/tools/lldb-dap/Handler/ResponseHandler.h deleted file mode 100644 index b09153ac2eda..000000000000 --- a/lldb/tools/lldb-dap/Handler/ResponseHandler.h +++ /dev/null @@ -1,56 +0,0 @@ -//===-- ResponseHandler.h -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_HANDLER_RESPONSEHANDLER_H -#define LLDB_TOOLS_LLDB_DAP_HANDLER_RESPONSEHANDLER_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/JSON.h" -#include - -namespace lldb_dap { -struct DAP; - -/// Handler for responses to reverse requests. -class ResponseHandler { -public: - ResponseHandler(llvm::StringRef command, int64_t id) - : m_command(command), m_id(id) {} - - /// ResponseHandlers are not copyable. - /// @{ - ResponseHandler(const ResponseHandler &) = delete; - ResponseHandler &operator=(const ResponseHandler &) = delete; - /// @} - - virtual ~ResponseHandler() = default; - - virtual void operator()(llvm::Expected value) const = 0; - -protected: - llvm::StringRef m_command; - int64_t m_id; -}; - -/// Response handler used for unknown responses. -class UnknownResponseHandler : public ResponseHandler { -public: - using ResponseHandler::ResponseHandler; - void operator()(llvm::Expected value) const override; -}; - -/// Response handler which logs to stderr in case of a failure. -class LogFailureResponseHandler : public ResponseHandler { -public: - using ResponseHandler::ResponseHandler; - void operator()(llvm::Expected value) const override; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp deleted file mode 100644 index 58091b622f7e..000000000000 --- a/lldb/tools/lldb-dap/Handler/RestartRequestHandler.cpp +++ /dev/null @@ -1,156 +0,0 @@ -//===-- RestartRequestHandler.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "llvm/Support/JSON.h" -#include "llvm/Support/raw_ostream.h" - -namespace lldb_dap { - -// "RestartRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Restarts a debug session. Clients should only call this -// request if the corresponding capability `supportsRestartRequest` is -// true.\nIf the capability is missing or has the value false, a typical -// client emulates `restart` by terminating the debug adapter first and then -// launching it anew.", -// "properties": { -// "command": { -// "type": "string", -// "enum": [ "restart" ] -// }, -// "arguments": { -// "$ref": "#/definitions/RestartArguments" -// } -// }, -// "required": [ "command" ] -// }] -// }, -// "RestartArguments": { -// "type": "object", -// "description": "Arguments for `restart` request.", -// "properties": { -// "arguments": { -// "oneOf": [ -// { "$ref": "#/definitions/LaunchRequestArguments" }, -// { "$ref": "#/definitions/AttachRequestArguments" } -// ], -// "description": "The latest version of the `launch` or `attach` -// configuration." -// } -// } -// }, -// "RestartResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `restart` request. This is just an -// acknowledgement, so no body field is required." -// }] -// }, -void RestartRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - if (!dap.target.GetProcess().IsValid()) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", - "Restart request received but no process was launched."); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - // Check if we were in a "launch" session or an "attach" session. - // - // Restarting is not well defined when we started the session by attaching to - // an existing process, because we don't know how the process was started, so - // we don't support it. - // - // Note that when using runInTerminal we're technically attached, but it's an - // implementation detail. The adapter *did* launch the process in response to - // a "launch" command, so we can still stop it and re-run it. This is why we - // don't just check `dap.is_attach`. - if (!dap.last_launch_request) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", - "Restarting an \"attach\" session is not supported."); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - const llvm::json::Object *arguments = request.getObject("arguments"); - if (arguments) { - // The optional `arguments` field in RestartRequest can contain an updated - // version of the launch arguments. If there's one, use it. - if (const llvm::json::Value *restart_arguments = - arguments->get("arguments")) { - protocol::LaunchRequestArguments updated_arguments; - llvm::json::Path::Root root; - if (!fromJSON(*restart_arguments, updated_arguments, root)) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString( - response, "message", - llvm::formatv("Failed to parse updated launch arguments: {0}", - llvm::toString(root.getError())) - .str()); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - dap.last_launch_request = updated_arguments; - // Update DAP configuration based on the latest copy of the launch - // arguments. - dap.SetConfiguration(updated_arguments.configuration, false); - dap.ConfigureSourceMaps(); - } - } - - // Keep track of the old PID so when we get a "process exited" event from the - // killed process we can detect it and not shut down the whole session. - lldb::SBProcess process = dap.target.GetProcess(); - dap.restarting_process_id = process.GetProcessID(); - - // Stop the current process if necessary. The logic here is similar to - // CommandObjectProcessLaunchOrAttach::StopProcessIfNecessary, except that - // we don't ask the user for confirmation. - if (process.IsValid()) { - ScopeSyncMode scope_sync_mode(dap.debugger); - lldb::StateType state = process.GetState(); - if (state != lldb::eStateConnected) { - process.Kill(); - } - // Clear the list of thread ids to avoid sending "thread exited" events - // for threads of the process we are terminating. - dap.thread_ids.clear(); - } - - // FIXME: Should we run 'preRunCommands'? - // FIXME: Should we add a 'preRestartCommands'? - if (llvm::Error err = LaunchProcess(*dap.last_launch_request)) { - response["success"] = llvm::json::Value(false); - EmplaceSafeString(response, "message", llvm::toString(std::move(err))); - dap.SendJSON(llvm::json::Value(std::move(response))); - return; - } - - // This is normally done after receiving a "configuration done" request. - // Because we're restarting, configuration has already happened so we can - // continue the process right away. - if (dap.stop_at_entry) { - SendThreadStoppedEvent(dap); - } else { - dap.target.GetProcess().Continue(); - } - - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp deleted file mode 100644 index aaad0e20f9c2..000000000000 --- a/lldb/tools/lldb-dap/Handler/ScopesRequestHandler.cpp +++ /dev/null @@ -1,98 +0,0 @@ -//===-- ScopesRequestHandler.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "RequestHandler.h" - -using namespace lldb_dap::protocol; -namespace lldb_dap { - -/// Creates a `protocol::Scope` struct. -/// -/// -/// \param[in] name -/// The value to place into the "name" key -/// -/// \param[in] variablesReference -/// The value to place into the "variablesReference" key -/// -/// \param[in] namedVariables -/// The value to place into the "namedVariables" key -/// -/// \param[in] expensive -/// The value to place into the "expensive" key -/// -/// \return -/// A `protocol::Scope` -static Scope CreateScope(const llvm::StringRef name, int64_t variablesReference, - int64_t namedVariables, bool expensive) { - Scope scope; - scope.name = name; - - // TODO: Support "arguments" and "return value" scope. - // At the moment lldb-dap includes the arguments and return_value into the - // "locals" scope. - // vscode only expands the first non-expensive scope, this causes friction - // if we add the arguments above the local scope as the locals scope will not - // be expanded if we enter a function with arguments. It becomes more - // annoying when the scope has arguments, return_value and locals. - if (variablesReference == VARREF_LOCALS) - scope.presentationHint = Scope::eScopePresentationHintLocals; - else if (variablesReference == VARREF_REGS) - scope.presentationHint = Scope::eScopePresentationHintRegisters; - - scope.variablesReference = variablesReference; - scope.namedVariables = namedVariables; - scope.expensive = expensive; - - return scope; -} - -llvm::Expected -ScopesRequestHandler::Run(const ScopesArguments &args) const { - lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); - - // As the user selects different stack frames in the GUI, a "scopes" request - // will be sent to the DAP. This is the only way we know that the user has - // selected a frame in a thread. There are no other notifications that are - // sent and VS code doesn't allow multiple frames to show variables - // concurrently. If we select the thread and frame as the "scopes" requests - // are sent, this allows users to type commands in the debugger console - // with a backtick character to run lldb commands and these lldb commands - // will now have the right context selected as they are run. If the user - // types "`bt" into the debugger console, and we had another thread selected - // in the LLDB library, we would show the wrong thing to the user. If the - // users switch threads with a lldb command like "`thread select 14", the - // GUI will not update as there are no "event" notification packets that - // allow us to change the currently selected thread or frame in the GUI that - // I am aware of. - if (frame.IsValid()) { - frame.GetThread().GetProcess().SetSelectedThread(frame.GetThread()); - frame.GetThread().SetSelectedFrame(frame.GetFrameID()); - } - dap.variables.locals = frame.GetVariables(/*arguments=*/true, - /*locals=*/true, - /*statics=*/false, - /*in_scope_only=*/true); - dap.variables.globals = frame.GetVariables(/*arguments=*/false, - /*locals=*/false, - /*statics=*/true, - /*in_scope_only=*/true); - dap.variables.registers = frame.GetRegisters(); - - std::vector scopes = {CreateScope("Locals", VARREF_LOCALS, - dap.variables.locals.GetSize(), false), - CreateScope("Globals", VARREF_GLOBALS, - dap.variables.globals.GetSize(), false), - CreateScope("Registers", VARREF_REGS, - dap.variables.registers.GetSize(), false)}; - - return ScopesResponseBody{std::move(scopes)}; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp deleted file mode 100644 index 5d336af740c9..000000000000 --- a/lldb/tools/lldb-dap/Handler/SetBreakpointsRequestHandler.cpp +++ /dev/null @@ -1,28 +0,0 @@ -//===-- SetBreakpointsRequestHandler.cpp ----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include - -namespace lldb_dap { - -/// Sets multiple breakpoints for a single source and clears all previous -/// breakpoints in that source. To clear all breakpoint for a source, specify an -/// empty array. When a breakpoint is hit, a `stopped` event (with reason -/// `breakpoint`) is generated. -llvm::Expected -SetBreakpointsRequestHandler::Run( - const protocol::SetBreakpointsArguments &args) const { - std::vector response_breakpoints = - dap.SetSourceBreakpoints(args.source, args.breakpoints); - return protocol::SetBreakpointsResponseBody{std::move(response_breakpoints)}; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp deleted file mode 100644 index 1caaa23bf06f..000000000000 --- a/lldb/tools/lldb-dap/Handler/SetDataBreakpointsRequestHandler.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//===-- SetDataBreakpointsRequestHandler.cpp ------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "Watchpoint.h" -#include - -namespace lldb_dap { - -/// Replaces all existing data breakpoints with new data breakpoints. -/// To clear all data breakpoints, specify an empty array. -/// When a data breakpoint is hit, a stopped event (with reason data breakpoint) -/// is generated. Clients should only call this request if the corresponding -/// capability supportsDataBreakpoints is true. -llvm::Expected -SetDataBreakpointsRequestHandler::Run( - const protocol::SetDataBreakpointsArguments &args) const { - std::vector response_breakpoints; - - dap.target.DeleteAllWatchpoints(); - std::vector watchpoints; - for (const auto &bp : args.breakpoints) - watchpoints.emplace_back(dap, bp); - - // If two watchpoints start at the same address, the latter overwrite the - // former. So, we only enable those at first-seen addresses when iterating - // backward. - std::set addresses; - for (auto iter = watchpoints.rbegin(); iter != watchpoints.rend(); ++iter) { - if (addresses.count(iter->GetAddress()) == 0) { - iter->SetWatchpoint(); - addresses.insert(iter->GetAddress()); - } - } - for (auto wp : watchpoints) - response_breakpoints.push_back(wp.ToProtocolBreakpoint()); - - return protocol::SetDataBreakpointsResponseBody{ - std::move(response_breakpoints)}; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp deleted file mode 100644 index 2214833f8a77..000000000000 --- a/lldb/tools/lldb-dap/Handler/SetExceptionBreakpointsRequestHandler.cpp +++ /dev/null @@ -1,93 +0,0 @@ -//===-- SetExceptionBreakpointsRequestHandler.cpp -------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" -#include - -namespace lldb_dap { - -// "SetExceptionBreakpointsRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "SetExceptionBreakpoints request; value of command field -// is 'setExceptionBreakpoints'. The request configures the debuggers -// response to thrown exceptions. If an exception is configured to break, a -// StoppedEvent is fired (event type 'exception').", "properties": { -// "command": { -// "type": "string", -// "enum": [ "setExceptionBreakpoints" ] -// }, -// "arguments": { -// "$ref": "#/definitions/SetExceptionBreakpointsArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "SetExceptionBreakpointsArguments": { -// "type": "object", -// "description": "Arguments for 'setExceptionBreakpoints' request.", -// "properties": { -// "filters": { -// "type": "array", -// "items": { -// "type": "string" -// }, -// "description": "IDs of checked exception options. The set of IDs is -// returned via the 'exceptionBreakpointFilters' capability." -// }, -// "exceptionOptions": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/ExceptionOptions" -// }, -// "description": "Configuration options for selected exceptions." -// } -// }, -// "required": [ "filters" ] -// }, -// "SetExceptionBreakpointsResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'setExceptionBreakpoints' request. This is -// just an acknowledgement, so no body field is required." -// }] -// } -void SetExceptionBreakpointsRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - lldb::SBError error; - FillResponse(request, response); - const auto *arguments = request.getObject("arguments"); - const auto *filters = arguments->getArray("filters"); - // Keep a list of any exception breakpoint filter names that weren't set - // so we can clear any exception breakpoints if needed. - std::set unset_filters; - for (const auto &bp : *dap.exception_breakpoints) - unset_filters.insert(bp.GetFilter()); - - for (const auto &value : *filters) { - const auto filter = GetAsString(value); - auto *exc_bp = dap.GetExceptionBreakpoint(filter); - if (exc_bp) { - exc_bp->SetBreakpoint(); - unset_filters.erase(std::string(filter)); - } - } - for (const auto &filter : unset_filters) { - auto *exc_bp = dap.GetExceptionBreakpoint(filter); - if (exc_bp) - exc_bp->ClearBreakpoint(); - } - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp deleted file mode 100644 index 1367aa3e864d..000000000000 --- a/lldb/tools/lldb-dap/Handler/SetFunctionBreakpointsRequestHandler.cpp +++ /dev/null @@ -1,56 +0,0 @@ -//===-- SetFunctionBreakpointsRequestHandler.cpp --------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -/// Replaces all existing function breakpoints with new function breakpoints. -/// To clear all function breakpoints, specify an empty array. -/// When a function breakpoint is hit, a stopped event (with reason function -/// breakpoint) is generated. Clients should only call this request if the -/// corresponding capability supportsFunctionBreakpoints is true. -llvm::Expected -SetFunctionBreakpointsRequestHandler::Run( - const protocol::SetFunctionBreakpointsArguments &args) const { - std::vector response_breakpoints; - - // Disable any function breakpoints that aren't in this request. - // There is no call to remove function breakpoints other than calling this - // function with a smaller or empty "breakpoints" list. - const auto name_iter = dap.function_breakpoints.keys(); - llvm::DenseSet seen(name_iter.begin(), name_iter.end()); - for (const auto &fb : args.breakpoints) { - FunctionBreakpoint fn_bp(dap, fb); - const auto [it, inserted] = - dap.function_breakpoints.try_emplace(fn_bp.GetFunctionName(), dap, fb); - if (inserted) - it->second.SetBreakpoint(); - else - it->second.UpdateBreakpoint(fn_bp); - - response_breakpoints.push_back(it->second.ToProtocolBreakpoint()); - seen.erase(fn_bp.GetFunctionName()); - } - - // Remove any breakpoints that are no longer in our list - for (const auto &name : seen) { - auto fn_bp = dap.function_breakpoints.find(name); - if (fn_bp == dap.function_breakpoints.end()) - continue; - dap.target.BreakpointDelete(fn_bp->second.GetID()); - dap.function_breakpoints.erase(name); - } - - return protocol::SetFunctionBreakpointsResponseBody{ - std::move(response_breakpoints)}; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp deleted file mode 100644 index 48b2ba5a2559..000000000000 --- a/lldb/tools/lldb-dap/Handler/SetInstructionBreakpointsRequestHandler.cpp +++ /dev/null @@ -1,57 +0,0 @@ -//===-- SetInstructionBreakpointsRequestHandler.cpp -----------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -/// Replaces all existing instruction breakpoints. Typically, instruction -/// breakpoints would be set from a disassembly window. To clear all instruction -/// breakpoints, specify an empty array. When an instruction breakpoint is hit, -/// a stopped event (with reason instruction breakpoint) is generated. Clients -/// should only call this request if the corresponding capability -/// supportsInstructionBreakpoints is true. -llvm::Expected -SetInstructionBreakpointsRequestHandler::Run( - const protocol::SetInstructionBreakpointsArguments &args) const { - std::vector response_breakpoints; - - // Disable any instruction breakpoints that aren't in this request. - // There is no call to remove instruction breakpoints other than calling this - // function with a smaller or empty "breakpoints" list. - llvm::DenseSet seen( - llvm::from_range, llvm::make_first_range(dap.instruction_breakpoints)); - - for (const auto &bp : args.breakpoints) { - // Read instruction breakpoint request. - InstructionBreakpoint inst_bp(dap, bp); - const auto [iv, inserted] = dap.instruction_breakpoints.try_emplace( - inst_bp.GetInstructionAddressReference(), dap, bp); - if (inserted) - iv->second.SetBreakpoint(); - else - iv->second.UpdateBreakpoint(inst_bp); - response_breakpoints.push_back(iv->second.ToProtocolBreakpoint()); - seen.erase(inst_bp.GetInstructionAddressReference()); - } - - for (const auto &addr : seen) { - auto inst_bp = dap.instruction_breakpoints.find(addr); - if (inst_bp == dap.instruction_breakpoints.end()) - continue; - dap.target.BreakpointDelete(inst_bp->second.GetID()); - dap.instruction_breakpoints.erase(addr); - } - - return protocol::SetInstructionBreakpointsResponseBody{ - std::move(response_breakpoints)}; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp deleted file mode 100644 index 5b8ff563968f..000000000000 --- a/lldb/tools/lldb-dap/Handler/SetVariableRequestHandler.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//===-- SetVariableRequestHandler.cpp -------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// Set the variable with the given name in the variable container to a new -/// value. Clients should only call this request if the corresponding capability -/// `supportsSetVariable` is true. -/// -/// If a debug adapter implements both `setVariable` and `setExpression`, -/// a client will only use `setExpression` if the variable has an evaluateName -/// property. -llvm::Expected -SetVariableRequestHandler::Run(const SetVariableArguments &args) const { - const auto args_name = llvm::StringRef(args.name); - - if (args.variablesReference == UINT64_MAX) { - return llvm::make_error( - llvm::formatv("invalid reference {}", args.variablesReference).str(), - llvm::inconvertibleErrorCode(), - /*show_user=*/false); - } - - constexpr llvm::StringRef return_value_name = "(Return Value)"; - if (args_name == return_value_name) - return llvm::make_error( - "cannot change the value of the return value"); - - lldb::SBValue variable = - dap.variables.FindVariable(args.variablesReference, args_name); - - if (!variable.IsValid()) - return llvm::make_error("could not find variable in scope"); - - lldb::SBError error; - const bool success = variable.SetValueFromCString(args.value.c_str(), error); - if (!success) - return llvm::make_error(error.GetCString()); - - VariableDescription desc(variable, - dap.configuration.enableAutoVariableSummaries); - - SetVariableResponseBody body; - body.value = desc.display_value; - body.type = desc.display_type_name; - - // We don't know the index of the variable in our dap.variables - // so always insert a new one to get its variablesReference. - // is_permanent is false because debug console does not support - // setVariable request. - const int64_t new_var_ref = - dap.variables.InsertVariable(variable, /*is_permanent=*/false); - if (variable.MightHaveChildren()) { - body.variablesReference = new_var_ref; - if (desc.type_obj.IsArrayType()) - body.indexedVariables = variable.GetNumChildren(); - else - body.namedVariables = variable.GetNumChildren(); - - } else { - body.variablesReference = 0; - } - - if (const lldb::addr_t addr = variable.GetLoadAddress(); - addr != LLDB_INVALID_ADDRESS) - body.memoryReference = EncodeMemoryReference(addr); - - if (ValuePointsToCode(variable)) - body.valueLocationReference = new_var_ref; - - return body; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp deleted file mode 100644 index 353d3365564f..000000000000 --- a/lldb/tools/lldb-dap/Handler/SourceRequestHandler.cpp +++ /dev/null @@ -1,62 +0,0 @@ -//===-- SourceRequestHandler.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "Handler/RequestHandler.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "Protocol/ProtocolTypes.h" -#include "lldb/API/SBAddress.h" -#include "lldb/API/SBExecutionContext.h" -#include "lldb/API/SBFrame.h" -#include "lldb/API/SBInstructionList.h" -#include "lldb/API/SBProcess.h" -#include "lldb/API/SBStream.h" -#include "lldb/API/SBSymbol.h" -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBThread.h" -#include "lldb/lldb-types.h" -#include "llvm/Support/Error.h" - -namespace lldb_dap { - -/// Source request; value of command field is 'source'. The request retrieves -/// the source code for a given source reference. -llvm::Expected -SourceRequestHandler::Run(const protocol::SourceArguments &args) const { - const auto source = - args.source->sourceReference.value_or(args.sourceReference); - - if (!source) - return llvm::make_error( - "invalid arguments, expected source.sourceReference to be set"); - - lldb::SBAddress address(source, dap.target); - if (!address.IsValid()) - return llvm::make_error("source not found"); - - lldb::SBSymbol symbol = address.GetSymbol(); - - lldb::SBStream stream; - lldb::SBExecutionContext exe_ctx(dap.target); - - if (symbol.IsValid()) { - lldb::SBInstructionList insts = symbol.GetInstructions(dap.target); - insts.GetDescription(stream, exe_ctx); - } else { - // No valid symbol, just return the disassembly. - lldb::SBInstructionList insts = dap.target.ReadInstructions( - address, dap.k_number_of_assembly_lines_for_nodebug); - insts.GetDescription(stream, exe_ctx); - } - - return protocol::SourceResponseBody{/*content=*/stream.GetData(), - /*mimeType=*/"text/x-lldb.disassembly"}; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp deleted file mode 100644 index 4ea4cd1e517d..000000000000 --- a/lldb/tools/lldb-dap/Handler/StackTraceRequestHandler.cpp +++ /dev/null @@ -1,242 +0,0 @@ -//===-- StackTraceRequestHandler.cpp --------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -/// Page size used for reporting addtional frames in the 'stackTrace' request. -static constexpr int StackPageSize = 20; - -// Fill in the stack frames of the thread. -// -// Threads stacks may contain runtime specific extended backtraces, when -// constructing a stack trace first report the full thread stack trace then -// perform a breadth first traversal of any extended backtrace frames. -// -// For example: -// -// Thread (id=th0) stack=[s0, s1, s2, s3] -// \ Extended backtrace "libdispatch" Thread (id=th1) stack=[s0, s1] -// \ Extended backtrace "libdispatch" Thread (id=th2) stack=[s0, s1] -// \ Extended backtrace "Application Specific Backtrace" Thread (id=th3) -// stack=[s0, s1, s2] -// -// Which will flatten into: -// -// 0. th0->s0 -// 1. th0->s1 -// 2. th0->s2 -// 3. th0->s3 -// 4. label - Enqueued from th1, sf=-1, i=-4 -// 5. th1->s0 -// 6. th1->s1 -// 7. label - Enqueued from th2 -// 8. th2->s0 -// 9. th2->s1 -// 10. label - Application Specific Backtrace -// 11. th3->s0 -// 12. th3->s1 -// 13. th3->s2 -// -// s=3,l=3 = [th0->s3, label1, th1->s0] -static bool FillStackFrames(DAP &dap, lldb::SBThread &thread, - lldb::SBFormat &frame_format, - llvm::json::Array &stack_frames, int64_t &offset, - const int64_t start_frame, const int64_t levels, - const bool include_all) { - bool reached_end_of_stack = false; - for (int64_t i = start_frame; - static_cast(stack_frames.size()) < levels; i++) { - if (i == -1) { - stack_frames.emplace_back( - CreateExtendedStackFrameLabel(thread, frame_format)); - continue; - } - - lldb::SBFrame frame = thread.GetFrameAtIndex(i); - if (!frame.IsValid()) { - offset += thread.GetNumFrames() + 1 /* label between threads */; - reached_end_of_stack = true; - break; - } - - stack_frames.emplace_back(CreateStackFrame(frame, frame_format)); - } - - if (include_all && reached_end_of_stack) { - // Check for any extended backtraces. - for (uint32_t bt = 0; - bt < thread.GetProcess().GetNumExtendedBacktraceTypes(); bt++) { - lldb::SBThread backtrace = thread.GetExtendedBacktraceThread( - thread.GetProcess().GetExtendedBacktraceTypeAtIndex(bt)); - if (!backtrace.IsValid()) - continue; - - reached_end_of_stack = FillStackFrames( - dap, backtrace, frame_format, stack_frames, offset, - (start_frame - offset) > 0 ? start_frame - offset : -1, levels, - include_all); - if (static_cast(stack_frames.size()) >= levels) - break; - } - } - - return reached_end_of_stack; -} - -// "StackTraceRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "StackTrace request; value of command field is -// 'stackTrace'. The request returns a stacktrace from the current execution -// state.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "stackTrace" ] -// }, -// "arguments": { -// "$ref": "#/definitions/StackTraceArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "StackTraceArguments": { -// "type": "object", -// "description": "Arguments for 'stackTrace' request.", -// "properties": { -// "threadId": { -// "type": "integer", -// "description": "Retrieve the stacktrace for this thread." -// }, -// "startFrame": { -// "type": "integer", -// "description": "The index of the first frame to return; if omitted -// frames start at 0." -// }, -// "levels": { -// "type": "integer", -// "description": "The maximum number of frames to return. If levels is -// not specified or 0, all frames are returned." -// }, -// "format": { -// "$ref": "#/definitions/StackFrameFormat", -// "description": "Specifies details on how to format the stack frames. -// The attribute is only honored by a debug adapter if the corresponding -// capability `supportsValueFormattingOptions` is true." -// } -// }, -// "required": [ "threadId" ] -// }, -// "StackTraceResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to `stackTrace` request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "stackFrames": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/StackFrame" -// }, -// "description": "The frames of the stackframe. If the array has -// length zero, there are no stackframes available. This means that -// there is no location information available." -// }, -// "totalFrames": { -// "type": "integer", -// "description": "The total number of frames available in the -// stack. If omitted or if `totalFrames` is larger than the -// available frames, a client is expected to request frames until -// a request returns less frames than requested (which indicates -// the end of the stack). Returning monotonically increasing -// `totalFrames` values for subsequent requests can be used to -// enforce paging in the client." -// } -// }, -// "required": [ "stackFrames" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void StackTraceRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - lldb::SBError error; - const auto *arguments = request.getObject("arguments"); - lldb::SBThread thread = dap.GetLLDBThread(*arguments); - llvm::json::Array stack_frames; - llvm::json::Object body; - - lldb::SBFormat frame_format = dap.frame_format; - bool include_all = dap.configuration.displayExtendedBacktrace; - - if (const auto *format = arguments->getObject("format")) { - // Indicates that all stack frames should be included, even those the debug - // adapter might otherwise hide. - include_all = GetBoolean(format, "includeAll").value_or(false); - - // Parse the properties that have a corresponding format string. - // FIXME: Support "parameterTypes" and "hex". - const bool module = GetBoolean(format, "module").value_or(false); - const bool line = GetBoolean(format, "line").value_or(false); - const bool parameters = GetBoolean(format, "parameters").value_or(false); - const bool parameter_names = - GetBoolean(format, "parameterNames").value_or(false); - const bool parameter_values = - GetBoolean(format, "parameterValues").value_or(false); - - // Only change the format string if we have to. - if (module || line || parameters || parameter_names || parameter_values) { - std::string format_str; - llvm::raw_string_ostream os(format_str); - - if (module) - os << "{${module.file.basename} }"; - - if (line) - os << "{${line.file.basename}:${line.number}:${line.column} }"; - - if (parameters || parameter_names || parameter_values) - os << "{${function.name-with-args}}"; - else - os << "{${function.name-without-args}}"; - - lldb::SBError error; - frame_format = lldb::SBFormat(format_str.c_str(), error); - assert(error.Success()); - } - } - - if (thread.IsValid()) { - const auto start_frame = - GetInteger(arguments, "startFrame").value_or(0); - const auto levels = GetInteger(arguments, "levels").value_or(0); - int64_t offset = 0; - bool reached_end_of_stack = FillStackFrames( - dap, thread, frame_format, stack_frames, offset, start_frame, - levels == 0 ? INT64_MAX : levels, include_all); - body.try_emplace("totalFrames", - start_frame + stack_frames.size() + - (reached_end_of_stack ? 0 : StackPageSize)); - } - - body.try_emplace("stackFrames", std::move(stack_frames)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp deleted file mode 100644 index 6742c791a548..000000000000 --- a/lldb/tools/lldb-dap/Handler/StepInRequestHandler.cpp +++ /dev/null @@ -1,63 +0,0 @@ -//===-- StepInRequestHandler.cpp ------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "Protocol/ProtocolTypes.h" -#include "RequestHandler.h" - -using namespace llvm; -using namespace lldb; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -// The request resumes the given thread to step into a function/method and -// allows all other threads to run freely by resuming them. If the debug adapter -// supports single thread execution (see capability -// `supportsSingleThreadExecutionRequests`), setting the `singleThread` argument -// to true prevents other suspended threads from resuming. If the request cannot -// step into a target, `stepIn` behaves like the `next` request. The debug -// adapter first sends the response and then a `stopped` event (with reason -// `step`) after the step has completed. If there are multiple function/method -// calls (or other targets) on the source line, the argument `targetId` can be -// used to control into which target the `stepIn` should occur. The list of -// possible targets for a given source line can be retrieved via the -// `stepInTargets` request. -Error StepInRequestHandler::Run(const StepInArguments &args) const { - SBThread thread = dap.GetLLDBThread(args.threadId); - if (!thread.IsValid()) - return make_error("invalid thread"); - - // Remember the thread ID that caused the resume so we can set the - // "threadCausedFocus" boolean value in the "stopped" events. - dap.focus_tid = thread.GetThreadID(); - - if (!SBDebugger::StateIsStoppedState(dap.target.GetProcess().GetState())) - return make_error(); - - lldb::SBError error; - if (args.granularity == eSteppingGranularityInstruction) { - thread.StepInstruction(/*step_over=*/false, error); - return ToError(error); - } - - std::string step_in_target; - auto it = dap.step_in_targets.find(args.targetId.value_or(0)); - if (it != dap.step_in_targets.end()) - step_in_target = it->second; - - RunMode run_mode = args.singleThread ? eOnlyThisThread : eOnlyDuringStepping; - thread.StepInto(step_in_target.c_str(), LLDB_INVALID_LINE_NUMBER, error, - run_mode); - return ToError(error); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp deleted file mode 100644 index 1a76371be2d5..000000000000 --- a/lldb/tools/lldb-dap/Handler/StepInTargetsRequestHandler.cpp +++ /dev/null @@ -1,91 +0,0 @@ -//===-- StepInTargetsRequestHandler.cpp -----------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "lldb/API/SBInstruction.h" -#include "lldb/lldb-defines.h" - -using namespace lldb_dap::protocol; -namespace lldb_dap { - -// This request retrieves the possible step-in targets for the specified stack -// frame. -// These targets can be used in the `stepIn` request. -// Clients should only call this request if the corresponding capability -// `supportsStepInTargetsRequest` is true. -llvm::Expected -StepInTargetsRequestHandler::Run(const StepInTargetsArguments &args) const { - dap.step_in_targets.clear(); - const lldb::SBFrame frame = dap.GetLLDBFrame(args.frameId); - if (!frame.IsValid()) - return llvm::make_error("Failed to get frame for input frameId."); - - lldb::SBAddress pc_addr = frame.GetPCAddress(); - lldb::SBAddress line_end_addr = - pc_addr.GetLineEntry().GetSameLineContiguousAddressRangeEnd(true); - lldb::SBInstructionList insts = dap.target.ReadInstructions( - pc_addr, line_end_addr, /*flavor_string=*/nullptr); - - if (!insts.IsValid()) - return llvm::make_error("Failed to get instructions for frame."); - - StepInTargetsResponseBody body; - const size_t num_insts = insts.GetSize(); - for (size_t i = 0; i < num_insts; ++i) { - lldb::SBInstruction inst = insts.GetInstructionAtIndex(i); - if (!inst.IsValid()) - break; - - const lldb::addr_t inst_addr = inst.GetAddress().GetLoadAddress(dap.target); - if (inst_addr == LLDB_INVALID_ADDRESS) - break; - - // Note: currently only x86/x64 supports flow kind. - const lldb::InstructionControlFlowKind flow_kind = - inst.GetControlFlowKind(dap.target); - - if (flow_kind == lldb::eInstructionControlFlowKindCall) { - - const llvm::StringRef call_operand_name = inst.GetOperands(dap.target); - lldb::addr_t call_target_addr = LLDB_INVALID_ADDRESS; - if (call_operand_name.getAsInteger(0, call_target_addr)) - continue; - - const lldb::SBAddress call_target_load_addr = - dap.target.ResolveLoadAddress(call_target_addr); - if (!call_target_load_addr.IsValid()) - continue; - - // The existing ThreadPlanStepInRange only accept step in target - // function with debug info. - lldb::SBSymbolContext sc = dap.target.ResolveSymbolContextForAddress( - call_target_load_addr, lldb::eSymbolContextFunction); - - // The existing ThreadPlanStepInRange only accept step in target - // function with debug info. - llvm::StringRef step_in_target_name; - if (sc.IsValid() && sc.GetFunction().IsValid()) - step_in_target_name = sc.GetFunction().GetDisplayName(); - - // Skip call sites if we fail to resolve its symbol name. - if (step_in_target_name.empty()) - continue; - - StepInTarget target; - target.id = inst_addr; - target.label = step_in_target_name; - dap.step_in_targets.try_emplace(inst_addr, step_in_target_name); - body.targets.emplace_back(std::move(target)); - } - } - return body; -}; - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp deleted file mode 100644 index e896e03720b6..000000000000 --- a/lldb/tools/lldb-dap/Handler/StepOutRequestHandler.cpp +++ /dev/null @@ -1,49 +0,0 @@ -//===-- StepOutRequestHandler.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "LLDBUtils.h" -#include "Protocol/ProtocolRequests.h" -#include "RequestHandler.h" -#include "llvm/Support/Error.h" - -using namespace llvm; -using namespace lldb_dap::protocol; - -namespace lldb_dap { - -/// The request resumes the given thread to step out (return) from a -/// function/method and allows all other threads to run freely by resuming -/// them. -/// -/// If the debug adapter supports single thread execution (see capability -/// `supportsSingleThreadExecutionRequests`), setting the `singleThread` -/// argument to true prevents other suspended threads from resuming. -/// -/// The debug adapter first sends the response and then a `stopped` event (with -/// reason `step`) after the step has completed." -Error StepOutRequestHandler::Run(const StepOutArguments &arguments) const { - lldb::SBThread thread = dap.GetLLDBThread(arguments.threadId); - if (!thread.IsValid()) - return make_error("invalid thread"); - - if (!lldb::SBDebugger::StateIsStoppedState( - dap.target.GetProcess().GetState())) - return make_error(); - - // Remember the thread ID that caused the resume so we can set the - // "threadCausedFocus" boolean value in the "stopped" events. - dap.focus_tid = thread.GetThreadID(); - lldb::SBError error; - thread.StepOut(error); - - return ToError(error); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp deleted file mode 100644 index 5f4f016f6a1e..000000000000 --- a/lldb/tools/lldb-dap/Handler/TestGetTargetBreakpointsRequestHandler.cpp +++ /dev/null @@ -1,31 +0,0 @@ -//===-- TestGetTargetBreakpointsRequestHandler.cpp ------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -void TestGetTargetBreakpointsRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Array response_breakpoints; - for (uint32_t i = 0; dap.target.GetBreakpointAtIndex(i).IsValid(); ++i) { - auto bp = Breakpoint(dap, dap.target.GetBreakpointAtIndex(i)); - response_breakpoints.push_back(bp.ToProtocolBreakpoint()); - } - llvm::json::Object body; - body.try_emplace("breakpoints", std::move(response_breakpoints)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/ThreadsRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/ThreadsRequestHandler.cpp deleted file mode 100644 index 16d797c2ab32..000000000000 --- a/lldb/tools/lldb-dap/Handler/ThreadsRequestHandler.cpp +++ /dev/null @@ -1,79 +0,0 @@ -//===-- ThreadsRequestHandler.cpp -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -// "ThreadsRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Thread request; value of command field is 'threads'. The -// request retrieves a list of all threads.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "threads" ] -// } -// }, -// "required": [ "command" ] -// }] -// }, -// "ThreadsResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'threads' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "threads": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Thread" -// }, -// "description": "All threads." -// } -// }, -// "required": [ "threads" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void ThreadsRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - - llvm::json::Array threads; - // Client requests the baseline of currently existing threads after - // a successful launch or attach by sending a 'threads' request - // right after receiving the configurationDone response. - // If no thread has reported to the client, it prevents something - // like the pause request from working in the running state. - // Return the cache of initial threads as the process might have resumed - if (dap.initial_thread_list) { - threads = dap.initial_thread_list.value(); - dap.initial_thread_list.reset(); - } else { - threads = GetThreads(dap.target.GetProcess(), dap.thread_format); - } - - if (threads.size() == 0) { - response["success"] = llvm::json::Value(false); - } - llvm::json::Object body; - body.try_emplace("threads", std::move(threads)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp b/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp deleted file mode 100644 index 19bcca2b22b9..000000000000 --- a/lldb/tools/lldb-dap/Handler/VariablesRequestHandler.cpp +++ /dev/null @@ -1,242 +0,0 @@ -//===-- VariablesRequestHandler.cpp ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "EventHelper.h" -#include "JSONUtils.h" -#include "RequestHandler.h" - -namespace lldb_dap { - -// "VariablesRequest": { -// "allOf": [ { "$ref": "#/definitions/Request" }, { -// "type": "object", -// "description": "Variables request; value of command field is 'variables'. -// Retrieves all child variables for the given variable reference. An -// optional filter can be used to limit the fetched children to either named -// or indexed children.", "properties": { -// "command": { -// "type": "string", -// "enum": [ "variables" ] -// }, -// "arguments": { -// "$ref": "#/definitions/VariablesArguments" -// } -// }, -// "required": [ "command", "arguments" ] -// }] -// }, -// "VariablesArguments": { -// "type": "object", -// "description": "Arguments for 'variables' request.", -// "properties": { -// "variablesReference": { -// "type": "integer", -// "description": "The Variable reference." -// }, -// "filter": { -// "type": "string", -// "enum": [ "indexed", "named" ], -// "description": "Optional filter to limit the child variables to either -// named or indexed. If ommited, both types are fetched." -// }, -// "start": { -// "type": "integer", -// "description": "The index of the first variable to return; if omitted -// children start at 0." -// }, -// "count": { -// "type": "integer", -// "description": "The number of variables to return. If count is missing -// or 0, all variables are returned." -// }, -// "format": { -// "$ref": "#/definitions/ValueFormat", -// "description": "Specifies details on how to format the Variable -// values." -// } -// }, -// "required": [ "variablesReference" ] -// }, -// "VariablesResponse": { -// "allOf": [ { "$ref": "#/definitions/Response" }, { -// "type": "object", -// "description": "Response to 'variables' request.", -// "properties": { -// "body": { -// "type": "object", -// "properties": { -// "variables": { -// "type": "array", -// "items": { -// "$ref": "#/definitions/Variable" -// }, -// "description": "All (or a range) of variables for the given -// variable reference." -// } -// }, -// "required": [ "variables" ] -// } -// }, -// "required": [ "body" ] -// }] -// } -void VariablesRequestHandler::operator()( - const llvm::json::Object &request) const { - llvm::json::Object response; - FillResponse(request, response); - llvm::json::Array variables; - const auto *arguments = request.getObject("arguments"); - const auto variablesReference = - GetInteger(arguments, "variablesReference").value_or(0); - const auto start = GetInteger(arguments, "start").value_or(0); - const auto count = GetInteger(arguments, "count").value_or(0); - bool hex = false; - const auto *format = arguments->getObject("format"); - if (format) - hex = GetBoolean(format, "hex").value_or(false); - - if (lldb::SBValueList *top_scope = - dap.variables.GetTopLevelScope(variablesReference)) { - // variablesReference is one of our scopes, not an actual variable it is - // asking for the list of args, locals or globals. - int64_t start_idx = 0; - int64_t num_children = 0; - - if (variablesReference == VARREF_REGS) { - // Change the default format of any pointer sized registers in the first - // register set to be the lldb::eFormatAddressInfo so we show the pointer - // and resolve what the pointer resolves to. Only change the format if the - // format was set to the default format or if it was hex as some registers - // have formats set for them. - const uint32_t addr_size = dap.target.GetProcess().GetAddressByteSize(); - lldb::SBValue reg_set = dap.variables.registers.GetValueAtIndex(0); - const uint32_t num_regs = reg_set.GetNumChildren(); - for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx) { - lldb::SBValue reg = reg_set.GetChildAtIndex(reg_idx); - const lldb::Format format = reg.GetFormat(); - if (format == lldb::eFormatDefault || format == lldb::eFormatHex) { - if (reg.GetByteSize() == addr_size) - reg.SetFormat(lldb::eFormatAddressInfo); - } - } - } - - num_children = top_scope->GetSize(); - if (num_children == 0 && variablesReference == VARREF_LOCALS) { - // Check for an error in the SBValueList that might explain why we don't - // have locals. If we have an error display it as the sole value in the - // the locals. - - // "error" owns the error string so we must keep it alive as long as we - // want to use the returns "const char *" - lldb::SBError error = top_scope->GetError(); - const char *var_err = error.GetCString(); - if (var_err) { - // Create a fake variable named "error" to explain why variables were - // not available. This new error will help let users know when there was - // a problem that kept variables from being available for display and - // allow users to fix this issue instead of seeing no variables. The - // errors are only set when there is a problem that the user could - // fix, so no error will show up when you have no debug info, only when - // we do have debug info and something that is fixable can be done. - llvm::json::Object object; - EmplaceSafeString(object, "name", ""); - EmplaceSafeString(object, "type", "const char *"); - EmplaceSafeString(object, "value", var_err); - object.try_emplace("variablesReference", (int64_t)0); - variables.emplace_back(std::move(object)); - } - } - const int64_t end_idx = start_idx + ((count == 0) ? num_children : count); - - // We first find out which variable names are duplicated - std::map variable_name_counts; - for (auto i = start_idx; i < end_idx; ++i) { - lldb::SBValue variable = top_scope->GetValueAtIndex(i); - if (!variable.IsValid()) - break; - variable_name_counts[GetNonNullVariableName(variable)]++; - } - - // Show return value if there is any ( in the local top frame ) - if (variablesReference == VARREF_LOCALS) { - auto process = dap.target.GetProcess(); - auto selected_thread = process.GetSelectedThread(); - lldb::SBValue stop_return_value = selected_thread.GetStopReturnValue(); - - if (stop_return_value.IsValid() && - (selected_thread.GetSelectedFrame().GetFrameID() == 0)) { - auto renamed_return_value = stop_return_value.Clone("(Return Value)"); - int64_t return_var_ref = 0; - - if (stop_return_value.MightHaveChildren() || - stop_return_value.IsSynthetic()) { - return_var_ref = dap.variables.InsertVariable(stop_return_value, - /*is_permanent=*/false); - } - variables.emplace_back(CreateVariable( - renamed_return_value, return_var_ref, hex, - dap.configuration.enableAutoVariableSummaries, - dap.configuration.enableSyntheticChildDebugging, false)); - } - } - - // Now we construct the result with unique display variable names - for (auto i = start_idx; i < end_idx; ++i) { - lldb::SBValue variable = top_scope->GetValueAtIndex(i); - - if (!variable.IsValid()) - break; - - int64_t var_ref = - dap.variables.InsertVariable(variable, /*is_permanent=*/false); - variables.emplace_back(CreateVariable( - variable, var_ref, hex, dap.configuration.enableAutoVariableSummaries, - dap.configuration.enableSyntheticChildDebugging, - variable_name_counts[GetNonNullVariableName(variable)] > 1)); - } - } else { - // We are expanding a variable that has children, so we will return its - // children. - lldb::SBValue variable = dap.variables.GetVariable(variablesReference); - if (variable.IsValid()) { - auto addChild = [&](lldb::SBValue child, - std::optional custom_name = {}) { - if (!child.IsValid()) - return; - bool is_permanent = - dap.variables.IsPermanentVariableReference(variablesReference); - int64_t var_ref = dap.variables.InsertVariable(child, is_permanent); - variables.emplace_back(CreateVariable( - child, var_ref, hex, dap.configuration.enableAutoVariableSummaries, - dap.configuration.enableSyntheticChildDebugging, - /*is_name_duplicated=*/false, custom_name)); - }; - const int64_t num_children = variable.GetNumChildren(); - int64_t end_idx = start + ((count == 0) ? num_children : count); - int64_t i = start; - for (; i < end_idx && i < num_children; ++i) - addChild(variable.GetChildAtIndex(i)); - - // If we haven't filled the count quota from the request, we insert a new - // "[raw]" child that can be used to inspect the raw version of a - // synthetic member. That eliminates the need for the user to go to the - // debug console and type `frame var to get these values. - if (dap.configuration.enableSyntheticChildDebugging && - variable.IsSynthetic() && i == num_children) - addChild(variable.GetNonSyntheticValue(), "[raw]"); - } - } - llvm::json::Object body; - body.try_emplace("variables", std::move(variables)); - response.try_emplace("body", std::move(body)); - dap.SendJSON(llvm::json::Value(std::move(response))); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp b/lldb/tools/lldb-dap/InstructionBreakpoint.cpp deleted file mode 100644 index ddae1a8b2024..000000000000 --- a/lldb/tools/lldb-dap/InstructionBreakpoint.cpp +++ /dev/null @@ -1,34 +0,0 @@ -//===-- InstructionBreakpoint.cpp ------------------------------------*- C++ -//-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "InstructionBreakpoint.h" -#include "DAP.h" -#include "lldb/API/SBBreakpoint.h" -#include "lldb/API/SBTarget.h" -#include "llvm/ADT/StringRef.h" - -namespace lldb_dap { - -InstructionBreakpoint::InstructionBreakpoint( - DAP &d, const protocol::InstructionBreakpoint &breakpoint) - : Breakpoint(d, breakpoint.condition, breakpoint.hitCondition), - m_instruction_address_reference(LLDB_INVALID_ADDRESS), - m_offset(breakpoint.offset.value_or(0)) { - llvm::StringRef instruction_reference(breakpoint.instructionReference); - instruction_reference.getAsInteger(0, m_instruction_address_reference); - m_instruction_address_reference += m_offset; -} - -void InstructionBreakpoint::SetBreakpoint() { - m_bp = - m_dap.target.BreakpointCreateByAddress(m_instruction_address_reference); - Breakpoint::SetBreakpoint(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/InstructionBreakpoint.h b/lldb/tools/lldb-dap/InstructionBreakpoint.h deleted file mode 100644 index a8c8f2113e5e..000000000000 --- a/lldb/tools/lldb-dap/InstructionBreakpoint.h +++ /dev/null @@ -1,41 +0,0 @@ -//===-- InstructionBreakpoint.h --------------------------------------*- C++ -//-*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_INSTRUCTIONBREAKPOINT_H -#define LLDB_TOOLS_LLDB_DAP_INSTRUCTIONBREAKPOINT_H - -#include "Breakpoint.h" -#include "DAPForward.h" -#include "Protocol/ProtocolTypes.h" -#include "lldb/lldb-types.h" -#include - -namespace lldb_dap { - -/// Instruction Breakpoint -class InstructionBreakpoint : public Breakpoint { -public: - InstructionBreakpoint(DAP &d, - const protocol::InstructionBreakpoint &breakpoint); - - /// Set instruction breakpoint in LLDB as a new breakpoint. - void SetBreakpoint(); - - lldb::addr_t GetInstructionAddressReference() const { - return m_instruction_address_reference; - } - -protected: - lldb::addr_t m_instruction_address_reference; - int32_t m_offset; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/JSONUtils.cpp b/lldb/tools/lldb-dap/JSONUtils.cpp deleted file mode 100644 index 573f3eba00f6..000000000000 --- a/lldb/tools/lldb-dap/JSONUtils.cpp +++ /dev/null @@ -1,1353 +0,0 @@ -//===-- JSONUtils.cpp -------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "JSONUtils.h" -#include "DAP.h" -#include "ExceptionBreakpoint.h" -#include "LLDBUtils.h" -#include "ProtocolUtils.h" -#include "lldb/API/SBAddress.h" -#include "lldb/API/SBCompileUnit.h" -#include "lldb/API/SBDeclaration.h" -#include "lldb/API/SBEnvironment.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBFileSpec.h" -#include "lldb/API/SBFrame.h" -#include "lldb/API/SBFunction.h" -#include "lldb/API/SBInstructionList.h" -#include "lldb/API/SBLineEntry.h" -#include "lldb/API/SBModule.h" -#include "lldb/API/SBQueue.h" -#include "lldb/API/SBSection.h" -#include "lldb/API/SBStream.h" -#include "lldb/API/SBStringList.h" -#include "lldb/API/SBStructuredData.h" -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBThread.h" -#include "lldb/API/SBType.h" -#include "lldb/API/SBValue.h" -#include "lldb/Host/PosixApi.h" // IWYU pragma: keep -#include "lldb/lldb-defines.h" -#include "lldb/lldb-enumerations.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Compiler.h" -#include "llvm/Support/Format.h" -#include "llvm/Support/FormatVariadic.h" -#include "llvm/Support/JSON.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include -#include -#include -#include - -namespace lldb_dap { - -void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, - llvm::StringRef str) { - if (LLVM_LIKELY(llvm::json::isUTF8(str))) - obj.try_emplace(key, str.str()); - else - obj.try_emplace(key, llvm::json::fixUTF8(str)); -} - -llvm::StringRef GetAsString(const llvm::json::Value &value) { - if (auto s = value.getAsString()) - return *s; - return llvm::StringRef(); -} - -// Gets a string from a JSON object using the key, or returns an empty string. -std::optional GetString(const llvm::json::Object &obj, - llvm::StringRef key) { - return obj.getString(key); -} - -std::optional GetString(const llvm::json::Object *obj, - llvm::StringRef key) { - if (obj == nullptr) - return std::nullopt; - - return GetString(*obj, key); -} - -std::optional GetBoolean(const llvm::json::Object &obj, - llvm::StringRef key) { - if (auto value = obj.getBoolean(key)) - return *value; - if (auto value = obj.getInteger(key)) - return *value != 0; - return std::nullopt; -} - -std::optional GetBoolean(const llvm::json::Object *obj, - llvm::StringRef key) { - if (obj != nullptr) - return GetBoolean(*obj, key); - return std::nullopt; -} - -bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key) { - return obj.find(key) != obj.end(); -} - -std::string EncodeMemoryReference(lldb::addr_t addr) { - return "0x" + llvm::utohexstr(addr); -} - -std::optional -DecodeMemoryReference(llvm::StringRef memoryReference) { - if (!memoryReference.starts_with("0x")) - return std::nullopt; - - lldb::addr_t addr; - if (memoryReference.consumeInteger(0, addr)) - return std::nullopt; - - return addr; -} - -std::vector GetStrings(const llvm::json::Object *obj, - llvm::StringRef key) { - std::vector strs; - const auto *json_array = obj->getArray(key); - if (!json_array) - return strs; - for (const auto &value : *json_array) { - switch (value.kind()) { - case llvm::json::Value::String: - strs.push_back(value.getAsString()->str()); - break; - case llvm::json::Value::Number: - case llvm::json::Value::Boolean: - strs.push_back(llvm::to_string(value)); - break; - case llvm::json::Value::Null: - case llvm::json::Value::Object: - case llvm::json::Value::Array: - break; - } - } - return strs; -} - -std::unordered_map -GetStringMap(const llvm::json::Object &obj, llvm::StringRef key) { - std::unordered_map strs; - const auto *const json_object = obj.getObject(key); - if (!json_object) - return strs; - - for (const auto &[key, value] : *json_object) { - switch (value.kind()) { - case llvm::json::Value::String: - strs.emplace(key.str(), value.getAsString()->str()); - break; - case llvm::json::Value::Number: - case llvm::json::Value::Boolean: - strs.emplace(key.str(), llvm::to_string(value)); - break; - case llvm::json::Value::Null: - case llvm::json::Value::Object: - case llvm::json::Value::Array: - break; - } - } - return strs; -} - -static bool IsClassStructOrUnionType(lldb::SBType t) { - return (t.GetTypeClass() & (lldb::eTypeClassUnion | lldb::eTypeClassStruct | - lldb::eTypeClassArray)) != 0; -} - -/// Create a short summary for a container that contains the summary of its -/// first children, so that the user can get a glimpse of its contents at a -/// glance. -static std::optional -TryCreateAutoSummaryForContainer(lldb::SBValue &v) { - if (!v.MightHaveChildren()) - return std::nullopt; - /// As this operation can be potentially slow, we limit the total time spent - /// fetching children to a few ms. - const auto max_evaluation_time = std::chrono::milliseconds(10); - /// We don't want to generate a extremely long summary string, so we limit its - /// length. - const size_t max_length = 32; - - auto start = std::chrono::steady_clock::now(); - std::string summary; - llvm::raw_string_ostream os(summary); - os << "{"; - - llvm::StringRef separator = ""; - - for (size_t i = 0, e = v.GetNumChildren(); i < e; ++i) { - // If we reached the time limit or exceeded the number of characters, we - // dump `...` to signal that there are more elements in the collection. - if (summary.size() > max_length || - (std::chrono::steady_clock::now() - start) > max_evaluation_time) { - os << separator << "..."; - break; - } - lldb::SBValue child = v.GetChildAtIndex(i); - - if (llvm::StringRef name = child.GetName(); !name.empty()) { - llvm::StringRef desc; - if (llvm::StringRef summary = child.GetSummary(); !summary.empty()) - desc = summary; - else if (llvm::StringRef value = child.GetValue(); !value.empty()) - desc = value; - else if (IsClassStructOrUnionType(child.GetType())) - desc = "{...}"; - else - continue; - - // If the child is an indexed entry, we don't show its index to save - // characters. - if (name.starts_with("[")) - os << separator << desc; - else - os << separator << name << ":" << desc; - separator = ", "; - } - } - os << "}"; - - if (summary == "{...}" || summary == "{}") - return std::nullopt; - return summary; -} - -/// Try to create a summary string for the given value that doesn't have a -/// summary of its own. -static std::optional TryCreateAutoSummary(lldb::SBValue &value) { - // We use the dereferenced value for generating the summary. - if (value.GetType().IsPointerType() || value.GetType().IsReferenceType()) - value = value.Dereference(); - - // We only support auto summaries for containers. - return TryCreateAutoSummaryForContainer(value); -} - -void FillResponse(const llvm::json::Object &request, - llvm::json::Object &response) { - // Fill in all of the needed response fields to a "request" and set "success" - // to true by default. - response.try_emplace("type", "response"); - response.try_emplace("seq", (int64_t)0); - EmplaceSafeString(response, "command", - GetString(request, "command").value_or("")); - const uint64_t seq = GetInteger(request, "seq").value_or(0); - response.try_emplace("request_seq", seq); - response.try_emplace("success", true); -} - -// "Scope": { -// "type": "object", -// "description": "A Scope is a named container for variables. Optionally -// a scope can map to a source or a range within a source.", -// "properties": { -// "name": { -// "type": "string", -// "description": "Name of the scope such as 'Arguments', 'Locals'." -// }, -// "presentationHint": { -// "type": "string", -// "description": "An optional hint for how to present this scope in the -// UI. If this attribute is missing, the scope is shown -// with a generic UI.", -// "_enum": [ "arguments", "locals", "registers" ], -// }, -// "variablesReference": { -// "type": "integer", -// "description": "The variables of this scope can be retrieved by -// passing the value of variablesReference to the -// VariablesRequest." -// }, -// "namedVariables": { -// "type": "integer", -// "description": "The number of named variables in this scope. The -// client can use this optional information to present -// the variables in a paged UI and fetch them in chunks." -// }, -// "indexedVariables": { -// "type": "integer", -// "description": "The number of indexed variables in this scope. The -// client can use this optional information to present -// the variables in a paged UI and fetch them in chunks." -// }, -// "expensive": { -// "type": "boolean", -// "description": "If true, the number of variables in this scope is -// large or expensive to retrieve." -// }, -// "source": { -// "$ref": "#/definitions/Source", -// "description": "Optional source for this scope." -// }, -// "line": { -// "type": "integer", -// "description": "Optional start line of the range covered by this -// scope." -// }, -// "column": { -// "type": "integer", -// "description": "Optional start column of the range covered by this -// scope." -// }, -// "endLine": { -// "type": "integer", -// "description": "Optional end line of the range covered by this scope." -// }, -// "endColumn": { -// "type": "integer", -// "description": "Optional end column of the range covered by this -// scope." -// } -// }, -// "required": [ "name", "variablesReference", "expensive" ] -// } -llvm::json::Value CreateScope(const llvm::StringRef name, - int64_t variablesReference, - int64_t namedVariables, bool expensive) { - llvm::json::Object object; - EmplaceSafeString(object, "name", name.str()); - - // TODO: Support "arguments" scope. At the moment lldb-dap includes the - // arguments into the "locals" scope. - if (variablesReference == VARREF_LOCALS) { - object.try_emplace("presentationHint", "locals"); - } else if (variablesReference == VARREF_REGS) { - object.try_emplace("presentationHint", "registers"); - } - - object.try_emplace("variablesReference", variablesReference); - object.try_emplace("expensive", expensive); - object.try_emplace("namedVariables", namedVariables); - return llvm::json::Value(std::move(object)); -} - -static uint64_t GetDebugInfoSizeInSection(lldb::SBSection section) { - uint64_t debug_info_size = 0; - llvm::StringRef section_name(section.GetName()); - if (section_name.starts_with(".debug") || - section_name.starts_with("__debug") || - section_name.starts_with(".apple") || section_name.starts_with("__apple")) - debug_info_size += section.GetFileByteSize(); - size_t num_sub_sections = section.GetNumSubSections(); - for (size_t i = 0; i < num_sub_sections; i++) { - debug_info_size += - GetDebugInfoSizeInSection(section.GetSubSectionAtIndex(i)); - } - return debug_info_size; -} - -static uint64_t GetDebugInfoSize(lldb::SBModule module) { - uint64_t debug_info_size = 0; - size_t num_sections = module.GetNumSections(); - for (size_t i = 0; i < num_sections; i++) { - debug_info_size += GetDebugInfoSizeInSection(module.GetSectionAtIndex(i)); - } - return debug_info_size; -} - -static std::string ConvertDebugInfoSizeToString(uint64_t debug_info) { - std::ostringstream oss; - oss << std::fixed << std::setprecision(1); - if (debug_info < 1024) { - oss << debug_info << "B"; - } else if (debug_info < 1024 * 1024) { - double kb = double(debug_info) / 1024.0; - oss << kb << "KB"; - } else if (debug_info < 1024 * 1024 * 1024) { - double mb = double(debug_info) / (1024.0 * 1024.0); - oss << mb << "MB"; - } else { - double gb = double(debug_info) / (1024.0 * 1024.0 * 1024.0); - oss << gb << "GB"; - } - return oss.str(); -} - -llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, - bool id_only) { - llvm::json::Object object; - if (!target.IsValid() || !module.IsValid()) - return llvm::json::Value(std::move(object)); - - const char *uuid = module.GetUUIDString(); - object.try_emplace("id", uuid ? std::string(uuid) : std::string("")); - - if (id_only) - return llvm::json::Value(std::move(object)); - - object.try_emplace("name", std::string(module.GetFileSpec().GetFilename())); - char module_path_arr[PATH_MAX]; - module.GetFileSpec().GetPath(module_path_arr, sizeof(module_path_arr)); - std::string module_path(module_path_arr); - object.try_emplace("path", module_path); - if (module.GetNumCompileUnits() > 0) { - std::string symbol_str = "Symbols loaded."; - std::string debug_info_size; - uint64_t debug_info = GetDebugInfoSize(module); - if (debug_info > 0) { - debug_info_size = ConvertDebugInfoSizeToString(debug_info); - } - object.try_emplace("symbolStatus", symbol_str); - object.try_emplace("debugInfoSize", debug_info_size); - char symbol_path_arr[PATH_MAX]; - module.GetSymbolFileSpec().GetPath(symbol_path_arr, - sizeof(symbol_path_arr)); - std::string symbol_path(symbol_path_arr); - object.try_emplace("symbolFilePath", symbol_path); - } else { - object.try_emplace("symbolStatus", "Symbols not found."); - } - std::string load_address = - llvm::formatv("{0:x}", - module.GetObjectFileHeaderAddress().GetLoadAddress(target)) - .str(); - object.try_emplace("addressRange", load_address); - std::string version_str; - uint32_t version_nums[3]; - uint32_t num_versions = - module.GetVersion(version_nums, sizeof(version_nums) / sizeof(uint32_t)); - for (uint32_t i = 0; i < num_versions; ++i) { - if (!version_str.empty()) - version_str += "."; - version_str += std::to_string(version_nums[i]); - } - if (!version_str.empty()) - object.try_emplace("version", version_str); - return llvm::json::Value(std::move(object)); -} - -// "Event": { -// "allOf": [ { "$ref": "#/definitions/ProtocolMessage" }, { -// "type": "object", -// "description": "Server-initiated event.", -// "properties": { -// "type": { -// "type": "string", -// "enum": [ "event" ] -// }, -// "event": { -// "type": "string", -// "description": "Type of event." -// }, -// "body": { -// "type": [ "array", "boolean", "integer", "null", "number" , -// "object", "string" ], -// "description": "Event-specific information." -// } -// }, -// "required": [ "type", "event" ] -// }] -// }, -// "ProtocolMessage": { -// "type": "object", -// "description": "Base class of requests, responses, and events.", -// "properties": { -// "seq": { -// "type": "integer", -// "description": "Sequence number." -// }, -// "type": { -// "type": "string", -// "description": "Message type.", -// "_enum": [ "request", "response", "event" ] -// } -// }, -// "required": [ "seq", "type" ] -// } -llvm::json::Object CreateEventObject(const llvm::StringRef event_name) { - llvm::json::Object event; - event.try_emplace("seq", 0); - event.try_emplace("type", "event"); - EmplaceSafeString(event, "event", event_name); - return event; -} - -protocol::ExceptionBreakpointsFilter -CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp) { - protocol::ExceptionBreakpointsFilter filter; - filter.filter = bp.GetFilter(); - filter.label = bp.GetLabel(); - filter.defaultState = ExceptionBreakpoint::kDefaultValue; - return filter; -} - -// "StackFrame": { -// "type": "object", -// "description": "A Stackframe contains the source location.", -// "properties": { -// "id": { -// "type": "integer", -// "description": "An identifier for the stack frame. It must be unique -// across all threads. This id can be used to retrieve -// the scopes of the frame with the 'scopesRequest' or -// to restart the execution of a stackframe." -// }, -// "name": { -// "type": "string", -// "description": "The name of the stack frame, typically a method name." -// }, -// "source": { -// "$ref": "#/definitions/Source", -// "description": "The optional source of the frame." -// }, -// "line": { -// "type": "integer", -// "description": "The line within the file of the frame. If source is -// null or doesn't exist, line is 0 and must be ignored." -// }, -// "column": { -// "type": "integer", -// "description": "The column within the line. If source is null or -// doesn't exist, column is 0 and must be ignored." -// }, -// "endLine": { -// "type": "integer", -// "description": "An optional end line of the range covered by the -// stack frame." -// }, -// "endColumn": { -// "type": "integer", -// "description": "An optional end column of the range covered by the -// stack frame." -// }, -// "instructionPointerReference": { -// "type": "string", -// "description": "A memory reference for the current instruction -// pointer in this frame." -// }, -// "moduleId": { -// "type": ["integer", "string"], -// "description": "The module associated with this frame, if any." -// }, -// "presentationHint": { -// "type": "string", -// "enum": [ "normal", "label", "subtle" ], -// "description": "An optional hint for how to present this frame in -// the UI. A value of 'label' can be used to indicate -// that the frame is an artificial frame that is used -// as a visual label or separator. A value of 'subtle' -// can be used to change the appearance of a frame in -// a 'subtle' way." -// } -// }, -// "required": [ "id", "name", "line", "column" ] -// } -llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, - lldb::SBFormat &format) { - llvm::json::Object object; - int64_t frame_id = MakeDAPFrameID(frame); - object.try_emplace("id", frame_id); - - std::string frame_name; - lldb::SBStream stream; - if (format && frame.GetDescriptionWithFormat(format, stream).Success()) { - frame_name = stream.GetData(); - - // `function_name` can be a nullptr, which throws an error when assigned to - // an `std::string`. - } else if (const char *name = frame.GetDisplayFunctionName()) { - frame_name = name; - } - - if (frame_name.empty()) { - // If the function name is unavailable, display the pc address as a 16-digit - // hex string, e.g. "0x0000000000012345" - frame_name = GetLoadAddressString(frame.GetPC()); - } - - // We only include `[opt]` if a custom frame format is not specified. - if (!format && frame.GetFunction().GetIsOptimized()) - frame_name += " [opt]"; - - EmplaceSafeString(object, "name", frame_name); - - auto target = frame.GetThread().GetProcess().GetTarget(); - auto source = CreateSource(frame.GetPCAddress(), target); - if (!IsAssemblySource(source)) { - // This is a normal source with a valid line entry. - auto line_entry = frame.GetLineEntry(); - object.try_emplace("line", line_entry.GetLine()); - auto column = line_entry.GetColumn(); - object.try_emplace("column", column); - } else if (frame.GetSymbol().IsValid()) { - // This is a source where the disassembly is used, but there is a valid - // symbol. Calculate the line of the current PC from the start of the - // current symbol. - lldb::SBTarget target = frame.GetThread().GetProcess().GetTarget(); - lldb::SBInstructionList inst_list = target.ReadInstructions( - frame.GetSymbol().GetStartAddress(), frame.GetPCAddress(), nullptr); - size_t inst_line = inst_list.GetSize(); - - // Line numbers are 1-based. - object.try_emplace("line", inst_line + 1); - object.try_emplace("column", 1); - } else { - // No valid line entry or symbol. - object.try_emplace("line", 1); - object.try_emplace("column", 1); - } - - object.try_emplace("source", std::move(source)); - - const auto pc = frame.GetPC(); - if (pc != LLDB_INVALID_ADDRESS) { - std::string formatted_addr = "0x" + llvm::utohexstr(pc); - object.try_emplace("instructionPointerReference", formatted_addr); - } - - if (frame.IsArtificial() || frame.IsHidden()) - object.try_emplace("presentationHint", "subtle"); - - return llvm::json::Value(std::move(object)); -} - -llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread, - lldb::SBFormat &format) { - std::string name; - lldb::SBStream stream; - if (format && thread.GetDescriptionWithFormat(format, stream).Success()) { - name = stream.GetData(); - } else { - const uint32_t thread_idx = thread.GetExtendedBacktraceOriginatingIndexID(); - const char *queue_name = thread.GetQueueName(); - if (queue_name != nullptr) { - name = llvm::formatv("Enqueued from {0} (Thread {1})", queue_name, - thread_idx); - } else { - name = llvm::formatv("Thread {0}", thread_idx); - } - } - - return llvm::json::Value(llvm::json::Object{{"id", thread.GetThreadID() + 1}, - {"name", name}, - {"presentationHint", "label"}}); -} - -// "Thread": { -// "type": "object", -// "description": "A Thread", -// "properties": { -// "id": { -// "type": "integer", -// "description": "Unique identifier for the thread." -// }, -// "name": { -// "type": "string", -// "description": "A name of the thread." -// } -// }, -// "required": [ "id", "name" ] -// } -llvm::json::Value CreateThread(lldb::SBThread &thread, lldb::SBFormat &format) { - llvm::json::Object object; - object.try_emplace("id", (int64_t)thread.GetThreadID()); - std::string thread_str; - lldb::SBStream stream; - if (format && thread.GetDescriptionWithFormat(format, stream).Success()) { - thread_str = stream.GetData(); - } else { - llvm::StringRef thread_name(thread.GetName()); - llvm::StringRef queue_name(thread.GetQueueName()); - - if (!thread_name.empty()) { - thread_str = thread_name.str(); - } else if (!queue_name.empty()) { - auto kind = thread.GetQueue().GetKind(); - std::string queue_kind_label = ""; - if (kind == lldb::eQueueKindSerial) { - queue_kind_label = " (serial)"; - } else if (kind == lldb::eQueueKindConcurrent) { - queue_kind_label = " (concurrent)"; - } - - thread_str = - llvm::formatv("Thread {0} Queue: {1}{2}", thread.GetIndexID(), - queue_name, queue_kind_label) - .str(); - } else { - thread_str = llvm::formatv("Thread {0}", thread.GetIndexID()).str(); - } - } - - EmplaceSafeString(object, "name", thread_str); - - return llvm::json::Value(std::move(object)); -} - -llvm::json::Array GetThreads(lldb::SBProcess process, lldb::SBFormat &format) { - lldb::SBMutex lock = process.GetTarget().GetAPIMutex(); - std::lock_guard guard(lock); - - llvm::json::Array threads; - const uint32_t num_threads = process.GetNumThreads(); - for (uint32_t thread_idx = 0; thread_idx < num_threads; ++thread_idx) { - lldb::SBThread thread = process.GetThreadAtIndex(thread_idx); - threads.emplace_back(CreateThread(thread, format)); - } - return threads; -} - -// "StoppedEvent": { -// "allOf": [ { "$ref": "#/definitions/Event" }, { -// "type": "object", -// "description": "Event message for 'stopped' event type. The event -// indicates that the execution of the debuggee has stopped -// due to some condition. This can be caused by a break -// point previously set, a stepping action has completed, -// by executing a debugger statement etc.", -// "properties": { -// "event": { -// "type": "string", -// "enum": [ "stopped" ] -// }, -// "body": { -// "type": "object", -// "properties": { -// "reason": { -// "type": "string", -// "description": "The reason for the event. For backward -// compatibility this string is shown in the UI if -// the 'description' attribute is missing (but it -// must not be translated).", -// "_enum": [ "step", "breakpoint", "exception", "pause", "entry" ] -// }, -// "description": { -// "type": "string", -// "description": "The full reason for the event, e.g. 'Paused -// on exception'. This string is shown in the UI -// as is." -// }, -// "threadId": { -// "type": "integer", -// "description": "The thread which was stopped." -// }, -// "text": { -// "type": "string", -// "description": "Additional information. E.g. if reason is -// 'exception', text contains the exception name. -// This string is shown in the UI." -// }, -// "allThreadsStopped": { -// "type": "boolean", -// "description": "If allThreadsStopped is true, a debug adapter -// can announce that all threads have stopped. -// The client should use this information to -// enable that all threads can be expanded to -// access their stacktraces. If the attribute -// is missing or false, only the thread with the -// given threadId can be expanded." -// } -// }, -// "required": [ "reason" ] -// } -// }, -// "required": [ "event", "body" ] -// }] -// } -llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, - uint32_t stop_id) { - llvm::json::Object event(CreateEventObject("stopped")); - llvm::json::Object body; - switch (thread.GetStopReason()) { - case lldb::eStopReasonTrace: - case lldb::eStopReasonPlanComplete: - body.try_emplace("reason", "step"); - break; - case lldb::eStopReasonBreakpoint: { - ExceptionBreakpoint *exc_bp = dap.GetExceptionBPFromStopReason(thread); - if (exc_bp) { - body.try_emplace("reason", "exception"); - EmplaceSafeString(body, "description", exc_bp->GetLabel()); - } else { - InstructionBreakpoint *inst_bp = - dap.GetInstructionBPFromStopReason(thread); - if (inst_bp) { - body.try_emplace("reason", "instruction breakpoint"); - } else { - body.try_emplace("reason", "breakpoint"); - } - lldb::break_id_t bp_id = thread.GetStopReasonDataAtIndex(0); - lldb::break_id_t bp_loc_id = thread.GetStopReasonDataAtIndex(1); - std::string desc_str = - llvm::formatv("breakpoint {0}.{1}", bp_id, bp_loc_id); - body.try_emplace("hitBreakpointIds", - llvm::json::Array{llvm::json::Value(bp_id)}); - EmplaceSafeString(body, "description", desc_str); - } - } break; - case lldb::eStopReasonWatchpoint: - case lldb::eStopReasonInstrumentation: - body.try_emplace("reason", "breakpoint"); - break; - case lldb::eStopReasonProcessorTrace: - body.try_emplace("reason", "processor trace"); - break; - case lldb::eStopReasonHistoryBoundary: - body.try_emplace("reason", "history boundary"); - break; - case lldb::eStopReasonSignal: - case lldb::eStopReasonException: - body.try_emplace("reason", "exception"); - break; - case lldb::eStopReasonExec: - body.try_emplace("reason", "entry"); - break; - case lldb::eStopReasonFork: - body.try_emplace("reason", "fork"); - break; - case lldb::eStopReasonVFork: - body.try_emplace("reason", "vfork"); - break; - case lldb::eStopReasonVForkDone: - body.try_emplace("reason", "vforkdone"); - break; - case lldb::eStopReasonInterrupt: - body.try_emplace("reason", "async interrupt"); - break; - case lldb::eStopReasonThreadExiting: - case lldb::eStopReasonInvalid: - case lldb::eStopReasonNone: - break; - } - if (stop_id == 0) - body.try_emplace("reason", "entry"); - const lldb::tid_t tid = thread.GetThreadID(); - body.try_emplace("threadId", (int64_t)tid); - // If no description has been set, then set it to the default thread stopped - // description. If we have breakpoints that get hit and shouldn't be reported - // as breakpoints, then they will set the description above. - if (!ObjectContainsKey(body, "description")) { - char description[1024]; - if (thread.GetStopDescription(description, sizeof(description))) { - EmplaceSafeString(body, "description", description); - } - } - // "threadCausedFocus" is used in tests to validate breaking behavior. - if (tid == dap.focus_tid) { - body.try_emplace("threadCausedFocus", true); - } - body.try_emplace("preserveFocusHint", tid != dap.focus_tid); - body.try_emplace("allThreadsStopped", true); - event.try_emplace("body", std::move(body)); - return llvm::json::Value(std::move(event)); -} - -const char *GetNonNullVariableName(lldb::SBValue &v) { - const char *name = v.GetName(); - return name ? name : ""; -} - -std::string CreateUniqueVariableNameForDisplay(lldb::SBValue &v, - bool is_name_duplicated) { - lldb::SBStream name_builder; - name_builder.Print(GetNonNullVariableName(v)); - if (is_name_duplicated) { - lldb::SBDeclaration declaration = v.GetDeclaration(); - const char *file_name = declaration.GetFileSpec().GetFilename(); - const uint32_t line = declaration.GetLine(); - - if (file_name != nullptr && line > 0) - name_builder.Printf(" @ %s:%u", file_name, line); - else if (const char *location = v.GetLocation()) - name_builder.Printf(" @ %s", location); - } - return name_builder.GetData(); -} - -VariableDescription::VariableDescription(lldb::SBValue v, - bool auto_variable_summaries, - bool format_hex, - bool is_name_duplicated, - std::optional custom_name) - : v(v) { - name = custom_name - ? *custom_name - : CreateUniqueVariableNameForDisplay(v, is_name_duplicated); - - type_obj = v.GetType(); - std::string raw_display_type_name = - llvm::StringRef(type_obj.GetDisplayTypeName()).str(); - display_type_name = - !raw_display_type_name.empty() ? raw_display_type_name : NO_TYPENAME; - - // Only format hex/default if there is no existing special format. - if (v.GetFormat() == lldb::eFormatDefault || - v.GetFormat() == lldb::eFormatHex) { - if (format_hex) - v.SetFormat(lldb::eFormatHex); - else - v.SetFormat(lldb::eFormatDefault); - } - - llvm::raw_string_ostream os_display_value(display_value); - - if (lldb::SBError sb_error = v.GetError(); sb_error.Fail()) { - error = sb_error.GetCString(); - os_display_value << ""; - } else { - value = llvm::StringRef(v.GetValue()).str(); - summary = llvm::StringRef(v.GetSummary()).str(); - if (summary.empty() && auto_variable_summaries) - auto_summary = TryCreateAutoSummary(v); - - std::optional effective_summary = - !summary.empty() ? summary : auto_summary; - - if (!value.empty()) { - os_display_value << value; - if (effective_summary) - os_display_value << " " << *effective_summary; - } else if (effective_summary) { - os_display_value << *effective_summary; - - // As last resort, we print its type and address if available. - } else { - if (!raw_display_type_name.empty()) { - os_display_value << raw_display_type_name; - lldb::addr_t address = v.GetLoadAddress(); - if (address != LLDB_INVALID_ADDRESS) - os_display_value << " @ " << llvm::format_hex(address, 0); - } - } - } - - lldb::SBStream evaluateStream; - v.GetExpressionPath(evaluateStream); - evaluate_name = llvm::StringRef(evaluateStream.GetData()).str(); -} - -llvm::json::Object VariableDescription::GetVariableExtensionsJSON() { - llvm::json::Object extensions; - if (error) - EmplaceSafeString(extensions, "error", *error); - if (!value.empty()) - EmplaceSafeString(extensions, "value", value); - if (!summary.empty()) - EmplaceSafeString(extensions, "summary", summary); - if (auto_summary) - EmplaceSafeString(extensions, "autoSummary", *auto_summary); - - if (lldb::SBDeclaration decl = v.GetDeclaration(); decl.IsValid()) { - llvm::json::Object decl_obj; - if (lldb::SBFileSpec file = decl.GetFileSpec(); file.IsValid()) { - char path[PATH_MAX] = ""; - if (file.GetPath(path, sizeof(path)) && - lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) { - decl_obj.try_emplace("path", std::string(path)); - } - } - - if (int line = decl.GetLine()) - decl_obj.try_emplace("line", line); - if (int column = decl.GetColumn()) - decl_obj.try_emplace("column", column); - - if (!decl_obj.empty()) - extensions.try_emplace("declaration", std::move(decl_obj)); - } - return extensions; -} - -std::string VariableDescription::GetResult(llvm::StringRef context) { - // In repl context, the results can be displayed as multiple lines so more - // detailed descriptions can be returned. - if (context != "repl") - return display_value; - - if (!v.IsValid()) - return display_value; - - // Try the SBValue::GetDescription(), which may call into language runtime - // specific formatters (see ValueObjectPrinter). - lldb::SBStream stream; - v.GetDescription(stream); - llvm::StringRef description = stream.GetData(); - return description.trim().str(); -} - -bool ValuePointsToCode(lldb::SBValue v) { - if (!v.GetType().GetPointeeType().IsFunctionType()) - return false; - - lldb::addr_t addr = v.GetValueAsAddress(); - lldb::SBLineEntry line_entry = - v.GetTarget().ResolveLoadAddress(addr).GetLineEntry(); - - return line_entry.IsValid(); -} - -int64_t PackLocation(int64_t var_ref, bool is_value_location) { - return var_ref << 1 | is_value_location; -} - -std::pair UnpackLocation(int64_t location_id) { - return std::pair{location_id >> 1, location_id & 1}; -} - -// "Variable": { -// "type": "object", -// "description": "A Variable is a name/value pair. Optionally a variable -// can have a 'type' that is shown if space permits or when -// hovering over the variable's name. An optional 'kind' is -// used to render additional properties of the variable, -// e.g. different icons can be used to indicate that a -// variable is public or private. If the value is -// structured (has children), a handle is provided to -// retrieve the children with the VariablesRequest. If -// the number of named or indexed children is large, the -// numbers should be returned via the optional -// 'namedVariables' and 'indexedVariables' attributes. The -// client can use this optional information to present the -// children in a paged UI and fetch them in chunks.", -// "properties": { -// "name": { -// "type": "string", -// "description": "The variable's name." -// }, -// "value": { -// "type": "string", -// "description": "The variable's value. This can be a multi-line text, -// e.g. for a function the body of a function." -// }, -// "type": { -// "type": "string", -// "description": "The type of the variable's value. Typically shown in -// the UI when hovering over the value." -// }, -// "presentationHint": { -// "$ref": "#/definitions/VariablePresentationHint", -// "description": "Properties of a variable that can be used to determine -// how to render the variable in the UI." -// }, -// "evaluateName": { -// "type": "string", -// "description": "Optional evaluatable name of this variable which can -// be passed to the 'EvaluateRequest' to fetch the -// variable's value." -// }, -// "variablesReference": { -// "type": "integer", -// "description": "If variablesReference is > 0, the variable is -// structured and its children can be retrieved by -// passing variablesReference to the VariablesRequest." -// }, -// "namedVariables": { -// "type": "integer", -// "description": "The number of named child variables. The client can -// use this optional information to present the children -// in a paged UI and fetch them in chunks." -// }, -// "indexedVariables": { -// "type": "integer", -// "description": "The number of indexed child variables. The client -// can use this optional information to present the -// children in a paged UI and fetch them in chunks." -// }, -// "memoryReference": { -// "type": "string", -// "description": "A memory reference associated with this variable. -// For pointer type variables, this is generally a -// reference to the memory address contained in the -// pointer. For executable data, this reference may later -// be used in a `disassemble` request. This attribute may -// be returned by a debug adapter if corresponding -// capability `supportsMemoryReferences` is true." -// }, -// "declarationLocationReference": { -// "type": "integer", -// "description": "A reference that allows the client to request the -// location where the variable is declared. This should be -// present only if the adapter is likely to be able to -// resolve the location.\n\nThis reference shares the same -// lifetime as the `variablesReference`. See 'Lifetime of -// Object References' in the Overview section for -// details." -// }, -// "valueLocationReference": { -// "type": "integer", -// "description": "A reference that allows the client to request the -// location where the variable's value is declared. For -// example, if the variable contains a function pointer, -// the adapter may be able to look up the function's -// location. This should be present only if the adapter -// is likely to be able to resolve the location.\n\nThis -// reference shares the same lifetime as the -// `variablesReference`. See 'Lifetime of Object -// References' in the Overview section for details." -// }, -// -// "$__lldb_extensions": { -// "description": "Unofficial extensions to the protocol", -// "properties": { -// "declaration": { -// "type": "object", -// "description": "The source location where the variable was -// declared. This value won't be present if no -// declaration is available. -// Superseded by `declarationLocationReference`", -// "properties": { -// "path": { -// "type": "string", -// "description": "The source file path where the variable was -// declared." -// }, -// "line": { -// "type": "number", -// "description": "The 1-indexed source line where the variable -// was declared." -// }, -// "column": { -// "type": "number", -// "description": "The 1-indexed source column where the variable -// was declared." -// } -// } -// }, -// "value": { -// "type": "string", -// "description": "The internal value of the variable as returned by -// This is effectively SBValue.GetValue(). The other -// `value` entry in the top-level variable response -// is, on the other hand, just a display string for -// the variable." -// }, -// "summary": { -// "type": "string", -// "description": "The summary string of the variable. This is -// effectively SBValue.GetSummary()." -// }, -// "autoSummary": { -// "type": "string", -// "description": "The auto generated summary if using -// `enableAutoVariableSummaries`." -// }, -// "error": { -// "type": "string", -// "description": "An error message generated if LLDB couldn't inspect -// the variable." -// } -// } -// } -// }, -// "required": [ "name", "value", "variablesReference" ] -// } -llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref, - bool format_hex, bool auto_variable_summaries, - bool synthetic_child_debugging, - bool is_name_duplicated, - std::optional custom_name) { - VariableDescription desc(v, auto_variable_summaries, format_hex, - is_name_duplicated, custom_name); - llvm::json::Object object; - EmplaceSafeString(object, "name", desc.name); - EmplaceSafeString(object, "value", desc.display_value); - - if (!desc.evaluate_name.empty()) - EmplaceSafeString(object, "evaluateName", desc.evaluate_name); - - // If we have a type with many children, we would like to be able to - // give a hint to the IDE that the type has indexed children so that the - // request can be broken up in grabbing only a few children at a time. We - // want to be careful and only call "v.GetNumChildren()" if we have an array - // type or if we have a synthetic child provider producing indexed children. - // We don't want to call "v.GetNumChildren()" on all objects as class, struct - // and union types don't need to be completed if they are never expanded. So - // we want to avoid calling this to only cases where we it makes sense to keep - // performance high during normal debugging. - - // If we have an array type, say that it is indexed and provide the number - // of children in case we have a huge array. If we don't do this, then we - // might take a while to produce all children at onces which can delay your - // debug session. - if (desc.type_obj.IsArrayType()) { - object.try_emplace("indexedVariables", v.GetNumChildren()); - } else if (v.IsSynthetic()) { - // For a type with a synthetic child provider, the SBType of "v" won't tell - // us anything about what might be displayed. Instead, we check if the first - // child's name is "[0]" and then say it is indexed. We call - // GetNumChildren() only if the child name matches to avoid a potentially - // expensive operation. - if (lldb::SBValue first_child = v.GetChildAtIndex(0)) { - llvm::StringRef first_child_name = first_child.GetName(); - if (first_child_name == "[0]") { - size_t num_children = v.GetNumChildren(); - // If we are creating a "[raw]" fake child for each synthetic type, we - // have to account for it when returning indexed variables. - if (synthetic_child_debugging) - ++num_children; - object.try_emplace("indexedVariables", num_children); - } - } - } - EmplaceSafeString(object, "type", desc.display_type_name); - - // A unique variable identifier to help in properly identifying variables with - // the same name. This is an extension to the VS protocol. - object.try_emplace("id", var_ref); - - if (v.MightHaveChildren()) - object.try_emplace("variablesReference", var_ref); - else - object.try_emplace("variablesReference", 0); - - if (v.GetDeclaration().IsValid()) - object.try_emplace("declarationLocationReference", - PackLocation(var_ref, false)); - - if (ValuePointsToCode(v)) - object.try_emplace("valueLocationReference", PackLocation(var_ref, true)); - - if (lldb::addr_t addr = v.GetLoadAddress(); addr != LLDB_INVALID_ADDRESS) - object.try_emplace("memoryReference", EncodeMemoryReference(addr)); - - object.try_emplace("$__lldb_extensions", desc.GetVariableExtensionsJSON()); - return llvm::json::Value(std::move(object)); -} - -llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit) { - llvm::json::Object object; - char unit_path_arr[PATH_MAX]; - unit.GetFileSpec().GetPath(unit_path_arr, sizeof(unit_path_arr)); - std::string unit_path(unit_path_arr); - object.try_emplace("compileUnitPath", unit_path); - return llvm::json::Value(std::move(object)); -} - -/// See -/// https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_RunInTerminal -llvm::json::Object CreateRunInTerminalReverseRequest( - llvm::StringRef program, const std::vector &args, - const llvm::StringMap &env, llvm::StringRef cwd, - llvm::StringRef comm_file, lldb::pid_t debugger_pid) { - llvm::json::Object run_in_terminal_args; - // This indicates the IDE to open an embedded terminal, instead of opening - // the terminal in a new window. - run_in_terminal_args.try_emplace("kind", "integrated"); - - // The program path must be the first entry in the "args" field - std::vector req_args = {DAP::debug_adapter_path.str(), - "--comm-file", comm_file.str()}; - if (debugger_pid != LLDB_INVALID_PROCESS_ID) { - req_args.push_back("--debugger-pid"); - req_args.push_back(std::to_string(debugger_pid)); - } - req_args.push_back("--launch-target"); - req_args.push_back(program.str()); - req_args.insert(req_args.end(), args.begin(), args.end()); - run_in_terminal_args.try_emplace("args", req_args); - - if (!cwd.empty()) - run_in_terminal_args.try_emplace("cwd", cwd); - - if (!env.empty()) { - llvm::json::Object env_json; - for (const auto &kv : env) { - if (!kv.first().empty()) - env_json.try_emplace(kv.first(), kv.second); - } - run_in_terminal_args.try_emplace("env", - llvm::json::Value(std::move(env_json))); - } - - return run_in_terminal_args; -} - -// Keep all the top level items from the statistics dump, except for the -// "modules" array. It can be huge and cause delay -// Array and dictionary value will return as pairs -static void FilterAndGetValueForKey(const lldb::SBStructuredData data, - const char *key, llvm::json::Object &out) { - lldb::SBStructuredData value = data.GetValueForKey(key); - std::string key_utf8 = llvm::json::fixUTF8(key); - if (llvm::StringRef(key) == "modules") - return; - switch (value.GetType()) { - case lldb::eStructuredDataTypeFloat: - out.try_emplace(key_utf8, value.GetFloatValue()); - break; - case lldb::eStructuredDataTypeUnsignedInteger: - out.try_emplace(key_utf8, value.GetIntegerValue((uint64_t)0)); - break; - case lldb::eStructuredDataTypeSignedInteger: - out.try_emplace(key_utf8, value.GetIntegerValue((int64_t)0)); - break; - case lldb::eStructuredDataTypeArray: { - lldb::SBStream contents; - value.GetAsJSON(contents); - out.try_emplace(key_utf8, llvm::json::fixUTF8(contents.GetData())); - } break; - case lldb::eStructuredDataTypeBoolean: - out.try_emplace(key_utf8, value.GetBooleanValue()); - break; - case lldb::eStructuredDataTypeString: { - // Get the string size before reading - const size_t str_length = value.GetStringValue(nullptr, 0); - std::string str(str_length + 1, 0); - value.GetStringValue(&str[0], str_length); - out.try_emplace(key_utf8, llvm::json::fixUTF8(str)); - } break; - case lldb::eStructuredDataTypeDictionary: { - lldb::SBStream contents; - value.GetAsJSON(contents); - out.try_emplace(key_utf8, llvm::json::fixUTF8(contents.GetData())); - } break; - case lldb::eStructuredDataTypeNull: - case lldb::eStructuredDataTypeGeneric: - case lldb::eStructuredDataTypeInvalid: - break; - } -} - -static void addStatistic(lldb::SBTarget &target, llvm::json::Object &event) { - lldb::SBStructuredData statistics = target.GetStatistics(); - bool is_dictionary = - statistics.GetType() == lldb::eStructuredDataTypeDictionary; - if (!is_dictionary) - return; - llvm::json::Object stats_body; - - lldb::SBStringList keys; - if (!statistics.GetKeys(keys)) - return; - for (size_t i = 0; i < keys.GetSize(); i++) { - const char *key = keys.GetStringAtIndex(i); - FilterAndGetValueForKey(statistics, key, stats_body); - } - llvm::json::Object body{{"$__lldb_statistics", std::move(stats_body)}}; - event.try_emplace("body", std::move(body)); -} - -llvm::json::Object CreateTerminatedEventObject(lldb::SBTarget &target) { - llvm::json::Object event(CreateEventObject("terminated")); - addStatistic(target, event); - return event; -} - -std::string JSONToString(const llvm::json::Value &json) { - std::string data; - llvm::raw_string_ostream os(data); - os << json; - return data; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/JSONUtils.h b/lldb/tools/lldb-dap/JSONUtils.h deleted file mode 100644 index 08699a94bbd8..000000000000 --- a/lldb/tools/lldb-dap/JSONUtils.h +++ /dev/null @@ -1,496 +0,0 @@ -//===-- JSONUtils.h ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_JSONUTILS_H -#define LLDB_TOOLS_LLDB_DAP_JSONUTILS_H - -#include "DAPForward.h" -#include "Protocol/ProtocolTypes.h" -#include "lldb/API/SBCompileUnit.h" -#include "lldb/API/SBFormat.h" -#include "lldb/API/SBType.h" -#include "lldb/API/SBValue.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/JSON.h" -#include -#include -#include -#include -#include -#include - -namespace lldb_dap { - -/// Emplace a StringRef in a json::Object after enusring that the -/// string is valid UTF8. If not, first call llvm::json::fixUTF8 -/// before emplacing. -/// -/// \param[in] obj -/// A JSON object that we will attempt to emplace the value in -/// -/// \param[in] key -/// The key to use when emplacing the value -/// -/// \param[in] str -/// The string to emplace -void EmplaceSafeString(llvm::json::Object &obj, llvm::StringRef key, - llvm::StringRef str); - -/// Extract simple values as a string. -/// -/// \param[in] value -/// A JSON value to extract the string from. -/// -/// \return -/// A llvm::StringRef that contains the string value, or an empty -/// string if \a value isn't a string. -llvm::StringRef GetAsString(const llvm::json::Value &value); - -/// Extract the string value for the specified key from the -/// specified object. -/// -/// \param[in] obj -/// A JSON object that we will attempt to extract the value from -/// -/// \param[in] key -/// The key to use when extracting the value -/// -/// \return -/// A llvm::StringRef that contains the string value for the -/// specified \a key, or \a std::nullopt if there is no key that -/// matches or if the value is not a string. -std::optional GetString(const llvm::json::Object &obj, - llvm::StringRef key); -std::optional GetString(const llvm::json::Object *obj, - llvm::StringRef key); - -/// Extract the integer value for the specified key from the specified object -/// and return it as the specified integer type T. -/// -/// \param[in] obj -/// A JSON object that we will attempt to extract the value from -/// -/// \param[in] key -/// The key to use when extracting the value -/// -/// \return -/// The integer value for the specified \a key, or std::nullopt if there is -/// no key that matches or if the value is not an integer. -/// @{ -template -std::optional GetInteger(const llvm::json::Object &obj, - llvm::StringRef key) { - return obj.getInteger(key); -} - -template -std::optional GetInteger(const llvm::json::Object *obj, - llvm::StringRef key) { - if (obj != nullptr) - return GetInteger(*obj, key); - return std::nullopt; -} -/// @} - -/// Extract the boolean value for the specified key from the -/// specified object. -/// -/// \param[in] obj -/// A JSON object that we will attempt to extract the value from -/// -/// \param[in] key -/// The key to use when extracting the value -/// -/// \return -/// The boolean value for the specified \a key, or std::nullopt -/// if there is no key that matches or if the value is not a -/// boolean value of an integer. -/// @{ -std::optional GetBoolean(const llvm::json::Object &obj, - llvm::StringRef key); -std::optional GetBoolean(const llvm::json::Object *obj, - llvm::StringRef key); -/// @} - -/// Check if the specified key exists in the specified object. -/// -/// \param[in] obj -/// A JSON object that we will attempt to extract the value from -/// -/// \param[in] key -/// The key to check for -/// -/// \return -/// \b True if the key exists in the \a obj, \b False otherwise. -bool ObjectContainsKey(const llvm::json::Object &obj, llvm::StringRef key); - -/// Encodes a memory reference -std::string EncodeMemoryReference(lldb::addr_t addr); - -/// Decodes a memory reference -std::optional -DecodeMemoryReference(llvm::StringRef memoryReference); - -/// Extract an array of strings for the specified key from an object. -/// -/// String values in the array will be extracted without any quotes -/// around them. Numbers and Booleans will be converted into -/// strings. Any NULL, array or objects values in the array will be -/// ignored. -/// -/// \param[in] obj -/// A JSON object that we will attempt to extract the array from -/// -/// \param[in] key -/// The key to use when extracting the value -/// -/// \return -/// An array of string values for the specified \a key, or -/// \a fail_value if there is no key that matches or if the -/// value is not an array or all items in the array are not -/// strings, numbers or booleans. -std::vector GetStrings(const llvm::json::Object *obj, - llvm::StringRef key); - -/// Extract an object of key value strings for the specified key from an object. -/// -/// String values in the object will be extracted without any quotes -/// around them. Numbers and Booleans will be converted into -/// strings. Any NULL, array or objects values in the array will be -/// ignored. -/// -/// \param[in] obj -/// A JSON object that we will attempt to extract the array from -/// -/// \param[in] key -/// The key to use when extracting the value -/// -/// \return -/// An object of key value strings for the specified \a key, or -/// \a fail_value if there is no key that matches or if the -/// value is not an object or key and values in the object are not -/// strings, numbers or booleans. -std::unordered_map -GetStringMap(const llvm::json::Object &obj, llvm::StringRef key); - -/// Fill a response object given the request object. -/// -/// The \a response object will get its "type" set to "response", -/// the "seq" set to zero, "response_seq" set to the "seq" value from -/// \a request, "command" set to the "command" from \a request, -/// and "success" set to true. -/// -/// \param[in] request -/// The request object received from a call to DAP::ReadJSON(). -/// -/// \param[in,out] response -/// An empty llvm::json::Object object that will be filled -/// in as noted in description. -void FillResponse(const llvm::json::Object &request, - llvm::json::Object &response); - -/// Converts a LLDB module to a VS Code DAP module for use in "modules" events. -/// -/// \param[in] target -/// A LLDB target object to convert into a JSON value. -/// -/// \param[in] module -/// A LLDB module object to convert into a JSON value -/// -/// \param[in] id_only -/// Only include the module ID in the JSON value. This is used when sending -/// a "removed" module event. -/// -/// \return -/// A "Module" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateModule(lldb::SBTarget &target, lldb::SBModule &module, - bool id_only = false); - -/// Create a "Event" JSON object using \a event_name as the event name -/// -/// \param[in] event_name -/// The string value to use for the "event" key in the JSON object. -/// -/// \return -/// A "Event" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Object CreateEventObject(const llvm::StringRef event_name); - -/// Create a "ExceptionBreakpointsFilter" JSON object as described in -/// the debug adapter definition. -/// -/// \param[in] bp -/// The exception breakpoint object to use -/// -/// \return -/// A "ExceptionBreakpointsFilter" JSON object with that follows -/// the formal JSON definition outlined by Microsoft. -protocol::ExceptionBreakpointsFilter -CreateExceptionBreakpointFilter(const ExceptionBreakpoint &bp); - -/// Create a "StackFrame" object for a LLDB frame object. -/// -/// This function will fill in the following keys in the returned -/// object: -/// "id" - the stack frame ID as an integer -/// "name" - the function name as a string -/// "source" - source file information as a "Source" DAP object -/// "line" - the source file line number as an integer -/// "column" - the source file column number as an integer -/// -/// \param[in] frame -/// The LLDB stack frame to use when populating out the "StackFrame" -/// object. -/// -/// \param[in] format -/// The LLDB format to use when populating out the "StackFrame" -/// object. -/// -/// \return -/// A "StackFrame" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateStackFrame(lldb::SBFrame &frame, - lldb::SBFormat &format); - -/// Create a "StackFrame" label object for a LLDB thread. -/// -/// This function will fill in the following keys in the returned -/// object: -/// "id" - the thread ID as an integer -/// "name" - the thread name as a string which combines the LLDB -/// thread index ID along with the string name of the thread -/// from the OS if it has a name. -/// "presentationHint" - "label" -/// -/// \param[in] thread -/// The LLDB thread to use when populating out the "Thread" -/// object. -/// -/// \param[in] format -/// The configured formatter for the DAP session. -/// -/// \return -/// A "StackFrame" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateExtendedStackFrameLabel(lldb::SBThread &thread, - lldb::SBFormat &format); - -/// Create a "Thread" object for a LLDB thread object. -/// -/// This function will fill in the following keys in the returned -/// object: -/// "id" - the thread ID as an integer -/// "name" - the thread name as a string which combines the LLDB -/// thread index ID along with the string name of the thread -/// from the OS if it has a name. -/// -/// \param[in] thread -/// The LLDB thread to use when populating out the "Thread" -/// object. -/// -/// \param[in] format -/// The LLDB format to use when populating out the "Thread" -/// object. -/// -/// \return -/// A "Thread" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateThread(lldb::SBThread &thread, lldb::SBFormat &format); - -llvm::json::Array GetThreads(lldb::SBProcess process, lldb::SBFormat &format); - -/// Create a "StoppedEvent" object for a LLDB thread object. -/// -/// This function will fill in the following keys in the returned -/// object's "body" object: -/// "reason" - With a valid stop reason enumeration string value -/// that Microsoft specifies -/// "threadId" - The thread ID as an integer -/// "description" - a stop description (like "breakpoint 12.3") as a -/// string -/// "preserveFocusHint" - a boolean value that states if this thread -/// should keep the focus in the GUI. -/// "allThreadsStopped" - set to True to indicate that all threads -/// stop when any thread stops. -/// -/// \param[in] dap -/// The DAP session associated with the stopped thread. -/// -/// \param[in] thread -/// The LLDB thread to use when populating out the "StoppedEvent" -/// object. -/// -/// \param[in] stop_id -/// The stop id for this event. -/// -/// \return -/// A "StoppedEvent" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateThreadStopped(DAP &dap, lldb::SBThread &thread, - uint32_t stop_id); - -/// \return -/// The variable name of \a value or a default placeholder. -const char *GetNonNullVariableName(lldb::SBValue &value); - -/// VSCode can't display two variables with the same name, so we need to -/// distinguish them by using a suffix. -/// -/// If the source and line information is present, we use it as the suffix. -/// Otherwise, we fallback to the variable address or register location. -std::string CreateUniqueVariableNameForDisplay(lldb::SBValue &v, - bool is_name_duplicated); - -/// Helper struct that parses the metadata of an \a lldb::SBValue and produces -/// a canonical set of properties that can be sent to DAP clients. -struct VariableDescription { - // The error message if SBValue.GetValue() fails. - std::optional error; - // The display description to show on the IDE. - std::string display_value; - // The display name to show on the IDE. - std::string name; - // The variable path for this variable. - std::string evaluate_name; - // The output of SBValue.GetValue() if it doesn't fail. It might be empty. - std::string value; - // The summary string of this variable. It might be empty. - std::string summary; - // The auto summary if using `enableAutoVariableSummaries`. - std::optional auto_summary; - // The type of this variable. - lldb::SBType type_obj; - // The display type name of this variable. - std::string display_type_name; - /// The SBValue for this variable. - lldb::SBValue v; - - VariableDescription(lldb::SBValue v, bool auto_variable_summaries, - bool format_hex = false, bool is_name_duplicated = false, - std::optional custom_name = {}); - - /// Create a JSON object that represents these extensions to the DAP variable - /// response. - llvm::json::Object GetVariableExtensionsJSON(); - - /// Returns a description of the value appropriate for the specified context. - std::string GetResult(llvm::StringRef context); -}; - -/// Does the given variable have an associated value location? -bool ValuePointsToCode(lldb::SBValue v); - -/// Pack a location into a single integer which we can send via -/// the debug adapter protocol. -int64_t PackLocation(int64_t var_ref, bool is_value_location); - -/// Reverse of `PackLocation` -std::pair UnpackLocation(int64_t location_id); - -/// Create a "Variable" object for a LLDB thread object. -/// -/// This function will fill in the following keys in the returned -/// object: -/// "name" - the name of the variable -/// "value" - the value of the variable as a string -/// "type" - the typename of the variable as a string -/// "id" - a unique identifier for a value in case there are multiple -/// variables with the same name. Other parts of the DAP -/// protocol refer to values by name so this can help -/// disambiguate such cases if a IDE passes this "id" value -/// back down. -/// "variablesReference" - Zero if the variable has no children, -/// non-zero integer otherwise which can be used to expand -/// the variable. -/// "evaluateName" - The name of the variable to use in expressions -/// as a string. -/// -/// \param[in] v -/// The LLDB value to use when populating out the "Variable" -/// object. -/// -/// \param[in] var_ref -/// The variable reference. Used to identify the value, e.g. -/// in the `variablesReference` or `declarationLocationReference` -/// properties. -/// -/// \param[in] format_hex -/// If set to true the variable will be formatted as hex in -/// the "value" key value pair for the value of the variable. -/// -/// \param[in] auto_variable_summaries -/// IF set to true the variable will create an automatic variable summary. -/// -/// \param[in] is_name_duplicated -/// Whether the same variable name appears multiple times within the same -/// context (e.g. locals). This can happen due to shadowed variables in -/// nested blocks. -/// -/// As VSCode doesn't render two of more variables with the same name, we -/// apply a suffix to distinguish duplicated variables. -/// -/// \param[in] custom_name -/// A provided custom name that is used instead of the SBValue's when -/// creating the JSON representation. -/// -/// \return -/// A "Variable" JSON object with that follows the formal JSON -/// definition outlined by Microsoft. -llvm::json::Value CreateVariable(lldb::SBValue v, int64_t var_ref, - bool format_hex, bool auto_variable_summaries, - bool synthetic_child_debugging, - bool is_name_duplicated = false, - std::optional custom_name = {}); - -llvm::json::Value CreateCompileUnit(lldb::SBCompileUnit &unit); - -/// Create a runInTerminal reverse request object -/// -/// \param[in] program -/// Path to the program to run in the terminal. -/// -/// \param[in] args -/// The arguments for the program. -/// -/// \param[in] env -/// The environment variables to set in the terminal. -/// -/// \param[in] cwd -/// The working directory for the run in terminal request. -/// -/// \param[in] comm_file -/// The fifo file used to communicate the with the target launcher. -/// -/// \param[in] debugger_pid -/// The PID of the lldb-dap instance that will attach to the target. The -/// launcher uses it on Linux tell the kernel that it should allow the -/// debugger process to attach. -/// -/// \return -/// A "runInTerminal" JSON object that follows the specification outlined by -/// Microsoft. -llvm::json::Object CreateRunInTerminalReverseRequest( - llvm::StringRef program, const std::vector &args, - const llvm::StringMap &env, llvm::StringRef cwd, - llvm::StringRef comm_file, lldb::pid_t debugger_pid); - -/// Create a "Terminated" JSON object that contains statistics -/// -/// \return -/// A body JSON object with debug info and breakpoint info -llvm::json::Object CreateTerminatedEventObject(lldb::SBTarget &target); - -/// Convert a given JSON object to a string. -std::string JSONToString(const llvm::json::Value &json); - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/LICENSE.TXT b/lldb/tools/lldb-dap/LICENSE.TXT deleted file mode 100644 index 53bb2e7fbc76..000000000000 --- a/lldb/tools/lldb-dap/LICENSE.TXT +++ /dev/null @@ -1,234 +0,0 @@ -============================================================================== -The LLVM Project is under the Apache License v2.0 with LLVM Exceptions: -============================================================================== - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - ----- LLVM Exceptions to the Apache 2.0 License ---- - -As an exception, if, as a result of your compiling your source code, portions -of this Software are embedded into an Object form of such source code, you -may redistribute such embedded portions in such Object form without complying -with the conditions of Sections 4(a), 4(b) and 4(d) of the License. - -In addition, if you combine or link compiled forms of this Software with -software that is licensed under the GPLv2 ("Combined Software") and if a -court of competent jurisdiction determines that the patent provision (Section -3), the indemnity provision (Section 9) or other Section of the License -conflicts with the conditions of the GPLv2, you may retroactively and -prospectively choose to deem waived or otherwise exclude such Section(s) of -the License, but only in their entirety and only with respect to the Combined -Software. - -============================================================================== -Software from third parties included in the LLVM Project: -============================================================================== -The LLVM Project contains third party software which is under different license -terms. All such code will be identified clearly using at least one of two -mechanisms: -1) It will be in a separate directory tree with its own `LICENSE.txt` or - `LICENSE` file at the top containing the specific license and restrictions - which apply to that software, or -2) It will contain specific license and restriction terms at the top of every - file. diff --git a/lldb/tools/lldb-dap/LLDBUtils.cpp b/lldb/tools/lldb-dap/LLDBUtils.cpp deleted file mode 100644 index 4db6caa1af38..000000000000 --- a/lldb/tools/lldb-dap/LLDBUtils.cpp +++ /dev/null @@ -1,262 +0,0 @@ -//===-- LLDBUtils.cpp -------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "LLDBUtils.h" -#include "JSONUtils.h" -#include "lldb/API/SBCommandInterpreter.h" -#include "lldb/API/SBCommandReturnObject.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBFrame.h" -#include "lldb/API/SBStringList.h" -#include "lldb/API/SBStructuredData.h" -#include "lldb/API/SBThread.h" -#include "lldb/lldb-enumerations.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/Support/JSON.h" -#include "llvm/Support/raw_ostream.h" - -#include -#include -#include - -namespace lldb_dap { - -bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, - const llvm::ArrayRef &commands, - llvm::raw_ostream &strm, bool parse_command_directives, - bool echo_commands) { - if (commands.empty()) - return true; - - bool did_print_prefix = false; - - // We only need the prompt when echoing commands. - std::string prompt_string; - if (echo_commands) { - prompt_string = "(lldb) "; - - // Get the current prompt from settings. - if (const lldb::SBStructuredData prompt = debugger.GetSetting("prompt")) { - const size_t prompt_length = prompt.GetStringValue(nullptr, 0); - - if (prompt_length != 0) { - prompt_string.resize(prompt_length + 1); - prompt.GetStringValue(prompt_string.data(), prompt_string.length()); - } - } - } - - lldb::SBCommandInterpreter interp = debugger.GetCommandInterpreter(); - for (llvm::StringRef command : commands) { - lldb::SBCommandReturnObject result; - bool quiet_on_success = false; - bool check_error = false; - - while (parse_command_directives) { - if (command.starts_with("?")) { - command = command.drop_front(); - quiet_on_success = true; - } else if (command.starts_with("!")) { - command = command.drop_front(); - check_error = true; - } else { - break; - } - } - - { - // Prevent simultaneous calls to HandleCommand, e.g. EventThreadFunction - // may asynchronously call RunExitCommands when we are already calling - // RunTerminateCommands. - static std::mutex handle_command_mutex; - std::lock_guard locker(handle_command_mutex); - interp.HandleCommand(command.str().c_str(), result, - /*add_to_history=*/true); - } - - const bool got_error = !result.Succeeded(); - // The if statement below is assuming we always print out `!` prefixed - // lines. The only time we don't print is when we have `quiet_on_success == - // true` and we don't have an error. - if (quiet_on_success ? got_error : true) { - if (!did_print_prefix && !prefix.empty()) { - strm << prefix << "\n"; - did_print_prefix = true; - } - - if (echo_commands) - strm << prompt_string.c_str() << command << '\n'; - - auto output_len = result.GetOutputSize(); - if (output_len) { - const char *output = result.GetOutput(); - strm << output; - } - auto error_len = result.GetErrorSize(); - if (error_len) { - const char *error = result.GetError(); - strm << error; - } - } - if (check_error && got_error) - return false; // Stop running commands. - } - return true; -} - -std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, - const llvm::ArrayRef &commands, - bool &required_command_failed, - bool parse_command_directives, bool echo_commands) { - required_command_failed = false; - std::string s; - llvm::raw_string_ostream strm(s); - required_command_failed = - !RunLLDBCommands(debugger, prefix, commands, strm, - parse_command_directives, echo_commands); - return s; -} - -bool ThreadHasStopReason(lldb::SBThread &thread) { - switch (thread.GetStopReason()) { - case lldb::eStopReasonTrace: - case lldb::eStopReasonPlanComplete: - case lldb::eStopReasonBreakpoint: - case lldb::eStopReasonWatchpoint: - case lldb::eStopReasonInstrumentation: - case lldb::eStopReasonSignal: - case lldb::eStopReasonException: - case lldb::eStopReasonExec: - case lldb::eStopReasonProcessorTrace: - case lldb::eStopReasonFork: - case lldb::eStopReasonVFork: - case lldb::eStopReasonVForkDone: - case lldb::eStopReasonInterrupt: - case lldb::eStopReasonHistoryBoundary: - return true; - case lldb::eStopReasonThreadExiting: - case lldb::eStopReasonInvalid: - case lldb::eStopReasonNone: - break; - } - return false; -} - -static uint32_t constexpr THREAD_INDEX_SHIFT = 19; - -uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id) { - return dap_frame_id >> THREAD_INDEX_SHIFT; -} - -uint32_t GetLLDBFrameID(uint64_t dap_frame_id) { - return dap_frame_id & ((1u << THREAD_INDEX_SHIFT) - 1); -} - -int64_t MakeDAPFrameID(lldb::SBFrame &frame) { - return ((int64_t)frame.GetThread().GetIndexID() << THREAD_INDEX_SHIFT) | - frame.GetFrameID(); -} - -lldb::SBEnvironment -GetEnvironmentFromArguments(const llvm::json::Object &arguments) { - lldb::SBEnvironment envs{}; - constexpr llvm::StringRef env_key = "env"; - const llvm::json::Value *raw_json_env = arguments.get(env_key); - - if (!raw_json_env) - return envs; - - if (raw_json_env->kind() == llvm::json::Value::Object) { - auto env_map = GetStringMap(arguments, env_key); - for (const auto &[key, value] : env_map) - envs.Set(key.c_str(), value.c_str(), true); - - } else if (raw_json_env->kind() == llvm::json::Value::Array) { - const auto envs_strings = GetStrings(&arguments, env_key); - lldb::SBStringList entries{}; - for (const auto &env : envs_strings) - entries.AppendString(env.c_str()); - - envs.SetEntries(entries, true); - } - return envs; -} - -lldb::StopDisassemblyType -GetStopDisassemblyDisplay(lldb::SBDebugger &debugger) { - lldb::StopDisassemblyType result = - lldb::StopDisassemblyType::eStopDisassemblyTypeNoDebugInfo; - lldb::SBStructuredData string_result = - debugger.GetSetting("stop-disassembly-display"); - const size_t result_length = string_result.GetStringValue(nullptr, 0); - if (result_length > 0) { - std::string result_string(result_length, '\0'); - string_result.GetStringValue(result_string.data(), result_length + 1); - - result = - llvm::StringSwitch(result_string) - .Case("never", lldb::StopDisassemblyType::eStopDisassemblyTypeNever) - .Case("always", - lldb::StopDisassemblyType::eStopDisassemblyTypeAlways) - .Case("no-source", - lldb::StopDisassemblyType::eStopDisassemblyTypeNoSource) - .Case("no-debuginfo", - lldb::StopDisassemblyType::eStopDisassemblyTypeNoDebugInfo) - .Default( - lldb::StopDisassemblyType::eStopDisassemblyTypeNoDebugInfo); - } - - return result; -} - -llvm::Error ToError(const lldb::SBError &error) { - if (error.Success()) - return llvm::Error::success(); - - return llvm::createStringError( - std::error_code(error.GetError(), std::generic_category()), - error.GetCString()); -} - -std::string GetStringValue(const lldb::SBStructuredData &data) { - if (!data.IsValid()) - return ""; - - const size_t str_length = data.GetStringValue(nullptr, 0); - if (!str_length) - return ""; - - std::string str(str_length, 0); - data.GetStringValue(str.data(), str_length + 1); - return str; -} - -ScopeSyncMode::ScopeSyncMode(lldb::SBDebugger &debugger) - : m_debugger(debugger), m_async(m_debugger.GetAsync()) { - m_debugger.SetAsync(false); -} - -ScopeSyncMode::~ScopeSyncMode() { m_debugger.SetAsync(m_async); } - -std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec) { - const auto directory_length = ::strlen(file_spec.GetDirectory()); - const auto file_name_length = ::strlen(file_spec.GetFilename()); - - std::string path(directory_length + file_name_length + 1, '\0'); - file_spec.GetPath(path.data(), path.length() + 1); - return path; -} - -lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target, - const lldb::SBAddress &address) { - lldb::SBSymbolContext sc = target.ResolveSymbolContextForAddress( - address, lldb::eSymbolContextLineEntry); - return sc.GetLineEntry(); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/LLDBUtils.h b/lldb/tools/lldb-dap/LLDBUtils.h deleted file mode 100644 index 9db721a47ccf..000000000000 --- a/lldb/tools/lldb-dap/LLDBUtils.h +++ /dev/null @@ -1,253 +0,0 @@ -//===-- LLDBUtils.h ---------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_LLDBUTILS_H -#define LLDB_TOOLS_LLDB_DAP_LLDBUTILS_H - -#include "DAPForward.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBEnvironment.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBFileSpec.h" -#include "lldb/API/SBLineEntry.h" -#include "lldb/API/SBTarget.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/JSON.h" -#include "llvm/Support/ScopedPrinter.h" -#include "llvm/Support/raw_ostream.h" -#include -#include - -namespace lldb_dap { - -/// Run a list of LLDB commands in the LLDB command interpreter. -/// -/// All output from every command, including the prompt + the command -/// is placed into the "strm" argument. -/// -/// Each individual command can be prefixed with \b ! and/or \b ? in no -/// particular order. If \b ? is provided, then the output of that command is -/// only emitted if it fails, and if \b ! is provided, then the output is -/// emitted regardless, and \b false is returned without executing the -/// remaining commands. -/// -/// \param[in] debugger -/// The debugger that will execute the lldb commands. -/// -/// \param[in] prefix -/// A string that will be printed into \a strm prior to emitting -/// the prompt + command and command output. Can be NULL. -/// -/// \param[in] commands -/// An array of LLDB commands to execute. -/// -/// \param[in] strm -/// The stream that will receive the prefix, prompt + command and -/// all command output. -/// -/// \param[in] parse_command_directives -/// If \b false, then command prefixes like \b ! or \b ? are not parsed and -/// each command is executed verbatim. -/// -/// \param[in] echo_commands -/// If \b true, the command are echoed to the stream. -/// -/// \return -/// \b true, unless a command prefixed with \b ! fails and parsing of -/// command directives is enabled. -bool RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, - const llvm::ArrayRef &commands, - llvm::raw_ostream &strm, bool parse_command_directives, - bool echo_commands); - -/// Run a list of LLDB commands in the LLDB command interpreter. -/// -/// All output from every command, including the prompt + the command -/// is returned in the std::string return value. -/// -/// \param[in] debugger -/// The debugger that will execute the lldb commands. -/// -/// \param[in] prefix -/// A string that will be printed into \a strm prior to emitting -/// the prompt + command and command output. Can be NULL. -/// -/// \param[in] commands -/// An array of LLDB commands to execute. -/// -/// \param[out] required_command_failed -/// If parsing of command directives is enabled, this variable is set to -/// \b true if one of the commands prefixed with \b ! fails. -/// -/// \param[in] parse_command_directives -/// If \b false, then command prefixes like \b ! or \b ? are not parsed and -/// each command is executed verbatim. -/// -/// \param[in] echo_commands -/// If \b true, the command are echoed to the stream. -/// -/// \return -/// A std::string that contains the prefix and all commands and -/// command output. -std::string RunLLDBCommands(lldb::SBDebugger &debugger, llvm::StringRef prefix, - const llvm::ArrayRef &commands, - bool &required_command_failed, - bool parse_command_directives = true, - bool echo_commands = false); - -/// Check if a thread has a stop reason. -/// -/// \param[in] thread -/// The LLDB thread object to check -/// -/// \return -/// \b True if the thread has a valid stop reason, \b false -/// otherwise. -bool ThreadHasStopReason(lldb::SBThread &thread); - -/// Given a LLDB frame, make a frame ID that is unique to a specific -/// thread and frame. -/// -/// DAP requires a Stackframe "id" to be unique, so we use the frame -/// index in the lower 32 bits and the thread index ID in the upper 32 -/// bits. -/// -/// \param[in] frame -/// The LLDB stack frame object generate the ID for -/// -/// \return -/// A unique integer that allows us to easily find the right -/// stack frame within a thread on subsequent VS code requests. -int64_t MakeDAPFrameID(lldb::SBFrame &frame); - -/// Given a DAP frame ID, convert to a LLDB thread index id. -/// -/// DAP requires a Stackframe "id" to be unique, so we use the frame -/// index in the lower THREAD_INDEX_SHIFT bits and the thread index ID in -/// the upper 32 - THREAD_INDEX_SHIFT bits. -/// -/// \param[in] dap_frame_id -/// The DAP frame ID to convert to a thread index ID. -/// -/// \return -/// The LLDB thread index ID. -uint32_t GetLLDBThreadIndexID(uint64_t dap_frame_id); - -/// Given a DAP frame ID, convert to a LLDB frame ID. -/// -/// DAP requires a Stackframe "id" to be unique, so we use the frame -/// index in the lower THREAD_INDEX_SHIFT bits and the thread index ID in -/// the upper 32 - THREAD_INDEX_SHIFT bits. -/// -/// \param[in] dap_frame_id -/// The DAP frame ID to convert to a frame ID. -/// -/// \return -/// The LLDB frame index ID. -uint32_t GetLLDBFrameID(uint64_t dap_frame_id); - -/// Gets all the environment variables from the json object depending on if the -/// kind is an object or an array. -/// -/// \param[in] arguments -/// The json object with the launch options -/// -/// \return -/// The environment variables stored in the env key -lldb::SBEnvironment -GetEnvironmentFromArguments(const llvm::json::Object &arguments); - -/// Gets an SBFileSpec and returns its path as a string. -/// -/// \param[in] file_spec -/// The file spec. -/// -/// \return -/// The file path as a string. -std::string GetSBFileSpecPath(const lldb::SBFileSpec &file_spec); - -/// Gets the line entry for a given address. -/// \param[in] target -/// The target that has the address. -/// -/// \param[in] address -/// The address for which to get the line entry. -/// -/// \return -/// The line entry for the given address. -lldb::SBLineEntry GetLineEntryForAddress(lldb::SBTarget &target, - const lldb::SBAddress &address); - -/// Helper for sending telemetry to lldb server, if client-telemetry is enabled. -class TelemetryDispatcher { -public: - TelemetryDispatcher(lldb::SBDebugger *debugger) { - m_telemetry_json = llvm::json::Object(); - m_telemetry_json.try_emplace( - "start_time", - std::chrono::steady_clock::now().time_since_epoch().count()); - this->debugger = debugger; - } - - void Set(std::string key, std::string value) { - m_telemetry_json.try_emplace(key, value); - } - - void Set(std::string key, int64_t value) { - m_telemetry_json.try_emplace(key, value); - } - - ~TelemetryDispatcher() { - m_telemetry_json.try_emplace( - "end_time", - std::chrono::steady_clock::now().time_since_epoch().count()); - - lldb::SBStructuredData telemetry_entry; - llvm::json::Value val(std::move(m_telemetry_json)); - - std::string string_rep = llvm::to_string(val); - telemetry_entry.SetFromJSON(string_rep.c_str()); - debugger->DispatchClientTelemetry(telemetry_entry); - } - -private: - llvm::json::Object m_telemetry_json; - lldb::SBDebugger *debugger; -}; - -/// RAII utility to put the debugger temporarily into synchronous mode. -class ScopeSyncMode { -public: - ScopeSyncMode(lldb::SBDebugger &debugger); - ~ScopeSyncMode(); - -private: - lldb::SBDebugger &m_debugger; - bool m_async; -}; - -/// Get the stop-disassembly-display settings -/// -/// \param[in] debugger -/// The debugger that will execute the lldb commands. -/// -/// \return -/// The value of the stop-disassembly-display setting -lldb::StopDisassemblyType GetStopDisassemblyDisplay(lldb::SBDebugger &debugger); - -/// Take ownership of the stored error. -llvm::Error ToError(const lldb::SBError &error); - -/// Provides the string value if this data structure is a string type. -std::string GetStringValue(const lldb::SBStructuredData &data); - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/Options.td b/lldb/tools/lldb-dap/Options.td deleted file mode 100644 index aecf91797ac7..000000000000 --- a/lldb/tools/lldb-dap/Options.td +++ /dev/null @@ -1,63 +0,0 @@ -include "llvm/Option/OptParser.td" - -class F: Flag<["--", "-"], name>; -class S: Separate<["--", "-"], name>; -class R prefixes, string name> - : Option; - -def help: F<"help">, - HelpText<"Prints out the usage information for the lldb-dap tool.">; -def: Flag<["-"], "h">, - Alias, - HelpText<"Alias for --help">; - -def version: F<"version">, - HelpText<"Prints out the lldb-dap version.">; -def: Flag<["-"], "v">, - Alias, - HelpText<"Alias for --version">; - -def wait_for_debugger: F<"wait-for-debugger">, - HelpText<"Pause the program at startup.">; -def: Flag<["-"], "g">, - Alias, - HelpText<"Alias for --wait-for-debugger">; - -def connection - : S<"connection">, - MetaVarName<"">, - HelpText< - "Communicate with the lldb-dap tool over the specified connection. " - "Connections are specified like 'tcp://[host]:port' or " - "'unix:///path'.">; - -def launch_target: S<"launch-target">, - MetaVarName<"">, - HelpText<"Launch a target for the launchInTerminal request. Any argument " - "provided after this one will be passed to the target. The parameter " - "--comm-file must also be specified.">; - -def comm_file: S<"comm-file">, - MetaVarName<"">, - HelpText<"The fifo file used to communicate the with the debug adapter " - "when using --launch-target.">; - -def debugger_pid: S<"debugger-pid">, - MetaVarName<"">, - HelpText<"The PID of the lldb-dap instance that sent the launchInTerminal " - "request when using --launch-target.">; - -def repl_mode - : S<"repl-mode">, - MetaVarName<"">, - HelpText< - "The mode for handling repl evaluation requests, supported modes: " - "variable, command, auto.">; - -def pre_init_command: S<"pre-init-command">, - MetaVarName<"">, - HelpText<"A command to execute before the DAP initialization request and " - "right after a Debugger has been created.">; -def: Separate<["-"], "c">, - Alias, - HelpText<"Alias for --pre-init-command">; diff --git a/lldb/tools/lldb-dap/OutputRedirector.cpp b/lldb/tools/lldb-dap/OutputRedirector.cpp deleted file mode 100644 index fe278faca87b..000000000000 --- a/lldb/tools/lldb-dap/OutputRedirector.cpp +++ /dev/null @@ -1,125 +0,0 @@ -//===-- OutputRedirector.cpp -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===/ - -#include "OutputRedirector.h" -#include "DAP.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include -#include -#if defined(_WIN32) -#include -#include -#else -#include -#endif - -using namespace llvm; - -static constexpr auto kCloseSentinel = StringLiteral::withInnerNUL("\0"); - -namespace lldb_dap { - -int OutputRedirector::kInvalidDescriptor = -1; - -OutputRedirector::OutputRedirector() - : m_fd(kInvalidDescriptor), m_original_fd(kInvalidDescriptor), - m_restore_fd(kInvalidDescriptor) {} - -Expected OutputRedirector::GetWriteFileDescriptor() { - if (m_fd == kInvalidDescriptor) - return createStringError(std::errc::bad_file_descriptor, - "write handle is not open for writing"); - return m_fd; -} - -Error OutputRedirector::RedirectTo(std::FILE *file_override, - std::function callback) { - assert(m_fd == kInvalidDescriptor && "Output readirector already started."); - int new_fd[2]; - -#if defined(_WIN32) - if (::_pipe(new_fd, OutputBufferSize, O_TEXT) == -1) { -#else - if (::pipe(new_fd) == -1) { -#endif - int error = errno; - return createStringError(inconvertibleErrorCode(), - "Couldn't create new pipe %s", strerror(error)); - } - - int read_fd = new_fd[0]; - m_fd = new_fd[1]; - - if (file_override) { - int override_fd = fileno(file_override); - - // Backup the FD to restore once redirection is complete. - m_original_fd = override_fd; - m_restore_fd = dup(override_fd); - - // Override the existing fd the new write end of the pipe. - if (::dup2(m_fd, override_fd) == -1) - return llvm::errorCodeToError(llvm::errnoAsErrorCode()); - } - - m_forwarder = std::thread([this, callback, read_fd]() { - char buffer[OutputBufferSize]; - while (!m_stopped) { - ssize_t bytes_count = ::read(read_fd, &buffer, sizeof(buffer)); - if (bytes_count == -1) { - // Skip non-fatal errors. - if (errno == EAGAIN || errno == EINTR || errno == EWOULDBLOCK) - continue; - break; - } - // Skip the null byte used to trigger a Stop. - if (bytes_count == 1 && buffer[0] == '\0') - continue; - - StringRef data(buffer, bytes_count); - if (m_stopped) - data.consume_back(kCloseSentinel); - if (data.empty()) - break; - - callback(data); - } - ::close(read_fd); - }); - - return Error::success(); -} - -void OutputRedirector::Stop() { - m_stopped = true; - - if (m_fd != kInvalidDescriptor) { - int fd = m_fd; - m_fd = kInvalidDescriptor; - // Closing the pipe may not be sufficient to wake up the thread in case the - // write descriptor is duplicated (to stdout/err or to another process). - // Write a null byte to ensure the read call returns. - (void)::write(fd, kCloseSentinel.data(), kCloseSentinel.size()); - ::close(fd); - m_forwarder.join(); - - // Restore the fd back to its original state since we stopped the - // redirection. - if (m_restore_fd != kInvalidDescriptor && - m_original_fd != kInvalidDescriptor) { - int restore_fd = m_restore_fd; - m_restore_fd = kInvalidDescriptor; - int original_fd = m_original_fd; - m_original_fd = kInvalidDescriptor; - ::dup2(restore_fd, original_fd); - } - } -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/OutputRedirector.h b/lldb/tools/lldb-dap/OutputRedirector.h deleted file mode 100644 index 77b1b76ec4d8..000000000000 --- a/lldb/tools/lldb-dap/OutputRedirector.h +++ /dev/null @@ -1,58 +0,0 @@ -//===-- OutputRedirector.h -------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===/ - -#ifndef LLDB_TOOLS_LLDB_DAP_OUTPUT_REDIRECTOR_H -#define LLDB_TOOLS_LLDB_DAP_OUTPUT_REDIRECTOR_H - -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include -#include -#include - -namespace lldb_dap { - -class OutputRedirector { -public: - static int kInvalidDescriptor; - - /// Creates writable file descriptor that will invoke the given callback on - /// each write in a background thread. - /// - /// \param[in] file_override - /// Updates the file descriptor to the redirection pipe, if not null. - /// - /// \param[in] callback - /// A callback invoked when any data is written to the file handle. - /// - /// \return - /// \a Error::success if the redirection was set up correctly, or an error - /// otherwise. - llvm::Error RedirectTo(std::FILE *file_override, - std::function callback); - - llvm::Expected GetWriteFileDescriptor(); - void Stop(); - - ~OutputRedirector() { Stop(); } - - OutputRedirector(); - OutputRedirector(const OutputRedirector &) = delete; - OutputRedirector &operator=(const OutputRedirector &) = delete; - -private: - std::atomic m_stopped = false; - int m_fd; - int m_original_fd; - int m_restore_fd; - std::thread m_forwarder; -}; - -} // namespace lldb_dap - -#endif // LLDB_TOOLS_LLDB_DAP_OUTPUT_REDIRECTOR_H diff --git a/lldb/tools/lldb-dap/ProgressEvent.cpp b/lldb/tools/lldb-dap/ProgressEvent.cpp deleted file mode 100644 index e53ec40180a6..000000000000 --- a/lldb/tools/lldb-dap/ProgressEvent.cpp +++ /dev/null @@ -1,237 +0,0 @@ -//===-- ProgressEvent.cpp ---------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "ProgressEvent.h" - -#include "JSONUtils.h" -#include "llvm/Support/ErrorHandling.h" -#include - -using namespace lldb_dap; -using namespace llvm; - -// The minimum duration of an event for it to be reported -const std::chrono::duration kStartProgressEventReportDelay = - std::chrono::seconds(1); -// The minimum time interval between update events for reporting. If multiple -// updates fall within the same time interval, only the latest is reported. -const std::chrono::duration kUpdateProgressEventReportDelay = - std::chrono::milliseconds(250); - -ProgressEvent::ProgressEvent(uint64_t progress_id, - std::optional message, - uint64_t completed, uint64_t total, - const ProgressEvent *prev_event) - : m_progress_id(progress_id) { - if (message) - m_message = message->str(); - - const bool calculate_percentage = total != UINT64_MAX; - if (completed == 0) { - // Start event - m_event_type = progressStart; - // Wait a bit before reporting the start event in case in completes really - // quickly. - m_minimum_allowed_report_time = - m_creation_time + kStartProgressEventReportDelay; - if (calculate_percentage) - m_percentage = 0; - } else if (completed == total) { - // End event - m_event_type = progressEnd; - // We should report the end event right away. - m_minimum_allowed_report_time = std::chrono::seconds::zero(); - if (calculate_percentage) - m_percentage = 100; - } else { - // Update event - m_event_type = progressUpdate; - m_percentage = std::min( - (uint32_t)((double)completed / (double)total * 100.0), (uint32_t)99); - if (prev_event->Reported()) { - // Add a small delay between reports - m_minimum_allowed_report_time = - prev_event->m_minimum_allowed_report_time + - kUpdateProgressEventReportDelay; - } else { - // We should use the previous timestamp, as it's still pending - m_minimum_allowed_report_time = prev_event->m_minimum_allowed_report_time; - } - } -} - -std::optional -ProgressEvent::Create(uint64_t progress_id, std::optional message, - uint64_t completed, uint64_t total, - const ProgressEvent *prev_event) { - // If it's an update without a previous event, we abort - if (completed > 0 && completed < total && !prev_event) - return std::nullopt; - ProgressEvent event(progress_id, message, completed, total, prev_event); - // We shouldn't show unnamed start events in the IDE - if (event.GetEventType() == progressStart && event.GetEventName().empty()) - return std::nullopt; - - if (prev_event && prev_event->EqualsForIDE(event)) - return std::nullopt; - - return event; -} - -bool ProgressEvent::EqualsForIDE(const ProgressEvent &other) const { - return m_progress_id == other.m_progress_id && - m_event_type == other.m_event_type && - m_percentage == other.m_percentage && m_message == other.m_message; -} - -ProgressEventType ProgressEvent::GetEventType() const { return m_event_type; } - -StringRef ProgressEvent::GetEventName() const { - switch (m_event_type) { - case progressStart: - return "progressStart"; - case progressUpdate: - return "progressUpdate"; - case progressEnd: - return "progressEnd"; - } - llvm_unreachable("All cases handled above!"); -} - -json::Value ProgressEvent::ToJSON() const { - llvm::json::Object event(CreateEventObject(GetEventName())); - llvm::json::Object body; - - std::string progress_id_str; - llvm::raw_string_ostream progress_id_strm(progress_id_str); - progress_id_strm << m_progress_id; - body.try_emplace("progressId", progress_id_str); - - if (m_event_type == progressStart) { - EmplaceSafeString(body, "title", m_message); - body.try_emplace("cancellable", false); - } - - if (m_event_type == progressUpdate) - EmplaceSafeString(body, "message", m_message); - - std::string timestamp(llvm::formatv("{0:f9}", m_creation_time.count())); - EmplaceSafeString(body, "timestamp", timestamp); - - if (m_percentage) - body.try_emplace("percentage", *m_percentage); - - event.try_emplace("body", std::move(body)); - return json::Value(std::move(event)); -} - -bool ProgressEvent::Report(ProgressEventReportCallback callback) { - if (Reported()) - return true; - if (std::chrono::system_clock::now().time_since_epoch() < - m_minimum_allowed_report_time) - return false; - - m_reported = true; - callback(*this); - return true; -} - -bool ProgressEvent::Reported() const { return m_reported; } - -ProgressEventManager::ProgressEventManager( - const ProgressEvent &start_event, - ProgressEventReportCallback report_callback) - : m_start_event(start_event), m_finished(false), - m_report_callback(report_callback) {} - -bool ProgressEventManager::ReportIfNeeded() { - // The event finished before we were able to report it. - if (!m_start_event.Reported() && Finished()) - return true; - - if (!m_start_event.Report(m_report_callback)) - return false; - - if (m_last_update_event) - m_last_update_event->Report(m_report_callback); - return true; -} - -const ProgressEvent &ProgressEventManager::GetMostRecentEvent() const { - return m_last_update_event ? *m_last_update_event : m_start_event; -} - -void ProgressEventManager::Update(uint64_t progress_id, llvm::StringRef message, - uint64_t completed, uint64_t total) { - if (std::optional event = ProgressEvent::Create( - progress_id, message, completed, total, &GetMostRecentEvent())) { - if (event->GetEventType() == progressEnd) - m_finished = true; - - m_last_update_event = *event; - ReportIfNeeded(); - } -} - -bool ProgressEventManager::Finished() const { return m_finished; } - -ProgressEventReporter::ProgressEventReporter( - ProgressEventReportCallback report_callback) - : m_report_callback(report_callback) { - m_thread_should_exit = false; - m_thread = std::thread([&] { - while (!m_thread_should_exit) { - std::this_thread::sleep_for(kUpdateProgressEventReportDelay); - ReportStartEvents(); - } - }); -} - -ProgressEventReporter::~ProgressEventReporter() { - m_thread_should_exit = true; - m_thread.join(); -} - -void ProgressEventReporter::ReportStartEvents() { - std::lock_guard locker(m_mutex); - - while (!m_unreported_start_events.empty()) { - ProgressEventManagerSP event_manager = m_unreported_start_events.front(); - if (event_manager->Finished()) - m_unreported_start_events.pop(); - else if (event_manager->ReportIfNeeded()) - m_unreported_start_events - .pop(); // we remove it from the queue as it started reporting - // already, the Push method will be able to continue its - // reports. - else - break; // If we couldn't report it, then the next event in the queue won't - // be able as well, as it came later. - } -} - -void ProgressEventReporter::Push(uint64_t progress_id, const char *message, - uint64_t completed, uint64_t total) { - std::lock_guard locker(m_mutex); - - auto it = m_event_managers.find(progress_id); - if (it == m_event_managers.end()) { - if (std::optional event = ProgressEvent::Create( - progress_id, StringRef(message), completed, total)) { - ProgressEventManagerSP event_manager = - std::make_shared(*event, m_report_callback); - m_event_managers.insert({progress_id, event_manager}); - m_unreported_start_events.push(event_manager); - } - } else { - it->second->Update(progress_id, StringRef(message), completed, total); - if (it->second->Finished()) - m_event_managers.erase(it); - } -} diff --git a/lldb/tools/lldb-dap/ProgressEvent.h b/lldb/tools/lldb-dap/ProgressEvent.h deleted file mode 100644 index d1b9b9dd887c..000000000000 --- a/lldb/tools/lldb-dap/ProgressEvent.h +++ /dev/null @@ -1,158 +0,0 @@ -//===-- ProgressEvent.cpp ---------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include -#include -#include -#include -#include -#include - -#include "DAPForward.h" - -#include "llvm/Support/JSON.h" - -namespace lldb_dap { - -enum ProgressEventType { progressStart, progressUpdate, progressEnd }; - -class ProgressEvent; -using ProgressEventReportCallback = std::function; - -class ProgressEvent { -public: - /// Actual constructor to use that returns an optional, as the event might be - /// not apt for the IDE, e.g. an unnamed start event, or a redundant one. - /// - /// \param[in] progress_id - /// ID for this event. - /// - /// \param[in] message - /// Message to display in the UI. Required for start events. - /// - /// \param[in] completed - /// Number of jobs completed. - /// - /// \param[in] total - /// Total number of jobs, or \b UINT64_MAX if not determined. - /// - /// \param[in] prev_event - /// Previous event if this one is an update. If \b nullptr, then a start - /// event will be created. - static std::optional - Create(uint64_t progress_id, std::optional message, - uint64_t completed, uint64_t total, - const ProgressEvent *prev_event = nullptr); - - llvm::json::Value ToJSON() const; - - /// \return - /// \b true if two event messages would result in the same event for the - /// IDE, e.g. same rounded percentage. - bool EqualsForIDE(const ProgressEvent &other) const; - - llvm::StringRef GetEventName() const; - - ProgressEventType GetEventType() const; - - /// Report this progress event to the provided callback only if enough time - /// has passed since the creation of the event and since the previous reported - /// update. - bool Report(ProgressEventReportCallback callback); - - bool Reported() const; - -private: - ProgressEvent(uint64_t progress_id, std::optional message, - uint64_t completed, uint64_t total, - const ProgressEvent *prev_event); - - uint64_t m_progress_id; - std::string m_message; - ProgressEventType m_event_type; - std::optional m_percentage; - std::chrono::duration m_creation_time = - std::chrono::system_clock::now().time_since_epoch(); - std::chrono::duration m_minimum_allowed_report_time; - bool m_reported = false; -}; - -/// Class that keeps the start event and its most recent update. -/// It controls when the event should start being reported to the IDE. -class ProgressEventManager { -public: - ProgressEventManager(const ProgressEvent &start_event, - ProgressEventReportCallback report_callback); - - /// Report the start event and the most recent update if the event has lasted - /// for long enough. - /// - /// \return - /// \b false if the event hasn't finished and hasn't reported anything - /// yet. - bool ReportIfNeeded(); - - /// Receive a new progress event for the start event and try to report it if - /// appropriate. - void Update(uint64_t progress_id, llvm::StringRef message, uint64_t completed, - uint64_t total); - - /// \return - /// \b true if a \a progressEnd event has been notified. There's no - /// need to try to report manually an event that has finished. - bool Finished() const; - - const ProgressEvent &GetMostRecentEvent() const; - -private: - ProgressEvent m_start_event; - std::optional m_last_update_event; - bool m_finished; - ProgressEventReportCallback m_report_callback; -}; - -using ProgressEventManagerSP = std::shared_ptr; - -/// Class that filters out progress event messages that shouldn't be reported -/// to the IDE, because they are invalid, they carry no new information, or they -/// don't last long enough. -/// -/// We need to limit the amount of events that are sent to the IDE, as they slow -/// the render thread of the UI user, and they end up spamming the DAP -/// connection, which also takes some processing time out of the IDE. -class ProgressEventReporter { -public: - /// \param[in] report_callback - /// Function to invoke to report the event to the IDE. - ProgressEventReporter(ProgressEventReportCallback report_callback); - - ~ProgressEventReporter(); - - /// Add a new event to the internal queue and report the event if - /// appropriate. - void Push(uint64_t progress_id, const char *message, uint64_t completed, - uint64_t total); - -private: - /// Report to the IDE events that haven't been reported to the IDE and have - /// lasted long enough. - void ReportStartEvents(); - - ProgressEventReportCallback m_report_callback; - std::map m_event_managers; - /// Queue of start events in chronological order - std::queue m_unreported_start_events; - /// Thread used to invoke \a ReportStartEvents periodically. - std::thread m_thread; - std::atomic m_thread_should_exit; - /// Mutex that prevents running \a Push and \a ReportStartEvents - /// simultaneously, as both read and modify the same underlying objects. - std::mutex m_mutex; -}; - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp deleted file mode 100644 index bc4fee4aa8b8..000000000000 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.cpp +++ /dev/null @@ -1,298 +0,0 @@ -//===-- ProtocolBase.cpp --------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Protocol/ProtocolBase.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/ADT/StringSwitch.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/JSON.h" -#include -#include - -using namespace llvm; - -static bool mapRaw(const json::Value &Params, StringLiteral Prop, - std::optional &V, json::Path P) { - const auto *O = Params.getAsObject(); - if (!O) { - P.report("expected object"); - return false; - } - const json::Value *E = O->get(Prop); - if (E) - V = std::move(*E); - return true; -} - -namespace lldb_dap::protocol { - -enum MessageType : unsigned { - eMessageTypeRequest, - eMessageTypeResponse, - eMessageTypeEvent -}; - -bool fromJSON(const json::Value &Params, MessageType &M, json::Path P) { - auto rawType = Params.getAsString(); - if (!rawType) { - P.report("expected a string"); - return false; - } - std::optional type = - StringSwitch>(*rawType) - .Case("request", eMessageTypeRequest) - .Case("response", eMessageTypeResponse) - .Case("event", eMessageTypeEvent) - .Default(std::nullopt); - if (!type) { - P.report("unexpected value, expected 'request', 'response' or 'event'"); - return false; - } - M = *type; - return true; -} - -json::Value toJSON(const Request &R) { - json::Object Result{ - {"type", "request"}, - {"seq", R.seq}, - {"command", R.command}, - }; - - if (R.arguments) - Result.insert({"arguments", R.arguments}); - - return std::move(Result); -} - -bool fromJSON(json::Value const &Params, Request &R, json::Path P) { - json::ObjectMapper O(Params, P); - if (!O) - return false; - - MessageType type; - if (!O.map("type", type) || !O.map("command", R.command) || - !O.map("seq", R.seq)) - return false; - - if (type != eMessageTypeRequest) { - P.field("type").report("expected to be 'request'"); - return false; - } - - if (R.command.empty()) { - P.field("command").report("expected to not be ''"); - return false; - } - - if (!R.seq) { - P.field("seq").report("expected to not be '0'"); - return false; - } - - return mapRaw(Params, "arguments", R.arguments, P); -} - -json::Value toJSON(const Response &R) { - json::Object Result{{"type", "response"}, - {"seq", 0}, - {"command", R.command}, - {"request_seq", R.request_seq}, - {"success", R.success}}; - - if (R.message) { - assert(!R.success && "message can only be used if success is false"); - if (const auto *messageEnum = std::get_if(&*R.message)) { - switch (*messageEnum) { - case eResponseMessageCancelled: - Result.insert({"message", "cancelled"}); - break; - case eResponseMessageNotStopped: - Result.insert({"message", "notStopped"}); - break; - } - } else if (const auto *messageString = - std::get_if(&*R.message)) { - Result.insert({"message", *messageString}); - } - } - - if (R.body) - Result.insert({"body", R.body}); - - return std::move(Result); -} - -bool fromJSON(json::Value const &Params, - std::variant &M, json::Path P) { - auto rawMessage = Params.getAsString(); - if (!rawMessage) { - P.report("expected a string"); - return false; - } - std::optional message = - StringSwitch>(*rawMessage) - .Case("cancelled", eResponseMessageCancelled) - .Case("notStopped", eResponseMessageNotStopped) - .Default(std::nullopt); - if (message) - M = *message; - else if (!rawMessage->empty()) - M = rawMessage->str(); - return true; -} - -bool fromJSON(json::Value const &Params, Response &R, json::Path P) { - json::ObjectMapper O(Params, P); - if (!O) - return false; - - MessageType type; - int64_t seq; - if (!O.map("type", type) || !O.map("seq", seq) || - !O.map("command", R.command) || !O.map("request_seq", R.request_seq)) - return false; - - if (type != eMessageTypeResponse) { - P.field("type").report("expected to be 'response'"); - return false; - } - - if (R.command.empty()) { - P.field("command").report("expected to not be ''"); - return false; - } - - if (R.request_seq == 0) { - P.field("request_seq").report("expected to not be '0'"); - return false; - } - - return O.map("success", R.success) && O.map("message", R.message) && - mapRaw(Params, "body", R.body, P); -} - -json::Value toJSON(const ErrorMessage &EM) { - json::Object Result{{"id", EM.id}, {"format", EM.format}}; - - if (EM.variables) { - json::Object variables; - for (auto &var : *EM.variables) - variables[var.first] = var.second; - Result.insert({"variables", std::move(variables)}); - } - if (EM.sendTelemetry) - Result.insert({"sendTelemetry", EM.sendTelemetry}); - if (EM.showUser) - Result.insert({"showUser", EM.showUser}); - if (EM.url) - Result.insert({"url", EM.url}); - if (EM.urlLabel) - Result.insert({"urlLabel", EM.urlLabel}); - - return std::move(Result); -} - -bool fromJSON(json::Value const &Params, ErrorMessage &EM, json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("id", EM.id) && O.map("format", EM.format) && - O.map("variables", EM.variables) && - O.map("sendTelemetry", EM.sendTelemetry) && - O.map("showUser", EM.showUser) && O.map("url", EM.url) && - O.map("urlLabel", EM.urlLabel); -} - -json::Value toJSON(const Event &E) { - json::Object Result{ - {"type", "event"}, - {"seq", 0}, - {"event", E.event}, - }; - - if (E.body) - Result.insert({"body", E.body}); - - return std::move(Result); -} - -bool fromJSON(json::Value const &Params, Event &E, json::Path P) { - json::ObjectMapper O(Params, P); - if (!O) - return false; - - MessageType type; - int64_t seq; - if (!O.map("type", type) || !O.map("seq", seq) || !O.map("event", E.event)) - return false; - - if (type != eMessageTypeEvent) { - P.field("type").report("expected to be 'event'"); - return false; - } - - if (seq != 0) { - P.field("seq").report("expected to be '0'"); - return false; - } - - if (E.event.empty()) { - P.field("event").report("expected to not be ''"); - return false; - } - - return mapRaw(Params, "body", E.body, P); -} - -bool fromJSON(const json::Value &Params, Message &PM, json::Path P) { - json::ObjectMapper O(Params, P); - if (!O) - return false; - - MessageType type; - if (!O.map("type", type)) - return false; - - switch (type) { - case eMessageTypeRequest: { - Request req; - if (!fromJSON(Params, req, P)) - return false; - PM = std::move(req); - return true; - } - case eMessageTypeResponse: { - Response resp; - if (!fromJSON(Params, resp, P)) - return false; - PM = std::move(resp); - return true; - } - case eMessageTypeEvent: - Event evt; - if (!fromJSON(Params, evt, P)) - return false; - PM = std::move(evt); - return true; - } - llvm_unreachable("unhandled message type request."); -} - -json::Value toJSON(const Message &M) { - return std::visit([](auto &M) { return toJSON(M); }, M); -} - -json::Value toJSON(const ErrorResponseBody &E) { - json::Object result{}; - - if (E.error) - result.insert({"error", *E.error}); - - return result; -} - -} // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h b/lldb/tools/lldb-dap/Protocol/ProtocolBase.h deleted file mode 100644 index 724da59b50cd..000000000000 --- a/lldb/tools/lldb-dap/Protocol/ProtocolBase.h +++ /dev/null @@ -1,164 +0,0 @@ -//===-- ProtocolBase.h ----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains POD structs based on the DAP specification at -// https://microsoft.github.io/debug-adapter-protocol/specification -// -// This is not meant to be a complete implementation, new interfaces are added -// when they're needed. -// -// Each struct has a toJSON and fromJSON function, that converts between -// the struct and a JSON representation. (See JSON.h) -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_H -#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_H - -#include "llvm/Support/JSON.h" -#include -#include -#include -#include - -namespace lldb_dap::protocol { - -// MARK: Base Protocol - -/// A client or debug adapter initiated request. -struct Request { - /// Sequence number of the message (also known as message ID). The `seq` for - /// the first message sent by a client or debug adapter is 1, and for each - /// subsequent message is 1 greater than the previous message sent by that - /// actor. `seq` can be used to order requests, responses, and events, and to - /// associate requests with their corresponding responses. For protocol - /// messages of type `request` the sequence number can be used to cancel the - /// request. - int64_t seq; - - /// The command to execute. - std::string command; - - /// Object containing arguments for the command. - /// - /// Request handlers are expected to validate the arguments, which is handled - /// by `RequestHandler`. - std::optional arguments; -}; -llvm::json::Value toJSON(const Request &); -bool fromJSON(const llvm::json::Value &, Request &, llvm::json::Path); - -/// A debug adapter initiated event. -struct Event { - /// Type of event. - std::string event; - - /// Event-specific information. - std::optional body; -}; -llvm::json::Value toJSON(const Event &); -bool fromJSON(const llvm::json::Value &, Event &, llvm::json::Path); - -enum ResponseMessage : unsigned { - /// The request was cancelled - eResponseMessageCancelled, - /// The request may be retried once the adapter is in a 'stopped' state - eResponseMessageNotStopped, -}; - -/// Response for a request. -struct Response { - /// Sequence number of the corresponding request. - int64_t request_seq; - - /// The command requested. - std::string command; - - /// Outcome of the request. If true, the request was successful and the `body` - /// attribute may contain the result of the request. If the value is false, - /// the attribute `message` contains the error in short form and the `body` - /// may contain additional information (see `ErrorMessage`). - bool success; - - // FIXME: Migrate usage of fallback string to ErrorMessage - - /// Contains the raw error in short form if `success` is false. This raw error - /// might be interpreted by the client and is not shown in the UI. Some - /// predefined values exist. - std::optional> message; - - /// Contains request result if success is true and error details if success is - /// false. - /// - /// Request handlers are expected to build an appropriate body, see - /// `RequestHandler`. - std::optional body; -}; -bool fromJSON(const llvm::json::Value &, Response &, llvm::json::Path); -llvm::json::Value toJSON(const Response &); - -/// A structured message object. Used to return errors from requests. -struct ErrorMessage { - /// Unique (within a debug adapter implementation) identifier for the message. - /// The purpose of these error IDs is to help extension authors that have the - /// requirement that every user visible error message needs a corresponding - /// error number, so that users or customer support can find information about - /// the specific error more easily. - uint64_t id = 0; - - /// A format string for the message. Embedded variables have the form - /// `{name}`. If variable name starts with an underscore character, the - /// variable does not contain user data (PII) and can be safely used for - /// telemetry purposes. - std::string format; - - /// An object used as a dictionary for looking up the variables in the format - /// string. - std::optional> variables; - - /// If true send to telemetry. - bool sendTelemetry = false; - - /// If true show user. - bool showUser = false; - - /// A url where additional information about this message can be found. - std::optional url; - - /// A label that is presented to the user as the UI for opening the url. - std::optional urlLabel; -}; -bool fromJSON(const llvm::json::Value &, ErrorMessage &, llvm::json::Path); -llvm::json::Value toJSON(const ErrorMessage &); - -/// An individual protocol message of requests, responses, and events. -using Message = std::variant; -bool fromJSON(const llvm::json::Value &, Message &, llvm::json::Path); -llvm::json::Value toJSON(const Message &); - -inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Message &V) { - OS << toJSON(V); - return OS; -} - -/// On error (whenever `success` is false), the body can provide more details. -struct ErrorResponseBody { - /// A structured error message. - std::optional error; -}; -llvm::json::Value toJSON(const ErrorResponseBody &); - -/// This is a placehold for requests with an empty, null or undefined arguments. -using EmptyArguments = std::optional; - -/// This is just an acknowledgement, so no body field is required. -using VoidResponse = llvm::Error; - -} // namespace lldb_dap::protocol - -#endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp deleted file mode 100644 index a7f28fb566d3..000000000000 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp +++ /dev/null @@ -1,490 +0,0 @@ -//===-- ProtocolRequests.cpp ----------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Protocol/ProtocolRequests.h" -#include "llvm/ADT/DenseMap.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/JSON.h" -#include - -using namespace llvm; - -// The 'env' field is either an object as a map of strings or as an array of -// strings formatted like 'key=value'. -static bool parseEnv(const json::Value &Params, StringMap &env, - json::Path P) { - const json::Object *O = Params.getAsObject(); - if (!O) { - P.report("expected object"); - return false; - } - - const json::Value *value = O->get("env"); - if (!value) - return true; - - if (const json::Object *env_obj = value->getAsObject()) { - for (const auto &kv : *env_obj) { - const std::optional value = kv.second.getAsString(); - if (!value) { - P.field("env").field(kv.first).report("expected string value"); - return false; - } - env.insert({kv.first.str(), value->str()}); - } - return true; - } - - if (const json::Array *env_arr = value->getAsArray()) { - for (size_t i = 0; i < env_arr->size(); ++i) { - const std::optional value = (*env_arr)[i].getAsString(); - if (!value) { - P.field("env").index(i).report("expected string"); - return false; - } - std::pair kv = value->split("="); - env.insert({kv.first, kv.second.str()}); - } - - return true; - } - - P.field("env").report("invalid format, expected array or object"); - return false; -} - -static bool parseTimeout(const json::Value &Params, std::chrono::seconds &S, - json::Path P) { - const json::Object *O = Params.getAsObject(); - if (!O) { - P.report("expected object"); - return false; - } - - const json::Value *value = O->get("timeout"); - if (!value) - return true; - std::optional timeout = value->getAsNumber(); - if (!timeout) { - P.field("timeout").report("expected number"); - return false; - } - - S = std::chrono::duration_cast( - std::chrono::duration(*value->getAsNumber())); - return true; -} - -static bool -parseSourceMap(const json::Value &Params, - std::vector> &sourceMap, - json::Path P) { - const json::Object *O = Params.getAsObject(); - if (!O) { - P.report("expected object"); - return false; - } - - const json::Value *value = O->get("sourceMap"); - if (!value) - return true; - - if (const json::Object *map_obj = value->getAsObject()) { - for (const auto &kv : *map_obj) { - const std::optional value = kv.second.getAsString(); - if (!value) { - P.field("sourceMap").field(kv.first).report("expected string value"); - return false; - } - sourceMap.emplace_back(std::make_pair(kv.first.str(), value->str())); - } - return true; - } - - if (const json::Array *env_arr = value->getAsArray()) { - for (size_t i = 0; i < env_arr->size(); ++i) { - const json::Array *kv = (*env_arr)[i].getAsArray(); - if (!kv) { - P.field("sourceMap").index(i).report("expected array"); - return false; - } - if (kv->size() != 2) { - P.field("sourceMap").index(i).report("expected array of pairs"); - return false; - } - const std::optional first = (*kv)[0].getAsString(); - if (!first) { - P.field("sourceMap").index(0).report("expected string"); - return false; - } - const std::optional second = (*kv)[1].getAsString(); - if (!second) { - P.field("sourceMap").index(1).report("expected string"); - return false; - } - sourceMap.emplace_back(std::make_pair(*first, second->str())); - } - - return true; - } - - P.report("invalid format, expected array or object"); - return false; -} - -namespace lldb_dap::protocol { - -bool fromJSON(const llvm::json::Value &Params, CancelArguments &CA, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.map("requestId", CA.requestId) && - O.map("progressId", CA.progressId); -} - -bool fromJSON(const json::Value &Params, DisconnectArguments &DA, - json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("restart", DA.restart) && - O.map("terminateDebuggee", DA.terminateDebuggee) && - O.map("suspendDebuggee", DA.suspendDebuggee); -} - -bool fromJSON(const json::Value &Params, PathFormat &PF, json::Path P) { - auto rawPathFormat = Params.getAsString(); - if (!rawPathFormat) { - P.report("expected a string"); - return false; - } - - std::optional pathFormat = - StringSwitch>(*rawPathFormat) - .Case("path", ePatFormatPath) - .Case("uri", ePathFormatURI) - .Default(std::nullopt); - if (!pathFormat) { - P.report("unexpected value, expected 'path' or 'uri'"); - return false; - } - - PF = *pathFormat; - return true; -} - -static const StringMap ClientFeatureByKey{ - {"supportsVariableType", eClientFeatureVariableType}, - {"supportsVariablePaging", eClientFeatureVariablePaging}, - {"supportsRunInTerminalRequest", eClientFeatureRunInTerminalRequest}, - {"supportsMemoryReferences", eClientFeatureMemoryReferences}, - {"supportsProgressReporting", eClientFeatureProgressReporting}, - {"supportsInvalidatedEvent", eClientFeatureInvalidatedEvent}, - {"supportsMemoryEvent", eClientFeatureMemoryEvent}, - {"supportsArgsCanBeInterpretedByShell", - eClientFeatureArgsCanBeInterpretedByShell}, - {"supportsStartDebuggingRequest", eClientFeatureStartDebuggingRequest}, - {"supportsANSIStyling", eClientFeatureANSIStyling}}; - -bool fromJSON(const json::Value &Params, InitializeRequestArguments &IRA, - json::Path P) { - json::ObjectMapper OM(Params, P); - if (!OM) - return false; - - const json::Object *O = Params.getAsObject(); - - for (auto &kv : ClientFeatureByKey) { - const json::Value *value_ref = O->get(kv.first()); - if (!value_ref) - continue; - - const std::optional value = value_ref->getAsBoolean(); - if (!value) { - P.field(kv.first()).report("expected bool"); - return false; - } - - if (*value) - IRA.supportedFeatures.insert(kv.second); - } - - return OM.map("adapterID", IRA.adapterID) && - OM.map("clientID", IRA.clientID) && - OM.map("clientName", IRA.clientName) && OM.map("locale", IRA.locale) && - OM.map("linesStartAt1", IRA.linesStartAt1) && - OM.map("columnsStartAt1", IRA.columnsStartAt1) && - OM.map("pathFormat", IRA.pathFormat) && - OM.map("$__lldb_sourceInitFile", IRA.lldbExtSourceInitFile); -} - -bool fromJSON(const json::Value &Params, Configuration &C, json::Path P) { - json::ObjectMapper O(Params, P); - return O.mapOptional("debuggerRoot", C.debuggerRoot) && - O.mapOptional("enableAutoVariableSummaries", - C.enableAutoVariableSummaries) && - O.mapOptional("enableSyntheticChildDebugging", - C.enableSyntheticChildDebugging) && - O.mapOptional("displayExtendedBacktrace", - C.displayExtendedBacktrace) && - O.mapOptional("stopOnEntry", C.stopOnEntry) && - O.mapOptional("commandEscapePrefix", C.commandEscapePrefix) && - O.mapOptional("customFrameFormat", C.customFrameFormat) && - O.mapOptional("customThreadFormat", C.customThreadFormat) && - O.mapOptional("sourcePath", C.sourcePath) && - O.mapOptional("initCommands", C.initCommands) && - O.mapOptional("preRunCommands", C.preRunCommands) && - O.mapOptional("postRunCommands", C.postRunCommands) && - O.mapOptional("stopCommands", C.stopCommands) && - O.mapOptional("exitCommands", C.exitCommands) && - O.mapOptional("terminateCommands", C.terminateCommands) && - O.mapOptional("program", C.program) && - O.mapOptional("targetTriple", C.targetTriple) && - O.mapOptional("platformName", C.platformName) && - parseSourceMap(Params, C.sourceMap, P) && - parseTimeout(Params, C.timeout, P); -} - -bool fromJSON(const json::Value &Params, BreakpointLocationsArguments &BLA, - json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("source", BLA.source) && O.map("line", BLA.line) && - O.mapOptional("column", BLA.column) && - O.mapOptional("endLine", BLA.endLine) && - O.mapOptional("endColumn", BLA.endColumn); -} - -llvm::json::Value toJSON(const BreakpointLocationsResponseBody &BLRB) { - llvm::json::Array breakpoints_json; - for (const auto &breakpoint : BLRB.breakpoints) { - breakpoints_json.push_back(toJSON(breakpoint)); - } - return llvm::json::Object{{"breakpoints", std::move(breakpoints_json)}}; -} - -bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA, - json::Path P) { - json::ObjectMapper O(Params, P); - return O && fromJSON(Params, LRA.configuration, P) && - O.mapOptional("noDebug", LRA.noDebug) && - O.mapOptional("launchCommands", LRA.launchCommands) && - O.mapOptional("cwd", LRA.cwd) && O.mapOptional("args", LRA.args) && - O.mapOptional("detachOnError", LRA.detachOnError) && - O.mapOptional("disableASLR", LRA.disableASLR) && - O.mapOptional("disableSTDIO", LRA.disableSTDIO) && - O.mapOptional("shellExpandArguments", LRA.shellExpandArguments) && - - O.mapOptional("runInTerminal", LRA.runInTerminal) && - parseEnv(Params, LRA.env, P); -} - -bool fromJSON(const json::Value &Params, AttachRequestArguments &ARA, - json::Path P) { - json::ObjectMapper O(Params, P); - return O && fromJSON(Params, ARA.configuration, P) && - O.mapOptional("attachCommands", ARA.attachCommands) && - O.mapOptional("pid", ARA.pid) && - O.mapOptional("waitFor", ARA.waitFor) && - O.mapOptional("gdb-remote-port", ARA.gdbRemotePort) && - O.mapOptional("gdb-remote-hostname", ARA.gdbRemoteHostname) && - O.mapOptional("coreFile", ARA.coreFile); -} - -bool fromJSON(const llvm::json::Value &Params, ContinueArguments &CA, - llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("threadId", CA.threadId) && - O.mapOptional("singleThread", CA.singleThread); -} - -llvm::json::Value toJSON(const ContinueResponseBody &CRB) { - json::Object Body{{"allThreadsContinued", CRB.allThreadsContinued}}; - return std::move(Body); -} - -bool fromJSON(const llvm::json::Value &Params, SetVariableArguments &SVA, - llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("variablesReference", SVA.variablesReference) && - O.map("name", SVA.name) && O.map("value", SVA.value) && - O.mapOptional("format", SVA.format); -} - -llvm::json::Value toJSON(const SetVariableResponseBody &SVR) { - json::Object Body{{"value", SVR.value}}; - if (SVR.type.has_value()) - Body.insert({"type", SVR.type}); - - if (SVR.variablesReference.has_value()) - Body.insert({"variablesReference", SVR.variablesReference}); - - if (SVR.namedVariables.has_value()) - Body.insert({"namedVariables", SVR.namedVariables}); - - if (SVR.indexedVariables.has_value()) - Body.insert({"indexedVariables", SVR.indexedVariables}); - - if (SVR.memoryReference.has_value()) - Body.insert({"memoryReference", SVR.memoryReference}); - - if (SVR.valueLocationReference.has_value()) - Body.insert({"valueLocationReference", SVR.valueLocationReference}); - - return llvm::json::Value(std::move(Body)); -} -bool fromJSON(const llvm::json::Value &Params, ScopesArguments &SCA, - llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("frameId", SCA.frameId); -} - -llvm::json::Value toJSON(const ScopesResponseBody &SCR) { - llvm::json::Array scopes; - for (const Scope &scope : SCR.scopes) { - scopes.emplace_back(toJSON(scope)); - } - - return llvm::json::Object{{"scopes", std::move(scopes)}}; -} - -bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("source", SA.source) && - O.map("sourceReference", SA.sourceReference); -} - -json::Value toJSON(const SourceResponseBody &SA) { - json::Object Result{{"content", SA.content}}; - - if (SA.mimeType) - Result.insert({"mimeType", SA.mimeType}); - - return std::move(Result); -} - -bool fromJSON(const llvm::json::Value &Params, NextArguments &NA, - llvm::json::Path P) { - json::ObjectMapper OM(Params, P); - return OM && OM.map("threadId", NA.threadId) && - OM.mapOptional("singleThread", NA.singleThread) && - OM.mapOptional("granularity", NA.granularity); -} - -bool fromJSON(const llvm::json::Value &Params, StepInArguments &SIA, - llvm::json::Path P) { - json::ObjectMapper OM(Params, P); - return OM && OM.map("threadId", SIA.threadId) && - OM.map("targetId", SIA.targetId) && - OM.mapOptional("singleThread", SIA.singleThread) && - OM.mapOptional("granularity", SIA.granularity); -} - -bool fromJSON(const llvm::json::Value &Params, StepInTargetsArguments &SITA, - llvm::json::Path P) { - json::ObjectMapper OM(Params, P); - return OM && OM.map("frameId", SITA.frameId); -} -llvm::json::Value toJSON(const StepInTargetsResponseBody &SITR) { - return llvm::json::Object{{"targets", SITR.targets}}; -} - -bool fromJSON(const llvm::json::Value &Params, StepOutArguments &SOA, - llvm::json::Path P) { - json::ObjectMapper OM(Params, P); - return OM && OM.map("threadId", SOA.threadId) && - OM.mapOptional("singleThread", SOA.singleThread) && - OM.mapOptional("granularity", SOA.granularity); -} - -bool fromJSON(const llvm::json::Value &Params, SetBreakpointsArguments &SBA, - llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("source", SBA.source) && - O.map("breakpoints", SBA.breakpoints) && O.map("lines", SBA.lines) && - O.map("sourceModified", SBA.sourceModified); -} - -llvm::json::Value toJSON(const SetBreakpointsResponseBody &SBR) { - json::Object result; - result["breakpoints"] = SBR.breakpoints; - return result; -} - -bool fromJSON(const llvm::json::Value &Params, - SetFunctionBreakpointsArguments &SFBA, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("breakpoints", SFBA.breakpoints); -} - -llvm::json::Value toJSON(const SetFunctionBreakpointsResponseBody &SFBR) { - json::Object result; - result["breakpoints"] = SFBR.breakpoints; - return result; -} - -bool fromJSON(const llvm::json::Value &Params, - SetInstructionBreakpointsArguments &SIBA, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("breakpoints", SIBA.breakpoints); -} - -llvm::json::Value toJSON(const SetInstructionBreakpointsResponseBody &SIBR) { - json::Object result; - result["breakpoints"] = SIBR.breakpoints; - return result; -} - -bool fromJSON(const llvm::json::Value &Params, - DataBreakpointInfoArguments &DBIA, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("variablesReference", DBIA.variablesReference) && - O.map("name", DBIA.name) && O.map("frameId", DBIA.frameId) && - O.map("bytes", DBIA.bytes) && O.map("asAddress", DBIA.asAddress) && - O.map("mode", DBIA.mode); -} - -llvm::json::Value toJSON(const DataBreakpointInfoResponseBody &DBIRB) { - json::Object result; - result["dataId"] = DBIRB.dataId ? *DBIRB.dataId : llvm::json::Value(nullptr); - result["description"] = DBIRB.description; - if (DBIRB.accessTypes) - result["accessTypes"] = *DBIRB.accessTypes; - if (DBIRB.canPersist) - result["canPersist"] = *DBIRB.canPersist; - return result; -} - -bool fromJSON(const llvm::json::Value &Params, - SetDataBreakpointsArguments &SDBA, llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("breakpoints", SDBA.breakpoints); -} - -llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) { - json::Object result; - result["breakpoints"] = SDBR.breakpoints; - return result; -} - -bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA, - llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("memoryReference", DA.memoryReference) && - O.mapOptional("offset", DA.offset) && - O.mapOptional("instructionOffset", DA.instructionOffset) && - O.map("instructionCount", DA.instructionCount) && - O.mapOptional("resolveSymbols", DA.resolveSymbols); -} - -llvm::json::Value toJSON(const DisassembleResponseBody &DRB) { - llvm::json::Array instructions; - for (const auto &instruction : DRB.instructions) { - instructions.push_back(toJSON(instruction)); - } - return llvm::json::Object{{"instructions", std::move(instructions)}}; -} - -} // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h b/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h deleted file mode 100644 index 570a0b6d3968..000000000000 --- a/lldb/tools/lldb-dap/Protocol/ProtocolRequests.h +++ /dev/null @@ -1,784 +0,0 @@ -//===-- ProtocolTypes.h ---------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains POD structs based on the DAP specification at -// https://microsoft.github.io/debug-adapter-protocol/specification -// -// This is not meant to be a complete implementation, new interfaces are added -// when they're needed. -// -// Each struct has a toJSON and fromJSON function, that converts between -// the struct and a JSON representation. (See JSON.h) -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_REQUESTS_H -#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_REQUESTS_H - -#include "Protocol/ProtocolBase.h" -#include "Protocol/ProtocolTypes.h" -#include "lldb/lldb-defines.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/StringMap.h" -#include "llvm/Support/JSON.h" -#include -#include -#include -#include -#include - -namespace lldb_dap::protocol { - -/// Arguments for `cancel` request. -struct CancelArguments { - /// The ID (attribute `seq`) of the request to cancel. If missing no request - /// is cancelled. - /// - /// Both a `requestId` and a `progressId` can be specified in one request. - std::optional requestId; - - /// The ID (attribute `progressId`) of the progress to cancel. If missing no - /// progress is cancelled. - /// - /// Both a `requestId` and a `progressId` can be specified in one request. - std::optional progressId; -}; -bool fromJSON(const llvm::json::Value &, CancelArguments &, llvm::json::Path); - -/// Response to `cancel` request. This is just an acknowledgement, so no body -/// field is required. -using CancelResponse = VoidResponse; - -/// Arguments for `disconnect` request. -struct DisconnectArguments { - /// A value of true indicates that this `disconnect` request is part of a - /// restart sequence. - std::optional restart; - - /// Indicates whether the debuggee should be terminated when the debugger is - /// disconnected. If unspecified, the debug adapter is free to do whatever it - /// thinks is best. The attribute is only honored by a debug adapter if the - /// corresponding capability `supportTerminateDebuggee` is true. - std::optional terminateDebuggee; - - /// Indicates whether the debuggee should stay suspended when the debugger is - /// disconnected. If unspecified, the debuggee should resume execution. The - /// attribute is only honored by a debug adapter if the corresponding - /// capability `supportSuspendDebuggee` is true. - std::optional suspendDebuggee; -}; -bool fromJSON(const llvm::json::Value &, DisconnectArguments &, - llvm::json::Path); - -/// Response to `disconnect` request. This is just an acknowledgement, so no -/// body field is required. -using DisconnectResponse = VoidResponse; - -/// Features supported by DAP clients. -enum ClientFeature : unsigned { - eClientFeatureVariableType, - eClientFeatureVariablePaging, - eClientFeatureRunInTerminalRequest, - eClientFeatureMemoryReferences, - eClientFeatureProgressReporting, - eClientFeatureInvalidatedEvent, - eClientFeatureMemoryEvent, - /// Client supports the `argsCanBeInterpretedByShell` attribute on the - /// `runInTerminal` request. - eClientFeatureArgsCanBeInterpretedByShell, - eClientFeatureStartDebuggingRequest, - /// The client will interpret ANSI escape sequences in the display of - /// `OutputEvent.output` and `Variable.value` fields when - /// `Capabilities.supportsANSIStyling` is also enabled. - eClientFeatureANSIStyling, -}; - -/// Format of paths reported by the debug adapter. -enum PathFormat : unsigned { ePatFormatPath, ePathFormatURI }; - -/// Arguments for `initialize` request. -struct InitializeRequestArguments { - /// The ID of the debug adapter. - std::string adapterID; - - /// The ID of the client using this adapter. - std::optional clientID; - - /// The human-readable name of the client using this adapter. - std::optional clientName; - - /// The ISO-639 locale of the client using this adapter, e.g. en-US or de-CH. - std::optional locale; - - /// Determines in what format paths are specified. The default is `path`, - /// which is the native format. - PathFormat pathFormat = ePatFormatPath; - - /// If true all line numbers are 1-based (default). - std::optional linesStartAt1; - - /// If true all column numbers are 1-based (default). - std::optional columnsStartAt1; - - /// The set of supported features reported by the client. - llvm::DenseSet supportedFeatures; - - /// lldb-dap Extensions - /// @{ - - /// Source init files when initializing lldb::SBDebugger. - std::optional lldbExtSourceInitFile; - - /// @} -}; -bool fromJSON(const llvm::json::Value &, InitializeRequestArguments &, - llvm::json::Path); - -/// Response to `initialize` request. The capabilities of this debug adapter. -using InitializeResponse = std::optional; - -/// DAP Launch and Attach common configurations. -/// -/// See package.json debuggers > configurationAttributes > launch or attach > -/// properties for common configurations. -struct Configuration { - /// Specify a working directory to use when launching `lldb-dap`. If the debug - /// information in your executable contains relative paths, this option can be - /// used so that `lldb-dap` can find source files and object files that have - /// relative paths. - std::string debuggerRoot; - - /// Enable auto generated summaries for variables when no summaries exist for - /// a given type. This feature can cause performance delays in large projects - /// when viewing variables. - bool enableAutoVariableSummaries = false; - - /// If a variable is displayed using a synthetic children, also display the - /// actual contents of the variable at the end under a [raw] entry. This is - /// useful when creating synthetic child plug-ins as it lets you see the - /// actual contents of the variable. - bool enableSyntheticChildDebugging = false; - - /// Enable language specific extended backtraces. - bool displayExtendedBacktrace = false; - - /// Stop at the entry point of the program when launching or attaching. - bool stopOnEntry = false; - - /// Optional timeout when waiting for the program to `runInTerminal` or - /// attach. - std::chrono::seconds timeout = std::chrono::seconds(30); - - /// The escape prefix to use for executing regular LLDB commands in the Debug - /// Console, instead of printing variables. Defaults to a backtick. If it's an - /// empty string, then all expression in the Debug Console are treated as - /// regular LLDB commands. - std::string commandEscapePrefix = "`"; - - /// If non-empty, stack frames will have descriptions generated based on the - /// provided format. See https://lldb.llvm.org/use/formatting.html for an - /// explanation on format strings for frames. If the format string contains - /// errors, an error message will be displayed on the Debug Console and the - /// default frame names will be used. This might come with a performance cost - /// because debug information might need to be processed to generate the - /// description. - std::optional customFrameFormat; - - /// Same as `customFrameFormat`, but for threads instead of stack frames. - std::optional customThreadFormat; - - /// Specify a source path to remap "./" to allow full paths to be used when - /// setting breakpoints in binaries that have relative source paths. - std::string sourcePath; - - /// Specify an array of path re-mappings. Each element in the array must be a - /// two element array containing a source and destination pathname. Overrides - /// sourcePath. - std::vector> sourceMap; - - /// LLDB commands executed upon debugger startup prior to creating the LLDB - /// target. - std::vector preInitCommands; - - /// LLDB commands executed upon debugger startup prior to creating the LLDB - /// target. - std::vector initCommands; - - /// LLDB commands executed just before launching/attaching, after the LLDB - /// target has been created. - std::vector preRunCommands; - - /// LLDB commands executed just after launching/attaching, after the LLDB - /// target has been created. - std::vector postRunCommands; - - /// LLDB commands executed just after each stop. - std::vector stopCommands; - - /// LLDB commands executed when the program exits. - std::vector exitCommands; - - /// LLDB commands executed when the debugging session ends. - std::vector terminateCommands; - - /// Path to the executable. - /// - /// *NOTE:* When launching, either `launchCommands` or `program` must be - /// configured. If both are configured then `launchCommands` takes priority. - std::string program; - - /// Target triple for the program (arch-vendor-os). If not set, inferred from - /// the binary. - std::string targetTriple; - - /// Specify name of the platform to use for this target, creating the platform - /// if necessary. - std::string platformName; -}; - -/// lldb-dap specific launch arguments. -struct LaunchRequestArguments { - /// Common lldb-dap configuration values for launching/attaching operations. - Configuration configuration; - - /// If true, the launch request should launch the program without enabling - /// debugging. - bool noDebug = false; - - /// Launch specific operations. - /// - /// See package.json debuggers > configurationAttributes > launch > - /// properties. - /// @{ - - /// LLDB commands executed to launch the program. - /// - /// *NOTE:* Either launchCommands or program must be configured. - /// - /// If set, takes priority over the 'program' when launching the target. - std::vector launchCommands; - - /// The program working directory. - std::string cwd; - - /// An array of command line argument strings to be passed to the program - /// being launched. - std::vector args; - - /// Environment variables to set when launching the program. The format of - /// each environment variable string is "VAR=VALUE" for environment variables - /// with values or just "VAR" for environment variables with no values. - llvm::StringMap env; - - /// If set, then the client stub should detach rather than killing the - /// debuggee if it loses connection with lldb. - bool detachOnError = false; - - /// Disable ASLR (Address Space Layout Randomization) when launching the - /// process. - bool disableASLR = true; - - /// Do not set up for terminal I/O to go to running process. - bool disableSTDIO = false; - - /// Set whether to shell expand arguments to the process when launching. - bool shellExpandArguments = false; - - /// Launch the program inside an integrated terminal in the IDE. Useful for - /// debugging interactive command line programs. - bool runInTerminal = false; - - /// @} -}; -bool fromJSON(const llvm::json::Value &, LaunchRequestArguments &, - llvm::json::Path); - -/// Response to `launch` request. This is just an acknowledgement, so no body -/// field is required. -using LaunchResponse = VoidResponse; - -#define LLDB_DAP_INVALID_PORT -1 - -/// lldb-dap specific attach arguments. -struct AttachRequestArguments { - /// Common lldb-dap configuration values for launching/attaching operations. - Configuration configuration; - - /// Attach specific operations. - /// - /// See package.json debuggers > configurationAttributes > attach > - /// properties. - /// @{ - - /// Custom commands that are executed instead of attaching to a process ID or - /// to a process by name. These commands may optionally create a new target - /// and must perform an attach. A valid process must exist after these - /// commands complete or the `"attach"` will fail. - std::vector attachCommands; - - /// System process ID to attach to. - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - - /// Wait for the process to launch. - bool waitFor = false; - - /// TCP/IP port to attach to a remote system. Specifying both pid and port is - /// an error. - int32_t gdbRemotePort = LLDB_DAP_INVALID_PORT; - - /// The hostname to connect to a remote system. The default hostname being - /// used `localhost`. - std::string gdbRemoteHostname = "localhost"; - - /// Path to the core file to debug. - std::string coreFile; - - /// @} -}; -bool fromJSON(const llvm::json::Value &, AttachRequestArguments &, - llvm::json::Path); - -/// Response to `attach` request. This is just an acknowledgement, so no body -/// field is required. -using AttachResponse = VoidResponse; - -/// Arguments for `continue` request. -struct ContinueArguments { - /// Specifies the active thread. If the debug adapter supports single thread - /// execution (see `supportsSingleThreadExecutionRequests`) and the argument - /// `singleThread` is true, only the thread with this ID is resumed. - lldb::tid_t threadId = LLDB_INVALID_THREAD_ID; - - /// If this flag is true, execution is resumed only for the thread with given - /// `threadId`. - bool singleThread = false; -}; -bool fromJSON(const llvm::json::Value &, ContinueArguments &, llvm::json::Path); - -/// Response to `continue` request. -struct ContinueResponseBody { - // If omitted or set to `true`, this response signals to the client that all - // threads have been resumed. The value `false` indicates that not all threads - // were resumed. - bool allThreadsContinued = true; -}; -llvm::json::Value toJSON(const ContinueResponseBody &); - -/// Arguments for `configurationDone` request. -using ConfigurationDoneArguments = EmptyArguments; - -/// Response to `configurationDone` request. This is just an acknowledgement, so -/// no body field is required. -using ConfigurationDoneResponse = VoidResponse; - -/// Arguments for `setVariable` request. -struct SetVariableArguments { - /// The reference of the variable container. The `variablesReference` must - /// have been obtained in the current suspended state. See 'Lifetime of Object - /// References' in the Overview section for details. - uint64_t variablesReference = UINT64_MAX; - - /// The name of the variable in the container. - std::string name; - - /// The value of the variable. - std::string value; - - /// Specifies details on how to format the response value. - ValueFormat format; -}; -bool fromJSON(const llvm::json::Value &, SetVariableArguments &, - llvm::json::Path); - -/// Response to `setVariable` request. -struct SetVariableResponseBody { - - /// The new value of the variable. - std::string value; - - /// The type of the new value. Typically shown in the UI when hovering over - /// the value. - std::optional type; - - /// If `variablesReference` is > 0, the new value is structured and its - /// children can be retrieved by passing `variablesReference` to the - /// `variables` request as long as execution remains suspended. See 'Lifetime - /// of Object References' in the Overview section for details. - /// - /// If this property is included in the response, any `variablesReference` - /// previously associated with the updated variable, and those of its - /// children, are no longer valid. - std::optional variablesReference; - - /// The number of named child variables. - /// The client can use this information to present the variables in a paged - /// UI and fetch them in chunks. - /// The value should be less than or equal to 2147483647 (2^31-1). - std::optional namedVariables; - - /// The number of indexed child variables. - /// The client can use this information to present the variables in a paged - /// UI and fetch them in chunks. - /// The value should be less than or equal to 2147483647 (2^31-1). - std::optional indexedVariables; - - /// A memory reference to a location appropriate for this result. - /// For pointer type eval results, this is generally a reference to the - /// memory address contained in the pointer. - /// This attribute may be returned by a debug adapter if corresponding - /// capability `supportsMemoryReferences` is true. - std::optional memoryReference; - - /// A reference that allows the client to request the location where the new - /// value is declared. For example, if the new value is function pointer, the - /// adapter may be able to look up the function's location. This should be - /// present only if the adapter is likely to be able to resolve the location. - /// - /// This reference shares the same lifetime as the `variablesReference`. See - /// 'Lifetime of Object References' in the Overview section for details. - std::optional valueLocationReference; -}; -llvm::json::Value toJSON(const SetVariableResponseBody &); - -struct ScopesArguments { - /// Retrieve the scopes for the stack frame identified by `frameId`. The - /// `frameId` must have been obtained in the current suspended state. See - /// 'Lifetime of Object References' in the Overview section for details. - uint64_t frameId = LLDB_INVALID_FRAME_ID; -}; -bool fromJSON(const llvm::json::Value &, ScopesArguments &, llvm::json::Path); - -struct ScopesResponseBody { - std::vector scopes; -}; -llvm::json::Value toJSON(const ScopesResponseBody &); - -/// Arguments for `source` request. -struct SourceArguments { - /// Specifies the source content to load. Either `source.path` or - /// `source.sourceReference` must be specified. - std::optional source; - - /// The reference to the source. This is the same as `source.sourceReference`. - /// This is provided for backward compatibility since old clients do not - /// understand the `source` attribute. - int64_t sourceReference; -}; -bool fromJSON(const llvm::json::Value &, SourceArguments &, llvm::json::Path); - -/// Response to `source` request. -struct SourceResponseBody { - /// Content of the source reference. - std::string content; - - /// Content type (MIME type) of the source. - std::optional mimeType; -}; -llvm::json::Value toJSON(const SourceResponseBody &); - -/// Arguments for `next` request. -struct NextArguments { - /// Specifies the thread for which to resume execution for one step (of the - /// given granularity). - lldb::tid_t threadId = LLDB_INVALID_THREAD_ID; - - /// If this flag is true, all other suspended threads are not resumed. - bool singleThread = false; - - /// Stepping granularity. If no granularity is specified, a granularity of - /// `statement` is assumed. - SteppingGranularity granularity = eSteppingGranularityStatement; -}; -bool fromJSON(const llvm::json::Value &, NextArguments &, llvm::json::Path); - -/// Response to `next` request. This is just an acknowledgement, so no -/// body field is required. -using NextResponse = VoidResponse; - -/// Arguments for `stepIn` request. -struct StepInArguments { - /// Specifies the thread for which to resume execution for one step-into (of - /// the given granularity). - lldb::tid_t threadId = LLDB_INVALID_THREAD_ID; - - /// If this flag is true, all other suspended threads are not resumed. - bool singleThread = false; - - /// Id of the target to step into. - std::optional targetId; - - /// Stepping granularity. If no granularity is specified, a granularity of - /// `statement` is assumed. - SteppingGranularity granularity = eSteppingGranularityStatement; -}; -bool fromJSON(const llvm::json::Value &, StepInArguments &, llvm::json::Path); - -/// Response to `stepIn` request. This is just an acknowledgement, so no -/// body field is required. -using StepInResponse = VoidResponse; - -/// Arguments for `stepInTargets` request. -struct StepInTargetsArguments { - /// The stack frame for which to retrieve the possible step-in targets. - uint64_t frameId = LLDB_INVALID_FRAME_ID; -}; -bool fromJSON(const llvm::json::Value &, StepInTargetsArguments &, - llvm::json::Path); - -/// Response to `stepInTargets` request. -struct StepInTargetsResponseBody { - /// The possible step-in targets of the specified source location. - std::vector targets; -}; -llvm::json::Value toJSON(const StepInTargetsResponseBody &); - -/// Arguments for `stepOut` request. -struct StepOutArguments { - /// Specifies the thread for which to resume execution for one step-out (of - /// the given granularity). - lldb::tid_t threadId = LLDB_INVALID_THREAD_ID; - - /// If this flag is true, all other suspended threads are not resumed. - std::optional singleThread; - - /// Stepping granularity. If no granularity is specified, a granularity of - /// `statement` is assumed. - SteppingGranularity granularity = eSteppingGranularityStatement; -}; -bool fromJSON(const llvm::json::Value &, StepOutArguments &, llvm::json::Path); - -/// Response to `stepOut` request. This is just an acknowledgement, so no -/// body field is required. -using StepOutResponse = VoidResponse; - -/// Arguments for `breakpointLocations` request. -struct BreakpointLocationsArguments { - /// The source location of the breakpoints; either `source.path` or - /// `source.sourceReference` must be specified. - Source source; - - /// Start line of range to search possible breakpoint locations in. If only - /// the line is specified, the request returns all possible locations in that - /// line. - uint32_t line; - - /// Start position within `line` to search possible breakpoint locations in. - /// It is measured in UTF-16 code units and the client capability - /// `columnsStartAt1` determines whether it is 0- or 1-based. If no column is - /// given, the first position in the start line is assumed. - std::optional column; - - /// End line of range to search possible breakpoint locations in. If no end - /// line is given, then the end line is assumed to be the start line. - std::optional endLine; - - /// End position within `endLine` to search possible breakpoint locations in. - /// It is measured in UTF-16 code units and the client capability - /// `columnsStartAt1` determines whether it is 0- or 1-based. If no end column - /// is given, the last position in the end line is assumed. - std::optional endColumn; -}; -bool fromJSON(const llvm::json::Value &, BreakpointLocationsArguments &, - llvm::json::Path); - -/// Response to `breakpointLocations` request. -struct BreakpointLocationsResponseBody { - /// Content of the source reference. - std::vector breakpoints; -}; -llvm::json::Value toJSON(const BreakpointLocationsResponseBody &); - -/// Arguments for `setBreakpoints` request. -struct SetBreakpointsArguments { - /// The source location of the breakpoints; either `source.path` or - /// `source.sourceReference` must be specified. - Source source; - - /// The code locations of the breakpoints. - std::optional> breakpoints; - - /// Deprecated: The code locations of the breakpoints. - std::optional> lines; - - /// A value of true indicates that the underlying source has been modified - /// which results in new breakpoint locations. - std::optional sourceModified; -}; -bool fromJSON(const llvm::json::Value &, SetBreakpointsArguments &, - llvm::json::Path); - -/// Response to `setBreakpoints` request. -/// Returned is information about each breakpoint created by this request. -/// This includes the actual code location and whether the breakpoint could be -/// verified. The breakpoints returned are in the same order as the elements of -/// the breakpoints (or the deprecated lines) array in the arguments. -struct SetBreakpointsResponseBody { - /// Information about the breakpoints. - /// The array elements are in the same order as the elements of the - /// `breakpoints` (or the deprecated `lines`) array in the arguments. - std::vector breakpoints; -}; -llvm::json::Value toJSON(const SetBreakpointsResponseBody &); - -/// Arguments for `setFunctionBreakpoints` request. -struct SetFunctionBreakpointsArguments { - /// The function names of the breakpoints. - std::vector breakpoints; -}; -bool fromJSON(const llvm::json::Value &, SetFunctionBreakpointsArguments &, - llvm::json::Path); - -/// Response to `setFunctionBreakpoints` request. -/// Returned is information about each breakpoint created by this request. -struct SetFunctionBreakpointsResponseBody { - /// Information about the breakpoints. The array elements correspond to the - /// elements of the `breakpoints` array. - std::vector breakpoints; -}; -llvm::json::Value toJSON(const SetFunctionBreakpointsResponseBody &); - -/// Arguments for `setInstructionBreakpoints` request. -struct SetInstructionBreakpointsArguments { - /// The instruction references of the breakpoints. - std::vector breakpoints; -}; -bool fromJSON(const llvm::json::Value &, SetInstructionBreakpointsArguments &, - llvm::json::Path); - -/// Response to `setInstructionBreakpoints` request. -struct SetInstructionBreakpointsResponseBody { - /// Information about the breakpoints. The array elements correspond to the - /// elements of the `breakpoints` array. - std::vector breakpoints; -}; -llvm::json::Value toJSON(const SetInstructionBreakpointsResponseBody &); - -/// Arguments for `dataBreakpointInfo` request. -struct DataBreakpointInfoArguments { - /// Reference to the variable container if the data breakpoint is requested - /// for a child of the container. The `variablesReference` must have been - /// obtained in the current suspended state.See 'Lifetime of Object - /// References' in the Overview section for details. - std::optional variablesReference; - - /// The name of the variable's child to obtain data breakpoint information - /// for. If `variablesReference` isn't specified, this can be an expression, - /// or an address if `asAddress` is also true. - std::string name; - - /// When `name` is an expression, evaluate it in the scope of this stack - /// frame. If not specified, the expression is evaluated in the global scope. - /// When `asAddress` is true, the `frameId` is ignored. - std::optional frameId; - - /// If specified, a debug adapter should return information for the range of - /// memory extending `bytes` number of bytes from the address or variable - /// specified by `name`. Breakpoints set using the resulting data ID should - /// pause on data access anywhere within that range. - /// Clients may set this property only if the `supportsDataBreakpointBytes` - /// capability is true. - std::optional bytes; - - /// If `true`, the `name` is a memory address and the debugger should - /// interpret it as a decimal value, or hex value if it is prefixed with `0x`. - /// Clients may set this property only if the `supportsDataBreakpointBytes` - /// capability is true. - std::optional asAddress; - - /// The mode of the desired breakpoint. If defined, this must be one of the - /// `breakpointModes` the debug adapter advertised in its `Capabilities`. - std::optional mode; -}; -bool fromJSON(const llvm::json::Value &, DataBreakpointInfoArguments &, - llvm::json::Path); - -/// Response to `dataBreakpointInfo` request. -struct DataBreakpointInfoResponseBody { - /// An identifier for the data on which a data breakpoint can be registered - /// with the `setDataBreakpoints` request or null if no data breakpoint is - /// available. If a `variablesReference` or `frameId` is passed, the `dataId` - /// is valid in the current suspended state, otherwise it's valid - /// indefinitely. See 'Lifetime of Object References' in the Overview section - /// for details. Breakpoints set using the `dataId` in the - /// `setDataBreakpoints` request may outlive the lifetime of the associated - /// `dataId`. - std::optional dataId; - - /// UI string that describes on what data the breakpoint is set on or why a - /// data breakpoint is not available. - std::string description; - - /// Attribute lists the available access types for a potential data - /// breakpoint. A UI client could surface this information. - std::optional> accessTypes; - - /// Attribute indicates that a potential data breakpoint could be persisted - /// across sessions. - std::optional canPersist; -}; -llvm::json::Value toJSON(const DataBreakpointInfoResponseBody &); - -/// Arguments for `setDataBreakpoints` request. -struct SetDataBreakpointsArguments { - /// The contents of this array replaces all existing data breakpoints. An - /// empty array clears all data breakpoints. - std::vector breakpoints; -}; -bool fromJSON(const llvm::json::Value &, SetDataBreakpointsArguments &, - llvm::json::Path); - -/// Response to `setDataBreakpoints` request. -struct SetDataBreakpointsResponseBody { - /// Information about the data breakpoints. The array elements correspond to - /// the elements of the input argument `breakpoints` array. - std::vector breakpoints; -}; -llvm::json::Value toJSON(const SetDataBreakpointsResponseBody &); - -/// Arguments to `disassemble` request. -struct DisassembleArguments { - /// Memory reference to the base location containing the instructions to - /// disassemble. - std::string memoryReference; - - /// Offset (in bytes) to be applied to the reference location before - /// disassembling. Can be negative. - std::optional offset; - - /// Offset (in instructions) to be applied after the byte offset (if any) - /// before disassembling. Can be negative. - std::optional instructionOffset; - - /// Number of instructions to disassemble starting at the specified location - /// and offset. - /// An adapter must return exactly this number of instructions - any - /// unavailable instructions should be replaced with an implementation-defined - /// 'invalid instruction' value. - uint32_t instructionCount; - - /// If true, the adapter should attempt to resolve memory addresses and other - /// values to symbolic names. - std::optional resolveSymbols; -}; -bool fromJSON(const llvm::json::Value &, DisassembleArguments &, - llvm::json::Path); -llvm::json::Value toJSON(const DisassembleArguments &); - -/// Response to `disassemble` request. -struct DisassembleResponseBody { - /// The list of disassembled instructions. - std::vector instructions; -}; -bool fromJSON(const llvm::json::Value &, DisassembleResponseBody &, - llvm::json::Path); -llvm::json::Value toJSON(const DisassembleResponseBody &); - -} // namespace lldb_dap::protocol - -#endif diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp deleted file mode 100644 index 33db5f0f4b89..000000000000 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.cpp +++ /dev/null @@ -1,902 +0,0 @@ -//===-- ProtocolTypes.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Protocol/ProtocolTypes.h" -#include "JSONUtils.h" -#include "lldb/lldb-types.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/JSON.h" -#include - -using namespace llvm; - -namespace lldb_dap::protocol { - -bool fromJSON(const json::Value &Params, Source::PresentationHint &PH, - json::Path P) { - auto rawHint = Params.getAsString(); - if (!rawHint) { - P.report("expected a string"); - return false; - } - std::optional hint = - StringSwitch>(*rawHint) - .Case("normal", Source::eSourcePresentationHintNormal) - .Case("emphasize", Source::eSourcePresentationHintEmphasize) - .Case("deemphasize", Source::eSourcePresentationHintDeemphasize) - .Default(std::nullopt); - if (!hint) { - P.report("unexpected value"); - return false; - } - PH = *hint; - return true; -} - -bool fromJSON(const json::Value &Params, Source &S, json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("name", S.name) && O.map("path", S.path) && - O.map("presentationHint", S.presentationHint) && - O.map("sourceReference", S.sourceReference); -} - -llvm::json::Value toJSON(Source::PresentationHint hint) { - switch (hint) { - case Source::eSourcePresentationHintNormal: - return "normal"; - case Source::eSourcePresentationHintEmphasize: - return "emphasize"; - case Source::eSourcePresentationHintDeemphasize: - return "deemphasize"; - } - llvm_unreachable("unhandled presentation hint."); -} - -llvm::json::Value toJSON(const Source &S) { - json::Object result; - if (S.name) - result.insert({"name", *S.name}); - if (S.path) - result.insert({"path", *S.path}); - if (S.sourceReference) - result.insert({"sourceReference", *S.sourceReference}); - if (S.presentationHint) - result.insert({"presentationHint", *S.presentationHint}); - - return result; -} - -bool fromJSON(const llvm::json::Value &Params, ExceptionBreakpointsFilter &EBF, - llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("filter", EBF.filter) && O.map("label", EBF.label) && - O.mapOptional("description", EBF.description) && - O.mapOptional("default", EBF.defaultState) && - O.mapOptional("supportsCondition", EBF.supportsCondition) && - O.mapOptional("conditionDescription", EBF.conditionDescription); -} - -json::Value toJSON(const ExceptionBreakpointsFilter &EBF) { - json::Object result{{"filter", EBF.filter}, {"label", EBF.label}}; - - if (EBF.description) - result.insert({"description", *EBF.description}); - if (EBF.defaultState) - result.insert({"default", *EBF.defaultState}); - if (EBF.supportsCondition) - result.insert({"supportsCondition", *EBF.supportsCondition}); - if (EBF.conditionDescription) - result.insert({"conditionDescription", *EBF.conditionDescription}); - - return result; -} - -bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) { - auto rawColumnType = Params.getAsString(); - if (!rawColumnType) { - P.report("expected a string"); - return false; - } - std::optional columnType = - StringSwitch>(*rawColumnType) - .Case("string", eColumnTypeString) - .Case("number", eColumnTypeNumber) - .Case("boolean", eColumnTypeBoolean) - .Case("unixTimestampUTC", eColumnTypeTimestamp) - .Default(std::nullopt); - if (!columnType) { - P.report("unexpected value, expected 'string', 'number', 'boolean', or " - "'unixTimestampUTC'"); - return false; - } - CT = *columnType; - return true; -} - -json::Value toJSON(const ColumnType &T) { - switch (T) { - case eColumnTypeString: - return "string"; - case eColumnTypeNumber: - return "number"; - case eColumnTypeBoolean: - return "boolean"; - case eColumnTypeTimestamp: - return "unixTimestampUTC"; - } - llvm_unreachable("unhandled column type."); -} - -bool fromJSON(const llvm::json::Value &Params, ColumnDescriptor &CD, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.map("attributeName", CD.attributeName) && - O.map("label", CD.label) && O.mapOptional("format", CD.format) && - O.mapOptional("type", CD.type) && O.mapOptional("width", CD.width); -} - -json::Value toJSON(const ColumnDescriptor &CD) { - json::Object result{{"attributeName", CD.attributeName}, {"label", CD.label}}; - - if (CD.format) - result.insert({"format", *CD.format}); - if (CD.type) - result.insert({"type", *CD.type}); - if (CD.width) - result.insert({"width", *CD.width}); - - return result; -} - -json::Value toJSON(const ChecksumAlgorithm &CA) { - switch (CA) { - case eChecksumAlgorithmMD5: - return "MD5"; - case eChecksumAlgorithmSHA1: - return "SHA1"; - case eChecksumAlgorithmSHA256: - return "SHA256"; - case eChecksumAlgorithmTimestamp: - return "timestamp"; - } - llvm_unreachable("unhandled checksum algorithm."); -} - -bool fromJSON(const llvm::json::Value &Params, ChecksumAlgorithm &CA, - llvm::json::Path P) { - auto rawAlgorithm = Params.getAsString(); - if (!rawAlgorithm) { - P.report("expected a string"); - return false; - } - - std::optional algorithm = - llvm::StringSwitch>(*rawAlgorithm) - .Case("MD5", eChecksumAlgorithmMD5) - .Case("SHA1", eChecksumAlgorithmSHA1) - .Case("SHA256", eChecksumAlgorithmSHA256) - .Case("timestamp", eChecksumAlgorithmTimestamp) - .Default(std::nullopt); - - if (!algorithm) { - P.report( - "unexpected value, expected 'MD5', 'SHA1', 'SHA256', or 'timestamp'"); - return false; - } - - CA = *algorithm; - return true; -} - -json::Value toJSON(const BreakpointModeApplicability &BMA) { - switch (BMA) { - case eBreakpointModeApplicabilitySource: - return "source"; - case eBreakpointModeApplicabilityException: - return "exception"; - case eBreakpointModeApplicabilityData: - return "data"; - case eBreakpointModeApplicabilityInstruction: - return "instruction"; - } - llvm_unreachable("unhandled breakpoint mode applicability."); -} - -bool fromJSON(const llvm::json::Value &Params, BreakpointModeApplicability &BMA, - llvm::json::Path P) { - auto rawApplicability = Params.getAsString(); - if (!rawApplicability) { - P.report("expected a string"); - return false; - } - std::optional applicability = - llvm::StringSwitch>( - *rawApplicability) - .Case("source", eBreakpointModeApplicabilitySource) - .Case("exception", eBreakpointModeApplicabilityException) - .Case("data", eBreakpointModeApplicabilityData) - .Case("instruction", eBreakpointModeApplicabilityInstruction) - .Default(std::nullopt); - if (!applicability) { - P.report("unexpected value, expected 'source', 'exception', 'data', or " - "'instruction'"); - return false; - } - BMA = *applicability; - return true; -} - -json::Value toJSON(const BreakpointMode &BM) { - json::Object result{ - {"mode", BM.mode}, - {"label", BM.label}, - {"appliesTo", BM.appliesTo}, - }; - - if (BM.description) - result.insert({"description", *BM.description}); - - return result; -} - -bool fromJSON(const llvm::json::Value &Params, BreakpointMode &BM, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.map("mode", BM.mode) && O.map("label", BM.label) && - O.mapOptional("description", BM.description) && - O.map("appliesTo", BM.appliesTo); -} - -static llvm::StringLiteral ToString(AdapterFeature feature) { - switch (feature) { - case eAdapterFeatureANSIStyling: - return "supportsANSIStyling"; - case eAdapterFeatureBreakpointLocationsRequest: - return "supportsBreakpointLocationsRequest"; - case eAdapterFeatureCancelRequest: - return "supportsCancelRequest"; - case eAdapterFeatureClipboardContext: - return "supportsClipboardContext"; - case eAdapterFeatureCompletionsRequest: - return "supportsCompletionsRequest"; - case eAdapterFeatureConditionalBreakpoints: - return "supportsConditionalBreakpoints"; - case eAdapterFeatureConfigurationDoneRequest: - return "supportsConfigurationDoneRequest"; - case eAdapterFeatureDataBreakpointBytes: - return "supportsDataBreakpointBytes"; - case eAdapterFeatureDataBreakpoints: - return "supportsDataBreakpoints"; - case eAdapterFeatureDelayedStackTraceLoading: - return "supportsDelayedStackTraceLoading"; - case eAdapterFeatureDisassembleRequest: - return "supportsDisassembleRequest"; - case eAdapterFeatureEvaluateForHovers: - return "supportsEvaluateForHovers"; - case eAdapterFeatureExceptionFilterOptions: - return "supportsExceptionFilterOptions"; - case eAdapterFeatureExceptionInfoRequest: - return "supportsExceptionInfoRequest"; - case eAdapterFeatureExceptionOptions: - return "supportsExceptionOptions"; - case eAdapterFeatureFunctionBreakpoints: - return "supportsFunctionBreakpoints"; - case eAdapterFeatureGotoTargetsRequest: - return "supportsGotoTargetsRequest"; - case eAdapterFeatureHitConditionalBreakpoints: - return "supportsHitConditionalBreakpoints"; - case eAdapterFeatureInstructionBreakpoints: - return "supportsInstructionBreakpoints"; - case eAdapterFeatureLoadedSourcesRequest: - return "supportsLoadedSourcesRequest"; - case eAdapterFeatureLogPoints: - return "supportsLogPoints"; - case eAdapterFeatureModulesRequest: - return "supportsModulesRequest"; - case eAdapterFeatureReadMemoryRequest: - return "supportsReadMemoryRequest"; - case eAdapterFeatureRestartFrame: - return "supportsRestartFrame"; - case eAdapterFeatureRestartRequest: - return "supportsRestartRequest"; - case eAdapterFeatureSetExpression: - return "supportsSetExpression"; - case eAdapterFeatureSetVariable: - return "supportsSetVariable"; - case eAdapterFeatureSingleThreadExecutionRequests: - return "supportsSingleThreadExecutionRequests"; - case eAdapterFeatureStepBack: - return "supportsStepBack"; - case eAdapterFeatureStepInTargetsRequest: - return "supportsStepInTargetsRequest"; - case eAdapterFeatureSteppingGranularity: - return "supportsSteppingGranularity"; - case eAdapterFeatureTerminateRequest: - return "supportsTerminateRequest"; - case eAdapterFeatureTerminateThreadsRequest: - return "supportsTerminateThreadsRequest"; - case eAdapterFeatureSuspendDebuggee: - return "supportSuspendDebuggee"; - case eAdapterFeatureValueFormattingOptions: - return "supportsValueFormattingOptions"; - case eAdapterFeatureWriteMemoryRequest: - return "supportsWriteMemoryRequest"; - case eAdapterFeatureTerminateDebuggee: - return "supportTerminateDebuggee"; - } - llvm_unreachable("unhandled adapter feature."); -} - -llvm::json::Value toJSON(const AdapterFeature &feature) { - return ToString(feature); -} - -bool fromJSON(const llvm::json::Value &Params, AdapterFeature &feature, - llvm::json::Path P) { - auto rawFeature = Params.getAsString(); - if (!rawFeature) { - P.report("expected a string"); - return false; - } - - std::optional parsedFeature = - llvm::StringSwitch>(*rawFeature) - .Case("supportsANSIStyling", eAdapterFeatureANSIStyling) - .Case("supportsBreakpointLocationsRequest", - eAdapterFeatureBreakpointLocationsRequest) - .Case("supportsCancelRequest", eAdapterFeatureCancelRequest) - .Case("supportsClipboardContext", eAdapterFeatureClipboardContext) - .Case("supportsCompletionsRequest", eAdapterFeatureCompletionsRequest) - .Case("supportsConditionalBreakpoints", - eAdapterFeatureConditionalBreakpoints) - .Case("supportsConfigurationDoneRequest", - eAdapterFeatureConfigurationDoneRequest) - .Case("supportsDataBreakpointBytes", - eAdapterFeatureDataBreakpointBytes) - .Case("supportsDataBreakpoints", eAdapterFeatureDataBreakpoints) - .Case("supportsDelayedStackTraceLoading", - eAdapterFeatureDelayedStackTraceLoading) - .Case("supportsDisassembleRequest", eAdapterFeatureDisassembleRequest) - .Case("supportsEvaluateForHovers", eAdapterFeatureEvaluateForHovers) - .Case("supportsExceptionFilterOptions", - eAdapterFeatureExceptionFilterOptions) - .Case("supportsExceptionInfoRequest", - eAdapterFeatureExceptionInfoRequest) - .Case("supportsExceptionOptions", eAdapterFeatureExceptionOptions) - .Case("supportsFunctionBreakpoints", - eAdapterFeatureFunctionBreakpoints) - .Case("supportsGotoTargetsRequest", eAdapterFeatureGotoTargetsRequest) - .Case("supportsHitConditionalBreakpoints", - eAdapterFeatureHitConditionalBreakpoints) - .Case("supportsInstructionBreakpoints", - eAdapterFeatureInstructionBreakpoints) - .Case("supportsLoadedSourcesRequest", - eAdapterFeatureLoadedSourcesRequest) - .Case("supportsLogPoints", eAdapterFeatureLogPoints) - .Case("supportsModulesRequest", eAdapterFeatureModulesRequest) - .Case("supportsReadMemoryRequest", eAdapterFeatureReadMemoryRequest) - .Case("supportsRestartFrame", eAdapterFeatureRestartFrame) - .Case("supportsRestartRequest", eAdapterFeatureRestartRequest) - .Case("supportsSetExpression", eAdapterFeatureSetExpression) - .Case("supportsSetVariable", eAdapterFeatureSetVariable) - .Case("supportsSingleThreadExecutionRequests", - eAdapterFeatureSingleThreadExecutionRequests) - .Case("supportsStepBack", eAdapterFeatureStepBack) - .Case("supportsStepInTargetsRequest", - eAdapterFeatureStepInTargetsRequest) - .Case("supportsSteppingGranularity", - eAdapterFeatureSteppingGranularity) - .Case("supportsTerminateRequest", eAdapterFeatureTerminateRequest) - .Case("supportsTerminateThreadsRequest", - eAdapterFeatureTerminateThreadsRequest) - .Case("supportSuspendDebuggee", eAdapterFeatureSuspendDebuggee) - .Case("supportsValueFormattingOptions", - eAdapterFeatureValueFormattingOptions) - .Case("supportsWriteMemoryRequest", eAdapterFeatureWriteMemoryRequest) - .Case("supportTerminateDebuggee", eAdapterFeatureTerminateDebuggee) - .Default(std::nullopt); - - if (!parsedFeature) { - P.report("unexpected value for AdapterFeature"); - return false; - } - - feature = *parsedFeature; - return true; -} - -json::Value toJSON(const Capabilities &C) { - json::Object result; - - for (const auto &feature : C.supportedFeatures) - result.insert({ToString(feature), true}); - - if (C.exceptionBreakpointFilters && !C.exceptionBreakpointFilters->empty()) - result.insert( - {"exceptionBreakpointFilters", *C.exceptionBreakpointFilters}); - if (C.completionTriggerCharacters && !C.completionTriggerCharacters->empty()) - result.insert( - {"completionTriggerCharacters", *C.completionTriggerCharacters}); - if (C.additionalModuleColumns && !C.additionalModuleColumns->empty()) - result.insert({"additionalModuleColumns", *C.additionalModuleColumns}); - if (C.supportedChecksumAlgorithms && !C.supportedChecksumAlgorithms->empty()) - result.insert( - {"supportedChecksumAlgorithms", *C.supportedChecksumAlgorithms}); - if (C.breakpointModes && !C.breakpointModes->empty()) - result.insert({"breakpointModes", *C.breakpointModes}); - - // lldb-dap extensions - if (C.lldbExtVersion && !C.lldbExtVersion->empty()) - result.insert({"$__lldb_version", *C.lldbExtVersion}); - - return result; -} - -bool fromJSON(const json::Value &Params, Scope::PresentationHint &PH, - json::Path P) { - auto rawHint = Params.getAsString(); - if (!rawHint) { - P.report("expected a string"); - return false; - } - const std::optional hint = - StringSwitch>(*rawHint) - .Case("arguments", Scope::eScopePresentationHintArguments) - .Case("locals", Scope::eScopePresentationHintLocals) - .Case("registers", Scope::eScopePresentationHintRegisters) - .Case("returnValue", Scope::eScopePresentationHintReturnValue) - .Default(std::nullopt); - if (!hint) { - P.report("unexpected value"); - return false; - } - PH = *hint; - return true; -} - -bool fromJSON(const json::Value &Params, Scope &S, json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("name", S.name) && - O.mapOptional("presentationHint", S.presentationHint) && - O.map("variablesReference", S.variablesReference) && - O.mapOptional("namedVariables", S.namedVariables) && - O.map("indexedVariables", S.indexedVariables) && - O.mapOptional("source", S.source) && O.map("expensive", S.expensive) && - O.mapOptional("line", S.line) && O.mapOptional("column", S.column) && - O.mapOptional("endLine", S.endLine) && - O.mapOptional("endColumn", S.endColumn); -} - -llvm::json::Value toJSON(const Scope &SC) { - llvm::json::Object result{{"name", SC.name}, - {"variablesReference", SC.variablesReference}, - {"expensive", SC.expensive}}; - - if (SC.presentationHint.has_value()) { - llvm::StringRef presentationHint; - switch (*SC.presentationHint) { - case Scope::eScopePresentationHintArguments: - presentationHint = "arguments"; - break; - case Scope::eScopePresentationHintLocals: - presentationHint = "locals"; - break; - case Scope::eScopePresentationHintRegisters: - presentationHint = "registers"; - break; - case Scope::eScopePresentationHintReturnValue: - presentationHint = "returnValue"; - break; - } - - result.insert({"presentationHint", presentationHint}); - } - - if (SC.namedVariables.has_value()) - result.insert({"namedVariables", SC.namedVariables}); - - if (SC.indexedVariables.has_value()) - result.insert({"indexedVariables", SC.indexedVariables}); - - if (SC.source.has_value()) - result.insert({"source", SC.source}); - - if (SC.line.has_value()) - result.insert({"line", SC.line}); - - if (SC.column.has_value()) - result.insert({"column", SC.column}); - - if (SC.endLine.has_value()) - result.insert({"endLine", SC.endLine}); - - if (SC.endColumn.has_value()) - result.insert({"endColumn", SC.endColumn}); - - return result; -} - -bool fromJSON(const llvm::json::Value &Params, Capabilities &C, - llvm::json::Path P) { - auto *Object = Params.getAsObject(); - if (!Object) { - P.report("expected an object"); - return false; - } - // Check for the presence of supported features. - for (unsigned i = eAdapterFeatureFirst; i <= eAdapterFeatureLast; ++i) { - AdapterFeature feature = static_cast(i); - if (Object->getBoolean(ToString(feature))) - C.supportedFeatures.insert(feature); - } - llvm::json::ObjectMapper O(Params, P); - return O && - O.mapOptional("exceptionBreakpointFilters", - C.exceptionBreakpointFilters) && - O.mapOptional("completionTriggerCharacters", - C.completionTriggerCharacters) && - O.mapOptional("additionalModuleColumns", C.additionalModuleColumns) && - O.mapOptional("supportedChecksumAlgorithms", - C.supportedChecksumAlgorithms) && - O.mapOptional("breakpointModes", C.breakpointModes) && - O.mapOptional("$__lldb_version", C.lldbExtVersion); -} - -bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG, - llvm::json::Path P) { - auto raw_granularity = Params.getAsString(); - if (!raw_granularity) { - P.report("expected a string"); - return false; - } - std::optional granularity = - StringSwitch>(*raw_granularity) - .Case("statement", eSteppingGranularityStatement) - .Case("line", eSteppingGranularityLine) - .Case("instruction", eSteppingGranularityInstruction) - .Default(std::nullopt); - if (!granularity) { - P.report("unexpected value"); - return false; - } - SG = *granularity; - return true; -} - -llvm::json::Value toJSON(const SteppingGranularity &SG) { - switch (SG) { - case eSteppingGranularityStatement: - return "statement"; - case eSteppingGranularityLine: - return "line"; - case eSteppingGranularityInstruction: - return "instruction"; - } - llvm_unreachable("unhandled stepping granularity."); -} - -bool fromJSON(const json::Value &Params, StepInTarget &SIT, json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.map("id", SIT.id) && O.map("label", SIT.label) && - O.map("line", SIT.line) && O.map("column", SIT.column) && - O.map("endLine", SIT.endLine) && O.map("endColumn", SIT.endColumn); -} - -llvm::json::Value toJSON(const StepInTarget &SIT) { - json::Object target{{"id", SIT.id}, {"label", SIT.label}}; - - if (SIT.line != LLDB_INVALID_LINE_NUMBER) - target.insert({"line", SIT.line}); - if (SIT.column != LLDB_INVALID_COLUMN_NUMBER) - target.insert({"column", SIT.column}); - if (SIT.endLine != LLDB_INVALID_LINE_NUMBER) - target.insert({"endLine", SIT.endLine}); - if (SIT.endLine != LLDB_INVALID_COLUMN_NUMBER) - target.insert({"endColumn", SIT.endColumn}); - - return target; -} - -bool fromJSON(const llvm::json::Value &Params, ValueFormat &VF, - llvm::json::Path P) { - json::ObjectMapper O(Params, P); - return O && O.mapOptional("hex", VF.hex); -} - -json::Value toJSON(const BreakpointLocation &B) { - json::Object result; - - result.insert({"line", B.line}); - if (B.column) - result.insert({"column", *B.column}); - if (B.endLine) - result.insert({"endLine", *B.endLine}); - if (B.endColumn) - result.insert({"endColumn", *B.endColumn}); - - return result; -} - -llvm::json::Value toJSON(const BreakpointReason &BR) { - switch (BR) { - case BreakpointReason::eBreakpointReasonPending: - return "pending"; - case BreakpointReason::eBreakpointReasonFailed: - return "failed"; - } - llvm_unreachable("unhandled breakpoint reason."); -} - -bool fromJSON(const llvm::json::Value &Params, BreakpointReason &BR, - llvm::json::Path P) { - auto rawReason = Params.getAsString(); - if (!rawReason) { - P.report("expected a string"); - return false; - } - std::optional reason = - llvm::StringSwitch>(*rawReason) - .Case("pending", BreakpointReason::eBreakpointReasonPending) - .Case("failed", BreakpointReason::eBreakpointReasonFailed) - .Default(std::nullopt); - if (!reason) { - P.report("unexpected value, expected 'pending' or 'failed'"); - return false; - } - BR = *reason; - return true; -} - -json::Value toJSON(const Breakpoint &BP) { - json::Object result{{"verified", BP.verified}}; - - if (BP.id) - result.insert({"id", *BP.id}); - if (BP.message) - result.insert({"message", *BP.message}); - if (BP.source) - result.insert({"source", *BP.source}); - if (BP.line) - result.insert({"line", *BP.line}); - if (BP.column) - result.insert({"column", *BP.column}); - if (BP.endLine) - result.insert({"endLine", *BP.endLine}); - if (BP.endColumn) - result.insert({"endColumn", *BP.endColumn}); - if (BP.instructionReference) - result.insert({"instructionReference", *BP.instructionReference}); - if (BP.offset) - result.insert({"offset", *BP.offset}); - if (BP.reason) { - result.insert({"reason", *BP.reason}); - } - - return result; -} - -bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.mapOptional("id", BP.id) && O.map("verified", BP.verified) && - O.mapOptional("message", BP.message) && - O.mapOptional("source", BP.source) && O.mapOptional("line", BP.line) && - O.mapOptional("column", BP.column) && - O.mapOptional("endLine", BP.endLine) && - O.mapOptional("endColumn", BP.endColumn) && - O.mapOptional("instructionReference", BP.instructionReference) && - O.mapOptional("offset", BP.offset) && - O.mapOptional("reason", BP.reason); -} - -bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.map("line", SB.line) && O.mapOptional("column", SB.column) && - O.mapOptional("condition", SB.condition) && - O.mapOptional("hitCondition", SB.hitCondition) && - O.mapOptional("logMessage", SB.logMessage) && - O.mapOptional("mode", SB.mode); -} - -llvm::json::Value toJSON(const SourceBreakpoint &SB) { - llvm::json::Object result{{"line", SB.line}}; - - if (SB.column) - result.insert({"column", *SB.column}); - if (SB.condition) - result.insert({"condition", *SB.condition}); - if (SB.hitCondition) - result.insert({"hitCondition", *SB.hitCondition}); - if (SB.logMessage) - result.insert({"logMessage", *SB.logMessage}); - if (SB.mode) - result.insert({"mode", *SB.mode}); - - return result; -} - -bool fromJSON(const llvm::json::Value &Params, FunctionBreakpoint &FB, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.map("name", FB.name) && - O.mapOptional("condition", FB.condition) && - O.mapOptional("hitCondition", FB.hitCondition); -} - -llvm::json::Value toJSON(const FunctionBreakpoint &FB) { - llvm::json::Object result{{"name", FB.name}}; - - if (FB.condition) - result.insert({"condition", *FB.condition}); - if (FB.hitCondition) - result.insert({"hitCondition", *FB.hitCondition}); - - return result; -} - -bool fromJSON(const llvm::json::Value &Params, DataBreakpointAccessType &DBAT, - llvm::json::Path P) { - auto rawAccessType = Params.getAsString(); - if (!rawAccessType) { - P.report("expected a string"); - return false; - } - std::optional accessType = - StringSwitch>(*rawAccessType) - .Case("read", eDataBreakpointAccessTypeRead) - .Case("write", eDataBreakpointAccessTypeWrite) - .Case("readWrite", eDataBreakpointAccessTypeReadWrite) - .Default(std::nullopt); - if (!accessType) { - P.report("unexpected value, expected 'read', 'write', or 'readWrite'"); - return false; - } - DBAT = *accessType; - return true; -} - -llvm::json::Value toJSON(const DataBreakpointAccessType &DBAT) { - switch (DBAT) { - case eDataBreakpointAccessTypeRead: - return "read"; - case eDataBreakpointAccessTypeWrite: - return "write"; - case eDataBreakpointAccessTypeReadWrite: - return "readWrite"; - } - llvm_unreachable("unhandled data breakpoint access type."); -} - -bool fromJSON(const llvm::json::Value &Params, DataBreakpoint &DBI, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.map("dataId", DBI.dataId) && - O.mapOptional("accessType", DBI.accessType) && - O.mapOptional("condition", DBI.condition) && - O.mapOptional("hitCondition", DBI.hitCondition); -} - -llvm::json::Value toJSON(const DataBreakpoint &DBI) { - llvm::json::Object result{{"dataId", DBI.dataId}}; - - if (DBI.accessType) - result.insert({"accessType", *DBI.accessType}); - if (DBI.condition) - result.insert({"condition", *DBI.condition}); - if (DBI.hitCondition) - result.insert({"hitCondition", *DBI.hitCondition}); - - return result; -} - -bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB, - llvm::json::Path P) { - llvm::json::ObjectMapper O(Params, P); - return O && O.map("instructionReference", IB.instructionReference) && - O.mapOptional("offset", IB.offset) && - O.mapOptional("condition", IB.condition) && - O.mapOptional("hitCondition", IB.hitCondition) && - O.mapOptional("mode", IB.mode); -} - -bool fromJSON(const llvm::json::Value &Params, - DisassembledInstruction::PresentationHint &PH, - llvm::json::Path P) { - auto rawHint = Params.getAsString(); - if (!rawHint) { - P.report("expected a string"); - return false; - } - std::optional hint = - StringSwitch>( - *rawHint) - .Case("normal", DisassembledInstruction:: - eDisassembledInstructionPresentationHintNormal) - .Case("invalid", DisassembledInstruction:: - eDisassembledInstructionPresentationHintInvalid) - .Default(std::nullopt); - if (!hint) { - P.report("unexpected value"); - return false; - } - PH = *hint; - return true; -} - -llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) { - switch (PH) { - case DisassembledInstruction::eDisassembledInstructionPresentationHintNormal: - return "normal"; - case DisassembledInstruction::eDisassembledInstructionPresentationHintInvalid: - return "invalid"; - } - llvm_unreachable("unhandled presentation hint."); -} - -bool fromJSON(const llvm::json::Value &Params, DisassembledInstruction &DI, - llvm::json::Path P) { - std::optional raw_address = - Params.getAsObject()->getString("address"); - if (!raw_address) { - P.report("missing 'address' field"); - return false; - } - - std::optional address = DecodeMemoryReference(*raw_address); - if (!address) { - P.report("invalid 'address'"); - return false; - } - - DI.address = *address; - llvm::json::ObjectMapper O(Params, P); - return O && O.map("instruction", DI.instruction) && - O.mapOptional("instructionBytes", DI.instructionBytes) && - O.mapOptional("symbol", DI.symbol) && - O.mapOptional("location", DI.location) && - O.mapOptional("line", DI.line) && O.mapOptional("column", DI.column) && - O.mapOptional("endLine", DI.endLine) && - O.mapOptional("endColumn", DI.endColumn) && - O.mapOptional("presentationHint", DI.presentationHint); -} - -llvm::json::Value toJSON(const DisassembledInstruction &DI) { - llvm::json::Object result{{"instruction", DI.instruction}}; - if (DI.address == LLDB_INVALID_ADDRESS) { - // VS Code has explicit comparisons to the string "-1" in order to check for - // invalid instructions. See - // https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/debug/browser/disassemblyView.ts - result.insert({"address", "-1"}); - } else { - result.insert({"address", "0x" + llvm::utohexstr(DI.address)}); - } - - if (DI.instructionBytes) - result.insert({"instructionBytes", *DI.instructionBytes}); - if (DI.symbol) - result.insert({"symbol", *DI.symbol}); - if (DI.location) - result.insert({"location", *DI.location}); - if (DI.line) - result.insert({"line", *DI.line}); - if (DI.column) - result.insert({"column", *DI.column}); - if (DI.endLine) - result.insert({"endLine", *DI.endLine}); - if (DI.endColumn) - result.insert({"endColumn", *DI.endColumn}); - if (DI.presentationHint) - result.insert({"presentationHint", *DI.presentationHint}); - - return result; -} - -} // namespace lldb_dap::protocol diff --git a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h b/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h deleted file mode 100644 index a9f67c280c92..000000000000 --- a/lldb/tools/lldb-dap/Protocol/ProtocolTypes.h +++ /dev/null @@ -1,721 +0,0 @@ -//===-- ProtocolTypes.h ---------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains POD structs based on the DAP specification at -// https://microsoft.github.io/debug-adapter-protocol/specification -// -// This is not meant to be a complete implementation, new interfaces are added -// when they're needed. -// -// Each struct has a toJSON and fromJSON function, that converts between -// the struct and a JSON representation. (See JSON.h) -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H -#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_TYPES_H - -#include "lldb/lldb-defines.h" -#include "llvm/ADT/DenseSet.h" -#include "llvm/Support/JSON.h" -#include -#include -#include -#include - -#define LLDB_DAP_INVALID_VARRERF UINT64_MAX - -namespace lldb_dap::protocol { - -/// An `ExceptionBreakpointsFilter` is shown in the UI as an filter option for -/// configuring how exceptions are dealt with. -struct ExceptionBreakpointsFilter { - /// The internal ID of the filter option. This value is passed to the - /// `setExceptionBreakpoints` request. - std::string filter; - - /// The name of the filter option. This is shown in the UI. - std::string label; - - /// A help text providing additional information about the exception filter. - /// This string is typically shown as a hover and can be translated. - std::optional description; - - /// Initial value of the filter option. If not specified a value false is - /// assumed. - std::optional defaultState; - - /// Controls whether a condition can be specified for this filter option. If - /// false or missing, a condition can not be set. - std::optional supportsCondition; - - /// A help text providing information about the condition. This string is - /// shown as the placeholder text for a text box and can be translated. - std::optional conditionDescription; -}; -bool fromJSON(const llvm::json::Value &, ExceptionBreakpointsFilter &, - llvm::json::Path); -llvm::json::Value toJSON(const ExceptionBreakpointsFilter &); - -enum ColumnType : unsigned { - eColumnTypeString, - eColumnTypeNumber, - eColumnTypeBoolean, - eColumnTypeTimestamp -}; -bool fromJSON(const llvm::json::Value &, ColumnType &, llvm::json::Path); -llvm::json::Value toJSON(const ColumnType &); - -/// A ColumnDescriptor specifies what module attribute to show in a column of -/// the modules view, how to format it, and what the column’s label should be. -/// -/// It is only used if the underlying UI actually supports this level of -/// customization. -struct ColumnDescriptor { - /// Name of the attribute rendered in this column. - std::string attributeName; - - /// Header UI label of column. - std::string label; - - /// Format to use for the rendered values in this column. TBD how the format - /// strings looks like. - std::optional format; - - /// Datatype of values in this column. Defaults to `string` if not specified. - /// Values: 'string', 'number', 'boolean', 'unixTimestampUTC'. - std::optional type; - - /// Width of this column in characters (hint only). - std::optional width; -}; -bool fromJSON(const llvm::json::Value &, ColumnDescriptor &, llvm::json::Path); -llvm::json::Value toJSON(const ColumnDescriptor &); - -/// Names of checksum algorithms that may be supported by a debug adapter. -/// Values: ‘MD5’, ‘SHA1’, ‘SHA256’, ‘timestamp’. -enum ChecksumAlgorithm : unsigned { - eChecksumAlgorithmMD5, - eChecksumAlgorithmSHA1, - eChecksumAlgorithmSHA256, - eChecksumAlgorithmTimestamp -}; -bool fromJSON(const llvm::json::Value &, ChecksumAlgorithm &, llvm::json::Path); -llvm::json::Value toJSON(const ChecksumAlgorithm &); - -/// Describes one or more type of breakpoint a BreakpointMode applies to. This -/// is a non-exhaustive enumeration and may expand as future breakpoint types -/// are added. -enum BreakpointModeApplicability : unsigned { - /// In `SourceBreakpoint`'s. - eBreakpointModeApplicabilitySource, - /// In exception breakpoints applied in the `ExceptionFilterOptions`. - eBreakpointModeApplicabilityException, - /// In data breakpoints requested in the `DataBreakpointInfo` request. - eBreakpointModeApplicabilityData, - /// In `InstructionBreakpoint`'s. - eBreakpointModeApplicabilityInstruction -}; -bool fromJSON(const llvm::json::Value &, BreakpointModeApplicability &, - llvm::json::Path); -llvm::json::Value toJSON(const BreakpointModeApplicability &); - -/// A `BreakpointMode` is provided as a option when setting breakpoints on -/// sources or instructions. -struct BreakpointMode { - /// The internal ID of the mode. This value is passed to the `setBreakpoints` - /// request. - std::string mode; - - /// The name of the breakpoint mode. This is shown in the UI. - std::string label; - - /// A help text providing additional information about the breakpoint mode. - /// This string is typically shown as a hover and can be translated. - std::optional description; - - /// Describes one or more type of breakpoint this mode applies to. - std::vector appliesTo; -}; -bool fromJSON(const llvm::json::Value &, BreakpointMode &, llvm::json::Path); -llvm::json::Value toJSON(const BreakpointMode &); - -/// Debug Adapter Features flags supported by lldb-dap. -enum AdapterFeature : unsigned { - /// The debug adapter supports ANSI escape sequences in styling of - /// `OutputEvent.output` and `Variable.value` fields. - eAdapterFeatureANSIStyling, - /// The debug adapter supports the `breakpointLocations` request. - eAdapterFeatureBreakpointLocationsRequest, - /// The debug adapter supports the `cancel` request. - eAdapterFeatureCancelRequest, - /// The debug adapter supports the `clipboard` context value in the - /// `evaluate` request. - eAdapterFeatureClipboardContext, - /// The debug adapter supports the `completions` request. - eAdapterFeatureCompletionsRequest, - /// The debug adapter supports conditional breakpoints. - eAdapterFeatureConditionalBreakpoints, - /// The debug adapter supports the `configurationDone` request. - eAdapterFeatureConfigurationDoneRequest, - /// The debug adapter supports the `asAddress` and `bytes` fields in the - /// `dataBreakpointInfo` request. - eAdapterFeatureDataBreakpointBytes, - /// The debug adapter supports data breakpoints. - eAdapterFeatureDataBreakpoints, - /// The debug adapter supports the delayed loading of parts of the stack, - /// which requires that both the `startFrame` and `levels` arguments and the - /// `totalFrames` result of the `stackTrace` request are supported. - eAdapterFeatureDelayedStackTraceLoading, - /// The debug adapter supports the `disassemble` request. - eAdapterFeatureDisassembleRequest, - /// The debug adapter supports a (side effect free) `evaluate` request for - /// data hovers. - eAdapterFeatureEvaluateForHovers, - /// The debug adapter supports `filterOptions` as an argument on the - /// `setExceptionBreakpoints` request. - eAdapterFeatureExceptionFilterOptions, - /// The debug adapter supports the `exceptionInfo` request. - eAdapterFeatureExceptionInfoRequest, - /// The debug adapter supports `exceptionOptions` on the - /// `setExceptionBreakpoints` request. - eAdapterFeatureExceptionOptions, - /// The debug adapter supports function breakpoints. - eAdapterFeatureFunctionBreakpoints, - /// The debug adapter supports the `gotoTargets` request. - eAdapterFeatureGotoTargetsRequest, - /// The debug adapter supports breakpoints that break execution after a - /// specified number of hits. - eAdapterFeatureHitConditionalBreakpoints, - /// The debug adapter supports adding breakpoints based on instruction - /// references. - eAdapterFeatureInstructionBreakpoints, - /// The debug adapter supports the `loadedSources` request. - eAdapterFeatureLoadedSourcesRequest, - /// The debug adapter supports log points by interpreting the `logMessage` - /// attribute of the `SourceBreakpoint`. - eAdapterFeatureLogPoints, - /// The debug adapter supports the `modules` request. - eAdapterFeatureModulesRequest, - /// The debug adapter supports the `readMemory` request. - eAdapterFeatureReadMemoryRequest, - /// The debug adapter supports restarting a frame. - eAdapterFeatureRestartFrame, - /// The debug adapter supports the `restart` request. In this case a client - /// should not implement `restart` by terminating and relaunching the - /// adapter but by calling the `restart` request. - eAdapterFeatureRestartRequest, - /// The debug adapter supports the `setExpression` request. - eAdapterFeatureSetExpression, - /// The debug adapter supports setting a variable to a value. - eAdapterFeatureSetVariable, - /// The debug adapter supports the `singleThread` property on the execution - /// requests (`continue`, `next`, `stepIn`, `stepOut`, `reverseContinue`, - /// `stepBack`). - eAdapterFeatureSingleThreadExecutionRequests, - /// The debug adapter supports stepping back via the `stepBack` and - /// `reverseContinue` requests. - eAdapterFeatureStepBack, - /// The debug adapter supports the `stepInTargets` request. - eAdapterFeatureStepInTargetsRequest, - /// The debug adapter supports stepping granularities (argument - /// `granularity`) for the stepping requests. - eAdapterFeatureSteppingGranularity, - /// The debug adapter supports the `terminate` request. - eAdapterFeatureTerminateRequest, - /// The debug adapter supports the `terminateThreads` request. - eAdapterFeatureTerminateThreadsRequest, - /// The debug adapter supports the `suspendDebuggee` attribute on the - /// `disconnect` request. - eAdapterFeatureSuspendDebuggee, - /// The debug adapter supports a `format` attribute on the `stackTrace`, - /// `variables`, and `evaluate` requests. - eAdapterFeatureValueFormattingOptions, - /// The debug adapter supports the `writeMemory` request. - eAdapterFeatureWriteMemoryRequest, - /// The debug adapter supports the `terminateDebuggee` attribute on the - /// `disconnect` request. - eAdapterFeatureTerminateDebuggee, - eAdapterFeatureFirst = eAdapterFeatureANSIStyling, - eAdapterFeatureLast = eAdapterFeatureTerminateDebuggee, -}; -bool fromJSON(const llvm::json::Value &, AdapterFeature &, llvm::json::Path); -llvm::json::Value toJSON(const AdapterFeature &); - -/// Information about the capabilities of a debug adapter. -struct Capabilities { - /// The supported features for this adapter. - llvm::DenseSet supportedFeatures; - - /// Available exception filter options for the `setExceptionBreakpoints` - /// request. - std::optional> - exceptionBreakpointFilters; - - /// The set of characters that should trigger completion in a REPL. If not - /// specified, the UI should assume the `.` character. - std::optional> completionTriggerCharacters; - - /// The set of additional module information exposed by the debug adapter. - std::optional> additionalModuleColumns; - - /// Checksum algorithms supported by the debug adapter. - std::optional> supportedChecksumAlgorithms; - - /// Modes of breakpoints supported by the debug adapter, such as 'hardware' or - /// 'software'. If present, the client may allow the user to select a mode and - /// include it in its `setBreakpoints` request. - /// - /// Clients may present the first applicable mode in this array as the - /// 'default' mode in gestures that set breakpoints. - std::optional> breakpointModes; - - /// lldb-dap Extensions - /// @{ - - /// The version of the adapter. - std::optional lldbExtVersion; - - /// @} -}; -bool fromJSON(const llvm::json::Value &, Capabilities &, llvm::json::Path); -llvm::json::Value toJSON(const Capabilities &); - -/// A `Source` is a descriptor for source code. It is returned from the debug -/// adapter as part of a `StackFrame` and it is used by clients when specifying -/// breakpoints. -struct Source { - enum PresentationHint : unsigned { - eSourcePresentationHintNormal, - eSourcePresentationHintEmphasize, - eSourcePresentationHintDeemphasize, - }; - - /// The short name of the source. Every source returned from the debug adapter - /// has a name. When sending a source to the debug adapter this name is - /// optional. - std::optional name; - - /// The path of the source to be shown in the UI. It is only used to locate - /// and load the content of the source if no `sourceReference` is specified - /// (or its value is 0). - std::optional path; - - /// If the value > 0 the contents of the source must be retrieved through the - /// `source` request (even if a path is specified). Since a `sourceReference` - /// is only valid for a session, it can not be used to persist a source. The - /// value should be less than or equal to 2147483647 (2^31-1). - std::optional sourceReference; - - /// A hint for how to present the source in the UI. A value of `deemphasize` - /// can be used to indicate that the source is not available or that it is - /// skipped on stepping. - std::optional presentationHint; - - // unsupported keys: origin, sources, adapterData, checksums -}; -bool fromJSON(const llvm::json::Value &, Source::PresentationHint &, - llvm::json::Path); -llvm::json::Value toJSON(Source::PresentationHint); -bool fromJSON(const llvm::json::Value &, Source &, llvm::json::Path); -llvm::json::Value toJSON(const Source &); - -/// A `Scope` is a named container for variables. Optionally a scope can map to -/// a source or a range within a source. -struct Scope { - enum PresentationHint : unsigned { - eScopePresentationHintArguments, - eScopePresentationHintLocals, - eScopePresentationHintRegisters, - eScopePresentationHintReturnValue - }; - /// Name of the scope such as 'Arguments', 'Locals', or 'Registers'. This - /// string is shown in the UI as is and can be translated. - //// - std::string name; - - /// A hint for how to present this scope in the UI. If this attribute is - /// missing, the scope is shown with a generic UI. - /// Values: - /// 'arguments': Scope contains method arguments. - /// 'locals': Scope contains local variables. - /// 'registers': Scope contains registers. Only a single `registers` scope - /// should be returned from a `scopes` request. - /// 'returnValue': Scope contains one or more return values. - /// etc. - std::optional presentationHint; - - /// The variables of this scope can be retrieved by passing the value of - /// `variablesReference` to the `variables` request as long as execution - /// remains suspended. See 'Lifetime of Object References' in the Overview - /// section for details. - //// - uint64_t variablesReference = LLDB_DAP_INVALID_VARRERF; - - /// The number of named variables in this scope. - /// The client can use this information to present the variables in a paged UI - /// and fetch them in chunks. - std::optional namedVariables; - - /// The number of indexed variables in this scope. - /// The client can use this information to present the variables in a paged UI - /// and fetch them in chunks. - std::optional indexedVariables; - - /// The source for this scope. - std::optional source; - - /// If true, the number of variables in this scope is large or expensive to - /// retrieve. - bool expensive = false; - - /// The start line of the range covered by this scope. - std::optional line; - - /// Start position of the range covered by the scope. It is measured in UTF-16 - /// code units and the client capability `columnsStartAt1` determines whether - /// it is 0- or 1-based. - std::optional column; - - /// The end line of the range covered by this scope. - std::optional endLine; - - /// End position of the range covered by the scope. It is measured in UTF-16 - /// code units and the client capability `columnsStartAt1` determines whether - /// it is 0- or 1-based. - std::optional endColumn; -}; -bool fromJSON(const llvm::json::Value &Params, Scope::PresentationHint &PH, - llvm::json::Path); -bool fromJSON(const llvm::json::Value &, Scope &, llvm::json::Path); -llvm::json::Value toJSON(const Scope &); - -/// The granularity of one `step` in the stepping requests `next`, `stepIn`, -/// `stepOut` and `stepBack`. -enum SteppingGranularity : unsigned { - /// The step should allow the program to run until the current statement has - /// finished executing. The meaning of a statement is determined by the - /// adapter and it may be considered equivalent to a line. For example - /// `for(int i = 0; i < 10; i++)` could be considered to have 3 statements - /// `int i = 0`, `i < 10`, and `i++`. - eSteppingGranularityStatement, - /// The step should allow the program to run until the current source line has - /// executed. - eSteppingGranularityLine, - /// The step should allow one instruction to execute (e.g. one x86 - /// instruction). - eSteppingGranularityInstruction, -}; -bool fromJSON(const llvm::json::Value &, SteppingGranularity &, - llvm::json::Path); -llvm::json::Value toJSON(const SteppingGranularity &); - -/// A `StepInTarget` can be used in the `stepIn` request and determines into -/// which single target the `stepIn` request should step. -struct StepInTarget { - /// Unique identifier for a step-in target. - lldb::addr_t id = LLDB_INVALID_ADDRESS; - - /// The name of the step-in target (shown in the UI). - std::string label; - - /// The line of the step-in target. - uint32_t line = LLDB_INVALID_LINE_NUMBER; - - /// Start position of the range covered by the step in target. It is measured - /// in UTF-16 code units and the client capability `columnsStartAt1` - /// determines whether it is 0- or 1-based. - uint32_t column = LLDB_INVALID_COLUMN_NUMBER; - - /// The end line of the range covered by the step-in target. - uint32_t endLine = LLDB_INVALID_LINE_NUMBER; - - /// End position of the range covered by the step in target. It is measured in - /// UTF-16 code units and the client capability `columnsStartAt1` determines - /// whether it is 0- or 1-based. - uint32_t endColumn = LLDB_INVALID_COLUMN_NUMBER; -}; -bool fromJSON(const llvm::json::Value &, StepInTarget &, llvm::json::Path); -llvm::json::Value toJSON(const StepInTarget &); - -/// Provides formatting information for a value. -struct ValueFormat { - /// Display the value in hex. - std::optional hex; -}; -bool fromJSON(const llvm::json::Value &, ValueFormat &, llvm::json::Path); - -/// Properties of a breakpoint location returned from the `breakpointLocations` -/// request. -struct BreakpointLocation { - /// Start line of breakpoint location. - uint32_t line; - - /// The start position of a breakpoint location. Position is measured in - /// UTF-16 code units and the client capability `columnsStartAt1` determines - /// whether it is 0- or 1-based. - std::optional column; - - /// The end line of breakpoint location if the location covers a range. - std::optional endLine; - - /// The end position of a breakpoint location (if the location covers a - /// range). Position is measured in UTF-16 code units and the client - /// capability `columnsStartAt1` determines whether it is 0- or 1-based. - std::optional endColumn; -}; -llvm::json::Value toJSON(const BreakpointLocation &); - -/// A machine-readable explanation of why a breakpoint may not be verified. -enum class BreakpointReason : unsigned { - /// Indicates a breakpoint might be verified in the future, but - /// the adapter cannot verify it in the current state. - eBreakpointReasonPending, - /// Indicates a breakpoint was not able to be verified, and the - /// adapter does not believe it can be verified without intervention. - eBreakpointReasonFailed, -}; -bool fromJSON(const llvm::json::Value &, BreakpointReason &, llvm::json::Path); -llvm::json::Value toJSON(const BreakpointReason &); - -/// Information about a breakpoint created in `setBreakpoints`, -/// `setFunctionBreakpoints`, `setInstructionBreakpoints`, or -/// `setDataBreakpoints` requests. -struct Breakpoint { - /// The identifier for the breakpoint. It is needed if breakpoint events are - /// used to update or remove breakpoints. - std::optional id; - - /// If true, the breakpoint could be set (but not necessarily at the desired - /// location). - bool verified = false; - - /// A message about the state of the breakpoint. - /// This is shown to the user and can be used to explain why a breakpoint - /// could not be verified. - std::optional message; - - /// The source where the breakpoint is located. - std::optional source; - - /// The start line of the actual range covered by the breakpoint. - std::optional line; - - /// Start position of the source range covered by the breakpoint. It is - /// measured in UTF-16 code units and the client capability `columnsStartAt1` - /// determines whether it is 0- or 1-based. - std::optional column; - - /// The end line of the actual range covered by the breakpoint. - std::optional endLine; - - /// End position of the source range covered by the breakpoint. It is measured - /// in UTF-16 code units and the client capability `columnsStartAt1` - /// determines whether it is 0- or 1-based. If no end line is given, then the - /// end column is assumed to be in the start line. - std::optional endColumn; - - /// A memory reference to where the breakpoint is set. - std::optional instructionReference; - - /// The offset from the instruction reference. - /// This can be negative. - std::optional offset; - - /// A machine-readable explanation of why a breakpoint may not be verified. If - /// a breakpoint is verified or a specific reason is not known, the adapter - /// should omit this property. - std::optional reason; -}; -bool fromJSON(const llvm::json::Value &, Breakpoint &, llvm::json::Path); -llvm::json::Value toJSON(const Breakpoint &); - -/// Properties of a breakpoint or logpoint passed to the `setBreakpoints` -/// request -struct SourceBreakpoint { - /// The source line of the breakpoint or logpoint. - uint32_t line = LLDB_INVALID_LINE_NUMBER; - - /// Start position within source line of the breakpoint or logpoint. It is - /// measured in UTF-16 code units and the client capability `columnsStartAt1` - /// determines whether it is 0- or 1-based. - std::optional column; - - /// The expression for conditional breakpoints. - /// It is only honored by a debug adapter if the corresponding capability - /// `supportsConditionalBreakpoints` is true. - std::optional condition; - - /// The expression that controls how many hits of the breakpoint are ignored. - /// The debug adapter is expected to interpret the expression as needed. - /// The attribute is only honored by a debug adapter if the corresponding - /// capability `supportsHitConditionalBreakpoints` is true. - /// If both this property and `condition` are specified, `hitCondition` should - /// be evaluated only if the `condition` is met, and the debug adapter should - /// stop only if both conditions are met. - std::optional hitCondition; - - /// If this attribute exists and is non-empty, the debug adapter must not - /// 'break' (stop) - /// but log the message instead. Expressions within `{}` are interpolated. - /// The attribute is only honored by a debug adapter if the corresponding - /// capability `supportsLogPoints` is true. - /// If either `hitCondition` or `condition` is specified, then the message - /// should only be logged if those conditions are met. - std::optional logMessage; - - /// The mode of this breakpoint. If defined, this must be one of the - /// `breakpointModes` the debug adapter advertised in its `Capabilities`. - std::optional mode; -}; -bool fromJSON(const llvm::json::Value &, SourceBreakpoint &, llvm::json::Path); -llvm::json::Value toJSON(const SourceBreakpoint &); - -/// Properties of a breakpoint passed to the `setFunctionBreakpoints` request. -struct FunctionBreakpoint { - /// The name of the function. - std::string name; - - /// An expression for conditional breakpoints. - /// It is only honored by a debug adapter if the corresponding capability - /// `supportsConditionalBreakpoints` is true. - std::optional condition; - - /// An expression that controls how many hits of the breakpoint are ignored. - /// The debug adapter is expected to interpret the expression as needed. - /// The attribute is only honored by a debug adapter if the corresponding - /// capability `supportsHitConditionalBreakpoints` is true. - std::optional hitCondition; -}; -bool fromJSON(const llvm::json::Value &, FunctionBreakpoint &, - llvm::json::Path); -llvm::json::Value toJSON(const FunctionBreakpoint &); - -/// This enumeration defines all possible access types for data breakpoints. -/// Values: ‘read’, ‘write’, ‘readWrite’ -enum DataBreakpointAccessType : unsigned { - eDataBreakpointAccessTypeRead, - eDataBreakpointAccessTypeWrite, - eDataBreakpointAccessTypeReadWrite -}; -bool fromJSON(const llvm::json::Value &, DataBreakpointAccessType &, - llvm::json::Path); -llvm::json::Value toJSON(const DataBreakpointAccessType &); - -/// Properties of a data breakpoint passed to the `setDataBreakpoints` request. -struct DataBreakpoint { - /// An id representing the data. This id is returned from the - /// `dataBreakpointInfo` request. - std::string dataId; - - /// The access type of the data. - std::optional accessType; - - /// An expression for conditional breakpoints. - std::optional condition; - - /// An expression that controls how many hits of the breakpoint are ignored. - /// The debug adapter is expected to interpret the expression as needed. - std::optional hitCondition; -}; -bool fromJSON(const llvm::json::Value &, DataBreakpoint &, llvm::json::Path); -llvm::json::Value toJSON(const DataBreakpoint &); - -/// Properties of a breakpoint passed to the `setInstructionBreakpoints` request -struct InstructionBreakpoint { - /// The instruction reference of the breakpoint. - /// This should be a memory or instruction pointer reference from an - /// `EvaluateResponse`, `Variable`, `StackFrame`, `GotoTarget`, or - /// `Breakpoint`. - std::string instructionReference; - - /// The offset from the instruction reference in bytes. - /// This can be negative. - std::optional offset; - - /// An expression for conditional breakpoints. - /// It is only honored by a debug adapter if the corresponding capability - /// `supportsConditionalBreakpoints` is true. - std::optional condition; - - /// An expression that controls how many hits of the breakpoint are ignored. - /// The debug adapter is expected to interpret the expression as needed. - /// The attribute is only honored by a debug adapter if the corresponding - /// capability `supportsHitConditionalBreakpoints` is true. - std::optional hitCondition; - - /// The mode of this breakpoint. If defined, this must be one of the - /// `breakpointModes` the debug adapter advertised in its `Capabilities`. - std::optional mode; -}; -bool fromJSON(const llvm::json::Value &, InstructionBreakpoint &, - llvm::json::Path); - -/// Properties of a single disassembled instruction, returned by `disassemble` -/// request. -struct DisassembledInstruction { - enum PresentationHint : unsigned { - eDisassembledInstructionPresentationHintNormal, - eDisassembledInstructionPresentationHintInvalid, - }; - - /// The address of the instruction. Treated as a hex value if prefixed with - /// `0x`, or as a decimal value otherwise. - lldb::addr_t address; - - /// Raw bytes representing the instruction and its operands, in an - /// implementation-defined format. - std::optional instructionBytes; - - /// Text representing the instruction and its operands, in an - /// implementation-defined format. - std::string instruction; - - /// Name of the symbol that corresponds with the location of this instruction, - /// if any. - std::optional symbol; - - /// Source location that corresponds to this instruction, if any. - /// Should always be set (if available) on the first instruction returned, - /// but can be omitted afterwards if this instruction maps to the same source - /// file as the previous instruction. - std::optional location; - - /// The line within the source location that corresponds to this instruction, - /// if any. - std::optional line; - - /// The column within the line that corresponds to this instruction, if any. - std::optional column; - - /// The end line of the range that corresponds to this instruction, if any. - std::optional endLine; - - /// The end column of the range that corresponds to this instruction, if any. - std::optional endColumn; - - /// A hint for how to present the instruction in the UI. - /// - /// A value of `invalid` may be used to indicate this instruction is 'filler' - /// and cannot be reached by the program. For example, unreadable memory - /// addresses may be presented is 'invalid.' - /// Values: 'normal', 'invalid' - std::optional presentationHint; - - DisassembledInstruction() : address(0) {} -}; -bool fromJSON(const llvm::json::Value &, - DisassembledInstruction::PresentationHint &, llvm::json::Path); -llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &); -bool fromJSON(const llvm::json::Value &, DisassembledInstruction &, - llvm::json::Path); -llvm::json::Value toJSON(const DisassembledInstruction &); - -} // namespace lldb_dap::protocol - -#endif diff --git a/lldb/tools/lldb-dap/ProtocolUtils.cpp b/lldb/tools/lldb-dap/ProtocolUtils.cpp deleted file mode 100644 index 4e47c87b7359..000000000000 --- a/lldb/tools/lldb-dap/ProtocolUtils.cpp +++ /dev/null @@ -1,113 +0,0 @@ -//===-- ProtocolUtils.cpp -------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "ProtocolUtils.h" -#include "LLDBUtils.h" - -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBTarget.h" -#include "lldb/Host/PosixApi.h" // Adds PATH_MAX for windows - -namespace lldb_dap { - -static bool ShouldDisplayAssemblySource( - lldb::SBAddress address, - lldb::StopDisassemblyType stop_disassembly_display) { - if (stop_disassembly_display == lldb::eStopDisassemblyTypeNever) - return false; - - if (stop_disassembly_display == lldb::eStopDisassemblyTypeAlways) - return true; - - // A line entry of 0 indicates the line is compiler generated i.e. no source - // file is associated with the frame. - auto line_entry = address.GetLineEntry(); - auto file_spec = line_entry.GetFileSpec(); - if (!file_spec.IsValid() || line_entry.GetLine() == 0 || - line_entry.GetLine() == LLDB_INVALID_LINE_NUMBER) - return true; - - if (stop_disassembly_display == lldb::eStopDisassemblyTypeNoSource && - !file_spec.Exists()) { - return true; - } - - return false; -} - -static protocol::Source CreateAssemblySource(const lldb::SBTarget &target, - lldb::SBAddress address) { - protocol::Source source; - - auto symbol = address.GetSymbol(); - std::string name; - if (symbol.IsValid()) { - source.sourceReference = symbol.GetStartAddress().GetLoadAddress(target); - name = symbol.GetName(); - } else { - const auto load_addr = address.GetLoadAddress(target); - source.sourceReference = load_addr; - name = GetLoadAddressString(load_addr); - } - - lldb::SBModule module = address.GetModule(); - if (module.IsValid()) { - lldb::SBFileSpec file_spec = module.GetFileSpec(); - if (file_spec.IsValid()) { - std::string path = GetSBFileSpecPath(file_spec); - if (!path.empty()) - source.path = path + '`' + name; - } - } - - source.name = std::move(name); - - // Mark the source as deemphasized since users will only be able to view - // assembly for these frames. - source.presentationHint = - protocol::Source::PresentationHint::eSourcePresentationHintDeemphasize; - - return source; -} - -protocol::Source CreateSource(const lldb::SBFileSpec &file) { - protocol::Source source; - if (file.IsValid()) { - if (const char *name = file.GetFilename()) - source.name = name; - char path[PATH_MAX] = ""; - if (file.GetPath(path, sizeof(path)) && - lldb::SBFileSpec::ResolvePath(path, path, PATH_MAX)) - source.path = path; - } - return source; -} - -protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target) { - lldb::SBDebugger debugger = target.GetDebugger(); - lldb::StopDisassemblyType stop_disassembly_display = - GetStopDisassemblyDisplay(debugger); - if (ShouldDisplayAssemblySource(address, stop_disassembly_display)) - return CreateAssemblySource(target, address); - - lldb::SBLineEntry line_entry = GetLineEntryForAddress(target, address); - return CreateSource(line_entry.GetFileSpec()); -} - -bool IsAssemblySource(const protocol::Source &source) { - // According to the specification, a source must have either `path` or - // `sourceReference` specified. We use `path` for sources with known source - // code, and `sourceReferences` when falling back to assembly. - return source.sourceReference.value_or(0) != 0; -} - -std::string GetLoadAddressString(const lldb::addr_t addr) { - return "0x" + llvm::utohexstr(addr, false, 16); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/ProtocolUtils.h b/lldb/tools/lldb-dap/ProtocolUtils.h deleted file mode 100644 index 6e4f07d6e347..000000000000 --- a/lldb/tools/lldb-dap/ProtocolUtils.h +++ /dev/null @@ -1,53 +0,0 @@ -//===-- ProtocolUtils.h ---------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file contains Utility function for protocol objects. -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_UTILS_H -#define LLDB_TOOLS_LLDB_DAP_PROTOCOL_PROTOCOL_UTILS_H - -#include "Protocol/ProtocolTypes.h" - -#include "lldb/API/SBAddress.h" - -namespace lldb_dap { - -/// Create a "Source" JSON object as described in the debug adapter definition. -/// -/// \param[in] file -/// The SBFileSpec to use when populating out the "Source" object -/// -/// \return -/// A "Source" JSON object that follows the formal JSON -/// definition outlined by Microsoft. -protocol::Source CreateSource(const lldb::SBFileSpec &file); - -/// Create a "Source" JSON object as described in the debug adapter definition. -/// -/// \param[in] address -/// The address to use when populating out the "Source" object. -/// -/// \param[in] target -/// The target that has the address. -/// -/// \return -/// A "Source" JSON object that follows the formal JSON -/// definition outlined by Microsoft. -protocol::Source CreateSource(lldb::SBAddress address, lldb::SBTarget &target); - -/// Checks if the given source is for assembly code. -bool IsAssemblySource(const protocol::Source &source); - -/// Get the address as a 16-digit hex string, e.g. "0x0000000000012345" -std::string GetLoadAddressString(const lldb::addr_t addr); - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/README.md b/lldb/tools/lldb-dap/README.md deleted file mode 100644 index 18bfa9d518b9..000000000000 --- a/lldb/tools/lldb-dap/README.md +++ /dev/null @@ -1,381 +0,0 @@ -# LLDB DAP - -## Procuring the `lldb-dap` binary - -The extension requires the `lldb-dap` (formerly `lldb-vscode`) binary. -This binary is not packaged with the VS Code extension. - -There are multiple ways to obtain this binary: - -- Use the binary provided by your toolchain (for example `xcrun -f lldb-dap` on macOS) or contact your toolchain vendor to include it. -- Download one of the release packages from the [LLVM release page](https://github.com/llvm/llvm-project/releases/). The `LLVM-19.1.0-{operating_system}.tar.xz` packages contain a prebuilt `lldb-dap` binary. -- Build it from source (see [LLDB's build instructions](https://lldb.llvm.org/resources/build.html)). - -By default, the VS Code extension will expect to find `lldb-dap` in your `PATH`. -Alternatively, you can explicitly specify the location of the `lldb-dap` binary using the `lldb-dap.executable-path` setting. - -### Usage with other IDEs - -The `lldb-dap` binary is a command line tool that implements the [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/). -It is used to power the VS Code extension but can also be used with other IDEs and editors that support DAP. -The protocol is easy to run remotely and also can allow other tools and IDEs to get a full featured debugger with a well defined protocol. - -## Launching & Attaching to a debugee - -Launching or attaching a debugee require you to create a [launch configuration](https://code.visualstudio.com/Docs/editor/debugging#_launch-configurations). -This file defines arguments that get passed to `lldb-dap` and the configuration settings control how the launch or attach happens. - -### Launching a debugee - -This will launch `/tmp/a.out` with arguments `one`, `two`, and `three` and -adds `FOO=1` and `bar` to the environment: - -```javascript -{ - "type": "lldb-dap", - "request": "launch", - "name": "Debug", - "program": "/tmp/a.out", - "args": [ "one", "two", "three" ], - "env": { - "FOO": "1", - "BAR": "" - } -} -``` - -### Attaching to a process - -When attaching to a process using LLDB, you can attach in multiple ways: - -1. Attach to an existing process using the process ID -2. Attach to an existing process by name -3. Attach by name by waiting for the next instance of a process to launch - -#### Attach using PID - -This will attach to a process `a.out` whose process ID is 123: - -```javascript -{ - "type": "lldb-dap", - "request": "attach", - "name": "Attach to PID", - "program": "/tmp/a.out", - "pid": 123 -} -``` - -#### Attach by Name - -This will attach to an existing process whose base -name matches `a.out`. All we have to do is leave the `pid` value out of the -above configuration: - -```javascript -{ - "name": "Attach to Name", - "type": "lldb-dap", - "request": "attach", - "program": "/tmp/a.out", -} -``` - -If you want to ignore any existing a.out processes and wait for the next instance -to be launched you can add the "waitFor" key value pair: - -```javascript -{ - "name": "Attach to Name (wait)", - "type": "lldb-dap", - "request": "attach", - "program": "/tmp/a.out", - "waitFor": true -} -``` - -This will work as long as the architecture, vendor and OS supports waiting -for processes. Currently MacOS is the only platform that supports this. - -### Loading a Core File - -This loads the coredump file `/cores/123.core` associated with the program -`/tmp/a.out`: - -```javascript -{ - "name": "Load coredump", - "type": "lldb-dap", - "request": "attach", - "coreFile": "/cores/123.core", - "program": "/tmp/a.out" -} -``` - -### Connect to a Debug Server on the Current Machine - -This connects to a debug server (e.g. `lldb-server`, `gdbserver`) on -the current machine, that is debugging the program `/tmp/a.out` and listening -locally on port `2345`. - -```javascript -{ - "name": "Local Debug Server", - "type": "lldb-dap", - "request": "attach", - "program": "/tmp/a.out", - "attachCommands": ["gdb-remote 2345"], -} -``` - -You can also use the `gdb-remote-port` parameter to send an attach request -to a debug server running on the current machine, -instead of using the custom command `attachCommands`. - -```javascript -{ - "name": "Local Debug Server", - "type": "lldb-dap", - "request": "attach", - "program": "/tmp/a.out", - "gdb-remote-port": 2345, -} -``` - -### Connect to a Debug Server on Another Machine - -This connects to a debug server running on another machine with hostname -`hostname`. Which is debugging the program `/tmp/a.out` and listening on -port `5678` of that other machine. - -```javascript -{ - "name": "Remote Debug Server", - "type": "lldb-dap", - "request": "attach", - "program": "/tmp/a.out", - "attachCommands": ["gdb-remote hostname:5678"], -} -``` - -You can also use the `gdb-remote-hostname` and `gdb-remote-port` parameters -to send an attach request to a debug server running on a different machine, -instead of custom command `attachCommands`. -The default hostname being used `localhost`. - -```javascript -{ - "name": "Local Debug Server", - "type": "lldb-dap", - "request": "attach", - "program": "/tmp/a.out", - "gdb-remote-port": 5678, - "gdb-remote-hostname": "hostname", -} -``` - -### Launching via `vscode://` URIs - -Debugging sessions can also be starting using special URIs. - -The `vscode://llvm-vs-code-extensions.lldb-dap/start?config={launch-config}` -URI accepts a [URL-encoded](https://en.wikipedia.org/wiki/Percent-encoding) -JSON launch config. The most frequently used arguments (`request`, `program`, -`args`, `cwd`, `pid`, ...) can also specified directly, e.g. -`vscode://llvm-vs-code-extensions.lldb-dap/start?request=attach&pid=1234`, or -`vscode://llvm-vs-code-extensions.lldb-dap/start?program=ls&args=-a&args=/etc`. - -This is useful for integration with custom scripts to start debugging -sessions. The URI might be printed to the terminal, potentially using -[OSC-8 hyperlinks](https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda), -or passed to `code --open-url` or `xdg-open`, although mileage may vary depending -on your specific debugging setup. E.g., `code --open-url` will not work when using a -SSH remote session. Furthermore, placeholders such as `${workspaceFolder}` are not -supported within launch URLs. - -### Configuration Settings Reference - -For both launch and attach configurations, lldb-dap accepts the following `lldb-dap` -specific key/value pairs: - -| Parameter | Type | Req | | -|-----------------------------------|-------------|:---:|---------| -| **name** | string | Y | A configuration name that will be displayed in the IDE. -| **type** | string | Y | Must be "lldb-dap". -| **request** | string | Y | Must be "launch" or "attach". -| **program** | string | Y | Path to the executable to launch. -| **sourcePath** | string | | Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths. -| **sourceMap** | [string[2]] | | Specify an array of path re-mappings. Each element in the array must be a two element array containing a source and destination pathname. Overrides sourcePath. -| **debuggerRoot** | string | | Specify a working directory to use when launching lldb-dap. If the debug information in your executable contains relative paths, this option can be used so that `lldb-dap` can find source files and object files that have relative paths. -| **commandEscapePrefix** | string | | The escape prefix to use for executing regular LLDB commands in the Debug Console, instead of printing variables. Defaults to a backtick. If it's an empty string, then all expression in the Debug Console are treated as regular LLDB commands. -| **customFrameFormat** | string | | If non-empty, stack frames will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html for an explanation on format strings for frames. If the format string contains errors, an error message will be displayed on the Debug Console and the default frame names will be used. This might come with a performance cost because debug information might need to be processed to generate the description. -| **customThreadFormat** | string | | Same as `customFrameFormat`, but for threads instead of stack frames. -| **displayExtendedBacktrace** | bool | | Enable language specific extended backtraces. -| **enableAutoVariableSummaries** | bool | | Enable auto generated summaries for variables when no summaries exist for a given type. This feature can cause performance delays in large projects when viewing variables. -| **enableSyntheticChildDebugging** | bool | | If a variable is displayed using a synthetic children, also display the actual contents of the variable at the end under a [raw] entry. This is useful when creating synthetic child plug-ins as it lets you see the actual contents of the variable. -| **initCommands** | [string] | | LLDB commands executed upon debugger startup prior to creating the LLDB target. -| **preRunCommands** | [string] | | LLDB commands executed just before launching/attaching, after the LLDB target has been created. -| **stopCommands** | [string] | | LLDB commands executed just after each stop. -| **exitCommands** | [string] | | LLDB commands executed when the program exits. -| **terminateCommands** | [string] | | LLDB commands executed when the debugging session ends. - -All commands and command outputs will be sent to the debugger console when they are executed. -Commands can be prefixed with `?` or `!` to modify their behavior: - -- Commands prefixed with `?` are quiet on success, i.e. nothing is written to stdout if the command succeeds. -- Prefixing a command with `!` enables error checking: If a command prefixed with `!` fails, subsequent commands will not be run. This is useful if one of the commands depends on another, as it will stop the chain of commands. - -For JSON configurations of `"type": "launch"`, the JSON configuration can additionally -contain the following key/value pairs: - -| Parameter | Type | Req | | -|-----------------------------------|-------------|:---:|---------| -| **program** | string | Y | Path to the executable to launch. -| **args** | [string] | | An array of command line argument strings to be passed to the program being launched. -| **cwd** | string | | The program working directory. -| **env** | dictionary | | Environment variables to set when launching the program. The format of each environment variable string is "VAR=VALUE" for environment variables with values or just "VAR" for environment variables with no values. -| **stopOnEntry** | boolean | | Whether to stop program immediately after launching. -| **runInTerminal** | boolean | | Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs. -| **launchCommands** | [string] | | LLDB commands executed to launch the program. - -For JSON configurations of `"type": "attach"`, the JSON configuration can contain -the following `lldb-dap` specific key/value pairs: - -| Parameter | Type | Req | | -|-----------------------------------|-------------|:---:|---------| -| **program** | string | | Path to the executable to attach to. This value is optional but can help to resolve breakpoints prior the attaching to the program. -| **pid** | number | | The process id of the process you wish to attach to. If **pid** is omitted, the debugger will attempt to attach to the program by finding a process whose file name matches the file name from **program**. Setting this value to `${command:pickMyProcess}` will allow interactive process selection in the IDE. -| **waitFor** | boolean | | Wait for the process to launch. -| **attachCommands** | [string] | | LLDB commands that will be executed after **preRunCommands** which take place of the code that normally does the attach. The commands can create a new target and attach or launch it however desired. This allows custom launch and attach configurations. Core files can use `target create --core /path/to/core` to attach to core files. - -### Configuring `lldb-dap` defaults - -User settings can set the default value for the following supported -`launch.json` configuration keys: - -| Parameter | Type | Default | -| --------------------------------- | -------- | :-----: | -| **commandEscapePrefix** | string | ``"`"`` | -| **customFrameFormat** | string | `""` | -| **customThreadFormat** | string | `""` | -| **detachOnError** | boolean | `false` | -| **disableASLR** | boolean | `true` | -| **disableSTDIO** | boolean | `false` | -| **displayExtendedBacktrace** | boolean | `false` | -| **enableAutoVariableSummaries** | boolean | `false` | -| **enableSyntheticChildDebugging** | boolean | `false` | -| **timeout** | number | `30` | -| **targetTriple** | string | `""` | -| **platformName** | string | `""` | -| **initCommands** | [string] | `[]` | -| **preRunCommands** | [string] | `[]` | -| **postRunCommands** | [string] | `[]` | -| **stopCommands** | [string] | `[]` | -| **exitCommands** | [string] | `[]` | -| **terminateCommands** | [string] | `[]` | - -To adjust your settings, open the Settings editor via the -`File > Preferences > Settings` menu or press `Ctrl+`, on Windows/Linux and -`Cmd+`, on Mac. - -## Debug Console - -The Debug Console allows printing variables / expressions and executing lldb commands. -By default, lldb-dap tries to auto-detect whether a provided command is a variable -name / expression whose values will be printed to the Debug Console or a LLDB command. -To side-step this auto-detection and execute a LLDB command, prefix it with the -`commandEscapePrefix`. - -The auto-detection can be disabled using the `lldb-dap repl-mode` command. -The escape character can be adjusted via the `commandEscapePrefix` configuration option. - -### lldb-dap specific commands - -The `lldb-dap` tool includes additional custom commands to support the Debug -Adapter Protocol features. - -#### `lldb-dap start-debugging` - -Using the command `lldb-dap start-debugging` it is possible to trigger a -reverse request to the client requesting a child debug session with the -specified configuration. For example, this can be used to attached to forked or -spawned processes. For more information see -[Reverse Requests StartDebugging](https://microsoft.github.io/debug-adapter-protocol/specification#Reverse_Requests_StartDebugging). - -The custom command has the following format: - -``` -lldb-dap start-debugging -``` - -This will launch a server and then request a child debug session for a client. - -```javascript -{ - "program": "server", - "postRunCommand": [ - "lldb-dap start-debugging launch '{\"program\":\"client\"}'" - ] -} -``` - -#### `lldb-dap repl-mode` - -Inspect or adjust the behavior of lldb-dap repl evaluation requests. The -supported modes are `variable`, `command` and `auto`. - -- `variable` - Variable mode expressions are evaluated in the context of the - current frame. -- `command` - Command mode expressions are evaluated as lldb commands, as a - result, values printed by lldb are always stringified representations of the - expression output. -- `auto` - Auto mode will attempt to infer if the expression represents an lldb - command or a variable expression. A heuristic is used to infer if the input - represents a variable or a command. - -In all three modes, you can use the `commandEscapePrefix` to ensure an expression -is evaluated as a command. - -The initial repl-mode can be configured with the cli flag `--repl-mode=` -and may also be adjusted at runtime using the lldb command -`lldb-dap repl-mode `. - -#### `lldb-dap send-event` - -lldb-dap includes a command to trigger a Debug Adapter Protocol event -from a script. - -The event maybe a custom DAP event or a standard event, if the event is not -handled internally by `lldb-dap`. - -This command has the format: - -``` -lldb-dap send-event ? -``` - -For example you can use a launch configuration hook to trigger custom events like: - -```json -{ - "program": "exe", - "stopCommands": [ - "lldb-dap send-event MyStopEvent", - "lldb-dap send-event MyStopEvent '{\"key\": 321}" - ] -} -``` - -[See the specification](https://microsoft.github.io/debug-adapter-protocol/specification#Base_Protocol_Event) -for more details on Debug Adapter Protocol events and the VS Code -[debug.onDidReceiveDebugSessionCustomEvent](https://code.visualstudio.com/api/references/vscode-api#debug.onDidReceiveDebugSessionCustomEvent) -API for handling a custom event from an extension. - -## Contributing - -`lldb-dap` and `lldb` are developed under the umbrella of the [LLVM project](https://llvm.org/). -The source code is part of the [LLVM repository](https://github.com/llvm/llvm-project/tree/main/lldb/tools/lldb-dap) on Github. -We use Github's [issue tracker](https://github.com/llvm/llvm-project/issues?q=label%3Alldb-dap) and patches can be submitted via [pull requests](https://github.com/llvm/llvm-project/pulls?q=label%3Alldb-dap). -Furthermore, there is a [LLDB category](https://discourse.llvm.org/c/subprojects/lldb/8) on the LLVM discourse forum. - -For instructions on how to get started with development on lldb-dap, see the "[Contributing to lldb-dap](https://lldb.llvm.org/resources/lldbdap.html)" guide. diff --git a/lldb/tools/lldb-dap/RunInTerminal.cpp b/lldb/tools/lldb-dap/RunInTerminal.cpp deleted file mode 100644 index 9f309dd78221..000000000000 --- a/lldb/tools/lldb-dap/RunInTerminal.cpp +++ /dev/null @@ -1,170 +0,0 @@ -//===-- RunInTerminal.cpp ---------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "RunInTerminal.h" -#include "JSONUtils.h" - -#if !defined(_WIN32) -#include -#include -#include -#endif - -#include -#include - -#include "llvm/Support/FileSystem.h" - -using namespace llvm; - -namespace lldb_dap { - -const RunInTerminalMessagePid *RunInTerminalMessage::GetAsPidMessage() const { - return static_cast(this); -} - -const RunInTerminalMessageError * -RunInTerminalMessage::GetAsErrorMessage() const { - return static_cast(this); -} - -RunInTerminalMessage::RunInTerminalMessage(RunInTerminalMessageKind kind) - : kind(kind) {} - -RunInTerminalMessagePid::RunInTerminalMessagePid(lldb::pid_t pid) - : RunInTerminalMessage(eRunInTerminalMessageKindPID), pid(pid) {} - -json::Value RunInTerminalMessagePid::ToJSON() const { - return json::Object{{"kind", "pid"}, {"pid", static_cast(pid)}}; -} - -RunInTerminalMessageError::RunInTerminalMessageError(StringRef error) - : RunInTerminalMessage(eRunInTerminalMessageKindError), error(error) {} - -json::Value RunInTerminalMessageError::ToJSON() const { - return json::Object{{"kind", "error"}, {"value", error}}; -} - -RunInTerminalMessageDidAttach::RunInTerminalMessageDidAttach() - : RunInTerminalMessage(eRunInTerminalMessageKindDidAttach) {} - -json::Value RunInTerminalMessageDidAttach::ToJSON() const { - return json::Object{{"kind", "didAttach"}}; -} - -static Expected -ParseJSONMessage(const json::Value &json) { - if (const json::Object *obj = json.getAsObject()) { - if (std::optional kind = obj->getString("kind")) { - if (*kind == "pid") { - if (std::optional pid = obj->getInteger("pid")) - return std::make_unique( - static_cast(*pid)); - } else if (*kind == "error") { - if (std::optional error = obj->getString("error")) - return std::make_unique(*error); - } else if (*kind == "didAttach") { - return std::make_unique(); - } - } - } - - return createStringError(inconvertibleErrorCode(), - "Incorrect JSON message: " + JSONToString(json)); -} - -static Expected -GetNextMessage(FifoFileIO &io, std::chrono::milliseconds timeout) { - if (Expected json = io.ReadJSON(timeout)) - return ParseJSONMessage(*json); - else - return json.takeError(); -} - -static Error ToError(const RunInTerminalMessage &message) { - if (message.kind == eRunInTerminalMessageKindError) - return createStringError(inconvertibleErrorCode(), - message.GetAsErrorMessage()->error); - return createStringError(inconvertibleErrorCode(), - "Unexpected JSON message: " + - JSONToString(message.ToJSON())); -} - -RunInTerminalLauncherCommChannel::RunInTerminalLauncherCommChannel( - StringRef comm_file) - : m_io(comm_file, "debug adapter") {} - -Error RunInTerminalLauncherCommChannel::WaitUntilDebugAdapterAttaches( - std::chrono::milliseconds timeout) { - if (Expected message = - GetNextMessage(m_io, timeout)) { - if (message.get()->kind == eRunInTerminalMessageKindDidAttach) - return Error::success(); - else - return ToError(*message.get()); - } else - return message.takeError(); -} - -Error RunInTerminalLauncherCommChannel::NotifyPid() { - return m_io.SendJSON(RunInTerminalMessagePid(getpid()).ToJSON()); -} - -void RunInTerminalLauncherCommChannel::NotifyError(StringRef error) { - if (Error err = m_io.SendJSON(RunInTerminalMessageError(error).ToJSON(), - std::chrono::seconds(2))) - llvm::errs() << llvm::toString(std::move(err)) << "\n"; -} - -RunInTerminalDebugAdapterCommChannel::RunInTerminalDebugAdapterCommChannel( - StringRef comm_file) - : m_io(comm_file, "runInTerminal launcher") {} - -// Can't use \a std::future because it doesn't compile on Windows -std::future -RunInTerminalDebugAdapterCommChannel::NotifyDidAttach() { - return std::async(std::launch::async, [&]() { - lldb::SBError error; - if (llvm::Error err = - m_io.SendJSON(RunInTerminalMessageDidAttach().ToJSON())) - error.SetErrorString(llvm::toString(std::move(err)).c_str()); - return error; - }); -} - -Expected RunInTerminalDebugAdapterCommChannel::GetLauncherPid() { - if (Expected message = - GetNextMessage(m_io, std::chrono::seconds(20))) { - if (message.get()->kind == eRunInTerminalMessageKindPID) - return message.get()->GetAsPidMessage()->pid; - return ToError(*message.get()); - } else { - return message.takeError(); - } -} - -std::string RunInTerminalDebugAdapterCommChannel::GetLauncherError() { - // We know there's been an error, so a small timeout is enough. - if (Expected message = - GetNextMessage(m_io, std::chrono::seconds(1))) - return toString(ToError(*message.get())); - else - return toString(message.takeError()); -} - -Expected> CreateRunInTerminalCommFile() { - SmallString<256> comm_file; - if (std::error_code EC = sys::fs::getPotentiallyUniqueTempFileName( - "lldb-dap-run-in-terminal-comm", "", comm_file)) - return createStringError(EC, "Error making unique file name for " - "runInTerminal communication files"); - - return CreateFifoFile(comm_file.str()); -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/RunInTerminal.h b/lldb/tools/lldb-dap/RunInTerminal.h deleted file mode 100644 index 457850c8ea53..000000000000 --- a/lldb/tools/lldb-dap/RunInTerminal.h +++ /dev/null @@ -1,131 +0,0 @@ -//===-- RunInTerminal.h ----------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_RUNINTERMINAL_H -#define LLDB_TOOLS_LLDB_DAP_RUNINTERMINAL_H - -#include "FifoFiles.h" -#include "lldb/API/SBError.h" - -#include -#include -#include - -namespace lldb_dap { - -enum RunInTerminalMessageKind { - eRunInTerminalMessageKindPID = 0, - eRunInTerminalMessageKindError, - eRunInTerminalMessageKindDidAttach, -}; - -struct RunInTerminalMessage; -struct RunInTerminalMessagePid; -struct RunInTerminalMessageError; -struct RunInTerminalMessageDidAttach; - -struct RunInTerminalMessage { - RunInTerminalMessage(RunInTerminalMessageKind kind); - - virtual ~RunInTerminalMessage() = default; - - /// Serialize this object to JSON - virtual llvm::json::Value ToJSON() const = 0; - - const RunInTerminalMessagePid *GetAsPidMessage() const; - - const RunInTerminalMessageError *GetAsErrorMessage() const; - - RunInTerminalMessageKind kind; -}; - -using RunInTerminalMessageUP = std::unique_ptr; - -struct RunInTerminalMessagePid : RunInTerminalMessage { - RunInTerminalMessagePid(lldb::pid_t pid); - - llvm::json::Value ToJSON() const override; - - lldb::pid_t pid; -}; - -struct RunInTerminalMessageError : RunInTerminalMessage { - RunInTerminalMessageError(llvm::StringRef error); - - llvm::json::Value ToJSON() const override; - - std::string error; -}; - -struct RunInTerminalMessageDidAttach : RunInTerminalMessage { - RunInTerminalMessageDidAttach(); - - llvm::json::Value ToJSON() const override; -}; - -class RunInTerminalLauncherCommChannel { -public: - RunInTerminalLauncherCommChannel(llvm::StringRef comm_file); - - /// Wait until the debug adapter attaches. - /// - /// \param[in] timeout - /// How long to wait to be attached. - // - /// \return - /// An \a llvm::Error object in case of errors or if this operation times - /// out. - llvm::Error WaitUntilDebugAdapterAttaches(std::chrono::milliseconds timeout); - - /// Notify the debug adapter this process' pid. - /// - /// \return - /// An \a llvm::Error object in case of errors or if this operation times - /// out. - llvm::Error NotifyPid(); - - /// Notify the debug adapter that there's been an error. - void NotifyError(llvm::StringRef error); - -private: - FifoFileIO m_io; -}; - -class RunInTerminalDebugAdapterCommChannel { -public: - RunInTerminalDebugAdapterCommChannel(llvm::StringRef comm_file); - - /// Notify the runInTerminal launcher that it was attached. - /// - /// \return - /// A future indicated whether the runInTerminal launcher received the - /// message correctly or not. - std::future NotifyDidAttach(); - - /// Fetch the pid of the runInTerminal launcher. - /// - /// \return - /// An \a llvm::Error object in case of errors or if this operation times - /// out. - llvm::Expected GetLauncherPid(); - - /// Fetch any errors emitted by the runInTerminal launcher or return a - /// default error message if a certain timeout if reached. - std::string GetLauncherError(); - -private: - FifoFileIO m_io; -}; - -/// Create a fifo file used to communicate the debug adapter with -/// the runInTerminal launcher. -llvm::Expected> CreateRunInTerminalCommFile(); - -} // namespace lldb_dap - -#endif // LLDB_TOOLS_LLDB_DAP_RUNINTERMINAL_H diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.cpp b/lldb/tools/lldb-dap/SourceBreakpoint.cpp deleted file mode 100644 index a4327ae18cf6..000000000000 --- a/lldb/tools/lldb-dap/SourceBreakpoint.cpp +++ /dev/null @@ -1,379 +0,0 @@ -//===-- SourceBreakpoint.cpp ------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "SourceBreakpoint.h" -#include "BreakpointBase.h" -#include "DAP.h" -#include "JSONUtils.h" -#include "lldb/API/SBBreakpoint.h" -#include "lldb/API/SBFileSpecList.h" -#include "lldb/API/SBFrame.h" -#include "lldb/API/SBInstruction.h" -#include "lldb/API/SBMutex.h" -#include "lldb/API/SBSymbol.h" -#include "lldb/API/SBTarget.h" -#include "lldb/API/SBThread.h" -#include "lldb/API/SBValue.h" -#include "lldb/lldb-enumerations.h" -#include "llvm/Support/Error.h" -#include -#include -#include -#include -#include - -namespace lldb_dap { - -SourceBreakpoint::SourceBreakpoint(DAP &dap, - const protocol::SourceBreakpoint &breakpoint) - : Breakpoint(dap, breakpoint.condition, breakpoint.hitCondition), - m_log_message(breakpoint.logMessage.value_or("")), - m_line(breakpoint.line), - m_column(breakpoint.column.value_or(LLDB_INVALID_COLUMN_NUMBER)) {} - -llvm::Error SourceBreakpoint::SetBreakpoint(const protocol::Source &source) { - lldb::SBMutex lock = m_dap.GetAPIMutex(); - std::lock_guard guard(lock); - - if (m_line == 0) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid line number."); - - if (source.sourceReference) { - // Breakpoint set by assembly source. - lldb::SBAddress source_address(*source.sourceReference, m_dap.target); - if (!source_address.IsValid()) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid sourceReference."); - - lldb::SBSymbol symbol = source_address.GetSymbol(); - if (!symbol.IsValid()) { - // FIXME: Support assembly breakpoints without a valid symbol. - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Breakpoints in assembly without a valid " - "symbol are not supported yet."); - } - - lldb::SBInstructionList inst_list = - m_dap.target.ReadInstructions(symbol.GetStartAddress(), m_line); - if (inst_list.GetSize() < m_line) - return llvm::createStringError(llvm::inconvertibleErrorCode(), - "Invalid instruction list size."); - - lldb::SBAddress address = - inst_list.GetInstructionAtIndex(m_line - 1).GetAddress(); - - m_bp = m_dap.target.BreakpointCreateBySBAddress(address); - } else { - // Breakpoint set by a regular source file. - const auto source_path = source.path.value_or(""); - lldb::SBFileSpecList module_list; - m_bp = m_dap.target.BreakpointCreateByLocation(source_path.c_str(), m_line, - m_column, 0, module_list); - } - - if (!m_log_message.empty()) - SetLogMessage(); - Breakpoint::SetBreakpoint(); - return llvm::Error::success(); -} - -void SourceBreakpoint::UpdateBreakpoint(const SourceBreakpoint &request_bp) { - if (m_log_message != request_bp.m_log_message) { - m_log_message = request_bp.m_log_message; - SetLogMessage(); - } - BreakpointBase::UpdateBreakpoint(request_bp); -} - -lldb::SBError SourceBreakpoint::AppendLogMessagePart(llvm::StringRef part, - bool is_expr) { - if (is_expr) { - m_log_message_parts.emplace_back(part, is_expr); - } else { - std::string formatted; - lldb::SBError error = FormatLogText(part, formatted); - if (error.Fail()) - return error; - m_log_message_parts.emplace_back(formatted, is_expr); - } - return lldb::SBError(); -} - -// TODO: consolidate this code with the implementation in -// FormatEntity::ParseInternal(). -lldb::SBError SourceBreakpoint::FormatLogText(llvm::StringRef text, - std::string &formatted) { - lldb::SBError error; - while (!text.empty()) { - size_t backslash_pos = text.find_first_of('\\'); - if (backslash_pos == std::string::npos) { - formatted += text.str(); - return error; - } - - formatted += text.substr(0, backslash_pos).str(); - // Skip the characters before and including '\'. - text = text.drop_front(backslash_pos + 1); - - if (text.empty()) { - error.SetErrorString( - "'\\' character was not followed by another character"); - return error; - } - - const char desens_char = text[0]; - text = text.drop_front(); // Skip the desensitized char character - switch (desens_char) { - case 'a': - formatted.push_back('\a'); - break; - case 'b': - formatted.push_back('\b'); - break; - case 'f': - formatted.push_back('\f'); - break; - case 'n': - formatted.push_back('\n'); - break; - case 'r': - formatted.push_back('\r'); - break; - case 't': - formatted.push_back('\t'); - break; - case 'v': - formatted.push_back('\v'); - break; - case '\'': - formatted.push_back('\''); - break; - case '\\': - formatted.push_back('\\'); - break; - case '0': - // 1 to 3 octal chars - { - if (text.empty()) { - error.SetErrorString("missing octal number following '\\0'"); - return error; - } - - // Make a string that can hold onto the initial zero char, up to 3 - // octal digits, and a terminating NULL. - char oct_str[5] = {0, 0, 0, 0, 0}; - - size_t i; - for (i = 0; - i < text.size() && i < 4 && (text[i] >= '0' && text[i] <= '7'); - ++i) { - oct_str[i] = text[i]; - } - - text = text.drop_front(i); - unsigned long octal_value = ::strtoul(oct_str, nullptr, 8); - if (octal_value <= UINT8_MAX) { - formatted.push_back((char)octal_value); - } else { - error.SetErrorString("octal number is larger than a single byte"); - return error; - } - } - break; - - case 'x': { - if (text.empty()) { - error.SetErrorString("missing hex number following '\\x'"); - return error; - } - // hex number in the text - if (std::isxdigit(text[0])) { - // Make a string that can hold onto two hex chars plus a - // NULL terminator - char hex_str[3] = {0, 0, 0}; - hex_str[0] = text[0]; - - text = text.drop_front(); - - if (!text.empty() && std::isxdigit(text[0])) { - hex_str[1] = text[0]; - text = text.drop_front(); - } - - unsigned long hex_value = strtoul(hex_str, nullptr, 16); - if (hex_value <= UINT8_MAX) { - formatted.push_back((char)hex_value); - } else { - error.SetErrorString("hex number is larger than a single byte"); - return error; - } - } else { - formatted.push_back(desens_char); - } - break; - } - - default: - // Just desensitize any other character by just printing what came - // after the '\' - formatted.push_back(desens_char); - break; - } - } - return error; -} - -// logMessage will be divided into array of LogMessagePart as two kinds: -// 1. raw print text message, and -// 2. interpolated expression for evaluation which is inside matching curly -// braces. -// -// The function tries to parse logMessage into a list of LogMessageParts -// for easy later access in BreakpointHitCallback. -void SourceBreakpoint::SetLogMessage() { - m_log_message_parts.clear(); - - // Contains unmatched open curly braces indices. - std::vector unmatched_curly_braces; - - // Contains all matched curly braces in logMessage. - // Loop invariant: matched_curly_braces_ranges are sorted by start index in - // ascending order without any overlap between them. - std::vector> matched_curly_braces_ranges; - - lldb::SBError error; - // Part1 - parse matched_curly_braces_ranges. - // locating all curly braced expression ranges in logMessage. - // The algorithm takes care of nested and imbalanced curly braces. - for (size_t i = 0; i < m_log_message.size(); ++i) { - if (m_log_message[i] == '{') { - unmatched_curly_braces.push_back(i); - } else if (m_log_message[i] == '}') { - if (unmatched_curly_braces.empty()) - // Nothing to match. - continue; - - int last_unmatched_index = unmatched_curly_braces.back(); - unmatched_curly_braces.pop_back(); - - // Erase any matched ranges included in the new match. - while (!matched_curly_braces_ranges.empty()) { - assert(matched_curly_braces_ranges.back().first != - last_unmatched_index && - "How can a curley brace be matched twice?"); - if (matched_curly_braces_ranges.back().first < last_unmatched_index) - break; - - // This is a nested range let's earse it. - assert((size_t)matched_curly_braces_ranges.back().second < i); - matched_curly_braces_ranges.pop_back(); - } - - // Assert invariant. - assert(matched_curly_braces_ranges.empty() || - matched_curly_braces_ranges.back().first < last_unmatched_index); - matched_curly_braces_ranges.emplace_back(last_unmatched_index, i); - } - } - - // Part2 - parse raw text and expresions parts. - // All expression ranges have been parsed in matched_curly_braces_ranges. - // The code below uses matched_curly_braces_ranges to divide logMessage - // into raw text parts and expression parts. - int last_raw_text_start = 0; - for (const std::pair &curly_braces_range : - matched_curly_braces_ranges) { - // Raw text before open curly brace. - assert(curly_braces_range.first >= last_raw_text_start); - size_t raw_text_len = curly_braces_range.first - last_raw_text_start; - if (raw_text_len > 0) { - error = AppendLogMessagePart( - llvm::StringRef(m_log_message.c_str() + last_raw_text_start, - raw_text_len), - /*is_expr=*/false); - if (error.Fail()) { - NotifyLogMessageError(error.GetCString()); - return; - } - } - - // Expression between curly braces. - assert(curly_braces_range.second > curly_braces_range.first); - size_t expr_len = curly_braces_range.second - curly_braces_range.first - 1; - error = AppendLogMessagePart( - llvm::StringRef(m_log_message.c_str() + curly_braces_range.first + 1, - expr_len), - /*is_expr=*/true); - if (error.Fail()) { - NotifyLogMessageError(error.GetCString()); - return; - } - - last_raw_text_start = curly_braces_range.second + 1; - } - // Trailing raw text after close curly brace. - assert(last_raw_text_start >= 0); - if (m_log_message.size() > (size_t)last_raw_text_start) { - error = AppendLogMessagePart( - llvm::StringRef(m_log_message.c_str() + last_raw_text_start, - m_log_message.size() - last_raw_text_start), - /*is_expr=*/false); - if (error.Fail()) { - NotifyLogMessageError(error.GetCString()); - return; - } - } - - m_bp.SetCallback(BreakpointHitCallback, this); -} - -void SourceBreakpoint::NotifyLogMessageError(llvm::StringRef error) { - std::string message = "Log message has error: "; - message += error; - m_dap.SendOutput(OutputType::Console, message); -} - -/*static*/ -bool SourceBreakpoint::BreakpointHitCallback( - void *baton, lldb::SBProcess &process, lldb::SBThread &thread, - lldb::SBBreakpointLocation &location) { - if (!baton) - return true; - - SourceBreakpoint *bp = (SourceBreakpoint *)baton; - lldb::SBFrame frame = thread.GetSelectedFrame(); - - std::string output; - for (const SourceBreakpoint::LogMessagePart &messagePart : - bp->m_log_message_parts) { - if (messagePart.is_expr) { - // Try local frame variables first before fall back to expression - // evaluation - const std::string &expr_str = messagePart.text; - const char *expr = expr_str.c_str(); - lldb::SBValue value = - frame.GetValueForVariablePath(expr, lldb::eDynamicDontRunTarget); - if (value.GetError().Fail()) - value = frame.EvaluateExpression(expr); - output += VariableDescription( - value, bp->m_dap.configuration.enableAutoVariableSummaries) - .display_value; - } else { - output += messagePart.text; - } - } - if (!output.empty() && output.back() != '\n') - output.push_back('\n'); // Ensure log message has line break. - bp->m_dap.SendOutput(OutputType::Console, output.c_str()); - - // Do not stop. - return false; -} - -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/SourceBreakpoint.h b/lldb/tools/lldb-dap/SourceBreakpoint.h deleted file mode 100644 index 857ac4286d59..000000000000 --- a/lldb/tools/lldb-dap/SourceBreakpoint.h +++ /dev/null @@ -1,72 +0,0 @@ -//===-- SourceBreakpoint.h --------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_SOURCEBREAKPOINT_H -#define LLDB_TOOLS_LLDB_DAP_SOURCEBREAKPOINT_H - -#include "Breakpoint.h" -#include "DAPForward.h" -#include "Protocol/ProtocolTypes.h" -#include "lldb/API/SBError.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include -#include -#include - -namespace lldb_dap { - -class SourceBreakpoint : public Breakpoint { -public: - SourceBreakpoint(DAP &d, const protocol::SourceBreakpoint &breakpoint); - - // Set this breakpoint in LLDB as a new breakpoint - llvm::Error SetBreakpoint(const protocol::Source &source); - void UpdateBreakpoint(const SourceBreakpoint &request_bp); - - void SetLogMessage(); - // Format \param text and return formatted text in \param formatted. - // \return any formatting failures. - lldb::SBError FormatLogText(llvm::StringRef text, std::string &formatted); - lldb::SBError AppendLogMessagePart(llvm::StringRef part, bool is_expr); - void NotifyLogMessageError(llvm::StringRef error); - - static bool BreakpointHitCallback(void *baton, lldb::SBProcess &process, - lldb::SBThread &thread, - lldb::SBBreakpointLocation &location); - - inline bool operator<(const SourceBreakpoint &rhs) { - if (m_line == rhs.m_line) - return m_column < rhs.m_column; - return m_line < rhs.m_line; - } - - uint32_t GetLine() const { return m_line; } - uint32_t GetColumn() const { return m_column; } - -protected: - // logMessage part can be either a raw text or an expression. - struct LogMessagePart { - LogMessagePart(llvm::StringRef text, bool is_expr) - : text(text), is_expr(is_expr) {} - std::string text; - bool is_expr; - }; - // If this attribute exists and is non-empty, the backend must not 'break' - // (stop) but log the message instead. Expressions within {} are - // interpolated. - std::string m_log_message; - std::vector m_log_message_parts; - - uint32_t m_line; ///< The source line of the breakpoint or logpoint - uint32_t m_column; ///< An optional source column of the breakpoint -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/Transport.cpp b/lldb/tools/lldb-dap/Transport.cpp deleted file mode 100644 index 4e322e9ff135..000000000000 --- a/lldb/tools/lldb-dap/Transport.cpp +++ /dev/null @@ -1,159 +0,0 @@ -//===-- Transport.cpp -----------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Transport.h" -#include "DAPLog.h" -#include "Protocol/ProtocolBase.h" -#include "lldb/Utility/IOObject.h" -#include "lldb/Utility/SelectHelper.h" -#include "lldb/Utility/Status.h" -#include "lldb/lldb-forward.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include - -using namespace llvm; -using namespace lldb; -using namespace lldb_private; -using namespace lldb_dap; -using namespace lldb_dap::protocol; - -/// ReadFull attempts to read the specified number of bytes. If EOF is -/// encountered, an empty string is returned. -static Expected -ReadFull(IOObject &descriptor, size_t length, - std::optional timeout = std::nullopt) { - if (!descriptor.IsValid()) - return createStringError("transport output is closed"); - - bool timeout_supported = true; - // FIXME: SelectHelper does not work with NativeFile on Win32. -#if _WIN32 - timeout_supported = descriptor.GetFdType() == IOObject::eFDTypeSocket; -#endif - - if (timeout && timeout_supported) { - SelectHelper sh; - sh.SetTimeout(*timeout); - sh.FDSetRead(descriptor.GetWaitableHandle()); - Status status = sh.Select(); - if (status.Fail()) { - // Convert timeouts into a specific error. - if (status.GetType() == lldb::eErrorTypePOSIX && - status.GetError() == ETIMEDOUT) - return make_error(); - return status.takeError(); - } - } - - std::string data; - data.resize(length); - Status status = descriptor.Read(data.data(), length); - if (status.Fail()) - return status.takeError(); - - // Read returns '' on EOF. - if (length == 0) - return make_error(); - - // Return the actual number of bytes read. - return data.substr(0, length); -} - -static Expected -ReadUntil(IOObject &descriptor, StringRef delimiter, - std::optional timeout = std::nullopt) { - std::string buffer; - buffer.reserve(delimiter.size() + 1); - while (!llvm::StringRef(buffer).ends_with(delimiter)) { - Expected next = - ReadFull(descriptor, buffer.empty() ? delimiter.size() : 1, timeout); - if (auto Err = next.takeError()) - return std::move(Err); - buffer += *next; - } - return buffer.substr(0, buffer.size() - delimiter.size()); -} - -/// DAP message format -/// ``` -/// Content-Length: (?\d+)\r\n\r\n(?.{\k}) -/// ``` -static constexpr StringLiteral kHeaderContentLength = "Content-Length: "; -static constexpr StringLiteral kHeaderSeparator = "\r\n\r\n"; - -namespace lldb_dap { - -char EndOfFileError::ID; -char TimeoutError::ID; - -Transport::Transport(StringRef client_name, Log *log, IOObjectSP input, - IOObjectSP output) - : m_client_name(client_name), m_log(log), m_input(std::move(input)), - m_output(std::move(output)) {} - -Expected Transport::Read(const std::chrono::microseconds &timeout) { - if (!m_input || !m_input->IsValid()) - return createStringError("transport output is closed"); - - IOObject *input = m_input.get(); - Expected message_header = - ReadFull(*input, kHeaderContentLength.size(), timeout); - if (!message_header) - return message_header.takeError(); - if (*message_header != kHeaderContentLength) - return createStringError(formatv("expected '{0}' and got '{1}'", - kHeaderContentLength, *message_header) - .str()); - - Expected raw_length = ReadUntil(*input, kHeaderSeparator); - if (!raw_length) - return handleErrors(raw_length.takeError(), - [&](const EndOfFileError &E) -> llvm::Error { - return createStringError( - "unexpected EOF while reading header separator"); - }); - - size_t length; - if (!to_integer(*raw_length, length)) - return createStringError( - formatv("invalid content length {0}", *raw_length).str()); - - Expected raw_json = ReadFull(*input, length); - if (!raw_json) - return handleErrors( - raw_json.takeError(), [&](const EndOfFileError &E) -> llvm::Error { - return createStringError("unexpected EOF while reading JSON"); - }); - - DAP_LOG(m_log, "--> ({0}) {1}", m_client_name, *raw_json); - - return json::parse(/*JSON=*/*raw_json, - /*RootName=*/"protocol_message"); -} - -Error Transport::Write(const Message &message) { - if (!m_output || !m_output->IsValid()) - return createStringError("transport output is closed"); - - std::string json = formatv("{0}", toJSON(message)).str(); - - DAP_LOG(m_log, "<-- ({0}) {1}", m_client_name, json); - - std::string Output; - raw_string_ostream OS(Output); - OS << kHeaderContentLength << json.length() << kHeaderSeparator << json; - size_t num_bytes = Output.size(); - return m_output->Write(Output.data(), num_bytes).takeError(); -} - -} // end namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Transport.h b/lldb/tools/lldb-dap/Transport.h deleted file mode 100644 index 4e347eaa5131..000000000000 --- a/lldb/tools/lldb-dap/Transport.h +++ /dev/null @@ -1,96 +0,0 @@ -//===-- Transport.h -------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// Debug Adapter Protocol transport layer for encoding and decoding protocol -// messages. -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_TRANSPORT_H -#define LLDB_TOOLS_LLDB_DAP_TRANSPORT_H - -#include "DAPForward.h" -#include "Protocol/ProtocolBase.h" -#include "lldb/lldb-forward.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Support/Error.h" -#include -#include - -namespace lldb_dap { - -class EndOfFileError : public llvm::ErrorInfo { -public: - static char ID; - - EndOfFileError() = default; - - void log(llvm::raw_ostream &OS) const override { - OS << "end of file reached"; - } - std::error_code convertToErrorCode() const override { - return llvm::inconvertibleErrorCode(); - } -}; - -class TimeoutError : public llvm::ErrorInfo { -public: - static char ID; - - TimeoutError() = default; - - void log(llvm::raw_ostream &OS) const override { - OS << "operation timed out"; - } - std::error_code convertToErrorCode() const override { - return std::make_error_code(std::errc::timed_out); - } -}; - -/// A transport class that performs the Debug Adapter Protocol communication -/// with the client. -class Transport { -public: - Transport(llvm::StringRef client_name, Log *log, lldb::IOObjectSP input, - lldb::IOObjectSP output); - ~Transport() = default; - - /// Transport is not copyable. - /// @{ - Transport(const Transport &rhs) = delete; - void operator=(const Transport &rhs) = delete; - /// @} - - /// Writes a Debug Adater Protocol message to the output stream. - llvm::Error Write(const protocol::Message &M); - - /// Reads the next Debug Adater Protocol message from the input stream. - /// - /// \param timeout[in] - /// A timeout to wait for reading the initial header. Once a message - /// header is recieved, this will block until the full message is - /// read. - /// - /// \returns Returns the next protocol message. - llvm::Expected - Read(const std::chrono::microseconds &timeout); - - /// Returns the name of this transport client, for example `stdin/stdout` or - /// `client_1`. - llvm::StringRef GetClientName() { return m_client_name; } - -private: - llvm::StringRef m_client_name; - Log *m_log; - lldb::IOObjectSP m_input; - lldb::IOObjectSP m_output; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/Variables.cpp b/lldb/tools/lldb-dap/Variables.cpp deleted file mode 100644 index 777e3183d8c0..000000000000 --- a/lldb/tools/lldb-dap/Variables.cpp +++ /dev/null @@ -1,105 +0,0 @@ -//===-- Variables.cpp ---------------------------------------------------*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Variables.h" -#include "JSONUtils.h" - -using namespace lldb_dap; - -lldb::SBValueList *Variables::GetTopLevelScope(int64_t variablesReference) { - switch (variablesReference) { - case VARREF_LOCALS: - return &locals; - case VARREF_GLOBALS: - return &globals; - case VARREF_REGS: - return ®isters; - default: - return nullptr; - } -} - -void Variables::Clear() { - locals.Clear(); - globals.Clear(); - registers.Clear(); - m_referencedvariables.clear(); -} - -int64_t Variables::GetNewVariableReference(bool is_permanent) { - if (is_permanent) - return m_next_permanent_var_ref++; - return m_next_temporary_var_ref++; -} - -bool Variables::IsPermanentVariableReference(int64_t var_ref) { - return var_ref >= PermanentVariableStartIndex; -} - -lldb::SBValue Variables::GetVariable(int64_t var_ref) const { - if (IsPermanentVariableReference(var_ref)) { - auto pos = m_referencedpermanent_variables.find(var_ref); - if (pos != m_referencedpermanent_variables.end()) - return pos->second; - } else { - auto pos = m_referencedvariables.find(var_ref); - if (pos != m_referencedvariables.end()) - return pos->second; - } - return lldb::SBValue(); -} - -int64_t Variables::InsertVariable(lldb::SBValue variable, bool is_permanent) { - int64_t var_ref = GetNewVariableReference(is_permanent); - if (is_permanent) - m_referencedpermanent_variables.insert(std::make_pair(var_ref, variable)); - else - m_referencedvariables.insert(std::make_pair(var_ref, variable)); - return var_ref; -} - -lldb::SBValue Variables::FindVariable(uint64_t variablesReference, - llvm::StringRef name) { - lldb::SBValue variable; - if (lldb::SBValueList *top_scope = GetTopLevelScope(variablesReference)) { - bool is_duplicated_variable_name = name.contains(" @"); - // variablesReference is one of our scopes, not an actual variable it is - // asking for a variable in locals or globals or registers - int64_t end_idx = top_scope->GetSize(); - // Searching backward so that we choose the variable in closest scope - // among variables of the same name. - for (int64_t i = end_idx - 1; i >= 0; --i) { - lldb::SBValue curr_variable = top_scope->GetValueAtIndex(i); - std::string variable_name = CreateUniqueVariableNameForDisplay( - curr_variable, is_duplicated_variable_name); - if (variable_name == name) { - variable = curr_variable; - break; - } - } - } else { - // This is not under the globals or locals scope, so there are no - // duplicated names. - - // We have a named item within an actual variable so we need to find it - // withing the container variable by name. - lldb::SBValue container = GetVariable(variablesReference); - variable = container.GetChildMemberWithName(name.data()); - if (!variable.IsValid()) { - if (name.starts_with("[")) { - llvm::StringRef index_str(name.drop_front(1)); - uint64_t index = 0; - if (!index_str.consumeInteger(0, index)) { - if (index_str == "]") - variable = container.GetChildAtIndex(index); - } - } - } - } - return variable; -} diff --git a/lldb/tools/lldb-dap/Variables.h b/lldb/tools/lldb-dap/Variables.h deleted file mode 100644 index 0ed84b36aef9..000000000000 --- a/lldb/tools/lldb-dap/Variables.h +++ /dev/null @@ -1,71 +0,0 @@ -//===-- Variables.h -----------------------------------------------------*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_VARIABLES_H -#define LLDB_TOOLS_LLDB_DAP_VARIABLES_H - -#include "lldb/API/SBValue.h" -#include "lldb/API/SBValueList.h" -#include "llvm/ADT/DenseMap.h" - -#define VARREF_FIRST_VAR_IDX (int64_t)4 -#define VARREF_LOCALS (int64_t)1 -#define VARREF_GLOBALS (int64_t)2 -#define VARREF_REGS (int64_t)3 - -namespace lldb_dap { - -struct Variables { - lldb::SBValueList locals; - lldb::SBValueList globals; - lldb::SBValueList registers; - - /// Check if \p var_ref points to a variable that should persist for the - /// entire duration of the debug session, e.g. repl expandable variables - static bool IsPermanentVariableReference(int64_t var_ref); - - /// \return a new variableReference. - /// Specify is_permanent as true for variable that should persist entire - /// debug session. - int64_t GetNewVariableReference(bool is_permanent); - - /// \return the expandable variable corresponding with variableReference - /// value of \p value. - /// If \p var_ref is invalid an empty SBValue is returned. - lldb::SBValue GetVariable(int64_t var_ref) const; - - /// Insert a new \p variable. - /// \return variableReference assigned to this expandable variable. - int64_t InsertVariable(lldb::SBValue variable, bool is_permanent); - - lldb::SBValueList *GetTopLevelScope(int64_t variablesReference); - - lldb::SBValue FindVariable(uint64_t variablesReference, llvm::StringRef name); - - /// Clear all scope variables and non-permanent expandable variables. - void Clear(); - -private: - /// Variable_reference start index of permanent expandable variable. - static constexpr int64_t PermanentVariableStartIndex = (1ll << 32); - - /// Variables that are alive in this stop state. - /// Will be cleared when debuggee resumes. - llvm::DenseMap m_referencedvariables; - - /// Variables that persist across entire debug session. - /// These are the variables evaluated from debug console REPL. - llvm::DenseMap m_referencedpermanent_variables; - - int64_t m_next_temporary_var_ref{VARREF_FIRST_VAR_IDX}; - int64_t m_next_permanent_var_ref{PermanentVariableStartIndex}; -}; - -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/Watchpoint.cpp b/lldb/tools/lldb-dap/Watchpoint.cpp deleted file mode 100644 index 0acc980890be..000000000000 --- a/lldb/tools/lldb-dap/Watchpoint.cpp +++ /dev/null @@ -1,61 +0,0 @@ -//===-- Watchpoint.cpp ------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "Watchpoint.h" -#include "DAP.h" -#include "Protocol/ProtocolTypes.h" -#include "lldb/API/SBTarget.h" -#include "lldb/lldb-enumerations.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include -#include - -namespace lldb_dap { -Watchpoint::Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint) - : BreakpointBase(d, breakpoint.condition, breakpoint.hitCondition) { - llvm::StringRef dataId = breakpoint.dataId; - auto [addr_str, size_str] = dataId.split('/'); - llvm::to_integer(addr_str, m_addr, 16); - llvm::to_integer(size_str, m_size); - m_options.SetWatchpointTypeRead(breakpoint.accessType != - protocol::eDataBreakpointAccessTypeWrite); - if (breakpoint.accessType != protocol::eDataBreakpointAccessTypeRead) - m_options.SetWatchpointTypeWrite(lldb::eWatchpointWriteTypeOnModify); -} - -void Watchpoint::SetCondition() { m_wp.SetCondition(m_condition.c_str()); } - -void Watchpoint::SetHitCondition() { - uint64_t hitCount = 0; - if (llvm::to_integer(m_hit_condition, hitCount)) - m_wp.SetIgnoreCount(hitCount - 1); -} - -protocol::Breakpoint Watchpoint::ToProtocolBreakpoint() { - protocol::Breakpoint breakpoint; - if (!m_error.IsValid() || m_error.Fail()) { - breakpoint.verified = false; - if (m_error.Fail()) - breakpoint.message = m_error.GetCString(); - } else { - breakpoint.verified = true; - } - - return breakpoint; -} - -void Watchpoint::SetWatchpoint() { - m_wp = m_dap.target.WatchpointCreateByAddress(m_addr, m_size, m_options, - m_error); - if (!m_condition.empty()) - SetCondition(); - if (!m_hit_condition.empty()) - SetHitCondition(); -} -} // namespace lldb_dap diff --git a/lldb/tools/lldb-dap/Watchpoint.h b/lldb/tools/lldb-dap/Watchpoint.h deleted file mode 100644 index d943e1218bdc..000000000000 --- a/lldb/tools/lldb-dap/Watchpoint.h +++ /dev/null @@ -1,47 +0,0 @@ -//===-- Watchpoint.h --------------------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H -#define LLDB_TOOLS_LLDB_DAP_WATCHPOINT_H - -#include "BreakpointBase.h" -#include "DAPForward.h" -#include "Protocol/ProtocolTypes.h" -#include "lldb/API/SBError.h" -#include "lldb/API/SBWatchpoint.h" -#include "lldb/API/SBWatchpointOptions.h" -#include "lldb/lldb-types.h" -#include - -namespace lldb_dap { - -class Watchpoint : public BreakpointBase { -public: - Watchpoint(DAP &d, const protocol::DataBreakpoint &breakpoint); - Watchpoint(DAP &d, lldb::SBWatchpoint wp) : BreakpointBase(d), m_wp(wp) {} - - void SetCondition() override; - void SetHitCondition() override; - - protocol::Breakpoint ToProtocolBreakpoint() override; - - void SetWatchpoint(); - - lldb::addr_t GetAddress() const { return m_addr; } - -protected: - lldb::addr_t m_addr; - size_t m_size; - lldb::SBWatchpointOptions m_options; - /// The LLDB breakpoint associated wit this watchpoint. - lldb::SBWatchpoint m_wp; - lldb::SBError m_error; -}; -} // namespace lldb_dap - -#endif diff --git a/lldb/tools/lldb-dap/llvm-logo.png b/lldb/tools/lldb-dap/llvm-logo.png deleted file mode 100644 index 039e8d67931c6b6154d4608edab1a3293ebbb9e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 261036 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

roH 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ℜpPg+CvnD0t0~UDL?n);DhzE_V~?2B0P= zp-K^cZR=8~NAi-Ej~0TH+RXKXLqC)DYXx4ge^z5~Q!ab{NVa`!G3-Odsgw;3>$|7j3!1W{*r7{Cr zg#0KT-OwOMXH~WPM)!ZooSGBVZC2wQ4PpK*mm589Z`yRANxaH! z{sF>)r7sm?ZG9cK86EeUd+Yz1`dJh}Us!yUvMkkqpIBKK9u;ibUJi0YP02!~j#O6~ z50ac=18.0.0" - } - }, - "node_modules/@azure/core-auth": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.9.0.tgz", - "integrity": "sha512-FPwHpZywuyasDSLMqJ6fhbOK3TqUdviZNF8OqRGA4W5Ewib2lEEZ+pBsYcBa88B2NGO/SEnYPGhyBqNlE8ilSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-util": "^1.11.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-client": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.9.2.tgz", - "integrity": "sha512-kRdry/rav3fUKHl/aDLd/pDLcB+4pOFwPPTVEExuMyaI5r+JBbMWqRbCY1pn5BniDaU3lRxO9eaQ1AmSMehl/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.4.0", - "@azure/core-rest-pipeline": "^1.9.1", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.6.1", - "@azure/logger": "^1.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-rest-pipeline": { - "version": "1.18.2", - "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.18.2.tgz", - "integrity": "sha512-IkTf/DWKyCklEtN/WYW3lqEsIaUDshlzWRlZNNwSYtFcCBQz++OtOjxNpm8rr1VcbMS6RpjybQa3u6B6nG0zNw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.8.0", - "@azure/core-tracing": "^1.0.1", - "@azure/core-util": "^1.11.0", - "@azure/logger": "^1.0.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-tracing": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.2.0.tgz", - "integrity": "sha512-UKTiEJPkWcESPYJz3X5uKRYyOcJD+4nYph+KpfdPRnQJVrZfk0KJgdnaAWKfhsBBtAf/D58Az4AvCJEmWgIBAg==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/core-util": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.11.0.tgz", - "integrity": "sha512-DxOSLua+NdpWoSqULhjDyAZTXFdP/LKkqtYuxxz1SCN289zk3OG8UOpnCQAz/tygyACBtWp/BoO72ptK7msY8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/identity": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.6.0.tgz", - "integrity": "sha512-ANpO1iAvcZmpD4QY7/kaE/P2n66pRXsDp3nMUC6Ow3c9KfXOZF7qMU9VgqPw8m7adP7TVIbVyrCEmD9cth3KQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/abort-controller": "^2.0.0", - "@azure/core-auth": "^1.9.0", - "@azure/core-client": "^1.9.2", - "@azure/core-rest-pipeline": "^1.17.0", - "@azure/core-tracing": "^1.0.0", - "@azure/core-util": "^1.11.0", - "@azure/logger": "^1.0.0", - "@azure/msal-browser": "^4.0.1", - "@azure/msal-node": "^2.15.0", - "events": "^3.0.0", - "jws": "^4.0.0", - "open": "^8.0.0", - "stoppable": "^1.1.0", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/logger": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.1.4.tgz", - "integrity": "sha512-4IXXzcCdLdlXuCG+8UKEwLA1T1NHqUfanhXYHiQTn+6sfWCZXduqbtXDGceg3Ce5QxTGo7EqmbV6Bi+aqKuClQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@azure/msal-browser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-4.2.0.tgz", - "integrity": "sha512-MXQjgAgjg/2VRKV+UPWHESoZPcue2ZvWKfpBLCyTUyixP+mhCl0q5D1+xDiwBGV3lru2poKZVZDQAOE40wKmWg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/msal-common": "15.1.1" - }, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-common": { - "version": "15.1.1", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-15.1.1.tgz", - "integrity": "sha512-bvLWYq9fleAcTJ6H+hfkG91On6vI/UhGyOB7Z6r0Bsa+KTL3zPtigmGCOJgdxrEklOYD88X9SehexLDH/5NRKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@azure/msal-node": { - "version": "2.16.2", - "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-2.16.2.tgz", - "integrity": "sha512-An7l1hEr0w1HMMh1LU+rtDtqL7/jw74ORlc9Wnh06v7TU/xpG39/Zdr1ZJu3QpjUfKJ+E0/OXMW8DRSWTlh7qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/msal-common": "14.16.0", - "jsonwebtoken": "^9.0.0", - "uuid": "^8.3.0" - }, - "engines": { - "node": ">=16" - } - }, - "node_modules/@azure/msal-node/node_modules/@azure/msal-common": { - "version": "14.16.0", - "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-14.16.0.tgz", - "integrity": "sha512-1KOZj9IpcDSwpNiQNjt0jDYZpQvNZay7QAEi/5DLubay40iGYtLzya/jbjRPLyOTZhEKyL1MzPuw2HqBCjceYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.26.2", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", - "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.25.9", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator": { - "version": "7.26.5", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.26.5.tgz", - "integrity": "sha512-2caSP6fN9I7HOe6nqhtft7V4g7/V/gfDsC3Ag4W7kEzzvRGKqiv0pu0HogPiZ3KaVSoNDhUws6IJjDjpfmYIXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.26.5", - "@babel/types": "^7.26.5", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^3.0.2" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", - "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.7.tgz", - "integrity": "sha512-kEvgGGgEjRUutvdVvZhbn/BxVt+5VSpwXz1j3WYXQbXDo8KzFOPNG2GQbdAiNq8g6wn1yKk7C/qrke03a84V+w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.26.7" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/template": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.25.9.tgz", - "integrity": "sha512-9DGttpmPvIxBb/2uwpVo3dqJ+O6RooAFOS+lB+xDqoE2PVCE8nfoHMdZLpfCQRLwvohzXISPZcgxt80xLfsuwg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.25.9", - "@babel/parser": "^7.25.9", - "@babel/types": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.26.7.tgz", - "integrity": "sha512-1x1sgeyRLC3r5fQOM0/xtQKsYjyxmFjaOrLJNtZ81inNjyJHGIolTULPiSc/2qe1/qfpFLisLQYFnnZl7QoedA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.26.2", - "@babel/generator": "^7.26.5", - "@babel/parser": "^7.26.7", - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.7", - "debug": "^4.3.1", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.26.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.7.tgz", - "integrity": "sha512-t8kDRGrKXyp6+tjUh7hw2RLyclsW4TRoRvRHtSyAX9Bb5ldlFh+90YAYY6awRXrlB4G5G2izNeGySpATlFzmOg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@types/node": { - "version": "18.19.75", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.75.tgz", - "integrity": "sha512-UIksWtThob6ZVSyxcOqCLOUNg/dyO1Qvx4McgeuhrEtHTLFTf7BBhEazaE4K806FGTPtzd/2sE90qn4fVr7cyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/vscode": { - "version": "1.75.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.75.0.tgz", - "integrity": "sha512-SAr0PoOhJS6FUq5LjNr8C/StBKALZwDVm3+U4pjF/3iYkt3GioJOPV/oB1Sf1l7lROe4TgrMyL5N1yaEgTWycw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vscode/debugprotocol": { - "version": "1.68.0", - "resolved": "https://registry.npmjs.org/@vscode/debugprotocol/-/debugprotocol-1.68.0.tgz", - "integrity": "sha512-2J27dysaXmvnfuhFGhfeuxfHRXunqNPxtBoR3koiTOA9rdxWNDTa1zIFLCFMSHJ9MPTPKFcBeblsyaCJCIlQxg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@vscode/vsce": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.2.2.tgz", - "integrity": "sha512-4TqdUq/yKlQTHcQMk/DamR632bq/+IJDomSbexOMee/UAYWqYm0XHWA6scGslsCpzY+sCWEhhl0nqdOB0XW1kw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@azure/identity": "^4.1.0", - "@vscode/vsce-sign": "^2.0.0", - "azure-devops-node-api": "^12.5.0", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "cockatiel": "^3.1.2", - "commander": "^12.1.0", - "form-data": "^4.0.0", - "glob": "^11.0.0", - "hosted-git-info": "^4.0.2", - "jsonc-parser": "^3.2.0", - "leven": "^3.1.0", - "markdown-it": "^14.1.0", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^7.5.2", - "tmp": "^0.2.3", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.5.0", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "keytar": "^7.7.0" - } - }, - "node_modules/@vscode/vsce-sign": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.0.5.tgz", - "integrity": "sha512-GfYWrsT/vypTMDMgWDm75iDmAOMe7F71sZECJ+Ws6/xyIfmB3ELVnVN+LwMFAvmXY+e6eWhR2EzNGF/zAhWY3Q==", - "dev": true, - "hasInstallScript": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optionalDependencies": { - "@vscode/vsce-sign-alpine-arm64": "2.0.2", - "@vscode/vsce-sign-alpine-x64": "2.0.2", - "@vscode/vsce-sign-darwin-arm64": "2.0.2", - "@vscode/vsce-sign-darwin-x64": "2.0.2", - "@vscode/vsce-sign-linux-arm": "2.0.2", - "@vscode/vsce-sign-linux-arm64": "2.0.2", - "@vscode/vsce-sign-linux-x64": "2.0.2", - "@vscode/vsce-sign-win32-arm64": "2.0.2", - "@vscode/vsce-sign-win32-x64": "2.0.2" - } - }, - "node_modules/@vscode/vsce-sign-alpine-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.2.tgz", - "integrity": "sha512-E80YvqhtZCLUv3YAf9+tIbbqoinWLCO/B3j03yQPbjT3ZIHCliKZlsy1peNc4XNZ5uIb87Jn0HWx/ZbPXviuAQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "alpine" - ] - }, - "node_modules/@vscode/vsce-sign-alpine-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.2.tgz", - "integrity": "sha512-n1WC15MSMvTaeJ5KjWCzo0nzjydwxLyoHiMJHu1Ov0VWTZiddasmOQHekA47tFRycnt4FsQrlkSCTdgHppn6bw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "alpine" - ] - }, - "node_modules/@vscode/vsce-sign-darwin-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.2.tgz", - "integrity": "sha512-rz8F4pMcxPj8fjKAJIfkUT8ycG9CjIp888VY/6pq6cuI2qEzQ0+b5p3xb74CJnBbSC0p2eRVoe+WgNCAxCLtzQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/vsce-sign-darwin-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.2.tgz", - "integrity": "sha512-MCjPrQ5MY/QVoZ6n0D92jcRb7eYvxAujG/AH2yM6lI0BspvJQxp0o9s5oiAM9r32r9tkLpiy5s2icsbwefAQIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@vscode/vsce-sign-linux-arm": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.2.tgz", - "integrity": "sha512-Fkb5jpbfhZKVw3xwR6t7WYfwKZktVGNXdg1m08uEx1anO0oUPUkoQRsNm4QniL3hmfw0ijg00YA6TrxCRkPVOQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-linux-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.2.tgz", - "integrity": "sha512-Ybeu7cA6+/koxszsORXX0OJk9N0GgfHq70Wqi4vv2iJCZvBrOWwcIrxKjvFtwyDgdeQzgPheH5nhLVl5eQy7WA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-linux-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.2.tgz", - "integrity": "sha512-NsPPFVtLaTlVJKOiTnO8Cl78LZNWy0Q8iAg+LlBiCDEgC12Gt4WXOSs2pmcIjDYzj2kY4NwdeN1mBTaujYZaPg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@vscode/vsce-sign-win32-arm64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.2.tgz", - "integrity": "sha512-wPs848ymZ3Ny+Y1Qlyi7mcT6VSigG89FWQnp2qRYCyMhdJxOpA4lDwxzlpL8fG6xC8GjQjGDkwbkWUcCobvksQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vscode/vsce-sign-win32-x64": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.2.tgz", - "integrity": "sha512-pAiRN6qSAhDM5SVOIxgx+2xnoVUePHbRNC7OD2aOR3WltTKxxF25OfpK8h8UQ7A0BuRkSgREbB59DBlFk4iAeg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "SEE LICENSE IN LICENSE.txt", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/azure-devops-node-api": { - "version": "12.5.0", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", - "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", - "dev": true, - "license": "MIT", - "dependencies": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-equal-constant-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz", - "integrity": "sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.3.tgz", - "integrity": "sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.12", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.12.tgz", - "integrity": "sha512-VqR8m68vM46BNnuZ5NtnGBKIE/DfN0cRIzg9n40EIq9NOv90ayxLBXA8fXC5gquFRGJSTRqBq25Jt2ECLR431Q==", - "dev": true, - "dependencies": { - "cheerio-select": "^2.1.0", - "dom-serializer": "^2.0.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "htmlparser2": "^8.0.1", - "parse5": "^7.0.0", - "parse5-htmlparser2-tree-adapter": "^7.0.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", - "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-select": "^5.1.0", - "css-what": "^6.1.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "optional": true - }, - "node_modules/cockatiel": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", - "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/css-select": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", - "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^6.1.0", - "domhandler": "^5.0.2", - "domutils": "^3.0.1", - "nth-check": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", - "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/define-lazy-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", - "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/detect-libc": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", - "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "dev": true, - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", - "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", - "dev": true, - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "optional": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/foreground-child": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.0.tgz", - "integrity": "sha512-Ld2g8rrAyMYFXBhEqMz8ZAHBi4J4uS1i/CxGMDnjyFWddMXLVcDp051DZfu+t7+ab7Wv6SMqpWmyFIj5UbfFvg==", - "dev": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz", - "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.7.tgz", - "integrity": "sha512-VW6Pxhsrk0KAOqs3WEd0klDiF/+V7gQOpAvY1jVU/LHmaD/kQO4523aiJuikX/QAKYiW6x8Jh+RJej1almdtCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "function-bind": "^1.1.2", - "get-proto": "^1.0.0", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", - "dev": true, - "optional": true - }, - "node_modules/glob": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", - "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", - "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "optional": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "optional": true - }, - "node_modules/is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, - "license": "MIT", - "bin": { - "is-docker": "cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-docker": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.2.tgz", - "integrity": "sha512-bZsjR/iRjl1Nk1UkjGpAzLNfQtzuijhn2g+pbZb98HQ1Gk8vM9hfbxeMBP+M2/UUdwj0RqGG3mlvk2MsAqwvEw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jsesc": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", - "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", - "dev": true, - "license": "MIT", - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/jsonwebtoken": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", - "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", - "ms": "^2.1.1", - "semver": "^7.5.4" - }, - "engines": { - "node": ">=12", - "npm": ">=6" - } - }, - "node_modules/jsonwebtoken/node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jsonwebtoken/node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jwa": "^1.4.1", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "dev": true, - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isplainobject": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", - "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", - "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, - "optional": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "optional": true - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true, - "optional": true - }, - "node_modules/node-abi": { - "version": "3.54.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", - "integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", - "dev": true, - "optional": true, - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true, - "optional": true - }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/object-inspect": { - "version": "1.13.4", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", - "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "optional": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", - "dev": true, - "dependencies": { - "semver": "^5.1.0" - } - }, - "node_modules/parse-semver/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/parse5": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", - "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", - "dev": true, - "dependencies": { - "entities": "^4.4.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.0.0.tgz", - "integrity": "sha512-B77tOZrqqfUfnVcOrUvfdLbz4pu4RopLD/4vmu3HUPswwTA8OH0EMW9BlWR2B0RCoiZRAHEUu7IxeP1Pd1UU+g==", - "dev": true, - "dependencies": { - "domhandler": "^5.0.2", - "parse5": "^7.0.0" - }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.2.tgz", - "integrity": "sha512-123qHRfJBmo2jXDbo/a5YOQrJoHF/GNQTLzQ5+IdK5pWpceK17yRc6ozlWd25FxvGKQbIUs91fDFkXmDHTKcyA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/prebuild-install": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.1.tgz", - "integrity": "sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==", - "dev": true, - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/prettier": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.4.2.tgz", - "integrity": "sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/prettier-plugin-curly": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/prettier-plugin-curly/-/prettier-plugin-curly-0.3.1.tgz", - "integrity": "sha512-GU3JJ4DB+j2gNA+8SxiyuAOuqalFu+JrX9JMNChTEwvgLCs+XXu2WJ1NbP1uK57Cbz04E2OhrkDpQFLMH5MsXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/generator": "^7.25.7", - "@babel/parser": "^7.25.8", - "@babel/traverse": "^7.25.7" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "prettier": "^2 || ^3" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "optional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", - "dev": true, - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dev": true, - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/sax": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", - "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "dev": true - }, - "node_modules/semver": { - "version": "7.5.4", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", - "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", - "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", - "side-channel-map": "^1.0.1", - "side-channel-weakmap": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-list": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", - "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-map": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", - "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/side-channel-weakmap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", - "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.5", - "object-inspect": "^1.13.3", - "side-channel-map": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/stoppable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stoppable/-/stoppable-1.1.0.tgz", - "integrity": "sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4", - "npm": ">=6" - } - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dev": true, - "optional": true, - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tmp": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.4.tgz", - "integrity": "sha512-UdiSoX6ypifLmrfQ/XfiawN6hkjSBpCjhKxxZcWlUUmoXLaCKQU0bx4HF/tdDK2uzRuchf1txGvrWBzYREssoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.14" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "dev": true, - "license": "0BSD" - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", - "dev": true, - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/typed-rest-client": { - "version": "1.8.11", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", - "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/underscore": { - "version": "1.13.7", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz", - "integrity": "sha512-GMXzWtsc57XAtguZgaQViUOzs0KTkk8ojr3/xAxXLITqf/3EMwxC0inyETfDFjH/Krbhuep0HNbbjI9i/q3F3g==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", - "dev": true, - "optional": true - }, - "node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", - "dev": true, - "license": "MIT", - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "optional": true - }, - "node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3" - } - } - } -} diff --git a/lldb/tools/lldb-dap/package.json b/lldb/tools/lldb-dap/package.json deleted file mode 100644 index 0f51c4f935e3..000000000000 --- a/lldb/tools/lldb-dap/package.json +++ /dev/null @@ -1,799 +0,0 @@ -{ - "name": "lldb-dap", - "displayName": "LLDB DAP", - "version": "0.2.15", - "publisher": "llvm-vs-code-extensions", - "homepage": "https://lldb.llvm.org", - "description": "Debugging with LLDB in Visual Studio Code", - "license": "Apache 2.0 License with LLVM exceptions", - "repository": { - "type": "git", - "url": "https://github.com/llvm/llvm-project.git", - "directory": "lldb/tools/lldb-dap/" - }, - "bugs": { - "url": "https://github.com/llvm/llvm-project/issues" - }, - "icon": "llvm-logo.png", - "keywords": [ - "C", - "C++", - "LLVM", - "LLDB" - ], - "engines": { - "vscode": "^1.75.0" - }, - "categories": [ - "Debuggers" - ], - "devDependencies": { - "@types/node": "^18.19.41", - "@types/vscode": "1.75.0", - "@vscode/debugprotocol": "^1.68.0", - "@vscode/vsce": "^3.2.2", - "prettier": "^3.4.2", - "prettier-plugin-curly": "^0.3.1", - "typescript": "^5.7.3" - }, - "activationEvents": [ - "onDebug", - "onUri" - ], - "main": "./out/extension", - "scripts": { - "vscode:prepublish": "tsc -p ./", - "watch": "tsc -watch -p ./", - "format": "npx prettier './src-ts/' --write", - "package": "vsce package --out ./out/lldb-dap.vsix", - "publish": "vsce publish", - "vscode-uninstall": "code --uninstall-extension llvm-vs-code-extensions.lldb-dap", - "vscode-install": "code --install-extension ./out/lldb-dap.vsix" - }, - "contributes": { - "languages": [ - { - "id": "lldb.disassembly", - "aliases": [ - "Disassembly" - ], - "extensions": [ - ".disasm" - ] - } - ], - "grammars": [ - { - "language": "lldb.disassembly", - "scopeName": "source.disassembly", - "path": "./syntaxes/disassembly.json" - } - ], - "configuration": [ - { - "type": "object", - "title": "Adapter", - "properties": { - "lldb-dap.executable-path": { - "order": 0, - "scope": "machine-overridable", - "type": "string", - "description": "The path to the lldb-dap binary, e.g. /usr/local/bin/lldb-dap" - }, - "lldb-dap.log-path": { - "order": 0, - "scope": "machine-overridable", - "type": "string", - "description": "The log path for lldb-dap (if any)" - }, - "lldb-dap.serverMode": { - "order": 0, - "scope": "resource", - "type": "boolean", - "markdownDescription": "Run lldb-dap in server mode.\n\nWhen enabled, lldb-dap will start a background server that will be reused between debug sessions. This allows caching of debug symbols between sessions and improves launch performance.", - "default": false - }, - "lldb-dap.arguments": { - "scope": "resource", - "type": "array", - "default": [], - "items": { - "type": "string" - }, - "description": "The list of additional arguments used to launch the debug adapter executable." - }, - "lldb-dap.environment": { - "scope": "resource", - "type": "object", - "default": {}, - "description": "The environment of the lldb-dap process.", - "additionalProperties": { - "type": "string" - } - } - } - }, - { - "title": "Defaults", - "type": "object", - "properties": { - "lldb-dap.commandEscapePrefix": { - "order": 0, - "type": "string", - "description": "The escape prefix to use for executing regular LLDB commands in the Debug Console, instead of printing variables. Defaults to a back-tick (`). If it's an empty string, then all expression in the Debug Console are treated as regular LLDB commands.", - "default": "`" - }, - "lldb-dap.customFrameFormat": { - "order": 0, - "type": "string", - "description": "If non-empty, stack frames will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html for an explanation on format strings for frames. If the format string contains errors, an error message will be displayed on the Debug Console and the default frame names will be used. This might come with a performance cost because debug information might need to be processed to generate the description.", - "default": "" - }, - "lldb-dap.customThreadFormat": { - "order": 0, - "type": "string", - "description": "If non-empty, threads will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html for an explanation on format strings for threads. If the format string contains errors, an error message will be displayed on the Debug Console and the default thread names will be used. This might come with a performance cost because debug information might need to be processed to generate the description.", - "default": "" - }, - "lldb-dap.detachOnError": { - "order": 0, - "type": "boolean", - "description": "Detach from the program.", - "default": false - }, - "lldb-dap.disableASLR": { - "order": 0, - "type": "boolean", - "description": "Enable or disable Address space layout randomization if the debugger supports it.", - "default": true - }, - "lldb-dap.disableSTDIO": { - "order": 0, - "type": "boolean", - "description": "Don't retrieve STDIN, STDOUT and STDERR as the program is running.", - "default": false - }, - "lldb-dap.displayExtendedBacktrace": { - "order": 0, - "type": "boolean", - "description": "Enable language specific extended backtraces.", - "default": false - }, - "lldb-dap.enableAutoVariableSummaries": { - "order": 0, - "type": "boolean", - "description": "Enable auto generated summaries for variables when no summaries exist for a given type. This feature can cause performance delays in large projects when viewing variables.", - "default": false - }, - "lldb-dap.enableSyntheticChildDebugging": { - "order": 0, - "type": "boolean", - "description": "If a variable is displayed using a synthetic children, also display the actual contents of the variable at the end under a [raw] entry. This is useful when creating sythetic child plug-ins as it lets you see the actual contents of the variable.", - "default": false - }, - "lldb-dap.timeout": { - "order": 0, - "type": "number", - "description": "The time in seconds to wait for a program to stop at entry point when launching with \"launchCommands\". Defaults to 30 seconds.", - "default": 30 - }, - "lldb-dap.targetTriple": { - "order": 1, - "type": "string", - "description": "Triplet of the target architecture to override value derived from the program file." - }, - "lldb-dap.platformName": { - "order": 1, - "type": "string", - "description": "Name of the execution platform to override value derived from the program file." - }, - "lldb-dap.initCommands": { - "order": 2, - "type": "array", - "items": { - "type": "string" - }, - "description": "Initialization commands executed upon debugger startup.", - "default": [] - }, - "lldb-dap.preRunCommands": { - "order": 3, - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed just before the program is launched.", - "default": [] - }, - "lldb-dap.postRunCommands": { - "order": 4, - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed just as soon as the program is successfully launched when it's in a stopped state prior to any automatic continuation.", - "default": [] - }, - "lldb-dap.stopCommands": { - "order": 5, - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed each time the program stops.", - "default": [] - }, - "lldb-dap.exitCommands": { - "order": 6, - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed when the program exits.", - "default": [] - }, - "lldb-dap.terminateCommands": { - "order": 7, - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed when the debugging session ends.", - "default": [] - } - } - } - ], - "commands": [ - { - "command": "lldb-dap.modules.copyProperty", - "title": "Copy Value" - } - ], - "menus": { - "commandPalette": [ - { - "command": "lldb-dap.modules.copyProperty", - "when": "false" - } - ], - "view/item/context": [ - { - "command": "lldb-dap.modules.copyProperty", - "when": "view == lldb-dap.modules && viewItem == property" - } - ] - }, - "breakpoints": [ - { - "language": "lldb.disassembly" - }, - { - "language": "ada" - }, - { - "language": "arm" - }, - { - "language": "asm" - }, - { - "language": "c" - }, - { - "language": "cpp" - }, - { - "language": "crystal" - }, - { - "language": "d" - }, - { - "language": "fortan" - }, - { - "language": "fortran-modern" - }, - { - "language": "nim" - }, - { - "language": "objective-c" - }, - { - "language": "objectpascal" - }, - { - "language": "pascal" - }, - { - "language": "rust" - }, - { - "language": "swift" - } - ], - "debuggers": [ - { - "type": "lldb-dap", - "label": "LLDB DAP Debugger", - "configurationAttributes": { - "launch": { - "required": [ - "program" - ], - "properties": { - "debugAdapterHostname": { - "type": "string", - "markdownDescription": "The hostname that an existing lldb-dap executable is listening on." - }, - "debugAdapterPort": { - "type": "number", - "markdownDescription": "The port that an existing lldb-dap executable is listening on." - }, - "debugAdapterExecutable": { - "type": "string", - "markdownDescription": "The absolute path to the LLDB debug adapter executable to use. Overrides any user or workspace settings." - }, - "debugAdapterArgs": { - "type": "array", - "items": { - "type": "string" - }, - "markdownDescription": "The list of additional arguments used to launch the debug adapter executable. Overrides any user or workspace settings." - }, - "program": { - "type": "string", - "description": "Path to the program to debug." - }, - "args": { - "type": [ - "array" - ], - "items": { - "type": "string" - }, - "description": "Program arguments.", - "default": [] - }, - "cwd": { - "type": "string", - "description": "Program working directory.", - "default": "${workspaceRoot}" - }, - "env": { - "anyOf": [ - { - "type": "object", - "description": "Additional environment variables to set when launching the program. E.g. `{ \"FOO\": \"1\" }`", - "patternProperties": { - ".*": { - "type": "string" - } - }, - "default": {} - }, - { - "type": "array", - "description": "Additional environment variables to set when launching the program. E.g. `[\"FOO=1\", \"BAR\"]`", - "items": { - "type": "string", - "pattern": "^((\\w+=.*)|^\\w+)$" - }, - "default": [] - } - ] - }, - "stopOnEntry": { - "type": "boolean", - "description": "Automatically stop after launch.", - "default": false - }, - "disableASLR": { - "type": "boolean", - "description": "Enable or disable Address space layout randomization if the debugger supports it.", - "default": true - }, - "disableSTDIO": { - "type": "boolean", - "description": "Don't retrieve STDIN, STDOUT and STDERR as the program is running.", - "default": false - }, - "shellExpandArguments": { - "type": "boolean", - "description": "Expand program arguments as a shell would without actually launching the program in a shell.", - "default": false - }, - "detachOnError": { - "type": "boolean", - "description": "Detach from the program.", - "default": false - }, - "sourcePath": { - "type": "string", - "description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths." - }, - "sourceMap": { - "anyOf": [ - { - "type": "object", - "description": "Specify an object of path remappings; each entry has a key containing the source path and a value containing the destination path. E.g `{ \"/the/source/path\": \"/the/destination/path\" }`. Overrides sourcePath.", - "patternProperties": { - ".*": { - "type": "string" - } - }, - "default": {} - }, - { - "type": "array", - "description": "Specify an array of path remappings; each element must itself be a two element array containing a source and destination path name. Overrides sourcePath.", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "type": "string" - } - }, - "default": [] - } - ] - }, - "debuggerRoot": { - "type": "string", - "description": "Specify a working directory to set the debug adapter to so relative object files can be located." - }, - "targetTriple": { - "type": "string", - "description": "Triplet of the target architecture to override value derived from the program file." - }, - "platformName": { - "type": "string", - "description": "Name of the execution platform to override value derived from the program file." - }, - "initCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Initialization commands executed upon debugger startup.", - "default": [] - }, - "preRunCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed just before the program is launched.", - "default": [] - }, - "postRunCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed just as soon as the program is successfully launched when it's in a stopped state prior to any automatic continuation.", - "default": [] - }, - "launchCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Custom commands that are executed instead of launching a process. A target will be created with the launch arguments prior to executing these commands. The commands may optionally create a new target and must perform a launch. A valid process must exist after these commands complete or the \"launch\" will fail. Launch the process with \"process launch -s\" to make the process to at the entry point since lldb-dap will auto resume if necessary.", - "default": [] - }, - "stopCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed each time the program stops.", - "default": [] - }, - "exitCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed when the program exits.", - "default": [] - }, - "terminateCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed when the debugging session ends.", - "default": [] - }, - "runInTerminal": { - "type": "boolean", - "description": "Launch the program inside an integrated terminal in the IDE. Useful for debugging interactive command line programs", - "default": false - }, - "timeout": { - "type": "number", - "description": "The time in seconds to wait for a program to stop at entry point when launching with \"launchCommands\". Defaults to 30 seconds." - }, - "enableAutoVariableSummaries": { - "type": "boolean", - "description": "Enable auto generated summaries for variables when no summaries exist for a given type. This feature can cause performance delays in large projects when viewing variables.", - "default": false - }, - "displayExtendedBacktrace": { - "type": "boolean", - "description": "Enable language specific extended backtraces.", - "default": false - }, - "enableSyntheticChildDebugging": { - "type": "boolean", - "description": "If a variable is displayed using a synthetic children, also display the actual contents of the variable at the end under a [raw] entry. This is useful when creating sythetic child plug-ins as it lets you see the actual contents of the variable.", - "default": false - }, - "commandEscapePrefix": { - "type": "string", - "description": "The escape prefix to use for executing regular LLDB commands in the Debug Console, instead of printing variables. Defaults to a back-tick (`). If it's an empty string, then all expression in the Debug Console are treated as regular LLDB commands.", - "default": "`" - }, - "customFrameFormat": { - "type": "string", - "description": "If non-empty, stack frames will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html for an explanation on format strings for frames. If the format string contains errors, an error message will be displayed on the Debug Console and the default frame names will be used. This might come with a performance cost because debug information might need to be processed to generate the description.", - "default": "" - }, - "customThreadFormat": { - "type": "string", - "description": "If non-empty, threads will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html for an explanation on format strings for threads. If the format string contains errors, an error message will be displayed on the Debug Console and the default thread names will be used. This might come with a performance cost because debug information might need to be processed to generate the description.", - "default": "" - } - } - }, - "attach": { - "properties": { - "debugAdapterHostname": { - "type": "string", - "markdownDescription": "The hostname that an existing lldb-dap executable is listening on." - }, - "debugAdapterPort": { - "type": "number", - "markdownDescription": "The port that an existing lldb-dap executable is listening on." - }, - "debugAdapterExecutable": { - "type": "string", - "markdownDescription": "The absolute path to the LLDB debug adapter executable to use. Overrides any user or workspace settings." - }, - "debugAdapterArgs": { - "type": "array", - "items": { - "type": "string" - }, - "markdownDescription": "The list of additional arguments used to launch the debug adapter executable. Overrides any user or workspace settings." - }, - "program": { - "type": "string", - "description": "Path to the program to attach to." - }, - "pid": { - "type": "number", - "description": "System process ID to attach to." - }, - "waitFor": { - "type": "boolean", - "description": "If set to true, then wait for the process to launch by looking for a process with a basename that matches `program`. No process ID needs to be specified when using this flag.", - "default": true - }, - "sourcePath": { - "type": "string", - "description": "Specify a source path to remap \"./\" to allow full paths to be used when setting breakpoints in binaries that have relative source paths." - }, - "sourceMap": { - "anyOf": [ - { - "type": "object", - "description": "Specify an object of path remappings; each entry has a key containing the source path and a value containing the destination path. E.g `{ \"/the/source/path\": \"/the/destination/path\" }`. Overrides sourcePath.", - "patternProperties": { - ".*": { - "type": "string" - } - }, - "default": {} - }, - { - "type": "array", - "description": "Specify an array of path remappings; each element must itself be a two element array containing a source and destination path name. Overrides sourcePath.", - "items": { - "type": "array", - "minItems": 2, - "maxItems": 2, - "items": { - "type": "string" - } - }, - "default": [] - } - ] - }, - "debuggerRoot": { - "type": "string", - "description": "Specify a working directory to set the debug adapter to so relative object files can be located." - }, - "targetTriple": { - "type": "string", - "description": "Triplet of the target architecture to override value derived from the program file." - }, - "platformName": { - "type": "string", - "description": "Name of the execution platform to override value derived from the program file." - }, - "attachCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Custom commands that are executed instead of attaching to a process ID or to a process by name. These commands may optionally create a new target and must perform an attach. A valid process must exist after these commands complete or the \"attach\" will fail.", - "default": [] - }, - "initCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Initialization commands executed upon debugger startup.", - "default": [] - }, - "preRunCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed just before the program is attached to.", - "default": [] - }, - "postRunCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed just as soon as the program is successfully attached when it's in a stopped state prior to any automatic continuation.", - "default": [] - }, - "stopCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed each time the program stops.", - "default": [] - }, - "exitCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed when the program exits.", - "default": [] - }, - "terminateCommands": { - "type": "array", - "items": { - "type": "string" - }, - "description": "Commands executed when the debugging session ends.", - "default": [] - }, - "coreFile": { - "type": "string", - "description": "Path to the core file to debug." - }, - "timeout": { - "type": "number", - "description": "The time in seconds to wait for a program to stop when attaching using \"attachCommands\". Defaults to 30 seconds." - }, - "gdb-remote-port": { - "type": [ - "number", - "string" - ], - "description": "TCP/IP port to attach to a remote system. Specifying both pid and port is an error." - }, - "gdb-remote-hostname": { - "type": "string", - "description": "The hostname to connect to a remote system. The default hostname being used localhost." - }, - "enableAutoVariableSummaries": { - "type": "boolean", - "description": "Enable auto generated summaries for variables when no summaries exist for a given type. This feature can cause performance delays in large projects when viewing variables.", - "default": false - }, - "displayExtendedBacktrace": { - "type": "boolean", - "description": "Enable language specific extended backtraces.", - "default": false - }, - "enableSyntheticChildDebugging": { - "type": "boolean", - "description": "If a variable is displayed using a synthetic children, also display the actual contents of the variable at the end under a [raw] entry. This is useful when creating sythetic child plug-ins as it lets you see the actual contents of the variable.", - "default": false - }, - "commandEscapePrefix": { - "type": "string", - "description": "The escape prefix character to use for executing regular LLDB commands in the Debug Console, instead of printing variables. Defaults to a back-tick (`). If empty, then all expression in the Debug Console are treated as regular LLDB commands.", - "default": "`" - }, - "customFrameFormat": { - "type": "string", - "description": "If non-empty, stack frames will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html for an explanation on format strings for frames. If the format string contains errors, an error message will be displayed on the Debug Console and the default frame names will be used. This might come with a performance cost because debug information might need to be processed to generate the description.", - "default": "" - }, - "customThreadFormat": { - "type": "string", - "description": "If non-empty, threads will have descriptions generated based on the provided format. See https://lldb.llvm.org/use/formatting.html for an explanation on format strings for threads. If the format string contains errors, an error message will be displayed on the Debug Console and the default thread names will be used. This might come with a performance cost because debug information might need to be processed to generate the description.", - "default": "" - } - } - } - }, - "initialConfigurations": [ - { - "type": "lldb-dap", - "request": "launch", - "name": "Debug", - "program": "${workspaceRoot}/", - "args": [], - "env": [], - "cwd": "${workspaceRoot}" - } - ], - "configurationSnippets": [ - { - "label": "LLDB: Launch", - "description": "", - "body": { - "type": "lldb-dap", - "request": "launch", - "name": "${2:Launch}", - "program": "^\"\\${workspaceRoot}/${1:}\"", - "args": [], - "env": [], - "cwd": "^\"\\${workspaceRoot}\"" - } - }, - { - "label": "LLDB: Attach", - "description": "", - "body": { - "type": "lldb-dap", - "request": "attach", - "name": "${2:Attach}", - "program": "${1:}", - "waitFor": true - } - }, - { - "label": "LLDB: Load Coredump", - "description": "", - "body": { - "type": "lldb-dap", - "request": "attach", - "name": "${2:Core}", - "program": "${1:}", - "coreFile": "${1:}.core" - } - } - ] - } - ], - "views": { - "debug": [ - { - "id": "lldb-dap.modules", - "name": "Modules", - "when": "inDebugMode && debugType == 'lldb-dap' && lldb-dap.showModules", - "icon": "$(symbol-module)" - } - ] - } - } -} diff --git a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts b/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts deleted file mode 100644 index b5db45b56d6a..000000000000 --- a/lldb/tools/lldb-dap/src-ts/debug-adapter-factory.ts +++ /dev/null @@ -1,224 +0,0 @@ -import * as path from "path"; -import * as util from "util"; -import * as vscode from "vscode"; -import * as child_process from "child_process"; -import * as fs from "node:fs/promises"; -import { ConfigureButton, OpenSettingsButton } from "./ui/show-error-message"; -import { ErrorWithNotification } from "./ui/error-with-notification"; - -const exec = util.promisify(child_process.execFile); - -async function isExecutable(path: string): Promise { - try { - await fs.access(path, fs.constants.X_OK); - } catch { - return false; - } - return true; -} - -async function findWithXcrun(executable: string): Promise { - if (process.platform === "darwin") { - try { - let { stdout, stderr } = await exec("/usr/bin/xcrun", [ - "-find", - executable, - ]); - if (stdout) { - return stdout.toString().trimEnd(); - } - } catch (error) {} - } - return undefined; -} - -async function findInPath(executable: string): Promise { - const env_path = - process.platform === "win32" ? process.env["Path"] : process.env["PATH"]; - if (!env_path) { - return undefined; - } - - const paths = env_path.split(path.delimiter); - for (const p of paths) { - const exe_path = path.join(p, executable); - if (await isExecutable(exe_path)) { - return exe_path; - } - } - return undefined; -} - -async function findDAPExecutable(): Promise { - const executable = process.platform === "win32" ? "lldb-dap.exe" : "lldb-dap"; - - // Prefer lldb-dap from Xcode on Darwin. - const xcrun_dap = await findWithXcrun(executable); - if (xcrun_dap) { - return xcrun_dap; - } - - // Find lldb-dap in the user's path. - const path_dap = await findInPath(executable); - if (path_dap) { - return path_dap; - } - - return undefined; -} - -/** - * Retrieves the lldb-dap executable path either from settings or the provided - * {@link vscode.DebugConfiguration}. - * - * @param workspaceFolder The {@link vscode.WorkspaceFolder} that the debug session will be launched within - * @param configuration The {@link vscode.DebugConfiguration} that will be launched - * @throws An {@link ErrorWithNotification} if something went wrong - * @returns The path to the lldb-dap executable - */ -async function getDAPExecutable( - workspaceFolder: vscode.WorkspaceFolder | undefined, - configuration: vscode.DebugConfiguration, -): Promise { - // Check if the executable was provided in the launch configuration. - const launchConfigPath = configuration["debugAdapterExecutable"]; - if (typeof launchConfigPath === "string" && launchConfigPath.length !== 0) { - if (!(await isExecutable(launchConfigPath))) { - throw new ErrorWithNotification( - `Debug adapter path "${launchConfigPath}" is not a valid file. The path comes from your launch configuration.`, - new ConfigureButton(), - ); - } - return launchConfigPath; - } - - // Check if the executable was provided in the extension's configuration. - const config = vscode.workspace.getConfiguration("lldb-dap", workspaceFolder); - const configPath = config.get("executable-path"); - if (configPath && configPath.length !== 0) { - if (!(await isExecutable(configPath))) { - throw new ErrorWithNotification( - `Debug adapter path "${configPath}" is not a valid file. The path comes from your settings.`, - new OpenSettingsButton("lldb-dap.executable-path"), - ); - } - return configPath; - } - - // Try finding the lldb-dap binary. - const foundPath = await findDAPExecutable(); - if (foundPath) { - if (!(await isExecutable(foundPath))) { - throw new ErrorWithNotification( - `Found a potential debug adapter on your system at "${configPath}", but it is not a valid file.`, - new OpenSettingsButton("lldb-dap.executable-path"), - ); - } - return foundPath; - } - - throw new ErrorWithNotification( - "Unable to find the path to the LLDB debug adapter executable.", - new OpenSettingsButton("lldb-dap.executable-path"), - ); -} - -/** - * Retrieves the arguments that will be provided to lldb-dap either from settings or the provided - * {@link vscode.DebugConfiguration}. - * - * @param workspaceFolder The {@link vscode.WorkspaceFolder} that the debug session will be launched within - * @param configuration The {@link vscode.DebugConfiguration} that will be launched - * @throws An {@link ErrorWithNotification} if something went wrong - * @returns The arguments that will be provided to lldb-dap - */ -async function getDAPArguments( - workspaceFolder: vscode.WorkspaceFolder | undefined, - configuration: vscode.DebugConfiguration, -): Promise { - // Check the debug configuration for arguments first. - const debugConfigArgs = configuration.debugAdapterArgs; - if (debugConfigArgs) { - if ( - !Array.isArray(debugConfigArgs) || - debugConfigArgs.findIndex((entry) => typeof entry !== "string") !== -1 - ) { - throw new ErrorWithNotification( - "The debugAdapterArgs property must be an array of string values. Please update your launch configuration", - new ConfigureButton(), - ); - } - return debugConfigArgs; - } - // Fall back on the workspace configuration. - return vscode.workspace - .getConfiguration("lldb-dap", workspaceFolder) - .get("arguments", []); -} - -/** - * Creates a new {@link vscode.DebugAdapterExecutable} based on the provided workspace folder and - * debug configuration. Assumes that the given debug configuration is for a local launch of lldb-dap. - * - * @param workspaceFolder The {@link vscode.WorkspaceFolder} that the debug session will be launched within - * @param configuration The {@link vscode.DebugConfiguration} that will be launched - * @throws An {@link ErrorWithNotification} if something went wrong - * @returns The {@link vscode.DebugAdapterExecutable} that can be used to launch lldb-dap - */ -export async function createDebugAdapterExecutable( - workspaceFolder: vscode.WorkspaceFolder | undefined, - configuration: vscode.DebugConfiguration, -): Promise { - const config = vscode.workspace.workspaceFile ? vscode.workspace.getConfiguration("lldb-dap") : vscode.workspace.getConfiguration("lldb-dap", workspaceFolder); - const log_path = config.get("log-path"); - let env: { [key: string]: string } = {}; - if (log_path) { - env["LLDBDAP_LOG"] = log_path; - } - const configEnvironment = - config.get<{ [key: string]: string }>("environment") || {}; - const dapPath = await getDAPExecutable(workspaceFolder, configuration); - - const dbgOptions = { - env: { - ...configEnvironment, - ...env, - }, - cwd: configuration.cwd ?? workspaceFolder?.uri.fsPath, - }; - const dbgArgs = await getDAPArguments(workspaceFolder, configuration); - - return new vscode.DebugAdapterExecutable(dapPath, dbgArgs, dbgOptions); -} - -/** - * This class defines a factory used to find the lldb-dap binary to use - * depending on the session configuration. - */ -export class LLDBDapDescriptorFactory - implements vscode.DebugAdapterDescriptorFactory -{ - async createDebugAdapterDescriptor( - session: vscode.DebugSession, - executable: vscode.DebugAdapterExecutable | undefined, - ): Promise { - if (executable) { - throw new Error( - "Setting the debug adapter executable in the package.json is not supported.", - ); - } - - // Use a server connection if the debugAdapterPort is provided - if (session.configuration.debugAdapterPort) { - return new vscode.DebugAdapterServer( - session.configuration.debugAdapterPort, - session.configuration.debugAdapterHostname, - ); - } - - return createDebugAdapterExecutable( - session.workspaceFolder, - session.configuration, - ); - } -} diff --git a/lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts b/lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts deleted file mode 100644 index 316ffaf47c3d..000000000000 --- a/lldb/tools/lldb-dap/src-ts/debug-configuration-provider.ts +++ /dev/null @@ -1,199 +0,0 @@ -import * as vscode from "vscode"; -import * as child_process from "child_process"; -import * as util from "util"; -import { LLDBDapServer } from "./lldb-dap-server"; -import { createDebugAdapterExecutable } from "./debug-adapter-factory"; -import { ConfigureButton, showErrorMessage } from "./ui/show-error-message"; -import { ErrorWithNotification } from "./ui/error-with-notification"; - -const exec = util.promisify(child_process.execFile); - -/** - * Determines whether or not the given lldb-dap executable supports executing - * in server mode. - * - * @param exe the path to the lldb-dap executable - * @returns a boolean indicating whether or not lldb-dap supports server mode - */ -async function isServerModeSupported(exe: string): Promise { - const { stdout } = await exec(exe, ["--help"]); - return /--connection/.test(stdout); -} - -interface BoolConfig { - type: "boolean"; - default: boolean; -} -interface StringConfig { - type: "string"; - default: string; -} -interface NumberConfig { - type: "number"; - default: number; -} -interface StringArrayConfig { - type: "stringArray"; - default: string[]; -} -type DefaultConfig = - | BoolConfig - | NumberConfig - | StringConfig - | StringArrayConfig; - -const configurations: Record = { - // Keys for debugger configurations. - commandEscapePrefix: { type: "string", default: "`" }, - customFrameFormat: { type: "string", default: "" }, - customThreadFormat: { type: "string", default: "" }, - detachOnError: { type: "boolean", default: false }, - disableASLR: { type: "boolean", default: true }, - disableSTDIO: { type: "boolean", default: false }, - displayExtendedBacktrace: { type: "boolean", default: false }, - enableAutoVariableSummaries: { type: "boolean", default: false }, - enableSyntheticChildDebugging: { type: "boolean", default: false }, - timeout: { type: "number", default: 30 }, - - // Keys for platform / target configuration. - platformName: { type: "string", default: "" }, - targetTriple: { type: "string", default: "" }, - - // Keys for debugger command hooks. - initCommands: { type: "stringArray", default: [] }, - preRunCommands: { type: "stringArray", default: [] }, - postRunCommands: { type: "stringArray", default: [] }, - stopCommands: { type: "stringArray", default: [] }, - exitCommands: { type: "stringArray", default: [] }, - terminateCommands: { type: "stringArray", default: [] }, -}; - -export class LLDBDapConfigurationProvider - implements vscode.DebugConfigurationProvider -{ - constructor(private readonly server: LLDBDapServer) {} - - async resolveDebugConfiguration( - folder: vscode.WorkspaceFolder | undefined, - debugConfiguration: vscode.DebugConfiguration, - token?: vscode.CancellationToken, - ): Promise { - let config = vscode.workspace.getConfiguration("lldb-dap"); - for (const [key, cfg] of Object.entries(configurations)) { - if (Reflect.has(debugConfiguration, key)) { - continue; - } - const value = config.get(key); - if (value === undefined || value === cfg.default) { - continue; - } - switch (cfg.type) { - case "string": - if (typeof value !== "string") { - throw new Error(`Expected ${key} to be a string, got ${value}`); - } - break; - case "number": - if (typeof value !== "number") { - throw new Error(`Expected ${key} to be a number, got ${value}`); - } - break; - case "boolean": - if (typeof value !== "boolean") { - throw new Error(`Expected ${key} to be a boolean, got ${value}`); - } - break; - case "stringArray": - if (typeof value !== "object" && Array.isArray(value)) { - throw new Error( - `Expected ${key} to be a array of strings, got ${value}`, - ); - } - if ((value as string[]).length === 0) { - continue; - } - break; - } - - debugConfiguration[key] = value; - } - - return debugConfiguration; - } - - async resolveDebugConfigurationWithSubstitutedVariables( - folder: vscode.WorkspaceFolder | undefined, - debugConfiguration: vscode.DebugConfiguration, - _token?: vscode.CancellationToken, - ): Promise { - try { - if ( - "debugAdapterHostname" in debugConfiguration && - !("debugAdapterPort" in debugConfiguration) - ) { - throw new ErrorWithNotification( - "A debugAdapterPort must be provided when debugAdapterHostname is set. Please update your launch configuration.", - new ConfigureButton(), - ); - } - - // Check if we're going to launch a debug session or use an existing process - if ("debugAdapterPort" in debugConfiguration) { - if ( - "debugAdapterExecutable" in debugConfiguration || - "debugAdapterArgs" in debugConfiguration - ) { - throw new ErrorWithNotification( - "The debugAdapterPort property is incompatible with debugAdapterExecutable and debugAdapterArgs. Please update your launch configuration.", - new ConfigureButton(), - ); - } - } else { - // Always try to create the debug adapter executable as this will show the user errors - // if there are any. - const executable = await createDebugAdapterExecutable( - folder, - debugConfiguration, - ); - if (!executable) { - return undefined; - } - - // Server mode needs to be handled here since DebugAdapterDescriptorFactory - // will show an unhelpful error if it returns undefined. We'd rather show a - // nicer error message here and allow stopping the debug session gracefully. - const config = vscode.workspace.getConfiguration("lldb-dap", folder); - if ( - config.get("serverMode", false) && - (await isServerModeSupported(executable.command)) - ) { - const serverInfo = await this.server.start( - executable.command, - executable.args, - executable.options, - ); - if (!serverInfo) { - return undefined; - } - // Use a debug adapter host and port combination rather than an executable - // and list of arguments. - delete debugConfiguration.debugAdapterExecutable; - delete debugConfiguration.debugAdapterArgs; - debugConfiguration.debugAdapterHostname = serverInfo.host; - debugConfiguration.debugAdapterPort = serverInfo.port; - } - } - - return debugConfiguration; - } catch (error) { - // Show a better error message to the user if possible - if (!(error instanceof ErrorWithNotification)) { - throw error; - } - return await error.showNotification({ - modal: true, - showConfigureButton: true, - }); - } - } -} diff --git a/lldb/tools/lldb-dap/src-ts/debug-session-tracker.ts b/lldb/tools/lldb-dap/src-ts/debug-session-tracker.ts deleted file mode 100644 index 50db1e1c3a7b..000000000000 --- a/lldb/tools/lldb-dap/src-ts/debug-session-tracker.ts +++ /dev/null @@ -1,139 +0,0 @@ -import { DebugProtocol } from "@vscode/debugprotocol"; -import * as vscode from "vscode"; - -/** A helper type for mapping event types to their corresponding data type. */ -// prettier-ignore -interface EventMap { - "module": DebugProtocol.ModuleEvent; -} - -/** A type assertion to check if a ProtocolMessage is an event or if it is a specific event. */ -function isEvent( - message: DebugProtocol.ProtocolMessage, -): message is DebugProtocol.Event; -function isEvent( - message: DebugProtocol.ProtocolMessage, - event: K, -): message is EventMap[K]; -function isEvent( - message: DebugProtocol.ProtocolMessage, - event?: string, -): boolean { - return ( - message.type === "event" && - (!event || (message as DebugProtocol.Event).event === event) - ); -} - -/** Tracks lldb-dap sessions for data visualizers. */ -export class DebugSessionTracker - implements vscode.DebugAdapterTrackerFactory, vscode.Disposable -{ - /** - * Tracks active modules for each debug sessions. - * - * The modules are kept in an array to maintain the load order of the modules. - */ - private modules = new Map(); - private modulesChanged = new vscode.EventEmitter< - vscode.DebugSession | undefined - >(); - - /** - * Fired when modules are changed for any active debug session. - * - * Use `debugSessionModules` to retieve the active modules for a given debug session. - */ - onDidChangeModules: vscode.Event = - this.modulesChanged.event; - - constructor() { - this.onDidChangeModules(this.moduleChangedListener, this); - vscode.debug.onDidChangeActiveDebugSession((session) => - this.modulesChanged.fire(session), - ); - } - - dispose() { - this.modules.clear(); - this.modulesChanged.dispose(); - } - - createDebugAdapterTracker( - session: vscode.DebugSession, - ): vscode.ProviderResult { - return { - onDidSendMessage: (message) => this.onDidSendMessage(session, message), - onExit: () => this.onExit(session), - }; - } - - /** - * Retrieves the modules for the given debug session. - * - * Modules are returned in load order. - */ - debugSessionModules(session: vscode.DebugSession): DebugProtocol.Module[] { - return this.modules.get(session) ?? []; - } - - /** Clear information from the active session. */ - private onExit(session: vscode.DebugSession) { - this.modules.delete(session); - this.modulesChanged.fire(undefined); - } - - private showModulesTreeView(showModules: boolean) { - vscode.commands.executeCommand( - "setContext", - "lldb-dap.showModules", - showModules, - ); - } - - private moduleChangedListener(session: vscode.DebugSession | undefined) { - if (!session) { - this.showModulesTreeView(false); - return; - } - - if (session == vscode.debug.activeDebugSession) { - const sessionHasModules = this.modules.get(session) != undefined; - this.showModulesTreeView(sessionHasModules); - } - } - - private onDidSendMessage( - session: vscode.DebugSession, - message: DebugProtocol.ProtocolMessage, - ) { - if (isEvent(message, "module")) { - const { module, reason } = message.body; - const modules = this.modules.get(session) ?? []; - switch (reason) { - case "new": - case "changed": { - const index = modules.findIndex((m) => m.id === module.id); - if (index !== -1) { - modules[index] = module; - } else { - modules.push(module); - } - break; - } - case "removed": { - const index = modules.findIndex((m) => m.id === module.id); - if (index !== -1) { - modules.splice(index, 1); - } - break; - } - default: - console.error("unexpected module event reason"); - break; - } - this.modules.set(session, modules); - this.modulesChanged.fire(session); - } - } -} diff --git a/lldb/tools/lldb-dap/src-ts/disposable-context.ts b/lldb/tools/lldb-dap/src-ts/disposable-context.ts deleted file mode 100644 index 42ece763d247..000000000000 --- a/lldb/tools/lldb-dap/src-ts/disposable-context.ts +++ /dev/null @@ -1,27 +0,0 @@ -import * as vscode from "vscode"; - -/** - * This class provides a simple wrapper around vscode.Disposable that allows - * for registering additional disposables. - */ -export class DisposableContext implements vscode.Disposable { - private _disposables: vscode.Disposable[] = []; - - constructor() {} - - public dispose() { - for (const disposable of this._disposables) { - disposable.dispose(); - } - this._disposables = []; - } - - /** - * Push an additional disposable to the context. - * - * @param disposable The disposable to register. - */ - public pushSubscription(...disposable: vscode.Disposable[]) { - this._disposables.push(...disposable); - } -} diff --git a/lldb/tools/lldb-dap/src-ts/extension.ts b/lldb/tools/lldb-dap/src-ts/extension.ts deleted file mode 100644 index c8e5146e29ce..000000000000 --- a/lldb/tools/lldb-dap/src-ts/extension.ts +++ /dev/null @@ -1,59 +0,0 @@ -import * as vscode from "vscode"; - -import { LLDBDapDescriptorFactory } from "./debug-adapter-factory"; -import { DisposableContext } from "./disposable-context"; -import { LaunchUriHandler } from "./uri-launch-handler"; -import { LLDBDapConfigurationProvider } from "./debug-configuration-provider"; -import { LLDBDapServer } from "./lldb-dap-server"; -import { DebugSessionTracker } from "./debug-session-tracker"; -import { - ModulesDataProvider, - ModuleProperty, -} from "./ui/modules-data-provider"; - -/** - * This class represents the extension and manages its life cycle. Other extensions - * using it as as library should use this class as the main entry point. - */ -export class LLDBDapExtension extends DisposableContext { - constructor() { - super(); - - const lldbDapServer = new LLDBDapServer(); - const sessionTracker = new DebugSessionTracker(); - - this.pushSubscription( - lldbDapServer, - sessionTracker, - vscode.debug.registerDebugConfigurationProvider( - "lldb-dap", - new LLDBDapConfigurationProvider(lldbDapServer), - ), - vscode.debug.registerDebugAdapterDescriptorFactory( - "lldb-dap", - new LLDBDapDescriptorFactory(), - ), - vscode.debug.registerDebugAdapterTrackerFactory( - "lldb-dap", - sessionTracker, - ), - vscode.window.registerTreeDataProvider( - "lldb-dap.modules", - new ModulesDataProvider(sessionTracker), - ), - vscode.window.registerUriHandler(new LaunchUriHandler()), - ); - - vscode.commands.registerCommand( - "lldb-dap.modules.copyProperty", - (node: ModuleProperty) => vscode.env.clipboard.writeText(node.value), - ); - } -} - -/** - * This is the entry point when initialized by VS Code. - */ -export function activate(context: vscode.ExtensionContext) { - context.subscriptions.push(new LLDBDapExtension()); -} diff --git a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts b/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts deleted file mode 100644 index f40dbf049a4b..000000000000 --- a/lldb/tools/lldb-dap/src-ts/lldb-dap-server.ts +++ /dev/null @@ -1,132 +0,0 @@ -import * as child_process from "node:child_process"; -import { isDeepStrictEqual } from "util"; -import * as vscode from "vscode"; - -/** - * Represents a running lldb-dap process that is accepting connections (i.e. in "server mode"). - * - * Handles startup of the process if it isn't running already as well as prompting the user - * to restart when arguments have changed. - */ -export class LLDBDapServer implements vscode.Disposable { - private serverProcess?: child_process.ChildProcessWithoutNullStreams; - private serverInfo?: Promise<{ host: string; port: number }>; - - /** - * Starts the server with the provided options. The server will be restarted or reused as - * necessary. - * - * @param dapPath the path to the debug adapter executable - * @param args the list of arguments to provide to the debug adapter - * @param options the options to provide to the debug adapter process - * @returns a promise that resolves with the host and port information or `undefined` if unable to launch the server. - */ - async start( - dapPath: string, - args: string[], - options?: child_process.SpawnOptionsWithoutStdio, - ): Promise<{ host: string; port: number } | undefined> { - const dapArgs = [...args, "--connection", "connect://localhost:0"]; - if (!(await this.shouldContinueStartup(dapPath, dapArgs))) { - return undefined; - } - - if (this.serverInfo) { - return this.serverInfo; - } - - this.serverInfo = new Promise((resolve, reject) => { - const process = child_process.spawn(dapPath, dapArgs, options); - process.on("error", (error) => { - reject(error); - this.serverProcess = undefined; - this.serverInfo = undefined; - }); - process.on("exit", (code, signal) => { - let errorMessage = "Server process exited early"; - if (code !== undefined) { - errorMessage += ` with code ${code}`; - } else if (signal !== undefined) { - errorMessage += ` due to signal ${signal}`; - } - reject(new Error(errorMessage)); - this.serverProcess = undefined; - this.serverInfo = undefined; - }); - process.stdout.setEncoding("utf8").on("data", (data) => { - const connection = /connection:\/\/\[([^\]]+)\]:(\d+)/.exec( - data.toString(), - ); - if (connection) { - const host = connection[1]; - const port = Number(connection[2]); - resolve({ host, port }); - process.stdout.removeAllListeners(); - } - }); - this.serverProcess = process; - }); - return this.serverInfo; - } - - /** - * Checks to see if the server needs to be restarted. If so, it will prompt the user - * to ask if they wish to restart. - * - * @param dapPath the path to the debug adapter - * @param args the arguments for the debug adapter - * @returns whether or not startup should continue depending on user input - */ - private async shouldContinueStartup( - dapPath: string, - args: string[], - ): Promise { - if (!this.serverProcess || !this.serverInfo) { - return true; - } - - if (isDeepStrictEqual(this.serverProcess.spawnargs, [dapPath, ...args])) { - return true; - } - - const userInput = await vscode.window.showInformationMessage( - "The arguments to lldb-dap have changed. Would you like to restart the server?", - { - modal: true, - detail: `An existing lldb-dap server (${this.serverProcess.pid}) is running with different arguments. - -The previous lldb-dap server was started with: - -${this.serverProcess.spawnargs.join(" ")} - -The new lldb-dap server will be started with: - -${dapPath} ${args.join(" ")} - -Restarting the server will interrupt any existing debug sessions and start a new server.`, - }, - "Restart", - "Use Existing", - ); - switch (userInput) { - case "Restart": - this.serverProcess.kill(); - this.serverProcess = undefined; - this.serverInfo = undefined; - return true; - case "Use Existing": - return true; - case undefined: - return false; - } - } - - dispose() { - if (!this.serverProcess) { - return; - } - this.serverProcess.kill(); - this.serverProcess = undefined; - this.serverInfo = undefined; - } -} diff --git a/lldb/tools/lldb-dap/src-ts/ui/error-with-notification.ts b/lldb/tools/lldb-dap/src-ts/ui/error-with-notification.ts deleted file mode 100644 index 1f8676d3eb13..000000000000 --- a/lldb/tools/lldb-dap/src-ts/ui/error-with-notification.ts +++ /dev/null @@ -1,68 +0,0 @@ -import * as vscode from "vscode"; -import { - ConfigureButton, - NotificationButton, - showErrorMessage, -} from "./show-error-message"; - -/** Options used to configure {@link ErrorWithNotification.showNotification}. */ -export interface ShowNotificationOptions extends vscode.MessageOptions { - /** - * Whether or not to show the configure launch configuration button. - * - * **IMPORTANT**: the configure launch configuration button will do nothing if the - * callee isn't a {@link vscode.DebugConfigurationProvider}. - */ - showConfigureButton?: boolean; -} - -/** - * An error that is able to be displayed to the user as a notification. - * - * Used in combination with {@link showErrorMessage showErrorMessage()} when whatever caused - * the error was the result of a direct action by the user. E.g. launching a debug session. - */ -export class ErrorWithNotification extends Error { - private readonly buttons: NotificationButton[]; - - constructor( - message: string, - ...buttons: NotificationButton[] - ) { - super(message); - this.buttons = buttons; - } - - /** - * Shows the notification to the user including the configure launch configuration button. - * - * **IMPORTANT**: the configure launch configuration button will do nothing if the - * callee isn't a {@link vscode.DebugConfigurationProvider}. - * - * @param options Configure the behavior of the notification - */ - showNotification( - options: ShowNotificationOptions & { showConfigureButton: true }, - ): Promise; - - /** - * Shows the notification to the user. - * - * @param options Configure the behavior of the notification - */ - showNotification(options?: ShowNotificationOptions): Promise; - - // Actual implementation of showNotification() - async showNotification( - options: ShowNotificationOptions = {}, - ): Promise { - // Filter out the configure button unless explicitly requested - let buttons = this.buttons; - if (options.showConfigureButton !== true) { - buttons = buttons.filter( - (button) => !(button instanceof ConfigureButton), - ); - } - return showErrorMessage(this.message, options, ...buttons); - } -} diff --git a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts b/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts deleted file mode 100644 index d0fb9270c734..000000000000 --- a/lldb/tools/lldb-dap/src-ts/ui/modules-data-provider.ts +++ /dev/null @@ -1,84 +0,0 @@ -import * as vscode from "vscode"; -import { DebugProtocol } from "@vscode/debugprotocol"; -import { DebugSessionTracker } from "../debug-session-tracker"; - -export interface ModuleProperty { - key: string; - value: string; -} - -/** Type to represent both Module and ModuleProperty since TreeDataProvider - * expects one concrete type */ -type TreeData = DebugProtocol.Module | ModuleProperty; - -function isModule(type: TreeData): type is DebugProtocol.Module { - return (type as DebugProtocol.Module).id !== undefined; -} - -class ModuleItem extends vscode.TreeItem { - constructor(module: DebugProtocol.Module) { - super(module.name, vscode.TreeItemCollapsibleState.Collapsed); - this.description = module.symbolStatus; - } - - static getProperties(module: DebugProtocol.Module): ModuleProperty[] { - // does not include the name and symbol status as it is show in the parent. - let children: ModuleProperty[] = []; - children.push({ key: "id:", value: module.id.toString() }); - - if (module.addressRange) { - children.push({ - key: "load address:", - value: module.addressRange, - }); - } - if (module.path) { - children.push({ key: "path:", value: module.path }); - } - if (module.version) { - children.push({ key: "version:", value: module.version }); - } - if (module.symbolFilePath) { - children.push({ key: "symbol filepath:", value: module.symbolFilePath }); - } - return children; - } -} - -/** A tree data provider for listing loaded modules for the active debug session. */ -export class ModulesDataProvider implements vscode.TreeDataProvider { - private changeTreeData = new vscode.EventEmitter(); - readonly onDidChangeTreeData = this.changeTreeData.event; - - constructor(private readonly tracker: DebugSessionTracker) { - tracker.onDidChangeModules(() => this.changeTreeData.fire()); - } - - getTreeItem(module: TreeData): vscode.TreeItem { - if (isModule(module)) { - return new ModuleItem(module); - } - - let item = new vscode.TreeItem(module.key); - item.description = module.value; - item.tooltip = `${module.key} ${module.value}`; - item.contextValue = "property"; - return item; - } - - getChildren(element?: TreeData): TreeData[] { - if (!vscode.debug.activeDebugSession) { - return []; - } - - if (!element) { - return this.tracker.debugSessionModules(vscode.debug.activeDebugSession); - } - - if (isModule(element)) { - return ModuleItem.getProperties(element); - } - - return []; - } -} diff --git a/lldb/tools/lldb-dap/src-ts/ui/show-error-message.ts b/lldb/tools/lldb-dap/src-ts/ui/show-error-message.ts deleted file mode 100644 index de7b07dc97a6..000000000000 --- a/lldb/tools/lldb-dap/src-ts/ui/show-error-message.ts +++ /dev/null @@ -1,98 +0,0 @@ -import * as vscode from "vscode"; - -/** - * A button with a particular label that can perform an action when clicked. - * - * Used to add buttons to {@link showErrorMessage showErrorMessage()}. - */ -export interface NotificationButton { - readonly label: T; - action(): Promise; -} - -/** - * Represents a button that, when clicked, will open a particular VS Code setting. - */ -export class OpenSettingsButton - implements NotificationButton<"Open Settings", undefined> -{ - readonly label = "Open Settings"; - - constructor(private readonly settingId?: string) {} - - async action(): Promise { - await vscode.commands.executeCommand( - "workbench.action.openSettings", - this.settingId ?? "@ext:llvm-vs-code-extensions.lldb-dap ", - ); - } -} - -/** - * Represents a button that, when clicked, will return `null`. - * - * Used by a {@link vscode.DebugConfigurationProvider} to indicate that VS Code should - * cancel a debug session and open its launch configuration. - * - * **IMPORTANT**: this button will do nothing if the callee isn't a - * {@link vscode.DebugConfigurationProvider}. - */ -export class ConfigureButton - implements NotificationButton<"Configure", null | undefined> -{ - readonly label = "Configure"; - - async action(): Promise { - return null; // Opens the launch.json if returned from a DebugConfigurationProvider - } -} - -/** Gets the Result type from a {@link NotificationButton} or string value. */ -type ResultOf = T extends string - ? T - : T extends NotificationButton - ? Result - : never; - -/** - * Shows an error message to the user with an optional array of buttons. - * - * This can be used with common buttons such as {@link OpenSettingsButton} or plain - * strings as would normally be accepted by {@link vscode.window.showErrorMessage}. - * - * @param message The error message to display to the user - * @param options Configures the behaviour of the message. - * @param buttons An array of {@link NotificationButton buttons} or strings that the user can click on - * @returns `undefined` or the result of a button's action - */ -export async function showErrorMessage< - T extends string | NotificationButton, ->( - message: string, - options: vscode.MessageOptions = {}, - ...buttons: T[] -): Promise | undefined> { - const userSelection = await vscode.window.showErrorMessage( - message, - options, - ...buttons.map((button) => { - if (typeof button === "string") { - return button; - } - return button.label; - }), - ); - - for (const button of buttons) { - if (typeof button === "string") { - if (userSelection === button) { - // Type assertion is required to let TypeScript know that "button" isn't just any old string. - return button as ResultOf; - } - } else if (userSelection === button.label) { - return await button.action(); - } - } - - return undefined; -} diff --git a/lldb/tools/lldb-dap/src-ts/uri-launch-handler.ts b/lldb/tools/lldb-dap/src-ts/uri-launch-handler.ts deleted file mode 100644 index d45c1820eec7..000000000000 --- a/lldb/tools/lldb-dap/src-ts/uri-launch-handler.ts +++ /dev/null @@ -1,102 +0,0 @@ -import * as vscode from "vscode"; - -export class LaunchUriHandler implements vscode.UriHandler { - async handleUri(uri: vscode.Uri) { - try { - const params = new URLSearchParams(uri.query); - if (uri.path == "/start") { - // Some properties have default values - let debugConfig: vscode.DebugConfiguration = { - type: "lldb-dap", - request: "launch", - name: "", - }; - // The `config` parameter allows providing a complete JSON-encoded configuration - const configJson = params.get("config"); - if (configJson !== null) { - Object.assign(debugConfig, JSON.parse(configJson)); - } - // Furthermore, some frequently used parameters can also be provided as separate parameters - const stringKeys = [ - "name", - "request", - "program", - "cwd", - "debuggerRoot", - ]; - const numberKeys = ["pid"]; - const arrayKeys = [ - "args", - "initCommands", - "preRunCommands", - "stopCommands", - "exitCommands", - "terminateCommands", - "launchCommands", - "attachCommands", - ]; - for (const key of stringKeys) { - const value = params.get(key); - if (value) { - debugConfig[key] = value; - } - } - for (const key of numberKeys) { - const value = params.get(key); - if (value) { - debugConfig[key] = Number(value); - } - } - for (const key of arrayKeys) { - // `getAll()` returns an array of strings. - const value = params.getAll(key); - if (value) { - debugConfig[key] = value; - } - } - // Report an error if we received any unknown parameters - const supportedKeys = new Set( - ["config"].concat(stringKeys).concat(numberKeys).concat(arrayKeys), - ); - const presentKeys = new Set(params.keys()); - // FIXME: Use `Set.difference` as soon as ES2024 is widely available - const unknownKeys = new Set(); - for (const k of presentKeys.keys()) { - if (!supportedKeys.has(k)) { - unknownKeys.add(k); - } - } - if (unknownKeys.size > 0) { - throw new Error( - `Unsupported URL parameters: ${Array.from(unknownKeys.keys()).join(", ")}`, - ); - } - // Prodide a default for the config name - const defaultName = - debugConfig.request == "launch" - ? "URL-based Launch" - : "URL-based Attach"; - debugConfig.name = - debugConfig.name || debugConfig.program || defaultName; - // Force the type to `lldb-dap`. We don't want to allow launching any other - // Debug Adapters using this URI scheme. - if (debugConfig.type != "lldb-dap") { - throw new Error(`Unsupported debugger type: ${debugConfig.type}`); - } - await vscode.debug.startDebugging(undefined, debugConfig); - } else { - throw new Error(`Unsupported Uri path: ${uri.path}`); - } - } catch (err) { - if (err instanceof Error) { - await vscode.window.showErrorMessage( - `Failed to handle lldb-dap URI request: ${err.message}`, - ); - } else { - await vscode.window.showErrorMessage( - `Failed to handle lldb-dap URI request: ${JSON.stringify(err)}`, - ); - } - } - } -} diff --git a/lldb/tools/lldb-dap/syntaxes/arm.disasm b/lldb/tools/lldb-dap/syntaxes/arm.disasm deleted file mode 100644 index 436a78bfc212..000000000000 --- a/lldb/tools/lldb-dap/syntaxes/arm.disasm +++ /dev/null @@ -1,45 +0,0 @@ -(lldb) -libIGL.so`igl::RenderPipelineDesc::TargetDesc::ColorAttachment::operator==: -libIGL.so[0x7694] <+0>: ldr r2, [r1] -libIGL.so[0x7696] <+2>: ldr r3, [r0] -libIGL.so[0x7698] <+4>: cmp r3, r2 -libIGL.so[0x769a] <+6>: bne 0x76da ; <+70> at RenderPipelineState.cpp -libIGL.so[0x769c] <+8>: ldrb r2, [r1, #0x5] -libIGL.so[0x769e] <+10>: ldrb r3, [r0, #0x5] -libIGL.so[0x76a0] <+12>: cmp r3, r2 -libIGL.so[0x76a2] <+14>: bne 0x76da ; <+70> at RenderPipelineState.cpp -libIGL.so[0x76a4] <+16>: ldr r2, [r1, #0x8] -libIGL.so[0x76a6] <+18>: ldr r3, [r0, #0x8] -libIGL.so[0x76a8] <+20>: cmp r3, r2 -libIGL.so[0x76aa] <+22>: bne 0x76da ; <+70> at RenderPipelineState.cpp -libIGL.so[0x76ac] <+24>: ldr r2, [r1, #0xc] -libIGL.so[0x76ae] <+26>: ldr r3, [r0, #0xc] -libIGL.so[0x76b0] <+28>: cmp r3, r2 -libIGL.so[0x76b2] <+30>: bne 0x76da ; <+70> at RenderPipelineState.cpp -libIGL.so[0x76b4] <+32>: ldr r2, [r1, #0x10] -libIGL.so[0x76b6] <+34>: ldr r3, [r0, #0x10] -libIGL.so[0x76b8] <+36>: cmp r3, r2 -libIGL.so[0x76ba] <+38>: bne 0x76da ; <+70> at RenderPipelineState.cpp -libIGL.so[0x76bc] <+40>: ldr r2, [r1, #0x14] -libIGL.so[0x76be] <+42>: ldr r3, [r0, #0x14] -libIGL.so[0x76c0] <+44>: cmp r3, r2 -libIGL.so[0x76c2] <+46>: bne 0x76da ; <+70> at RenderPipelineState.cpp -libIGL.so[0x76c4] <+48>: ldr r2, [r1, #0x18] -libIGL.so[0x76c6] <+50>: ldr r3, [r0, #0x18] -libIGL.so[0x76c8] <+52>: cmp r3, r2 -libIGL.so[0x76ca] <+54>: bne 0x76da ; <+70> at RenderPipelineState.cpp -libIGL.so[0x76cc] <+56>: ldr r1, [r1, #0x1c] -libIGL.so[0x76ce] <+58>: ldr r0, [r0, #0x1c] -libIGL.so[0x76d0] <+60>: subs r0, r0, r1 -libIGL.so[0x76d2] <+62>: clz r0, r0 -libIGL.so[0x76d6] <+66>: lsrs r0, r0, #0x5 -libIGL.so[0x76d8] <+68>: bx lr -libIGL.so[0x76da] <+70>: movs r0, #0x0 -libIGL.so[0x76dc] <+72>: bx lr -(lldb) disassemble --name _ZN3igl20VertexInputStateDesc28sizeForVertexAttributeFormatENS_21VertexAttributeFormatE -libIGL.so`igl::VertexInputStateDesc::sizeForVertexAttributeFormat: -libIGL.so[0x787c] <+0>: ldr r1, [pc, #0x8] ; <+12> at VertexInputState.cpp -libIGL.so[0x787e] <+2>: add r1, pc -libIGL.so[0x7880] <+4>: ldr.w r0, [r1, r0, lsl #2] -libIGL.so[0x7884] <+8>: bx lr -libIGL.so[0x7886] <+10>: nop \ No newline at end of file diff --git a/lldb/tools/lldb-dap/syntaxes/arm64.disasm b/lldb/tools/lldb-dap/syntaxes/arm64.disasm deleted file mode 100644 index dfe201d907dd..000000000000 --- a/lldb/tools/lldb-dap/syntaxes/arm64.disasm +++ /dev/null @@ -1,91 +0,0 @@ -(lldb) disassemble --name __android_log_config_read -liblog.so`::__android_log_config_read(): -liblog.so[0x6014] <+0>: stp x22, x21, [sp, #-0x30]! -liblog.so[0x6018] <+4>: stp x20, x19, [sp, #0x10] -liblog.so[0x601c] <+8>: stp x29, x30, [sp, #0x20] -liblog.so[0x6020] <+12>: add x29, sp, #0x20 ; =0x20 -liblog.so[0x6024] <+16>: adrp x8, 15 -liblog.so[0x6028] <+20>: ldr x8, [x8, #0x230] -liblog.so[0x602c] <+24>: ldr w8, [x8] -liblog.so[0x6030] <+28>: cbz w8, 0x6038 ; <+36> at config_read.cpp -liblog.so[0x6034] <+32>: tbz w8, #0x0, 0x6168 ; <+340> at config_read.cpp:65:1 -liblog.so[0x6038] <+36>: adrp x20, 15 -liblog.so[0x603c] <+40>: adrp x21, 15 -liblog.so[0x6040] <+44>: ldr x20, [x20, #0x238] -liblog.so[0x6044] <+48>: ldr x21, [x21, #0x240] -liblog.so[0x6048] <+52>: mov w19, wzr -liblog.so[0x604c] <+56>: ldr x22, [x20] -liblog.so[0x6050] <+60>: cmp x22, x20 -liblog.so[0x6054] <+64>: b.eq 0x609c ; <+136> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 80 at config_read.cpp:61 -liblog.so[0x6058] <+68>: ldr x8, [x22] -liblog.so[0x605c] <+72>: cmp x22, x8 -liblog.so[0x6060] <+76>: b.eq 0x60b0 ; <+156> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:61 -liblog.so[0x6064] <+80>: ldr x8, [x22, #0x18] -liblog.so[0x6068] <+84>: cbz x8, 0x60d0 ; <+188> at config_read.cpp -liblog.so[0x606c] <+88>: mov w0, w19 -liblog.so[0x6070] <+92>: blr x8 -liblog.so[0x6074] <+96>: tbz w0, #0x1f, 0x608c ; <+120> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 64 at config_read.cpp:61 -liblog.so[0x6078] <+100>: ldr x8, [x21, #0x18] -liblog.so[0x607c] <+104>: cbz x8, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 -liblog.so[0x6080] <+108>: mov w0, w19 -liblog.so[0x6084] <+112>: blr x8 -liblog.so[0x6088] <+116>: tbz w0, #0x1f, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 -liblog.so[0x608c] <+120>: ldr x22, [x22] -liblog.so[0x6090] <+124>: cmp x22, x20 -liblog.so[0x6094] <+128>: b.ne 0x6058 ; <+68> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 12 at config_read.cpp:61 -liblog.so[0x6098] <+132>: b 0x60b0 ; <+156> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:61 -liblog.so[0x609c] <+136>: ldr x8, [x21, #0x18] -liblog.so[0x60a0] <+140>: cbz x8, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 -liblog.so[0x60a4] <+144>: mov w0, w19 -liblog.so[0x60a8] <+148>: blr x8 -liblog.so[0x60ac] <+152>: tbz w0, #0x1f, 0x60c0 ; <+172> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:61 -liblog.so[0x60b0] <+156>: add w19, w19, #0x1 ; =0x1 -liblog.so[0x60b4] <+160>: cmp w19, #0x8 ; =0x8 -liblog.so[0x60b8] <+164>: b.lo 0x604c ; <+56> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) at config_read.cpp:61 -liblog.so[0x60bc] <+168>: b 0x60d0 ; <+188> at config_read.cpp -liblog.so[0x60c0] <+172>: ldr x8, [x20, #0x8] -liblog.so[0x60c4] <+176>: stp x20, x8, [x21] -liblog.so[0x60c8] <+180>: str x21, [x8] -liblog.so[0x60cc] <+184>: str x21, [x20, #0x8] -liblog.so[0x60d0] <+188>: adrp x20, 15 -liblog.so[0x60d4] <+192>: adrp x21, 15 -liblog.so[0x60d8] <+196>: ldr x20, [x20, #0x248] -liblog.so[0x60dc] <+200>: ldr x21, [x21, #0x250] -liblog.so[0x60e0] <+204>: mov w19, wzr -liblog.so[0x60e4] <+208>: ldr x22, [x20] -liblog.so[0x60e8] <+212>: cmp x22, x20 -liblog.so[0x60ec] <+216>: b.eq 0x6134 ; <+288> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 80 at config_read.cpp:62 -liblog.so[0x60f0] <+220>: ldr x8, [x22] -liblog.so[0x60f4] <+224>: cmp x22, x8 -liblog.so[0x60f8] <+228>: b.eq 0x6148 ; <+308> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:62 -liblog.so[0x60fc] <+232>: ldr x8, [x22, #0x18] -liblog.so[0x6100] <+236>: cbz x8, 0x6168 ; <+340> at config_read.cpp:65:1 -liblog.so[0x6104] <+240>: mov w0, w19 -liblog.so[0x6108] <+244>: blr x8 -liblog.so[0x610c] <+248>: tbz w0, #0x1f, 0x6124 ; <+272> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 64 at config_read.cpp:62 -liblog.so[0x6110] <+252>: ldr x8, [x21, #0x18] -liblog.so[0x6114] <+256>: cbz x8, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 -liblog.so[0x6118] <+260>: mov w0, w19 -liblog.so[0x611c] <+264>: blr x8 -liblog.so[0x6120] <+268>: tbz w0, #0x1f, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 -liblog.so[0x6124] <+272>: ldr x22, [x22] -liblog.so[0x6128] <+276>: cmp x22, x20 -liblog.so[0x612c] <+280>: b.ne 0x60f0 ; <+220> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 12 at config_read.cpp:62 -liblog.so[0x6130] <+284>: b 0x6148 ; <+308> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 100 at config_read.cpp:62 -liblog.so[0x6134] <+288>: ldr x8, [x21, #0x18] -liblog.so[0x6138] <+292>: cbz x8, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 -liblog.so[0x613c] <+296>: mov w0, w19 -liblog.so[0x6140] <+300>: blr x8 -liblog.so[0x6144] <+304>: tbz w0, #0x1f, 0x6158 ; <+324> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) + 116 at config_read.cpp:62 -liblog.so[0x6148] <+308>: add w19, w19, #0x1 ; =0x1 -liblog.so[0x614c] <+312>: cmp w19, #0x8 ; =0x8 -liblog.so[0x6150] <+316>: b.lo 0x60e4 ; <+208> [inlined] __android_log_add_transport(listnode*, android_log_transport_read*) at config_read.cpp:62 -liblog.so[0x6154] <+320>: b 0x6168 ; <+340> at config_read.cpp:65:1 -liblog.so[0x6158] <+324>: ldr x8, [x20, #0x8] -liblog.so[0x615c] <+328>: stp x20, x8, [x21] -liblog.so[0x6160] <+332>: str x21, [x8] -liblog.so[0x6164] <+336>: str x21, [x20, #0x8] -liblog.so[0x6168] <+340>: ldp x29, x30, [sp, #0x20] -liblog.so[0x616c] <+344>: ldp x20, x19, [sp, #0x10] -liblog.so[0x6170] <+348>: ldp x22, x21, [sp], #0x30 -liblog.so[0x6174] <+352>: ret diff --git a/lldb/tools/lldb-dap/syntaxes/disassembly.json b/lldb/tools/lldb-dap/syntaxes/disassembly.json deleted file mode 100644 index cd086fe2f49f..000000000000 --- a/lldb/tools/lldb-dap/syntaxes/disassembly.json +++ /dev/null @@ -1,64 +0,0 @@ -{ - "name": "Disassembly", - "scopeName": "source.disassembly", - "uuid": "9ade615f-5d82-4ac5-b22f-a1998c356ebe", - "patterns": [ - { - "comment": "x86 Address, bytes and opcode", - "name": "meta.instruction", - "match": "^([A-Za-z0-9]+):\\s([A-Z0-9]{2}\\s)+>?\\s+(\\w+)", - "captures": { - "1": {"name": "constant.numeric"}, - "3": {"name": "keyword.opcode"} - } - }, - { - "comment": "ARM Address, bytes and opcode", - "name": "meta.instruction", - "match": "^libIGL.so\\[([A-Za-z0-9]+)\\]\\s+(\\<\\+[0-9]*\\>):\\s+([A-Za-z]+.?[A-Za-z]*)", - "captures": { - "1": {"name": "constant.numeric"}, - "3": {"name": "keyword.opcode"} - } - }, - { - "comment": "ARM64 Address, bytes and opcode", - "name": "meta.instruction", - "match": "^liblog.so\\[([A-Za-z0-9]+)\\]\\s+(\\<\\+[0-9]*\\>):\\s+([A-Za-z]+.?[A-Za-z]*)", - "captures": { - "1": {"name": "constant.numeric"}, - "3": {"name": "keyword.opcode"} - } - }, - { - "comment": "Numeric constant", - "name": "constant.numeric", - "match": "(\\$|\\b)((0x)|[0-9])[A-Za-z0-9]+\\b" - }, - { - "comment": "x86 Register", - "name": "variable.language", - "match": "%[A-Za-z][A-Za-z0-9]*" - }, - { - "comment": "ARM Register", - "name": "variable.language", - "match": "r\\d+" - }, - { - "comment": "ARM Register Shortnames", - "name": "variable.language", - "match": "(fp|sp|lr|pc|wzr|xzr)" - }, - { - "comment": "ARM64 Register", - "name": "variable.language", - "match": "(x|w)[0-9]+" - }, - { - "comment": "End of line comment", - "name": "comment.line.semicolon", - "match": ";.*$" - } - ] -} diff --git a/lldb/tools/lldb-dap/syntaxes/x86.disasm b/lldb/tools/lldb-dap/syntaxes/x86.disasm deleted file mode 100644 index d86a798cb982..000000000000 --- a/lldb/tools/lldb-dap/syntaxes/x86.disasm +++ /dev/null @@ -1,28 +0,0 @@ -0x100008000: <0> popq %rdi -0x100008001: <1> pushq $0x0 -0x100008003: <3> movq %rsp, %rbp -0x100008006: <6> andq $-0x10, %rsp -0x10000800A: <10> subq $0x10, %rsp -0x10000800E: <14> movl 0x8(%rbp), %esi -0x100008011: <17> leaq 0x10(%rbp), %rdx -0x100008015: <21> leaq -0x101c(%rip), %rcx -0x10000801C: <28> leaq -0x8(%rbp), %r8 -0x100008020: <32> callq 0x100008062 # dyldbootstrap::start(dyld3::MachOLoaded const*, int, char const**, dyld3::MachOLoaded const*, unsigned long*) -0x100008025: <37> movq -0x8(%rbp), %rdi -0x100008029: <41> cmpq $0x0, %rdi -0x10000802D: <45> jne 0x10000803f # <+63> -0x10000802F: <47> movq %rbp, %rsp -0x100008032: <50> addq $0x8, %rsp -0x100008036: <54> movq $0x0, %rbp -0x10000803D: <61> jmpq *%rax -0x10000803F: <63> addq $0x10, %rsp -0x100008043: <67> pushq %rdi -0x100008044: <68> movq 0x8(%rbp), %rdi -0x100008048: <72> leaq 0x10(%rbp), %rsi -0x10000804C: <76> leaq 0x8(%rsi,%rdi,8), %rdx -0x100008051: <81> movq %rdx, %rcx -0x100008054: <84> movq (%rcx), %r8 -0x100008057: <87> addq $0x8, %rcx -0x10000805B: <91> testq %r8, %r8 -0x10000805E: <94> jne 0x100008054 # <+84> -0x100008060: <96> jmpq *%rax diff --git a/lldb/tools/lldb-dap/tool/CMakeLists.txt b/lldb/tools/lldb-dap/tool/CMakeLists.txt deleted file mode 100644 index b39a4ed9c40e..000000000000 --- a/lldb/tools/lldb-dap/tool/CMakeLists.txt +++ /dev/null @@ -1,28 +0,0 @@ -add_lldb_tool(lldb-dap - lldb-dap.cpp - - LINK_LIBS - lldbDAP - ) - -if(APPLE) - configure_file( - ${CMAKE_CURRENT_SOURCE_DIR}/lldb-dap-Info.plist.in - ${CMAKE_CURRENT_BINARY_DIR}/lldb-dap-Info.plist - ) - target_link_options(lldb-dap - PRIVATE LINKER:-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-dap-Info.plist) -endif() - -if(LLDB_BUILD_FRAMEWORK) - # In the build-tree, we know the exact path to the framework directory. - # The installed framework can be in different locations. - lldb_setup_rpaths(lldb-dap - BUILD_RPATH - "${LLDB_FRAMEWORK_ABSOLUTE_BUILD_DIR}" - INSTALL_RPATH - "@loader_path/../../../SharedFrameworks" - "@loader_path/../../System/Library/PrivateFrameworks" - "@loader_path/../../Library/PrivateFrameworks" - ) -endif() diff --git a/lldb/tools/lldb-dap/tool/lldb-dap-Info.plist.in b/lldb/tools/lldb-dap/tool/lldb-dap-Info.plist.in deleted file mode 100644 index 7d01d3145d92..000000000000 --- a/lldb/tools/lldb-dap/tool/lldb-dap-Info.plist.in +++ /dev/null @@ -1,21 +0,0 @@ - - - - - CFBundleDevelopmentRegion - English - CFBundleIdentifier - com.apple.lldb-dap - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - lldb-dap - CFBundleVersion - ${LLDB_VERSION} - SecTaskAccess - - allowed - debug - - - diff --git a/lldb/tools/lldb-dap/tool/lldb-dap.cpp b/lldb/tools/lldb-dap/tool/lldb-dap.cpp deleted file mode 100644 index 9b9de5e21a74..000000000000 --- a/lldb/tools/lldb-dap/tool/lldb-dap.cpp +++ /dev/null @@ -1,568 +0,0 @@ -//===-- lldb-dap.cpp ------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "DAP.h" -#include "DAPLog.h" -#include "EventHelper.h" -#include "Handler/RequestHandler.h" -#include "RunInTerminal.h" -#include "Transport.h" -#include "lldb/API/SBDebugger.h" -#include "lldb/API/SBStream.h" -#include "lldb/Host/Config.h" -#include "lldb/Host/File.h" -#include "lldb/Host/MainLoop.h" -#include "lldb/Host/MainLoopBase.h" -#include "lldb/Host/MemoryMonitor.h" -#include "lldb/Host/Socket.h" -#include "lldb/Utility/Status.h" -#include "lldb/Utility/UriParser.h" -#include "lldb/lldb-forward.h" -#include "llvm/ADT/ArrayRef.h" -#include "llvm/ADT/ScopeExit.h" -#include "llvm/ADT/StringExtras.h" -#include "llvm/ADT/StringRef.h" -#include "llvm/Option/Arg.h" -#include "llvm/Option/ArgList.h" -#include "llvm/Option/OptTable.h" -#include "llvm/Option/Option.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Error.h" -#include "llvm/Support/FileSystem.h" -#include "llvm/Support/InitLLVM.h" -#include "llvm/Support/Path.h" -#include "llvm/Support/PrettyStackTrace.h" -#include "llvm/Support/Signals.h" -#include "llvm/Support/Threading.h" -#include "llvm/Support/raw_ostream.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#if defined(_WIN32) -// We need to #define NOMINMAX in order to skip `min()` and `max()` macro -// definitions that conflict with other system headers. -// We also need to #undef GetObject (which is defined to GetObjectW) because -// the JSON code we use also has methods named `GetObject()` and we conflict -// against these. -#define NOMINMAX -#include -#undef GetObject -#include -typedef int socklen_t; -#else -#include -#include -#include -#include -#endif - -#if defined(__linux__) -#include -#endif - -using namespace lldb_dap; -using lldb_private::File; -using lldb_private::IOObject; -using lldb_private::MainLoop; -using lldb_private::MainLoopBase; -using lldb_private::NativeFile; -using lldb_private::Socket; -using lldb_private::Status; - -namespace { -using namespace llvm::opt; - -enum ID { - OPT_INVALID = 0, // This is not an option ID. -#define OPTION(...) LLVM_MAKE_OPT_ID(__VA_ARGS__), -#include "Options.inc" -#undef OPTION -}; - -#define OPTTABLE_STR_TABLE_CODE -#include "Options.inc" -#undef OPTTABLE_STR_TABLE_CODE - -#define OPTTABLE_PREFIXES_TABLE_CODE -#include "Options.inc" -#undef OPTTABLE_PREFIXES_TABLE_CODE - -static constexpr llvm::opt::OptTable::Info InfoTable[] = { -#define OPTION(...) LLVM_CONSTRUCT_OPT_INFO(__VA_ARGS__), -#include "Options.inc" -#undef OPTION -}; -class LLDBDAPOptTable : public llvm::opt::GenericOptTable { -public: - LLDBDAPOptTable() - : llvm::opt::GenericOptTable(OptionStrTable, OptionPrefixesTable, - InfoTable, true) {} -}; -} // anonymous namespace - -static void PrintHelp(LLDBDAPOptTable &table, llvm::StringRef tool_name) { - std::string usage_str = tool_name.str() + " options"; - table.printHelp(llvm::outs(), usage_str.c_str(), "LLDB DAP", false); - - llvm::outs() << R"___( -EXAMPLES: - The debug adapter can be started in two modes. - - Running lldb-dap without any arguments will start communicating with the - parent over stdio. Passing a --connection URI will cause lldb-dap to listen - for a connection in the specified mode. - - lldb-dap --connection connection://localhost: - - Passing --wait-for-debugger will pause the process at startup and wait for a - debugger to attach to the process. - - lldb-dap -g -)___"; -} - -static void PrintVersion() { - llvm::outs() << "lldb-dap: "; - llvm::cl::PrintVersionMessage(); - llvm::outs() << "liblldb: " << lldb::SBDebugger::GetVersionString() << '\n'; -} - -// If --launch-target is provided, this instance of lldb-dap becomes a -// runInTerminal launcher. It will ultimately launch the program specified in -// the --launch-target argument, which is the original program the user wanted -// to debug. This is done in such a way that the actual debug adapter can -// place breakpoints at the beginning of the program. -// -// The launcher will communicate with the debug adapter using a fifo file in the -// directory specified in the --comm-file argument. -// -// Regarding the actual flow, this launcher will first notify the debug adapter -// of its pid. Then, the launcher will be in a pending state waiting to be -// attached by the adapter. -// -// Once attached and resumed, the launcher will exec and become the program -// specified by --launch-target, which is the original target the -// user wanted to run. -// -// In case of errors launching the target, a suitable error message will be -// emitted to the debug adapter. -static llvm::Error LaunchRunInTerminalTarget(llvm::opt::Arg &target_arg, - llvm::StringRef comm_file, - lldb::pid_t debugger_pid, - char *argv[]) { -#if defined(_WIN32) - return llvm::createStringError( - "runInTerminal is only supported on POSIX systems"); -#else - - // On Linux with the Yama security module enabled, a process can only attach - // to its descendants by default. In the runInTerminal case the target - // process is launched by the client so we need to allow tracing explicitly. -#if defined(__linux__) - if (debugger_pid != LLDB_INVALID_PROCESS_ID) - (void)prctl(PR_SET_PTRACER, debugger_pid, 0, 0, 0); -#endif - - RunInTerminalLauncherCommChannel comm_channel(comm_file); - if (llvm::Error err = comm_channel.NotifyPid()) - return err; - - // We will wait to be attached with a timeout. We don't wait indefinitely - // using a signal to prevent being paused forever. - - // This env var should be used only for tests. - const char *timeout_env_var = getenv("LLDB_DAP_RIT_TIMEOUT_IN_MS"); - int timeout_in_ms = - timeout_env_var != nullptr ? atoi(timeout_env_var) : 20000; - if (llvm::Error err = comm_channel.WaitUntilDebugAdapterAttaches( - std::chrono::milliseconds(timeout_in_ms))) { - return err; - } - - const char *target = target_arg.getValue(); - execvp(target, argv); - - std::string error = std::strerror(errno); - comm_channel.NotifyError(error); - return llvm::createStringError(llvm::inconvertibleErrorCode(), - std::move(error)); -#endif -} - -/// used only by TestVSCode_redirection_to_console.py -static void redirection_test() { - printf("stdout message\n"); - fprintf(stderr, "stderr message\n"); - fflush(stdout); - fflush(stderr); -} - -/// Duplicates a file descriptor, setting FD_CLOEXEC if applicable. -static int DuplicateFileDescriptor(int fd) { -#if defined(F_DUPFD_CLOEXEC) - // Ensure FD_CLOEXEC is set. - return ::fcntl(fd, F_DUPFD_CLOEXEC, 0); -#else - return ::dup(fd); -#endif -} - -static llvm::Expected> -validateConnection(llvm::StringRef conn) { - auto uri = lldb_private::URI::Parse(conn); - - if (uri && (uri->scheme == "tcp" || uri->scheme == "connect" || - !uri->hostname.empty() || uri->port)) { - return std::make_pair( - Socket::ProtocolTcp, - formatv("[{0}]:{1}", uri->hostname.empty() ? "0.0.0.0" : uri->hostname, - uri->port.value_or(0))); - } - - if (uri && (uri->scheme == "unix" || uri->scheme == "unix-connect" || - uri->path != "/")) { - return std::make_pair(Socket::ProtocolUnixDomain, uri->path.str()); - } - - return llvm::createStringError( - "Unsupported connection specifier, expected 'unix-connect:///path' or " - "'connect://[host]:port', got '%s'.", - conn.str().c_str()); -} - -static llvm::Error -serveConnection(const Socket::SocketProtocol &protocol, const std::string &name, - Log *log, const ReplMode default_repl_mode, - const std::vector &pre_init_commands) { - Status status; - static std::unique_ptr listener = Socket::Create(protocol, status); - if (status.Fail()) { - return status.takeError(); - } - - status = listener->Listen(name, /*backlog=*/5); - if (status.Fail()) { - return status.takeError(); - } - - std::string address = llvm::join(listener->GetListeningConnectionURI(), ", "); - DAP_LOG(log, "started with connection listeners {0}", address); - - llvm::outs() << "Listening for: " << address << "\n"; - // Ensure listening address are flushed for calles to retrieve the resolve - // address. - llvm::outs().flush(); - - static MainLoop g_loop; - llvm::sys::SetInterruptFunction([]() { - g_loop.AddPendingCallback( - [](MainLoopBase &loop) { loop.RequestTermination(); }); - }); - std::condition_variable dap_sessions_condition; - std::mutex dap_sessions_mutex; - std::map dap_sessions; - unsigned int clientCount = 0; - auto handle = listener->Accept(g_loop, [=, &dap_sessions_condition, - &dap_sessions_mutex, &dap_sessions, - &clientCount]( - std::unique_ptr sock) { - std::string client_name = llvm::formatv("client_{0}", clientCount++).str(); - DAP_LOG(log, "({0}) client connected", client_name); - - lldb::IOObjectSP io(std::move(sock)); - - // Move the client into a background thread to unblock accepting the next - // client. - std::thread client([=, &dap_sessions_condition, &dap_sessions_mutex, - &dap_sessions]() { - llvm::set_thread_name(client_name + ".runloop"); - Transport transport(client_name, log, io, io); - DAP dap(log, default_repl_mode, pre_init_commands, transport); - - if (auto Err = dap.ConfigureIO()) { - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), - "Failed to configure stdout redirect: "); - return; - } - - { - std::scoped_lock lock(dap_sessions_mutex); - dap_sessions[io.get()] = &dap; - } - - if (auto Err = dap.Loop()) { - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), - "DAP session (" + client_name + - ") error: "); - } - - DAP_LOG(log, "({0}) client disconnected", client_name); - std::unique_lock lock(dap_sessions_mutex); - dap_sessions.erase(io.get()); - std::notify_all_at_thread_exit(dap_sessions_condition, std::move(lock)); - }); - client.detach(); - }); - - if (auto Err = handle.takeError()) { - return Err; - } - - status = g_loop.Run(); - if (status.Fail()) { - return status.takeError(); - } - - DAP_LOG( - log, - "lldb-dap server shutdown requested, disconnecting remaining clients..."); - - bool client_failed = false; - { - std::scoped_lock lock(dap_sessions_mutex); - for (auto [sock, dap] : dap_sessions) { - if (llvm::Error error = dap->Disconnect()) { - client_failed = true; - llvm::errs() << "DAP client " << dap->transport.GetClientName() - << " disconnected failed: " - << llvm::toString(std::move(error)) << "\n"; - } - // Close the socket to ensure the DAP::Loop read finishes. - sock->Close(); - } - } - - // Wait for all clients to finish disconnecting. - std::unique_lock lock(dap_sessions_mutex); - dap_sessions_condition.wait(lock, [&] { return dap_sessions.empty(); }); - - if (client_failed) - return llvm::make_error( - "disconnecting all clients failed", llvm::inconvertibleErrorCode()); - - return llvm::Error::success(); -} - -int main(int argc, char *argv[]) { - llvm::InitLLVM IL(argc, argv, /*InstallPipeSignalExitHandler=*/false); -#if !defined(__APPLE__) - llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL - " and include the crash backtrace.\n"); -#else - llvm::setBugReportMsg("PLEASE submit a bug report to " LLDB_BUG_REPORT_URL - " and include the crash report from " - "~/Library/Logs/DiagnosticReports/.\n"); -#endif - - llvm::SmallString<256> program_path(argv[0]); - llvm::sys::fs::make_absolute(program_path); - DAP::debug_adapter_path = program_path; - - LLDBDAPOptTable T; - unsigned MAI, MAC; - llvm::ArrayRef ArgsArr = llvm::ArrayRef(argv + 1, argc); - llvm::opt::InputArgList input_args = T.ParseArgs(ArgsArr, MAI, MAC); - - if (input_args.hasArg(OPT_help)) { - PrintHelp(T, llvm::sys::path::filename(argv[0])); - return EXIT_SUCCESS; - } - - if (input_args.hasArg(OPT_version)) { - PrintVersion(); - return EXIT_SUCCESS; - } - - ReplMode default_repl_mode = ReplMode::Auto; - if (input_args.hasArg(OPT_repl_mode)) { - llvm::opt::Arg *repl_mode = input_args.getLastArg(OPT_repl_mode); - llvm::StringRef repl_mode_value = repl_mode->getValue(); - if (repl_mode_value == "auto") { - default_repl_mode = ReplMode::Auto; - } else if (repl_mode_value == "variable") { - default_repl_mode = ReplMode::Variable; - } else if (repl_mode_value == "command") { - default_repl_mode = ReplMode::Command; - } else { - llvm::errs() << "'" << repl_mode_value - << "' is not a valid option, use 'variable', 'command' or " - "'auto'.\n"; - return EXIT_FAILURE; - } - } - - if (llvm::opt::Arg *target_arg = input_args.getLastArg(OPT_launch_target)) { - if (llvm::opt::Arg *comm_file = input_args.getLastArg(OPT_comm_file)) { - lldb::pid_t pid = LLDB_INVALID_PROCESS_ID; - llvm::opt::Arg *debugger_pid = input_args.getLastArg(OPT_debugger_pid); - if (debugger_pid) { - llvm::StringRef debugger_pid_value = debugger_pid->getValue(); - if (debugger_pid_value.getAsInteger(10, pid)) { - llvm::errs() << "'" << debugger_pid_value - << "' is not a valid " - "PID\n"; - return EXIT_FAILURE; - } - } - int target_args_pos = argc; - for (int i = 0; i < argc; i++) { - if (strcmp(argv[i], "--launch-target") == 0) { - target_args_pos = i + 1; - break; - } - } - if (llvm::Error err = - LaunchRunInTerminalTarget(*target_arg, comm_file->getValue(), pid, - argv + target_args_pos)) { - llvm::errs() << llvm::toString(std::move(err)) << '\n'; - return EXIT_FAILURE; - } - } else { - llvm::errs() << "\"--launch-target\" requires \"--comm-file\" to be " - "specified\n"; - return EXIT_FAILURE; - } - } - - std::string connection; - if (auto *arg = input_args.getLastArg(OPT_connection)) { - const auto *path = arg->getValue(); - connection.assign(path); - } - -#if !defined(_WIN32) - if (input_args.hasArg(OPT_wait_for_debugger)) { - printf("Paused waiting for debugger to attach (pid = %i)...\n", getpid()); - pause(); - } -#endif - - std::unique_ptr log = nullptr; - const char *log_file_path = getenv("LLDBDAP_LOG"); - if (log_file_path) { - std::error_code EC; - log = std::make_unique(log_file_path, EC); - if (EC) { - llvm::logAllUnhandledErrors(llvm::errorCodeToError(EC), llvm::errs(), - "Failed to create log file: "); - return EXIT_FAILURE; - } - } - - // Initialize LLDB first before we do anything. - lldb::SBError error = lldb::SBDebugger::InitializeWithErrorHandling(); - if (error.Fail()) { - lldb::SBStream os; - error.GetDescription(os); - llvm::errs() << "lldb initialize failed: " << os.GetData() << "\n"; - return EXIT_FAILURE; - } - - // Create a memory monitor. This can return nullptr if the host platform is - // not supported. - std::unique_ptr memory_monitor = - lldb_private::MemoryMonitor::Create([log = log.get()]() { - DAP_LOG(log, "memory pressure detected"); - lldb::SBDebugger::MemoryPressureDetected(); - }); - - if (memory_monitor) - memory_monitor->Start(); - - // Terminate the debugger before the C++ destructor chain kicks in. - auto terminate_debugger = llvm::make_scope_exit([&] { - if (memory_monitor) - memory_monitor->Stop(); - lldb::SBDebugger::Terminate(); - }); - - std::vector pre_init_commands; - for (const std::string &arg : - input_args.getAllArgValues(OPT_pre_init_command)) { - pre_init_commands.push_back(arg); - } - - if (!connection.empty()) { - auto maybeProtoclAndName = validateConnection(connection); - if (auto Err = maybeProtoclAndName.takeError()) { - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), - "Invalid connection: "); - return EXIT_FAILURE; - } - - Socket::SocketProtocol protocol; - std::string name; - std::tie(protocol, name) = *maybeProtoclAndName; - if (auto Err = serveConnection(protocol, name, log.get(), default_repl_mode, - pre_init_commands)) { - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), - "Connection failed: "); - return EXIT_FAILURE; - } - - return EXIT_SUCCESS; - } - -#if defined(_WIN32) - // Windows opens stdout and stdin in text mode which converts \n to 13,10 - // while the value is just 10 on Darwin/Linux. Setting the file mode to - // binary fixes this. - int result = _setmode(fileno(stdout), _O_BINARY); - assert(result); - result = _setmode(fileno(stdin), _O_BINARY); - UNUSED_IF_ASSERT_DISABLED(result); - assert(result); -#endif - - int stdout_fd = DuplicateFileDescriptor(fileno(stdout)); - if (stdout_fd == -1) { - llvm::logAllUnhandledErrors( - llvm::errorCodeToError(llvm::errnoAsErrorCode()), llvm::errs(), - "Failed to configure stdout redirect: "); - return EXIT_FAILURE; - } - - lldb::IOObjectSP input = std::make_shared( - fileno(stdin), File::eOpenOptionReadOnly, NativeFile::Unowned); - lldb::IOObjectSP output = std::make_shared( - stdout_fd, File::eOpenOptionWriteOnly, NativeFile::Unowned); - - constexpr llvm::StringLiteral client_name = "stdio"; - Transport transport(client_name, log.get(), input, output); - DAP dap(log.get(), default_repl_mode, pre_init_commands, transport); - - // stdout/stderr redirection to the IDE's console - if (auto Err = dap.ConfigureIO(stdout, stderr)) { - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), - "Failed to configure stdout redirect: "); - return EXIT_FAILURE; - } - - // used only by TestVSCode_redirection_to_console.py - if (getenv("LLDB_DAP_TEST_STDOUT_STDERR_REDIRECTION") != nullptr) - redirection_test(); - - if (auto Err = dap.Loop()) { - DAP_LOG(log.get(), "({0}) DAP session error: {1}", client_name, - llvm::toStringWithoutConsuming(Err)); - llvm::logAllUnhandledErrors(std::move(Err), llvm::errs(), - "DAP session error: "); - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} diff --git a/lldb/tools/lldb-dap/tsconfig.json b/lldb/tools/lldb-dap/tsconfig.json deleted file mode 100644 index 209214888890..000000000000 --- a/lldb/tools/lldb-dap/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "outDir": "out", - "rootDir": "src-ts", - "sourceMap": true, - "strict": true, - "target": "es6" - }, - "include": [ - "src-ts" - ], - "exclude": [ - "node_modules", - ] -} diff --git a/mlir/utils/vscode/.gitignore b/mlir/utils/vscode/.gitignore deleted file mode 100644 index 9354f9119287..000000000000 --- a/mlir/utils/vscode/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -out -node_modules -.vscode-test -*.vsix -grammar.json -tablegen-grammar.json - -!.vscode \ No newline at end of file diff --git a/mlir/utils/vscode/.vscode/launch.json b/mlir/utils/vscode/.vscode/launch.json deleted file mode 100644 index dfe1753e6a66..000000000000 --- a/mlir/utils/vscode/.vscode/launch.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "type": "extensionHost", - "request": "launch", - "name": "Run Extension", - "runtimeExecutable": "${execPath}", - "args": [ - "--extensionDevelopmentPath=${workspaceRoot}" - ], - "outFiles": [ - "${workspaceRoot}/out/**/*.js" - ], - "preLaunchTask": { - "type": "npm", - "script": "watch" - } - } - ] -} \ No newline at end of file diff --git a/mlir/utils/vscode/.vscode/tasks.json b/mlir/utils/vscode/.vscode/tasks.json deleted file mode 100644 index 5efd8048880a..000000000000 --- a/mlir/utils/vscode/.vscode/tasks.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "version": "2.0.0", - "tasks": [ - { - "type": "npm", - "script": "compile", - "group": "build", - "presentation": { - "panel": "dedicated", - "reveal": "never" - }, - "problemMatcher": [ - "$tsc" - ] - }, - { - "type": "npm", - "script": "watch", - "isBackground": true, - "group": { - "kind": "build", - "isDefault": true - }, - "presentation": { - "panel": "dedicated", - "reveal": "never" - }, - "problemMatcher": [ - "$tsc-watch" - ] - } - ] -} \ No newline at end of file diff --git a/mlir/utils/vscode/.vscodeignore b/mlir/utils/vscode/.vscodeignore deleted file mode 100644 index f369b5e55b68..000000000000 --- a/mlir/utils/vscode/.vscodeignore +++ /dev/null @@ -1,4 +0,0 @@ -.vscode/** -.vscode-test/** -.gitignore -vsc-extension-quickstart.md diff --git a/mlir/utils/vscode/cpp-grammar.json b/mlir/utils/vscode/cpp-grammar.json deleted file mode 100644 index 36063c6a5210..000000000000 --- a/mlir/utils/vscode/cpp-grammar.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "scopeName": "source.cpp.mlir", - "injectionSelector": "L:source.cpp -string.quoted.double.cpp -string.quoted.double.raw", - "patterns": [ - { - "include": "#mlir-raw-string" - } - ], - "repository": { - "mlir-raw-string": { - "begin": "R\"(?i:mlir)(\\()", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.cpp" - }, - "1": { - "name": "mlir.delimeter.raw.string.cpp" - } - }, - "end": "\\)(?i:mlir)\"", - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.cpp" - }, - "1": { - "name": "mlir.delimeter.raw.string.cpp" - } - }, - "name": "mlir.raw.string.cpp", - "patterns": [ - { - "contentName": "source.mlir", - "begin": "(?!\\G)", - "end": "(?i)(?=\\)mlir\")", - "patterns": [ - { - "include": "source.mlir" - } - ] - } - ] - } - } -} diff --git a/mlir/utils/vscode/language-configuration.json b/mlir/utils/vscode/language-configuration.json deleted file mode 100644 index 8a34cc83a53c..000000000000 --- a/mlir/utils/vscode/language-configuration.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "comments": { - "lineComment": "//" - }, - "brackets": [ - ["{", "}"], - ["[", "]"], - ["(", ")"] - ], - "autoClosingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"", "\""] - ], - "surroundingPairs": [ - ["{", "}"], - ["[", "]"], - ["(", ")"], - ["\"", "\""] - ] -} diff --git a/mlir/utils/vscode/markdown-grammar.json b/mlir/utils/vscode/markdown-grammar.json deleted file mode 100644 index 2a285a0705bc..000000000000 --- a/mlir/utils/vscode/markdown-grammar.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "fileTypes": [], - "injectionSelector": "L:text.html.markdown", - "patterns": [ - { - "include": "#mlir-code-block" - }, - { - "include": "#pdll-code-block" - }, - { - "include": "#tablegen-code-block" - } - ], - "repository": { - "mlir-code-block": { - "begin": "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(mlir)(\\s+[^`~]*)?$)", - "name": "markup.fenced_code.block.markdown", - "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", - "beginCaptures": { - "3": { - "name": "punctuation.definition.markdown" - }, - "4": { - "name": "fenced_code.block.language.markdown" - }, - "5": { - "name": "fenced_code.block.language.attributes.markdown" - } - }, - "endCaptures": { - "3": { - "name": "punctuation.definition.markdown" - } - }, - "patterns": [ - { - "begin": "(^|\\G)(\\s*)(.*)", - "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", - "contentName": "meta.embedded.block.mlir", - "patterns": [ - { - "include": "source.mlir" - } - ] - } - ] - }, - "pdll-code-block": { - "begin": "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(pdll)(\\s+[^`~]*)?$)", - "name": "markup.fenced_code.block.markdown", - "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", - "beginCaptures": { - "3": { - "name": "punctuation.definition.markdown" - }, - "4": { - "name": "fenced_code.block.language.markdown" - }, - "5": { - "name": "fenced_code.block.language.attributes.markdown" - } - }, - "endCaptures": { - "3": { - "name": "punctuation.definition.markdown" - } - }, - "patterns": [ - { - "begin": "(^|\\G)(\\s*)(.*)", - "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", - "contentName": "meta.embedded.block.pdll", - "patterns": [ - { - "include": "source.pdll" - } - ] - } - ] - }, - "tablegen-code-block": { - "begin": "(^|\\G)(\\s*)(\\`{3,}|~{3,})\\s*(?i:(tablegen)(\\s+[^`~]*)?$)", - "name": "markup.fenced_code.block.markdown", - "end": "(^|\\G)(\\2|\\s{0,3})(\\3)\\s*$", - "beginCaptures": { - "3": { - "name": "punctuation.definition.markdown" - }, - "4": { - "name": "fenced_code.block.language.markdown" - }, - "5": { - "name": "fenced_code.block.language.attributes.markdown" - } - }, - "endCaptures": { - "3": { - "name": "punctuation.definition.markdown" - } - }, - "patterns": [ - { - "begin": "(^|\\G)(\\s*)(.*)", - "while": "(^|\\G)(?!\\s*([`~]{3,})\\s*$)", - "contentName": "meta.embedded.block.tablegen", - "patterns": [ - { - "include": "source.tablegen" - } - ] - } - ] - } - }, - "scopeName": "markdown.mlir.codeblock" -} \ No newline at end of file diff --git a/mlir/utils/vscode/package-lock.json b/mlir/utils/vscode/package-lock.json deleted file mode 100644 index e7e717862161..000000000000 --- a/mlir/utils/vscode/package-lock.json +++ /dev/null @@ -1,3559 +0,0 @@ -{ - "name": "vscode-mlir", - "version": "0.0.12", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "vscode-mlir", - "version": "0.0.12", - "dependencies": { - "base64-js": "^1.5.1", - "chokidar": "3.5.2", - "vscode-languageclient": "^8.0.2-next.5" - }, - "devDependencies": { - "@types/mocha": "^7.0.2", - "@types/node": "^14.17.0", - "@types/vscode": "~1.67.0", - "@vscode/vsce": "^2.19.0", - "clang-format": "^1.8.0", - "typescript": "^4.9.5", - "vscode-test": "^1.3.0" - }, - "engines": { - "vscode": "^1.67.0" - } - }, - "node_modules/@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@types/mocha": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", - "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", - "dev": true - }, - "node_modules/@types/node": { - "version": "14.18.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz", - "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==", - "dev": true - }, - "node_modules/@types/vscode": { - "version": "1.67.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.67.0.tgz", - "integrity": "sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==", - "dev": true - }, - "node_modules/@vscode/vsce": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", - "integrity": "sha512-dAlILxC5ggOutcvJY24jxz913wimGiUrHaPkk16Gm9/PGFbz1YezWtrXsTKUtJws4fIlpX2UIlVlVESWq8lkfQ==", - "dev": true, - "dependencies": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "jsonc-parser": "^3.2.0", - "leven": "^3.1.0", - "markdown-it": "^12.3.2", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.5.0", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "bin": { - "vsce": "vsce" - }, - "engines": { - "node": ">= 14" - }, - "optionalDependencies": { - "keytar": "^7.7.0" - } - }, - "node_modules/@vscode/vsce/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/@vscode/vsce/node_modules/xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "dependencies": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true, - "optional": true - }, - "node_modules/are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "node_modules/async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "node_modules/azure-devops-node-api": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.0.1.tgz", - "integrity": "sha512-YMdjAw9l5p/6leiyIloxj3k7VIvYThKjvqgiQn88r3nhT93ENwsoDS3A83CyJ4uTWzCZ5f5jCi6c27rTU5Pz+A==", - "dev": true, - "dependencies": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/big-integer": { - "version": "1.6.48", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", - "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", - "dev": true, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", - "dev": true, - "dependencies": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - }, - "engines": { - "node": "*" - } - }, - "node_modules/binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "optional": true, - "dependencies": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/bl/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", - "dev": true - }, - "node_modules/boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "node_modules/buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true, - "engines": { - "node": ">=0.2.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "dependencies": { - "traverse": ">=0.3.0 <0.4" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "dependencies": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/cheeriojs/cheerio?sponsor=1" - } - }, - "node_modules/cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "dependencies": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/cheerio/node_modules/tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "dev": true - }, - "node_modules/chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "optional": true - }, - "node_modules/clang-format": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.8.0.tgz", - "integrity": "sha512-pK8gzfu55/lHzIpQ1givIbWfn3eXnU7SfxqIwVgnn5jEM6j4ZJYjpFqFs4iSBPNedzRMmfjYjuQhu657WAXHXw==", - "dev": true, - "dependencies": { - "async": "^3.2.3", - "glob": "^7.0.0", - "resolve": "^1.1.6" - }, - "bin": { - "check-clang-format": "bin/check-clang-format.js", - "clang-format": "index.js", - "git-clang-format": "bin/git-clang-format" - } - }, - "node_modules/code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true, - "engines": { - "node": ">= 6" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true - }, - "node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "node_modules/css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/css-what": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", - "dev": true, - "engines": { - "node": ">= 6" - }, - "funding": { - "url": "https://github.com/sponsors/fb55" - } - }, - "node_modules/debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "optional": true, - "dependencies": { - "mimic-response": "^3.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "optional": true, - "engines": { - "node": ">=4.0.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true, - "optional": true - }, - "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "dev": true, - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ] - }, - "node_modules/domhandler": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", - "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", - "dev": true, - "dependencies": { - "domelementtype": "^2.2.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", - "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", - "dev": true, - "dependencies": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "dependencies": { - "readable-stream": "^2.0.2" - } - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "optional": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "optional": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "dependencies": { - "pend": "~1.2.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "hasInstallScript": true, - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "engines": { - "node": ">=0.6" - } - }, - "node_modules/fstream/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "optional": true, - "dependencies": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true, - "optional": true - }, - "node_modules/glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true, - "optional": true - }, - "node_modules/hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "dependencies": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "node_modules/http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "dependencies": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "optional": true - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "optional": true, - "dependencies": { - "number-is-nan": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "node_modules/keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "dev": true, - "hasInstallScript": true, - "optional": true, - "dependencies": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "node_modules/leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", - "dev": true - }, - "node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, - "node_modules/markdown-it/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/markdown-it/node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "optional": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "optional": true - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true, - "optional": true - }, - "node_modules/node-abi": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.15.0.tgz", - "integrity": "sha512-Ic6z/j6I9RLm4ov7npo1I48UQr2BEyFCqh6p7S1dhEx9jPO0GPGq/e2Rb7x7DroQrmiVMz/Bw1vJm9sPAl2nxA==", - "dev": true, - "optional": true, - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-abi/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "optional": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true, - "optional": true - }, - "node_modules/normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "optional": true, - "dependencies": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "node_modules/nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "dependencies": { - "boolbase": "^1.0.0" - }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" - } - }, - "node_modules/number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", - "dev": true, - "dependencies": { - "semver": "^7.5.3" - } - }, - "node_modules/parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "node_modules/parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "dependencies": { - "parse5": "^6.0.1" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "node_modules/picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/prebuild-install": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.0.tgz", - "integrity": "sha512-CNcMgI1xBypOyGqjp3wOc8AAo1nMhZS3Cwd3iHIxOdAUbb+YxdNuM4Z5iIrZ8RLvOsf3F3bl7b7xGq6DjQoNYA==", - "dev": true, - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - }, - "bin": { - "prebuild-install": "bin.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "optional": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "dependencies": { - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">=0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "optional": true, - "dependencies": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "bin": { - "rc": "cli.js" - } - }, - "node_modules/read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "dependencies": { - "mute-stream": "~0.0.4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } - }, - "node_modules/resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true, - "optional": true - }, - "node_modules/setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "optional": true - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true - }, - "node_modules/simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "optional": true, - "dependencies": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "optional": true, - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "optional": true, - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "optional": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dev": true, - "optional": true, - "dependencies": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "optional": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "dev": true, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true, - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, - "node_modules/tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "optional": true, - "dependencies": { - "safe-buffer": "^5.0.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/typed-rest-client": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.4.tgz", - "integrity": "sha512-MyfKKYzk3I6/QQp6e1T50py4qg+c+9BzOEl2rBmQIpStwNUoqQ73An+Tkfy9YuV7O+o2mpVVJpe+fH//POZkbg==", - "dev": true, - "dependencies": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "node_modules/underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", - "dev": true - }, - "node_modules/unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "dependencies": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "node_modules/url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/vscode-jsonrpc": { - "version": "8.0.2-next.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz", - "integrity": "sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA==", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/vscode-languageclient": { - "version": "8.0.2-next.5", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.2-next.5.tgz", - "integrity": "sha512-g87RJLHz0XlRyk6DOTbAk4JHcj8CKggXy4JiFL7OlhETkcYzTOR8d+Qdb4GqZr37PDs1Cl21omtTNK5LyR/RQg==", - "dependencies": { - "minimatch": "^3.0.4", - "semver": "^7.5.3", - "vscode-languageserver-protocol": "3.17.2-next.6" - }, - "engines": { - "vscode": "^1.67.0" - } - }, - "node_modules/vscode-languageclient/node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.17.2-next.6", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.6.tgz", - "integrity": "sha512-WtsebNOOkWyNn4oFYoAMPC8Q/ZDoJ/K7Ja53OzTixiitvrl/RpXZETrtzH79R8P5kqCyx6VFBPb6KQILJfkDkA==", - "dependencies": { - "vscode-jsonrpc": "8.0.2-next.1", - "vscode-languageserver-types": "3.17.2-next.2" - } - }, - "node_modules/vscode-languageserver-types": { - "version": "3.17.2-next.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz", - "integrity": "sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w==" - }, - "node_modules/vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "deprecated": "This package has been renamed to @vscode/test-electron, please update to the new name", - "dev": true, - "dependencies": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - }, - "engines": { - "node": ">=8.9.3" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "optional": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "node_modules/yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "node_modules/yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "dependencies": { - "buffer-crc32": "~0.2.3" - } - } - }, - "dependencies": { - "@tootallnate/once": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", - "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true - }, - "@types/mocha": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-7.0.2.tgz", - "integrity": "sha512-ZvO2tAcjmMi8V/5Z3JsyofMe3hasRcaw88cto5etSVMwVQfeivGAlEYmaQgceUSVYFofVjT+ioHsATjdWcFt1w==", - "dev": true - }, - "@types/node": { - "version": "14.18.18", - "resolved": "https://registry.npmjs.org/@types/node/-/node-14.18.18.tgz", - "integrity": "sha512-B9EoJFjhqcQ9OmQrNorItO+OwEOORNn3S31WuiHvZY/dm9ajkB7AKD/8toessEtHHNL+58jofbq7hMMY9v4yig==", - "dev": true - }, - "@types/vscode": { - "version": "1.67.0", - "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.67.0.tgz", - "integrity": "sha512-GH8BDf8cw9AC9080uneJfulhSa7KHSMI2s/CyKePXoGNos9J486w2V4YKoeNUqIEkW4hKoEAWp6/cXTwyGj47g==", - "dev": true - }, - "@vscode/vsce": { - "version": "2.19.0", - "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-2.19.0.tgz", - "integrity": "sha512-dAlILxC5ggOutcvJY24jxz913wimGiUrHaPkk16Gm9/PGFbz1YezWtrXsTKUtJws4fIlpX2UIlVlVESWq8lkfQ==", - "dev": true, - "requires": { - "azure-devops-node-api": "^11.0.1", - "chalk": "^2.4.2", - "cheerio": "^1.0.0-rc.9", - "commander": "^6.1.0", - "glob": "^7.0.6", - "hosted-git-info": "^4.0.2", - "jsonc-parser": "^3.2.0", - "keytar": "^7.7.0", - "leven": "^3.1.0", - "markdown-it": "^12.3.2", - "mime": "^1.3.4", - "minimatch": "^3.0.3", - "parse-semver": "^1.1.1", - "read": "^1.0.7", - "semver": "^5.1.0", - "tmp": "^0.2.1", - "typed-rest-client": "^1.8.4", - "url-join": "^4.0.1", - "xml2js": "^0.5.0", - "yauzl": "^2.3.1", - "yazl": "^2.2.2" - }, - "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - }, - "xml2js": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", - "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", - "dev": true, - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - } - } - } - }, - "agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dev": true, - "requires": { - "debug": "4" - } - }, - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "optional": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "anymatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", - "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", - "requires": { - "normalize-path": "^3.0.0", - "picomatch": "^2.0.4" - } - }, - "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.7.tgz", - "integrity": "sha512-nxwy40TuMiUGqMyRHgCSWZ9FM4VAoRP4xUYSTv5ImRog+h9yISPbVH7H8fASCIzYn9wlEv4zvFL7uKDMCFQm3g==", - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "async": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", - "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==", - "dev": true - }, - "azure-devops-node-api": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-11.0.1.tgz", - "integrity": "sha512-YMdjAw9l5p/6leiyIloxj3k7VIvYThKjvqgiQn88r3nhT93ENwsoDS3A83CyJ4uTWzCZ5f5jCi6c27rTU5Pz+A==", - "dev": true, - "requires": { - "tunnel": "0.0.6", - "typed-rest-client": "^1.8.4" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" - }, - "big-integer": { - "version": "1.6.48", - "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.48.tgz", - "integrity": "sha512-j51egjPa7/i+RdiRuJbPdJ2FIUYYPhvYLjzoYbcMMm62ooO6F94fETG4MTs46zPAF9Brs04OajboA/qTGuz78w==", - "dev": true - }, - "binary": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", - "integrity": "sha1-n2BVO8XOjDOG87VTz/R0Yq3sqnk=", - "dev": true, - "requires": { - "buffers": "~0.1.1", - "chainsaw": "~0.1.0" - } - }, - "binary-extensions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", - "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==" - }, - "bl": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", - "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", - "dev": true, - "optional": true, - "requires": { - "buffer": "^5.5.0", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "optional": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "bluebird": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz", - "integrity": "sha1-9y12C+Cbf3bQjtj66Ysomo0F+rM=", - "dev": true - }, - "boolbase": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", - "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=", - "dev": true - }, - "brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "requires": { - "fill-range": "^7.1.1" - } - }, - "buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "dev": true, - "optional": true, - "requires": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" - } - }, - "buffer-crc32": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", - "integrity": "sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=", - "dev": true - }, - "buffer-indexof-polyfill": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/buffer-indexof-polyfill/-/buffer-indexof-polyfill-1.0.2.tgz", - "integrity": "sha512-I7wzHwA3t1/lwXQh+A5PbNvJxgfo5r3xulgpYDB5zckTu/Z9oUK9biouBKQUjEqzaz3HnAT6TYoovmE+GqSf7A==", - "dev": true - }, - "buffers": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz", - "integrity": "sha1-skV5w77U1tOWru5tmorn9Ugqt7s=", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "chainsaw": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", - "integrity": "sha1-XqtQsor+WAdNDVgpE4iCi15fvJg=", - "dev": true, - "requires": { - "traverse": ">=0.3.0 <0.4" - } - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "cheerio": { - "version": "1.0.0-rc.10", - "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.0.0-rc.10.tgz", - "integrity": "sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw==", - "dev": true, - "requires": { - "cheerio-select": "^1.5.0", - "dom-serializer": "^1.3.2", - "domhandler": "^4.2.0", - "htmlparser2": "^6.1.0", - "parse5": "^6.0.1", - "parse5-htmlparser2-tree-adapter": "^6.0.1", - "tslib": "^2.2.0" - }, - "dependencies": { - "tslib": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", - "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==", - "dev": true - } - } - }, - "cheerio-select": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-1.5.0.tgz", - "integrity": "sha512-qocaHPv5ypefh6YNxvnbABM07KMxExbtbfuJoIie3iZXX1ERwYmJcIiRrr9H05ucQP1k28dav8rpdDgjQd8drg==", - "dev": true, - "requires": { - "css-select": "^4.1.3", - "css-what": "^5.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0", - "domutils": "^2.7.0" - } - }, - "chokidar": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", - "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", - "requires": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "fsevents": "~2.3.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - } - }, - "chownr": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", - "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", - "dev": true, - "optional": true - }, - "clang-format": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/clang-format/-/clang-format-1.8.0.tgz", - "integrity": "sha512-pK8gzfu55/lHzIpQ1givIbWfn3eXnU7SfxqIwVgnn5jEM6j4ZJYjpFqFs4iSBPNedzRMmfjYjuQhu657WAXHXw==", - "dev": true, - "requires": { - "async": "^3.2.3", - "glob": "^7.0.0", - "resolve": "^1.1.6" - } - }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true, - "optional": true - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "css-select": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz", - "integrity": "sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA==", - "dev": true, - "requires": { - "boolbase": "^1.0.0", - "css-what": "^5.0.0", - "domhandler": "^4.2.0", - "domutils": "^2.6.0", - "nth-check": "^2.0.0" - } - }, - "css-what": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz", - "integrity": "sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg==", - "dev": true - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "decompress-response": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", - "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", - "dev": true, - "optional": true, - "requires": { - "mimic-response": "^3.1.0" - } - }, - "deep-extend": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", - "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", - "dev": true, - "optional": true - }, - "dom-serializer": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz", - "integrity": "sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.2.0", - "entities": "^2.0.0" - } - }, - "domelementtype": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz", - "integrity": "sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A==", - "dev": true - }, - "domhandler": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-4.2.0.tgz", - "integrity": "sha512-zk7sgt970kzPks2Bf+dwT/PLzghLnsivb9CcxkvR8Mzr66Olr0Ofd8neSbglHJHaHa2MadfoSdNlKYAaafmWfA==", - "dev": true, - "requires": { - "domelementtype": "^2.2.0" - } - }, - "domutils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-2.7.0.tgz", - "integrity": "sha512-8eaHa17IwJUPAiB+SoTYBo5mCdeMgdcAoXJ59m6DT1vw+5iLS3gNoqYaRowaBKtGVrOF1Jz4yDTgYKLK2kvfJg==", - "dev": true, - "requires": { - "dom-serializer": "^1.0.1", - "domelementtype": "^2.2.0", - "domhandler": "^4.2.0" - } - }, - "duplexer2": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", - "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", - "dev": true, - "requires": { - "readable-stream": "^2.0.2" - } - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "optional": true, - "requires": { - "once": "^1.4.0" - } - }, - "entities": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", - "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "expand-template": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", - "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", - "dev": true, - "optional": true - }, - "fd-slicer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", - "integrity": "sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=", - "dev": true, - "requires": { - "pend": "~1.2.0" - } - }, - "fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "requires": { - "to-regex-range": "^5.0.1" - } - }, - "fs-constants": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true, - "optional": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "optional": true - }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - }, - "dependencies": { - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "github-from-package": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", - "integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4=", - "dev": true, - "optional": true - }, - "glob": { - "version": "7.1.7", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", - "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "requires": { - "is-glob": "^4.0.1" - } - }, - "graceful-fs": { - "version": "4.2.6", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.6.tgz", - "integrity": "sha512-nTnJ528pbqxYanhpDYsi4Rd8MAeaBA67+RZ10CM1m3bTAVFEDcd5AuA4a6W5YkGZ1iNXHzZz8T6TBKLeBuNriQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", - "dev": true, - "optional": true - }, - "hosted-git-info": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", - "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "htmlparser2": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-6.1.0.tgz", - "integrity": "sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==", - "dev": true, - "requires": { - "domelementtype": "^2.0.1", - "domhandler": "^4.0.0", - "domutils": "^2.5.2", - "entities": "^2.0.0" - } - }, - "http-proxy-agent": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", - "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, - "requires": { - "@tootallnate/once": "1", - "agent-base": "6", - "debug": "4" - } - }, - "https-proxy-agent": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz", - "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==", - "dev": true, - "requires": { - "agent-base": "6", - "debug": "4" - } - }, - "ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "dev": true, - "optional": true - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "optional": true - }, - "is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "requires": { - "binary-extensions": "^2.0.0" - } - }, - "is-core-module": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz", - "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "is-glob": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz", - "integrity": "sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==", - "requires": { - "is-extglob": "^2.1.1" - } - }, - "is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true - }, - "keytar": { - "version": "7.9.0", - "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", - "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", - "dev": true, - "optional": true, - "requires": { - "node-addon-api": "^4.3.0", - "prebuild-install": "^7.0.1" - } - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "requires": { - "uc.micro": "^1.0.1" - } - }, - "listenercount": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/listenercount/-/listenercount-1.0.1.tgz", - "integrity": "sha1-hMinKrWcRyUyFIDJdeZQg0LnCTc=", - "dev": true - }, - "lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "requires": { - "yallist": "^4.0.0" - } - }, - "markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "requires": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "dependencies": { - "argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true - } - } - }, - "mdurl": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", - "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", - "dev": true - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mimic-response": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", - "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "mkdirp-classic": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", - "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", - "dev": true, - "optional": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "napi-build-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz", - "integrity": "sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==", - "dev": true, - "optional": true - }, - "node-abi": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.15.0.tgz", - "integrity": "sha512-Ic6z/j6I9RLm4ov7npo1I48UQr2BEyFCqh6p7S1dhEx9jPO0GPGq/e2Rb7x7DroQrmiVMz/Bw1vJm9sPAl2nxA==", - "dev": true, - "optional": true, - "requires": { - "semver": "^7.5.3" - }, - "dependencies": { - "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "optional": true, - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "node-addon-api": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", - "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", - "dev": true, - "optional": true - }, - "normalize-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", - "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" - }, - "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "nth-check": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz", - "integrity": "sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w==", - "dev": true, - "requires": { - "boolbase": "^1.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", - "dev": true, - "optional": true - }, - "object-inspect": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz", - "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg==", - "dev": true - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "parse-semver": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", - "integrity": "sha1-mkr9bfBj3Egm+T+6SpnPIj9mbLg=", - "dev": true, - "requires": { - "semver": "^7.5.3" - } - }, - "parse5": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz", - "integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==", - "dev": true - }, - "parse5-htmlparser2-tree-adapter": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz", - "integrity": "sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA==", - "dev": true, - "requires": { - "parse5": "^6.0.1" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "pend": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha1-elfrVQpng/kRUzH89GY9XI4AelA=", - "dev": true - }, - "picomatch": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", - "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==" - }, - "prebuild-install": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.0.tgz", - "integrity": "sha512-CNcMgI1xBypOyGqjp3wOc8AAo1nMhZS3Cwd3iHIxOdAUbb+YxdNuM4Z5iIrZ8RLvOsf3F3bl7b7xGq6DjQoNYA==", - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^2.0.0", - "expand-template": "^2.0.3", - "github-from-package": "0.0.0", - "minimist": "^1.2.3", - "mkdirp-classic": "^0.5.3", - "napi-build-utils": "^1.0.1", - "node-abi": "^3.3.0", - "npmlog": "^4.0.1", - "pump": "^3.0.0", - "rc": "^1.2.7", - "simple-get": "^4.0.0", - "tar-fs": "^2.0.0", - "tunnel-agent": "^0.6.0" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "optional": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "dev": true, - "requires": { - "side-channel": "^1.0.4" - } - }, - "rc": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", - "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - } - }, - "read": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", - "integrity": "sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ=", - "dev": true, - "requires": { - "mute-stream": "~0.0.4" - } - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "requires": { - "picomatch": "^2.2.1" - } - }, - "resolve": { - "version": "1.20.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz", - "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "dev": true, - "requires": { - "lru-cache": "^6.0.0" - } - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true, - "optional": true - }, - "setimmediate": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", - "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "dev": true, - "optional": true - }, - "simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "dev": true, - "optional": true - }, - "simple-get": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", - "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", - "dev": true, - "optional": true, - "requires": { - "decompress-response": "^6.0.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", - "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", - "dev": true, - "optional": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "tar-fs": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", - "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "mkdirp-classic": "^0.5.2", - "pump": "^3.0.0", - "tar-stream": "^2.1.4" - } - }, - "tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, - "optional": true, - "requires": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" - }, - "dependencies": { - "readable-stream": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", - "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", - "dev": true, - "optional": true, - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - } - } - }, - "tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", - "dev": true - }, - "to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "requires": { - "is-number": "^7.0.0" - } - }, - "traverse": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz", - "integrity": "sha1-cXuPIgzAu3tE5AUUwisui7xw2Lk=", - "dev": true - }, - "tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "dev": true - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "typed-rest-client": { - "version": "1.8.4", - "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.4.tgz", - "integrity": "sha512-MyfKKYzk3I6/QQp6e1T50py4qg+c+9BzOEl2rBmQIpStwNUoqQ73An+Tkfy9YuV7O+o2mpVVJpe+fH//POZkbg==", - "dev": true, - "requires": { - "qs": "^6.9.1", - "tunnel": "0.0.6", - "underscore": "^1.12.1" - } - }, - "typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "dev": true - }, - "uc.micro": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz", - "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA==", - "dev": true - }, - "underscore": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz", - "integrity": "sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g==", - "dev": true - }, - "unzipper": { - "version": "0.10.11", - "resolved": "https://registry.npmjs.org/unzipper/-/unzipper-0.10.11.tgz", - "integrity": "sha512-+BrAq2oFqWod5IESRjL3S8baohbevGcVA+teAIOYWM3pDVdseogqbzhhvvmiyQrUNKFUnDMtELW3X8ykbyDCJw==", - "dev": true, - "requires": { - "big-integer": "^1.6.17", - "binary": "~0.3.0", - "bluebird": "~3.4.1", - "buffer-indexof-polyfill": "~1.0.0", - "duplexer2": "~0.1.4", - "fstream": "^1.0.12", - "graceful-fs": "^4.2.2", - "listenercount": "~1.0.1", - "readable-stream": "~2.3.6", - "setimmediate": "~1.0.4" - } - }, - "url-join": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", - "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "vscode-jsonrpc": { - "version": "8.0.2-next.1", - "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-8.0.2-next.1.tgz", - "integrity": "sha512-sbbvGSWja7NVBLHPGawtgezc8DHYJaP4qfr/AaJiyDapWcSFtHyPtm18+LnYMLTmB7bhOUW/lf5PeeuLpP6bKA==" - }, - "vscode-languageclient": { - "version": "8.0.2-next.5", - "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-8.0.2-next.5.tgz", - "integrity": "sha512-g87RJLHz0XlRyk6DOTbAk4JHcj8CKggXy4JiFL7OlhETkcYzTOR8d+Qdb4GqZr37PDs1Cl21omtTNK5LyR/RQg==", - "requires": { - "minimatch": "^3.0.4", - "semver": "^7.5.3", - "vscode-languageserver-protocol": "3.17.2-next.6" - }, - "dependencies": { - "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", - "requires": { - "lru-cache": "^6.0.0" - } - } - } - }, - "vscode-languageserver-protocol": { - "version": "3.17.2-next.6", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.17.2-next.6.tgz", - "integrity": "sha512-WtsebNOOkWyNn4oFYoAMPC8Q/ZDoJ/K7Ja53OzTixiitvrl/RpXZETrtzH79R8P5kqCyx6VFBPb6KQILJfkDkA==", - "requires": { - "vscode-jsonrpc": "8.0.2-next.1", - "vscode-languageserver-types": "3.17.2-next.2" - } - }, - "vscode-languageserver-types": { - "version": "3.17.2-next.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.17.2-next.2.tgz", - "integrity": "sha512-TiAkLABgqkVWdAlC3XlOfdhdjIAdVU4YntPUm9kKGbXr+MGwpVnKz2KZMNBcvG0CFx8Hi8qliL0iq+ndPB720w==" - }, - "vscode-test": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.6.1.tgz", - "integrity": "sha512-086q88T2ca1k95mUzffvbzb7esqQNvJgiwY4h29ukPhFo8u+vXOOmelUoU5EQUHs3Of8+JuQ3oGdbVCqaxuTXA==", - "dev": true, - "requires": { - "http-proxy-agent": "^4.0.1", - "https-proxy-agent": "^5.0.0", - "rimraf": "^3.0.2", - "unzipper": "^0.10.11" - } - }, - "wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", - "dev": true - }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, - "yauzl": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", - "integrity": "sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3", - "fd-slicer": "~1.1.0" - } - }, - "yazl": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", - "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", - "dev": true, - "requires": { - "buffer-crc32": "~0.2.3" - } - } - } -} diff --git a/mlir/utils/vscode/package.json b/mlir/utils/vscode/package.json deleted file mode 100644 index 6d0f6f5c88ad..000000000000 --- a/mlir/utils/vscode/package.json +++ /dev/null @@ -1,230 +0,0 @@ -{ - "name": "vscode-mlir", - "displayName": "MLIR", - "description": "MLIR Language Extension", - "version": "0.0.12", - "publisher": "llvm-vs-code-extensions", - "homepage": "https://mlir.llvm.org/", - "icon": "icon.png", - "engines": { - "vscode": "^1.67.0" - }, - "categories": [ - "Programming Languages" - ], - "keywords": [ - "LLVM", - "MLIR", - "PDLL", - "TableGen", - "tblgen", - "tablegen" - ], - "activationEvents": [ - "onFileSystem:mlir.bytecode-mlir", - "onCustomEditor:mlir.bytecode", - "onLanguage:mlir", - "onLanguage:pdll", - "onLanguage:tablegen" - ], - "main": "./out/extension", - "scripts": { - "vscode:prepublish": "tsc -p ./", - "compile": "tsc -watch -p ./", - "format": "clang-format -i --glob=\"{src,test}/*.ts\"", - "package": "vsce package", - "publish": "vsce publish", - "git-clang-format": "git-clang-format" - }, - "dependencies": { - "base64-js": "^1.5.1", - "chokidar": "3.5.2", - "vscode-languageclient": "^8.0.2-next.5" - }, - "devDependencies": { - "@types/mocha": "^7.0.2", - "@types/node": "^14.17.0", - "@types/vscode": "~1.67.0", - "@vscode/vsce": "^2.19.0", - "clang-format": "^1.8.0", - "typescript": "^4.9.5", - "vscode-test": "^1.3.0" - }, - "repository": { - "type": "git", - "url": "https://github.com/llvm/vscode-mlir.git" - }, - "contributes": { - "customEditors": [ - { - "viewType": "mlir.bytecode", - "displayName": "MLIR Bytecode", - "priority": "default", - "selector": [ - { - "filenamePattern": "*.mlirbc" - } - ] - } - ], - "languages": [ - { - "id": "mlir", - "aliases": [ - "MLIR", - "mlir" - ], - "extensions": [ - ".mlir", - ".mlirbc" - ], - "configuration": "./language-configuration.json" - }, - { - "id": "mlir-injection" - }, - { - "id": "pdll", - "aliases": [ - "PDLL", - "pdll" - ], - "extensions": [ - ".pdll" - ], - "configuration": "./pdll-language-configuration.json" - }, - { - "id": "tablegen", - "aliases": [ - "TableGen", - "tblgen" - ], - "extensions": [ - ".td" - ], - "configuration": "./tablegen-language-configuration.json" - } - ], - "grammars": [ - { - "language": "mlir", - "scopeName": "source.mlir", - "path": "./grammar.json" - }, - { - "language": "mlir-injection", - "scopeName": "markdown.mlir.codeblock", - "path": "markdown-grammar.json", - "injectTo": [ - "text.html.markdown" - ], - "embeddedLanguages": { - "meta.embedded.block.mlir": "mlir", - "meta.embedded.block.pdll": "pdll", - "meta.embedded.block.tablegen": "tablegen" - } - }, - { - "scopeName": "source.cpp.mlir", - "path": "./cpp-grammar.json", - "injectTo": [ - "source.cpp" - ], - "embeddedLanguages": { - "source.mlir": "mlir" - } - }, - { - "language": "pdll", - "scopeName": "source.pdll", - "path": "./pdll-grammar.json" - }, - { - "language": "tablegen", - "scopeName": "source.tablegen", - "path": "./tablegen-grammar.json" - } - ], - "configuration": { - "type": "object", - "title": "MLIR", - "properties": { - "mlir.server_path": { - "scope": "resource", - "type": "string", - "description": "The file path of the mlir-lsp-server executable." - }, - "mlir.mlir_additional_server_args": { - "scope": "resource", - "type": "array", - "description": "A list of additional arguments for mlir-lsp-server executable. E.g. --log=verbose." - }, - "mlir.pdll_server_path": { - "scope": "resource", - "type": "string", - "description": "The file path of the mlir-pdll-lsp-server executable." - }, - "mlir.pdll_compilation_databases": { - "scope": "resource", - "type": "array", - "description": "A list of `pdll_compile_commands.yml` database files containing information about .pdll files processed by the server." - }, - "mlir.pdll_additional_server_args": { - "scope": "resource", - "type": "array", - "description": "A list of additional arguments for pdll-lsp-server executable. E.g. --log=verbose." - }, - "mlir.tablegen_server_path": { - "scope": "resource", - "type": "string", - "description": "The file path of the tblgen-lsp-server executable." - }, - "mlir.tablegen_compilation_databases": { - "scope": "resource", - "type": "array", - "description": "A list of `tablegen_compile_commands.yml` database files containing information about .td files processed by the server." - }, - "mlir.tablegen_additional_server_args": { - "scope": "resource", - "type": "array", - "description": "A list of additional arguments for tblgen-lsp-server executable. E.g. --log=verbose." - }, - "mlir.onSettingsChanged": { - "type": "string", - "default": "prompt", - "description": "Action taken when a setting change requires a server restart to take effect.", - "enum": [ - "prompt", - "restart", - "ignore" - ], - "enumDescriptions": [ - "Prompt the user for restarting the server", - "Automatically restart the server", - "Do nothing" - ] - } - } - }, - "commands": [ - { - "command": "mlir.restart", - "title": "mlir: Restart language server" - }, - { - "command": "mlir.viewPDLLOutput", - "title": "mlir-pdll: View PDLL output" - } - ], - "menus": { - "editor/context": [ - { - "command": "mlir.viewPDLLOutput", - "group": "z_commands", - "when": "editorLangId == pdll" - } - ] - } - } -} diff --git a/mlir/utils/vscode/pdll-grammar.json b/mlir/utils/vscode/pdll-grammar.json deleted file mode 100644 index 47c8968c3ac0..000000000000 --- a/mlir/utils/vscode/pdll-grammar.json +++ /dev/null @@ -1,524 +0,0 @@ -{ - "name": "PDLL", - "fileTypes": [ - "pdll" - ], - "patterns": [ - { - "include": "#comment" - }, - { - "include": "#string" - }, - { - "include": "#string_block" - }, - { - "include": "#integer" - }, - { - "include": "#include" - }, - { - "include": "#user_constraint" - }, - { - "include": "#user_rewrite" - }, - { - "include": "#pattern" - }, - { - "include": "#inside_pattern" - } - ], - "repository": { - "comment": { - "match": "\/\/.*$", - "name": "comment.line.double-slash.pdll" - }, - "string": { - "name": "string.quoted.double.pdll", - "begin": "\"", - "end": "\"", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.pdll" - } - }, - "patterns": [ - { - "match": "\\\\[nt\"]", - "name": "constant.character.escape.pdll" - }, - { - "match": "\\\\.", - "name": "invalid.illegal.pdll" - } - ], - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.pdll" - } - } - }, - "string_block": { - "name": "string.quoted.triple.pdll", - "begin": "\\[{", - "end": "}]", - "beginCaptures": { - "0": { - "name": "punctuation.definition.string.begin.pdll" - } - }, - "patterns": [ - { - "match": "\\\\[nt\"]", - "name": "constant.character.escape.pdll" - }, - { - "match": "\\\\.", - "name": "invalid.illegal.pdll" - } - ], - "endCaptures": { - "0": { - "name": "punctuation.definition.string.end.pdll" - } - } - }, - "integer": { - "match": "[0-9]+", - "name": "constant.numeric.pdll" - }, - "include": { - "patterns": [ - { - "match": "(#include)", - "name": "keyword.control.pdll" - } - ] - }, - "argument_or_result_list": { - "patterns": [ - { - "match": "\\b([aA-zZ_0-9]*)\\b\\s*:\\s*([aA-zZ_0-9]+)\\b(\\<([^\\>]+)\\>)?", - "captures": { - "1": { - "name": "variable.parameter.pdll" - }, - "2": { - "name": "entity.name.type.pdll" - }, - "4": { - "name": "variable.other.enummember.pdll" - } - } - }, - { - "match": "(\\(|\\>|,)\\s*([aA-zZ_0-9]+)\\b(\\<([^\\>]+)\\>)?\\s*(?=[^:])", - "captures": { - "2": { - "name": "entity.name.type.pdll" - }, - "4": { - "name": "variable.other.enummember.pdll" - } - } - } - ] - }, - "user_constraint": { - "patterns": [ - { - "begin": "\\b(Constraint)\\b\\s*(\\b[aA-zZ_0-9]*\\b)?", - "beginCaptures": { - "1": { - "name": "keyword.other.pdll" - }, - "2": { - "name": "entity.name.type.pdll" - } - }, - "patterns": [ - { - "begin": "(\\[{)", - "patterns": [ - { - "include": "source.cpp" - } - ], - "end": "(}])" - }, - { - "begin": "(?=\\()", - "patterns": [ - { - "include": "#argument_or_result_list" - } - ], - "end": "\\)" - }, - { - "include": "#argument_or_result_list" - }, - { - "begin": "{", - "patterns": [ - { - "include": "#inside_pattern" - } - ], - "end": "(?=})" - }, - { - "begin": "=>", - "patterns": [ - { - "include": "#inside_pattern" - } - ], - "end": "(?=;|,|\\))" - } - ], - "end": "(}|;|,)|(?=\\))" - } - ] - }, - "user_rewrite": { - "patterns": [ - { - "begin": "\\b(Rewrite)\\b\\s*(\\b[aA-zZ_0-9]*\\b)?", - "beginCaptures": { - "1": { - "name": "keyword.other.pdll" - }, - "2": { - "name": "entity.name.function.pdll" - } - }, - "patterns": [ - { - "begin": "(\\[{)", - "patterns": [ - { - "include": "source.cpp" - } - ], - "end": "(}])" - }, - { - "begin": "(?=\\()", - "patterns": [ - { - "include": "#argument_or_result_list" - } - ], - "end": "\\)" - }, - { - "include": "#argument_or_result_list" - }, - { - "begin": "{", - "patterns": [ - { - "include": "#inside_pattern" - } - ], - "end": "(?=})" - }, - { - "begin": "=>", - "patterns": [ - { - "include": "#inside_pattern" - } - ], - "end": "(?=;|,|\\))" - } - ], - "end": "(}|;|,)|(?=\\))" - } - ] - }, - "pattern_metadata": { - "patterns": [ - { - "match": "\\b(with)\\b", - "name": "keyword.other.pdll" - }, - { - "match": "\\b(benefit)\\b\\(([0-9]+)\\)", - "captures": { - "1": { - "name": "entity.name.variable.pdll" - }, - "2": { - "name": "constant.numeric.pdll" - } - } - }, - { - "match": "\\b(recursion)\\b", - "name": "entity.name.variable.pdll" - } - ] - }, - "pattern": { - "patterns": [ - { - "begin": "\\b(Pattern)\\b\\s*(\\b[aA-zZ_0-9]*\\b)?\\s*(\\bwith\\b\\s*[^\\{]*)?\\s*({)", - "beginCaptures": { - "1": { - "name": "keyword.other.pdll" - }, - "2": { - "name": "entity.name.function.pdll" - }, - "3": { - "patterns": [ - { - "include": "#pattern_metadata" - } - ] - } - }, - "patterns": [ - { - "include": "#inside_pattern" - } - ], - "end": "(})" - }, - { - "begin": "\\b(Pattern)\\b\\s*(\\b[aA-zZ_0-9]*\\b)?\\s*(\\bwith\\b\\s*[^\\=]*)?\\s*(=>)", - "beginCaptures": { - "1": { - "name": "keyword.other.pdll" - }, - "2": { - "name": "entity.name.function.pdll" - }, - "3": { - "patterns": [ - { - "include": "#pattern_metadata" - } - ] - } - }, - "patterns": [ - { - "include": "#inside_pattern" - } - ], - "end": ";" - } - ] - }, - "inside_pattern": { - "patterns": [ - { - "match": "\\b(erase|let|replace|return|rewrite|with)\\b", - "captures": { - "1": { - "name": "keyword.control.pdll" - } - } - }, - { - "include": "#expressions" - } - ] - }, - "variable_constraint": { - "patterns": [ - { - "match": "\\b(Op)<([a-zA-Z0-9_\\.$-]*)>", - "captures": { - "1": { - "name": "entity.name.type.pdll" - }, - "2": { - "name": "variable.other.enummember.pdll" - } - } - }, - { - "begin": "<", - "patterns": [ - { - "include": "#expressions" - } - ], - "end": ">" - }, - { - "match": "[a-zA-Z_0-9]+", - "name": "entity.name.type.pdll" - } - ] - }, - "variable_definition": { - "patterns": [ - { - "begin": "\\b([aA-zZ_0-9]*)\\b\\s*:\\s*\\[", - "beginCaptures": { - "1": { - "name": "entity.name.variable.pdll" - } - }, - "patterns": [ - { - "include": "#variable_constraint" - } - ], - "end": "\\]" - }, - { - "match": "\\b([aA-zZ_0-9]*)\\b\\s*:\\s*([aA-zZ_0-9]+(\\<([^\\>]+)\\>)?)", - "captures": { - "1": { - "name": "entity.name.variable.pdll" - }, - "2": { - "patterns": [ - { - "include": "#variable_constraint" - } - ] - } - } - } - ] - }, - "expressions": { - "patterns": [ - { - "include": "#user_constraint" - }, - { - "include": "#user_rewrite" - }, - { - "include": "#attr_expr" - }, - { - "include": "#op_expr" - }, - { - "include": "#type_expr" - }, - { - "include": "#call_expr" - }, - { - "include": "#variable_definition" - }, - { - "include": "#identifier_expr" - }, - { - "include": "#string" - }, - { - "include": "#string_block" - }, - { - "include": "#comment" - }, - { - "begin": "{", - "patterns": [ - { - "include": "#inside_pattern" - } - ], - "end": "}" - }, - { - "begin": "\\(", - "patterns": [ - { - "include": "#expressions" - } - ], - "end": "\\)" - } - ] - }, - "attr_expr": { - "patterns": [ - { - "begin": "(attr)<", - "beginCaptures": { - "1": { - "name": "keyword.other.pdll" - } - }, - "patterns": [ - { - "include": "#string" - }, - { - "include": "#string_block" - } - ], - "end": ">" - } - ] - }, - "call_expr": { - "begin": "\\b([a-zA-Z0-9_]+)\\(", - "beginCaptures": { - "1": { - "name": "entity.name.variable.pdll" - } - }, - "patterns": [ - { - "include": "#expressions" - } - ], - "end": "\\)" - }, - "identifier_expr": { - "match": "\\b([a-zA-Z0-9_]+)\\b", - "name": "entity.name.variable.pdll" - }, - "op_expr": { - "match": "\\b(op)<([0-9a-zA-Z_\\.]*)>", - "captures": { - "1": { - "name": "keyword.other.pdll" - }, - "2": { - "name": "variable.other.enummember.pdll" - } - } - }, - "type_expr": { - "patterns": [ - { - "begin": "\\b(type)<", - "beginCaptures": { - "1": { - "name": "keyword.other.pdll" - } - }, - "patterns": [ - { - "include": "#string" - }, - { - "include": "#string_block" - } - ], - "end": ">" - } - ] - } - }, - "scopeName": "source.pdll" -} \ No newline at end of file diff --git a/mlir/utils/vscode/pdll-language-configuration.json b/mlir/utils/vscode/pdll-language-configuration.json deleted file mode 100644 index 1357db8a9d4d..000000000000 --- a/mlir/utils/vscode/pdll-language-configuration.json +++ /dev/null @@ -1,67 +0,0 @@ -{ - "comments": { - "lineComment": "//" - }, - "brackets": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "<", - ">" - ] - ], - "autoClosingPairs": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "<", - ">" - ], - [ - "\"", - "\"" - ] - ], - "surroundingPairs": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "<", - ">" - ], - [ - "\"", - "\"" - ] - ] -} \ No newline at end of file diff --git a/mlir/utils/vscode/src/MLIR/bytecodeProvider.ts b/mlir/utils/vscode/src/MLIR/bytecodeProvider.ts deleted file mode 100644 index 28ce02398a31..000000000000 --- a/mlir/utils/vscode/src/MLIR/bytecodeProvider.ts +++ /dev/null @@ -1,194 +0,0 @@ -import * as base64 from 'base64-js' -import * as vscode from 'vscode' - -import {MLIRContext} from '../mlirContext'; - -/** - * The parameters to the mlir/convert(To|From)Bytecode commands. These - * parameters are: - * - `uri`: The URI of the file to convert. - */ -type ConvertBytecodeParams = Partial<{uri : string}>; - -/** - * The output of the mlir/convert(To|From)Bytecode commands: - * - `output`: The output buffer of the command, e.g. a .mlir or bytecode - * buffer. - */ -type ConvertBytecodeResult = Partial<{output : string}>; - -/** - * A custom filesystem that is used to convert MLIR bytecode files to text for - * use in the editor, but still use bytecode on disk. - */ -class BytecodeFS implements vscode.FileSystemProvider { - mlirContext: MLIRContext; - - constructor(mlirContext: MLIRContext) { this.mlirContext = mlirContext; } - - /* - * Forward to the default filesystem for the various methods that don't need - * to understand the bytecode <-> text translation. - */ - readDirectory(uri: vscode.Uri): Thenable<[ string, vscode.FileType ][]> { - return vscode.workspace.fs.readDirectory(uri); - } - delete(uri: vscode.Uri): void { - vscode.workspace.fs.delete(uri.with({scheme : "file"})); - } - stat(uri: vscode.Uri): Thenable { - return vscode.workspace.fs.stat(uri.with({scheme : "file"})); - } - rename(oldUri: vscode.Uri, newUri: vscode.Uri, - options: {overwrite: boolean}): void { - vscode.workspace.fs.rename(oldUri.with({scheme : "file"}), - newUri.with({scheme : "file"}), options); - } - createDirectory(uri: vscode.Uri): void { - vscode.workspace.fs.createDirectory(uri.with({scheme : "file"})); - } - watch(_uri: vscode.Uri, _options: { - readonly recursive: boolean; readonly excludes : readonly string[] - }): vscode.Disposable { - return new vscode.Disposable(() => {}); - } - - private _emitter = new vscode.EventEmitter(); - readonly onDidChangeFile: vscode.Event = - this._emitter.event; - - /* - * Read in a bytecode file, converting it to text before returning it to the - * caller. - */ - async readFile(uri: vscode.Uri): Promise { - // Try to start a language client for this file so that we can parse - // it. - const client = - await this.mlirContext.getOrActivateLanguageClient(uri, 'mlir'); - if (!client) { - throw new Error( - 'Failed to activate mlir language server to read bytecode'); - } - - // Ask the client to do the conversion. - let result: ConvertBytecodeResult; - try { - let params: ConvertBytecodeParams = {uri : uri.toString()}; - result = await client.sendRequest('mlir/convertFromBytecode', params); - } catch (e) { - vscode.window.showErrorMessage(e.message); - throw new Error(`Failed to read bytecode file: ${e}`); - } - let resultBuffer = new TextEncoder().encode(result.output); - - // NOTE: VSCode does not allow for extensions to manage files above 50mb. - // Detect that here and if our result is too large for us to manage, alert - // the user and open it as a new temporary .mlir file. - if (resultBuffer.length > (50 * 1024 * 1024)) { - const openAsTempInstead: vscode.MessageItem = { - title : 'Open as temporary .mlir instead', - }; - const message: string = `Failed to open bytecode file "${ - uri.toString()}". Cannot edit converted bytecode files larger than 50MB.`; - const errorResult: vscode.MessageItem|undefined = - await vscode.window.showErrorMessage(message, openAsTempInstead); - if (errorResult === openAsTempInstead) { - let tempFile = await vscode.workspace.openTextDocument({ - language : 'mlir', - content : result.output, - }); - await vscode.window.showTextDocument(tempFile); - } - throw new Error(message); - } - - return resultBuffer; - } - - /* - * Save the provided content, which contains MLIR text, as bytecode. - */ - async writeFile(uri: vscode.Uri, content: Uint8Array, - _options: {create: boolean, overwrite: boolean}) { - // Get the language client managing this file. - let client = this.mlirContext.getLanguageClient(uri, 'mlir'); - if (!client) { - throw new Error( - 'Failed to activate mlir language server to write bytecode'); - } - - // Ask the client to do the conversion. - let convertParams: ConvertBytecodeParams = { - uri : uri.toString(), - }; - const result: ConvertBytecodeResult = - await client.sendRequest('mlir/convertToBytecode', convertParams); - await vscode.workspace.fs.writeFile(uri.with({scheme : "file"}), - base64.toByteArray(result.output)); - } -} - -/** - * A custom bytecode document for use by the custom editor provider below. - */ -class BytecodeDocument implements vscode.CustomDocument { - readonly uri: vscode.Uri; - - constructor(uri: vscode.Uri) { this.uri = uri; } - dispose(): void {} -} - -/** - * A custom editor provider for MLIR bytecode that allows for non-binary - * interpretation. - */ -class BytecodeEditorProvider implements - vscode.CustomReadonlyEditorProvider { - public async openCustomDocument(uri: vscode.Uri, _openContext: any, - _token: vscode.CancellationToken): - Promise { - return new BytecodeDocument(uri); - } - - public async resolveCustomEditor(document: BytecodeDocument, - _webviewPanel: vscode.WebviewPanel, - _token: vscode.CancellationToken): - Promise { - // Ask the user for the desired view type. - const editType = await vscode.window.showQuickPick( - [ {label : '.mlir', description : "Edit as a .mlir text file"} ], - {title : 'Select an editor for the bytecode.'}, - ); - - // If we don't have a valid view type, just bail. - if (!editType) { - await vscode.commands.executeCommand( - 'workbench.action.closeActiveEditor'); - return; - } - - // TODO: We should also provide a non-`.mlir` way of viewing the - // bytecode, which should also ideally have some support for invalid - // bytecode files. - - // Close the active editor given that we aren't using it. - await vscode.commands.executeCommand('workbench.action.closeActiveEditor'); - - // Display the file using a .mlir format. - await vscode.window.showTextDocument( - document.uri.with({scheme : "mlir.bytecode-mlir"}), - {preview : true, preserveFocus : false}); - } -} - -/** - * Register the necessary providers for supporting MLIR bytecode. - */ -export function registerMLIRBytecodeExtensions(context: vscode.ExtensionContext, - mlirContext: MLIRContext) { - vscode.workspace.registerFileSystemProvider("mlir.bytecode-mlir", - new BytecodeFS(mlirContext)); - vscode.window.registerCustomEditorProvider('mlir.bytecode', - new BytecodeEditorProvider()); -} diff --git a/mlir/utils/vscode/src/MLIR/mlir.ts b/mlir/utils/vscode/src/MLIR/mlir.ts deleted file mode 100644 index bd026bd0a42e..000000000000 --- a/mlir/utils/vscode/src/MLIR/mlir.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as vscode from 'vscode'; - -import {MLIRContext} from '../mlirContext'; -import {registerMLIRBytecodeExtensions} from './bytecodeProvider'; - -/** - * Register the necessary extensions for supporting MLIR. - */ -export function registerMLIRExtensions(context: vscode.ExtensionContext, - mlirContext: MLIRContext) { - registerMLIRBytecodeExtensions(context, mlirContext); -} diff --git a/mlir/utils/vscode/src/PDLL/commands/viewOutput.ts b/mlir/utils/vscode/src/PDLL/commands/viewOutput.ts deleted file mode 100644 index 3c165ad1067d..000000000000 --- a/mlir/utils/vscode/src/PDLL/commands/viewOutput.ts +++ /dev/null @@ -1,65 +0,0 @@ -import * as vscode from 'vscode' - -import {Command} from '../../command'; -import {MLIRContext} from '../../mlirContext'; - -/** - * The parameters to the pdll/viewOutput command. These parameters are: - * - `uri`: The URI of the file to view. - * - `kind`: The kind of the output to generate. - */ -type ViewOutputParams = Partial<{uri : string, kind : string}>; - -/** - * The output of the commands: - * - `output`: The output string of the command, e.g. a .mlir PDL string. - */ -type ViewOutputResult = Partial<{output : string}>; - -/** - * A command that displays the output of the current PDLL document. - */ -export class ViewPDLLCommand extends Command { - constructor(context: MLIRContext) { super('mlir.viewPDLLOutput', context); } - - async execute() { - const editor = vscode.window.activeTextEditor; - if (editor.document.languageId != 'pdll') - return; - - // Check to see if a language client is active for this document. - const pdllClient = - this.context.getLanguageClient(editor.document.uri, "pdll"); - if (!pdllClient) { - return; - } - - // Ask the user for the desired output type. - const outputType = - await vscode.window.showQuickPick([ 'ast', 'mlir', 'cpp' ]); - if (!outputType) { - return; - } - - // If we have the language client, ask it to try compiling the document. - let outputParams: ViewOutputParams = { - uri : editor.document.uri.toString(), - kind : outputType, - }; - const result: ViewOutputResult|undefined = - await pdllClient.sendRequest('pdll/viewOutput', outputParams); - if (!result || result.output.length === 0) { - return; - } - - // Display the output in a new editor. - let outputFileType = 'plaintext'; - if (outputType == 'mlir') { - outputFileType = 'mlir'; - } else if (outputType == 'cpp') { - outputFileType = 'cpp'; - } - await vscode.workspace.openTextDocument( - {language : outputFileType, content : result.output}); - } -} diff --git a/mlir/utils/vscode/src/PDLL/pdll.ts b/mlir/utils/vscode/src/PDLL/pdll.ts deleted file mode 100644 index 79262d9f9572..000000000000 --- a/mlir/utils/vscode/src/PDLL/pdll.ts +++ /dev/null @@ -1,12 +0,0 @@ -import * as vscode from 'vscode'; - -import {MLIRContext} from '../mlirContext'; -import {ViewPDLLCommand} from './commands/viewOutput'; - -/** - * Register the necessary extensions for supporting PDLL. - */ -export function registerPDLLExtensions(context: vscode.ExtensionContext, - mlirContext: MLIRContext) { - context.subscriptions.push(new ViewPDLLCommand(mlirContext)); -} diff --git a/mlir/utils/vscode/src/command.ts b/mlir/utils/vscode/src/command.ts deleted file mode 100644 index 4623a5bed085..000000000000 --- a/mlir/utils/vscode/src/command.ts +++ /dev/null @@ -1,25 +0,0 @@ -import * as vscode from 'vscode'; -import {MLIRContext} from './mlirContext'; - -/** - * This class represents a base vscode command. It handles all of the necessary - * command registration and disposal boilerplate. - */ -export abstract class Command extends vscode.Disposable { - private disposable: vscode.Disposable; - protected context: MLIRContext; - - constructor(command: string, context: MLIRContext) { - super(() => this.dispose()); - this.disposable = - vscode.commands.registerCommand(command, this.execute, this); - this.context = context; - } - - dispose() { this.disposable && this.disposable.dispose(); } - - /** - * The function executed when this command is invoked. - */ - abstract execute(...args: any[]): any; -} diff --git a/mlir/utils/vscode/src/config.ts b/mlir/utils/vscode/src/config.ts deleted file mode 100644 index 04ff8f53c9e5..000000000000 --- a/mlir/utils/vscode/src/config.ts +++ /dev/null @@ -1,19 +0,0 @@ -import * as vscode from 'vscode'; - -/** - * Gets the config value `mlir.`, with an optional workspace folder. - */ -export function get(key: string, - workspaceFolder: vscode.WorkspaceFolder = null, - defaultValue: T = undefined): T { - return vscode.workspace.getConfiguration('mlir', workspaceFolder) - .get(key, defaultValue); -} - -/** - * Sets the config value `mlir.`. - */ -export function update(key: string, value: T, - target?: vscode.ConfigurationTarget) { - return vscode.workspace.getConfiguration('mlir').update(key, value, target); -} diff --git a/mlir/utils/vscode/src/configWatcher.ts b/mlir/utils/vscode/src/configWatcher.ts deleted file mode 100644 index 68426873c18e..000000000000 --- a/mlir/utils/vscode/src/configWatcher.ts +++ /dev/null @@ -1,85 +0,0 @@ -import * as chokidar from 'chokidar'; -import * as vscode from 'vscode'; - -import * as config from './config'; -import {MLIRContext} from './mlirContext'; - -/** - * Prompt the user to see if we should restart the server. - */ -async function promptRestart(settingName: string, promptMessage: string) { - switch (config.get(settingName)) { - case 'restart': - vscode.commands.executeCommand('mlir.restart'); - break; - case 'ignore': - break; - case 'prompt': - default: - switch (await vscode.window.showInformationMessage( - promptMessage, 'Yes', 'Yes, always', 'No, never')) { - case 'Yes': - vscode.commands.executeCommand('mlir.restart'); - break; - case 'Yes, always': - vscode.commands.executeCommand('mlir.restart'); - config.update(settingName, 'restart', - vscode.ConfigurationTarget.Global); - break; - case 'No, never': - config.update(settingName, 'ignore', - vscode.ConfigurationTarget.Global); - break; - default: - break; - } - break; - } -} - -/** - * Activate watchers that track configuration changes for the given workspace - * folder, or null if the workspace is top-level. - */ -export async function activate( - mlirContext: MLIRContext, workspaceFolder: vscode.WorkspaceFolder, - serverSettings: string[], serverPaths: string[]) { - // When a configuration change happens, check to see if we should restart the - // server. - mlirContext.subscriptions.push(vscode.workspace.onDidChangeConfiguration(event => { - for (const serverSetting of serverSettings) { - const expandedSetting = `mlir.${serverSetting}`; - if (event.affectsConfiguration(expandedSetting, workspaceFolder)) { - promptRestart( - 'onSettingsChanged', - `setting '${ - expandedSetting}' has changed. Do you want to reload the server?`); - } - } - })); - - // Setup watchers for the provided server paths. - const fileWatcherConfig = { - disableGlobbing : true, - followSymlinks : true, - ignoreInitial : true, - awaitWriteFinish : true, - }; - for (const serverPath of serverPaths) { - if (serverPath === '') { - return; - } - - // If the server path actually exists, track it in case it changes. - const fileWatcher = chokidar.watch(serverPath, fileWatcherConfig); - fileWatcher.on('all', (event, _filename, _details) => { - if (event != 'unlink') { - promptRestart( - 'onSettingsChanged', - 'MLIR language server file has changed. Do you want to reload the server?'); - } - }); - mlirContext.subscriptions.push( - new vscode.Disposable(() => { fileWatcher.close(); })); - } -} diff --git a/mlir/utils/vscode/src/extension.ts b/mlir/utils/vscode/src/extension.ts deleted file mode 100644 index 133fb8f6cf6a..000000000000 --- a/mlir/utils/vscode/src/extension.ts +++ /dev/null @@ -1,29 +0,0 @@ -import * as vscode from 'vscode'; - -import {registerMLIRExtensions} from './MLIR/mlir'; -import {MLIRContext} from './mlirContext'; -import {registerPDLLExtensions} from './PDLL/pdll'; - -/** - * This method is called when the extension is activated. The extension is - * activated the very first time a command is executed. - */ -export function activate(context: vscode.ExtensionContext) { - const outputChannel = vscode.window.createOutputChannel('MLIR'); - context.subscriptions.push(outputChannel); - - const mlirContext = new MLIRContext(); - context.subscriptions.push(mlirContext); - - // Initialize the commands of the extension. - context.subscriptions.push( - vscode.commands.registerCommand('mlir.restart', async () => { - // Dispose and reactivate the context. - mlirContext.dispose(); - await mlirContext.activate(outputChannel); - })); - registerMLIRExtensions(context, mlirContext); - registerPDLLExtensions(context, mlirContext); - - mlirContext.activate(outputChannel); -} diff --git a/mlir/utils/vscode/src/mlirContext.ts b/mlir/utils/vscode/src/mlirContext.ts deleted file mode 100644 index e12aa92522d0..000000000000 --- a/mlir/utils/vscode/src/mlirContext.ts +++ /dev/null @@ -1,392 +0,0 @@ -import * as fs from 'fs'; -import * as path from 'path'; -import * as vscode from 'vscode'; -import * as vscodelc from 'vscode-languageclient/node'; - -import * as config from './config'; -import * as configWatcher from './configWatcher'; - -/** - * This class represents the context of a specific workspace folder. - */ -class WorkspaceFolderContext implements vscode.Disposable { - dispose() { - this.clients.forEach(async client => await client.stop()); - this.clients.clear(); - } - - clients: Map = new Map(); -} - -/** - * This class manages all of the MLIR extension state, - * including the language client. - */ -export class MLIRContext implements vscode.Disposable { - subscriptions: vscode.Disposable[] = []; - workspaceFolders: Map = new Map(); - outputChannel: vscode.OutputChannel; - - /** - * Activate the MLIR context, and start the language clients. - */ - async activate(outputChannel: vscode.OutputChannel) { - this.outputChannel = outputChannel; - - // This lambda is used to lazily start language clients for the given - // document. It removes the need to pro-actively start language clients for - // every folder within the workspace and every language type we provide. - const startClientOnOpenDocument = async (document: vscode.TextDocument) => { - await this.getOrActivateLanguageClient(document.uri, document.languageId); - }; - // Process any existing documents. - for (const textDoc of vscode.workspace.textDocuments) { - await startClientOnOpenDocument(textDoc); - } - - // Watch any new documents to spawn servers when necessary. - this.subscriptions.push( - vscode.workspace.onDidOpenTextDocument(startClientOnOpenDocument)); - this.subscriptions.push( - vscode.workspace.onDidChangeWorkspaceFolders((event) => { - for (const folder of event.removed) { - const client = this.workspaceFolders.get(folder.uri.toString()); - if (client) { - client.dispose(); - this.workspaceFolders.delete(folder.uri.toString()); - } - } - })); - } - - /** - * Open or return a language server for the given uri and language. - */ - async getOrActivateLanguageClient(uri: vscode.Uri, languageId: string): - Promise { - let serverSettingName: string; - if (languageId === 'mlir') { - serverSettingName = 'server_path'; - } else if (languageId === 'pdll') { - serverSettingName = 'pdll_server_path'; - } else if (languageId === 'tablegen') { - serverSettingName = 'tablegen_server_path'; - } else { - return null; - } - - // Check the scheme of the uri. - let validSchemes = [ 'file', 'mlir.bytecode-mlir' ]; - if (!validSchemes.includes(uri.scheme)) { - return null; - } - - // Resolve the workspace folder if this document is in one. We use the - // workspace folder when determining if a server needs to be started. - let workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); - let workspaceFolderStr = - workspaceFolder ? workspaceFolder.uri.toString() : ""; - - // Get or create a client context for this folder. - let folderContext = this.workspaceFolders.get(workspaceFolderStr); - if (!folderContext) { - folderContext = new WorkspaceFolderContext(); - this.workspaceFolders.set(workspaceFolderStr, folderContext); - } - // Start the client for this language if necessary. - let client = folderContext.clients.get(languageId); - if (!client) { - client = await this.activateWorkspaceFolder( - workspaceFolder, serverSettingName, languageId, this.outputChannel); - folderContext.clients.set(languageId, client); - } - return client; - } - - /** - * Prepare a compilation database option for a server. - */ - async prepareCompilationDatabaseServerOptions( - languageName: string, workspaceFolder: vscode.WorkspaceFolder, - configsToWatch: string[], pathsToWatch: string[], - additionalServerArgs: string[]) { - // Process the compilation databases attached for the workspace folder. - let databases = config.get( - `${languageName}_compilation_databases`, workspaceFolder, []); - - // If no databases were explicitly specified, default to a database in the - // 'build' directory within the current workspace. - if (databases.length === 0) { - if (workspaceFolder) { - databases.push(workspaceFolder.uri.fsPath + - `/build/${languageName}_compile_commands.yml`); - } - - // Otherwise, try to resolve each of the paths. - } else { - for await (let database of databases) { - database = await this.resolvePath(database, '', workspaceFolder); - } - } - - configsToWatch.push(`${languageName}_compilation_databases`); - pathsToWatch.push(...databases); - - // Setup the compilation databases as additional arguments to pass to the - // server. - databases.filter(database => database !== ''); - additionalServerArgs.push(...databases.map( - (database) => `--${languageName}-compilation-database=${database}`)); - } - - /** - * Prepare the server options for a PDLL server, e.g. populating any - * accessible compilation databases. - */ - async preparePDLLServerOptions(workspaceFolder: vscode.WorkspaceFolder, - configsToWatch: string[], - pathsToWatch: string[], - additionalServerArgs: string[]) { - await this.prepareCompilationDatabaseServerOptions( - 'pdll', workspaceFolder, configsToWatch, pathsToWatch, - additionalServerArgs); - } - - /** - * Prepare the server options for a TableGen server, e.g. populating any - * accessible compilation databases. - */ - async prepareTableGenServerOptions(workspaceFolder: vscode.WorkspaceFolder, - configsToWatch: string[], - pathsToWatch: string[], - additionalServerArgs: string[]) { - await this.prepareCompilationDatabaseServerOptions( - 'tablegen', workspaceFolder, configsToWatch, pathsToWatch, - additionalServerArgs); - } - - /** - * Activate the language client for the given language in the given workspace - * folder. - */ - async activateWorkspaceFolder(workspaceFolder: vscode.WorkspaceFolder, - serverSettingName: string, languageName: string, - outputChannel: vscode.OutputChannel): - Promise { - let configsToWatch: string[] = []; - let filepathsToWatch: string[] = []; - let additionalServerArgs: string[] = []; - additionalServerArgs = config.get(languageName + "_additional_server_args", null, []); - - // Initialize additional configurations for this server. - if (languageName === 'pdll') { - await this.preparePDLLServerOptions(workspaceFolder, configsToWatch, - filepathsToWatch, - additionalServerArgs); - } else if (languageName == 'tablegen') { - await this.prepareTableGenServerOptions(workspaceFolder, configsToWatch, - filepathsToWatch, - additionalServerArgs); - } - - // Try to activate the language client. - const [server, serverPath] = await this.startLanguageClient( - workspaceFolder, outputChannel, serverSettingName, languageName, - additionalServerArgs); - configsToWatch.push(serverSettingName); - filepathsToWatch.push(serverPath); - - // Watch for configuration changes on this folder. - await configWatcher.activate(this, workspaceFolder, configsToWatch, - filepathsToWatch); - return server; - } - - /** - * Start a new language client for the given language. Returns an array - * containing the opened server, or null if the server could not be started, - * and the resolved server path. - */ - async startLanguageClient(workspaceFolder: vscode.WorkspaceFolder, - outputChannel: vscode.OutputChannel, - serverSettingName: string, languageName: string, - additionalServerArgs: string[]): - Promise<[ vscodelc.LanguageClient, string ]> { - const clientTitle = languageName.toUpperCase() + ' Language Client'; - - // Get the path of the lsp-server that is used to provide language - // functionality. - var serverPath = - await this.resolveServerPath(serverSettingName, workspaceFolder); - - // If the server path is empty, bail. We don't emit errors if the user - // hasn't explicitly configured the server. - if (serverPath === '') { - return [ null, serverPath ]; - } - - // Check that the file actually exists. - if (!fs.existsSync(serverPath)) { - vscode.window - .showErrorMessage( - `${clientTitle}: Unable to resolve path for '${ - serverSettingName}', please ensure the path is correct`, - "Open Setting") - .then((value) => { - if (value === "Open Setting") { - vscode.commands.executeCommand( - 'workbench.action.openWorkspaceSettings', - {openToSide : false, query : `mlir.${serverSettingName}`}); - } - }); - return [ null, serverPath ]; - } - - // Configure the server options. - const serverOptions: vscodelc.ServerOptions = { - command : serverPath, - args : additionalServerArgs - }; - - // Configure file patterns relative to the workspace folder. - let filePattern: vscode.GlobPattern = '**/*.' + languageName; - let selectorPattern: string = null; - if (workspaceFolder) { - filePattern = new vscode.RelativePattern(workspaceFolder, filePattern); - selectorPattern = `${workspaceFolder.uri.fsPath}/**/*`; - } - - // Configure the middleware of the client. This is sort of abused to allow - // for defining a "fallback" language server that operates on non-workspace - // folders. Workspace folder language servers can properly filter out - // documents not within the folder, but we can't effectively filter for - // documents outside of the workspace. To support this, and avoid having two - // servers targeting the same set of files, we use middleware to inject the - // dynamic logic for checking if a document is in the workspace. - let middleware = {}; - if (!workspaceFolder) { - middleware = { - didOpen : (document, next) : Promise => { - if (!vscode.workspace.getWorkspaceFolder(document.uri)) { - return next(document); - } - return Promise.resolve(); - } - }; - } - - // Configure the client options. - const clientOptions: vscodelc.LanguageClientOptions = { - documentSelector : [ - {language : languageName, pattern : selectorPattern}, - ], - synchronize : { - // Notify the server about file changes to language files contained in - // the workspace. - fileEvents : vscode.workspace.createFileSystemWatcher(filePattern) - }, - outputChannel : outputChannel, - workspaceFolder : workspaceFolder, - middleware : middleware, - - // Don't switch to output window when the server returns output. - revealOutputChannelOn : vscodelc.RevealOutputChannelOn.Never, - }; - - // Create the language client and start the client. - let languageClient = new vscodelc.LanguageClient( - languageName + '-lsp', clientTitle, serverOptions, clientOptions); - languageClient.start(); - return [ languageClient, serverPath ]; - } - - /** - * Given a server setting, return the default server path. - */ - static getDefaultServerFilename(serverSettingName: string): string { - if (serverSettingName === 'pdll_server_path') { - return 'mlir-pdll-lsp-server'; - } - if (serverSettingName === 'server_path') { - return 'mlir-lsp-server'; - } - if (serverSettingName === 'tablegen_server_path') { - return 'tblgen-lsp-server'; - } - return ''; - } - - /** - * Try to resolve the given path, or the default path, with an optional - * workspace folder. If a path could not be resolved, just returns the - * input filePath. - */ - async resolvePath(filePath: string, defaultPath: string, - workspaceFolder: vscode.WorkspaceFolder): Promise { - const configPath = filePath; - - // If the path is already fully resolved, there is nothing to do. - if (path.isAbsolute(filePath)) { - return filePath; - } - - // If a path hasn't been set, try to use the default path. - if (filePath === '') { - if (defaultPath === '') { - return filePath; - } - filePath = defaultPath; - - // Fallthrough to try resolving the default path. - } - - // Try to resolve the path relative to the workspace. - let filePattern: vscode.GlobPattern = '**/' + filePath; - if (workspaceFolder) { - filePattern = new vscode.RelativePattern(workspaceFolder, filePattern); - } - let foundUris = await vscode.workspace.findFiles(filePattern, null, 1); - if (foundUris.length === 0) { - // If we couldn't resolve it, just return the original path anyways. The - // file might not exist yet. - return configPath; - } - // Otherwise, return the resolved path. - return foundUris[0].fsPath; - } - - /** - * Try to resolve the path for the given server setting, with an optional - * workspace folder. - */ - async resolveServerPath(serverSettingName: string, - workspaceFolder: vscode.WorkspaceFolder): - Promise { - const serverPath = config.get(serverSettingName, workspaceFolder); - const defaultPath = MLIRContext.getDefaultServerFilename(serverSettingName); - return this.resolvePath(serverPath, defaultPath, workspaceFolder); - } - - /** - * Return the language client for the given language and uri, or null if no - * client is active. - */ - getLanguageClient(uri: vscode.Uri, - languageName: string): vscodelc.LanguageClient { - let workspaceFolder = vscode.workspace.getWorkspaceFolder(uri); - let workspaceFolderStr = - workspaceFolder ? workspaceFolder.uri.toString() : ""; - let folderContext = this.workspaceFolders.get(workspaceFolderStr); - if (!folderContext) { - return null; - } - return folderContext.clients.get(languageName); - } - - dispose() { - this.subscriptions.forEach((d) => { d.dispose(); }); - this.subscriptions = []; - this.workspaceFolders.forEach((d) => { d.dispose(); }); - this.workspaceFolders.clear(); - } -} diff --git a/mlir/utils/vscode/tablegen-language-configuration.json b/mlir/utils/vscode/tablegen-language-configuration.json deleted file mode 100644 index 6a1455bf8ca7..000000000000 --- a/mlir/utils/vscode/tablegen-language-configuration.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "comments": { - "lineComment": "//", - "blockComment": [ - "/*", - "*/" - ] - }, - "colorizedBracketPairs": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "<", - ">" - ] - ], - "brackets": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "<", - ">" - ] - ], - "autoClosingPairs": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "<", - ">" - ], - [ - "\"", - "\"" - ] - ], - "surroundingPairs": [ - [ - "{", - "}" - ], - [ - "[", - "]" - ], - [ - "(", - ")" - ], - [ - "<", - ">" - ], - [ - "\"", - "\"" - ] - ] -} \ No newline at end of file diff --git a/mlir/utils/vscode/tsconfig.json b/mlir/utils/vscode/tsconfig.json deleted file mode 100644 index f913b0d2d9da..000000000000 --- a/mlir/utils/vscode/tsconfig.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "compilerOptions": { - "module": "commonjs", - "target": "es6", - "outDir": "out", - "rootDir": "src", - "sourceMap": true - }, - "include": [ - "src" - ], - "exclude": [ - "node_modules", - ".vscode-test" - ] -}