From 8f0a64faa69935c2b4da81d35324db12d35c4c3d Mon Sep 17 00:00:00 2001 From: Haoyang Date: Fri, 9 Sep 2022 16:57:37 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E5=9F=BA=E4=BA=8E=E5=BC=80=E6=BA=90?= =?UTF-8?q?=E9=A1=B9=E7=9B=AEnative-debug=20tag=200.26.0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Haoyang --- .github/ISSUE_TEMPLATE.md | 12 + .github/workflows/release.yml | 100 + .gitignore | 4 + .travis.yml | 20 + .vscode/launch.json | 50 + .vscode/settings.json | 11 + .vscode/tasks.json | 28 + .vscodeignore | 9 + CHANGELOG.md | 82 + LICENSE | 24 + README.md | 217 ++- images/icon-plain.svg | 136 ++ images/icon.png | Bin 0 -> 7097 bytes images/icon.svg | 181 ++ images/preview.png | Bin 0 -> 91243 bytes images/tutorial1-alt.png | Bin 0 -> 86647 bytes images/tutorial1.png | Bin 0 -> 44078 bytes images/tutorial2.png | Bin 0 -> 54388 bytes package-lock.json | 2632 ++++++++++++++++++++++++++ package.json | 1041 ++++++++++ src/backend/backend.ts | 165 ++ src/backend/gdb_expansion.ts | 258 +++ src/backend/linux/console.ts | 21 + src/backend/mi2/mi2.ts | 888 +++++++++ src/backend/mi2/mi2lldb.ts | 72 + src/backend/mi2/mi2mago.ts | 45 + src/backend/mi_parse.ts | 313 +++ src/frontend/extension.ts | 175 ++ src/gdb.ts | 173 ++ src/lldb.ts | 126 ++ src/mago.ts | 93 + src/mibase.ts | 763 ++++++++ src/test/runTest.ts | 24 + src/test/suite/gdb_expansion.test.ts | 306 +++ src/test/suite/index.ts | 37 + src/test/suite/mi_parse.test.ts | 207 ++ tsconfig.json | 21 + tslint.json | 38 + 38 files changed, 8245 insertions(+), 27 deletions(-) create mode 100644 .github/ISSUE_TEMPLATE.md create mode 100644 .github/workflows/release.yml create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 .vscodeignore create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 images/icon-plain.svg create mode 100644 images/icon.png create mode 100644 images/icon.svg create mode 100644 images/preview.png create mode 100644 images/tutorial1-alt.png create mode 100644 images/tutorial1.png create mode 100644 images/tutorial2.png create mode 100644 package-lock.json create mode 100644 package.json create mode 100644 src/backend/backend.ts create mode 100644 src/backend/gdb_expansion.ts create mode 100644 src/backend/linux/console.ts create mode 100644 src/backend/mi2/mi2.ts create mode 100644 src/backend/mi2/mi2lldb.ts create mode 100644 src/backend/mi2/mi2mago.ts create mode 100644 src/backend/mi_parse.ts create mode 100644 src/frontend/extension.ts create mode 100644 src/gdb.ts create mode 100644 src/lldb.ts create mode 100644 src/mago.ts create mode 100644 src/mibase.ts create mode 100644 src/test/runTest.ts create mode 100644 src/test/suite/gdb_expansion.test.ts create mode 100644 src/test/suite/index.ts create mode 100644 src/test/suite/mi_parse.test.ts create mode 100644 tsconfig.json create mode 100644 tslint.json diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100644 index 0000000..9afcdee --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,12 @@ +If submitting a bug please make sure + +- [ ] If you are using gdb + - [ ] `gdb --version` >= 7.7.1 + - [ ] it works on the command line with `gdb` + - [ ] `cwd` and `target` are properly set +- [ ] If you are using lldb + - [ ] `lldb --version` >= 3.7.1 + - [ ] it works on the command line with `lldb-mi` + - [ ] `cwd` and `target` are properly set + +Screenshots are helpful but not required \ No newline at end of file diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..6b1629a --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,100 @@ +name: Release +on: + release: + types: [published] + +jobs: + release: + strategy: + matrix: + os: ['ubuntu-latest'] + node-version: ['16.x'] + runs-on: ${{ matrix.os }} + steps: + # + # Basic Setup + # + - name: Checkout + uses: actions/checkout@v3 + + - name: Install Node.js ${{ matrix.node-version }} + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node-version }} + + # + # Audit Versions for Consistency + # + - name: Query package.json Version + id: package + run: node -e "console.log('::set-output name=version::' + require('./package.json').version)" + + - name: Query package-lock.json Version + id: package-lock + run: node -e "console.log('::set-output name=version::' + require('./package-lock.json').version)" + + - name: Query Latest Changelog Version + id: changelog + shell: bash + run: echo ::set-output name=version::$(grep --perl-regexp "^# " --max-count=1 CHANGELOG.md | awk '{print $2}') + + - name: Audit package.json/package-lock.json/CHANGELOG.md/git tag Version Consistency + shell: bash + run: > + test ${{ steps.package.outputs.version }} = ${{ steps.package-lock.outputs.version }} -a \ + ${{ steps.package.outputs.version }} = ${{ steps.changelog.outputs.version }} -a \ + refs/tags/v${{ steps.package.outputs.version }} = ${{ github.ref }} + + # + # Install Dependencies + # + # NOTE: + # Use the `clean-install` instead of just `install` so that the versions identified in the + # package-lock.json file are used instead of attempting to install later versions that might + # exist. This drives consistency between what the developers have been using and what is to + # be released. + # + # NOTE: + # Use the `--no-optional` switch to prevent installation of the `ssh2` optional dependency + # (i.e., `cpu-features`) package which is used to provide accelerated crypto functionality, + # but which is a native add-on and would require platform specific packages. + # + - name: Install Module Dependencies + run: npm clean-install --no-optional + + # + # Package and Upload Extension + # + # NOTE: + # The "vscode:prepublish" script in package.json will be executed to compile the extension + # prior to packaging. + # + - name: Package Extension into .vsix file + id: asset + shell: bash + run: > + npx vsce package; + echo ::set-output name=vsix_path::$(ls *.vsix) + + - name: Upload .vsix file to Github as release asset + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ github.event.release.upload_url }} + asset_path: ${{ steps.asset.outputs.vsix_path }} + asset_name: ${{ steps.asset.outputs.vsix_path }} + asset_content_type: application/zip + + # + # Publish Extension + # + - name: Publish to VSCode Extension Marketplace + env: + VSCE_PAT: ${{ secrets.VS_MARKETPLACE_TOKEN }} + run: npx vsce publish --packagePath ${{ steps.asset.outputs.vsix_path }} + + - name: Publish to Open VSX Registry + env: + OVSX_PAT: ${{ secrets.OPEN_VSX_TOKEN }} + run: npx ovsx publish ${{ steps.asset.outputs.vsix_path }} diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1262404 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +out +node_modules +*.vsix +.vscode-test \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..84bcea5 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,20 @@ +sudo: false +language: node_js +node_js: + - stable +os: + - osx + - linux + +before_install: + - if [ $TRAVIS_OS_NAME == "linux" ]; then + export CXX="g++-4.9" CC="gcc-4.9" DISPLAY=:99.0; + sh -e /etc/init.d/xvfb start; + sleep 3; + fi + +script: +- | + npm install + tsc + node out/src/test/runTest.js diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000..6fc6c05 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,50 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +{ + "version": "0.1.0", + "configurations": [ + { + "name": "Launch Extension", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": ["--extensionDevelopmentPath=${workspaceRoot}" ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/out/**/*.js" + ], + "preLaunchTask": "npm" + }, + { + "name": "code-debug server", + "type": "node", + "request": "launch", + "runtimeArgs": [ "--nolazy" ], + "program": "${workspaceRoot}/src/gdb.ts", + "stopOnEntry": false, + "args": [ "--server=4711" ], + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/out/**/*.js" + ], + "cwd": "${workspaceRoot}", + "preLaunchTask": "npm" + }, + { + "name": "Launch Tests", + "type": "extensionHost", + "request": "launch", + "runtimeExecutable": "${execPath}", + "args": [ + "--extensionDevelopmentPath=${workspaceRoot}", + "--extensionTestsPath=${workspaceRoot}/out/src/test/suite/index" + ], + "stopOnEntry": false, + "sourceMaps": true, + "outFiles": [ + "${workspaceRoot}/out/**/*.js" + ], + "preLaunchTask": "npm" + } + ] +} \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..7bfd42c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,11 @@ +// Place your settings in this file to overwrite default and user settings. +{ + "editor.insertSpaces": false, + "files.exclude": { + "out": false // set this to true to hide the "out" folder with the compiled JS files + }, + "search.exclude": { + "out": true // set this to false to include "out" folder in search results + }, + "typescript.tsdk": "./node_modules/typescript/lib" // we want to use the TS server from our node_modules folder to control its version +} \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000..e14d181 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,28 @@ +// Available variables which can be used inside of strings. +// ${workspaceRoot}: the root folder of the team +// ${file}: the current opened file +// ${fileBasename}: the current opened file's basename +// ${fileDirname}: the current opened file's dirname +// ${fileExtname}: the current opened file's extension +// ${cwd}: the current working directory of the spawned process + +// A task runner that calls a custom npm script that compiles the extension. +{ + "version": "2.0.0", + + // Run in a shell so "npm" command is properly resolved to "npm.cmd" on Windows systems. + "type": "shell", + + // we want to run npm + "command": "npm", + + // we run the custom script "compile" as defined in package.json + "args": ["run", "compile", "--loglevel", "silent"], + + // The tsc compiler is started in background mode + "isBackground": true, + + // use the standard tsc in watch mode problem matcher to find compile problems in the output. + "problemMatcher": "$tsc-watch", + "tasks": [] +} \ No newline at end of file diff --git a/.vscodeignore b/.vscodeignore new file mode 100644 index 0000000..795e714 --- /dev/null +++ b/.vscodeignore @@ -0,0 +1,9 @@ +.vscode/** +typings/** +out/test/** +test/** +src/** +**/*.map +.gitignore +tsconfig.json +vsc-extension-quickstart.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..12302fe --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,82 @@ +# 0.26.0 + +* vscode dependency was increased from 1.28 to 1.55 along with the debug-adapter protocol to get rid of some outdated dependencies (@GitMensch) +* SSH2 module updated from deprecated 0.8.9 to current 1.6.0 (@GitMensch), + allowing connections with more modern key algorithms, improved error handling (including user messages passed on) and other improvements. + See [SSH2 Update Notices](https://github.com/mscdex/ssh2/issues/935) for more details. +* Path Substitutions working with attach+ssh configuration #293 (@brownts) +* Path Substitutions working with LLDB #295 (@brownts) +* Path Substitutions working with Windows-Style paths #294 (@brownts) +* Breakpoints may be deleted when not recognized correctly #259 fixing #230 (@kvinwang) +* New `stopAtConnect` configuration #299, #302 (@brownts) +* New `stopAtEntry` configuration to run debugger to application's entry point #306 (@brownts) +* New `ssh.sourceFileMap` configuration to allow multiple substitutions between local and ssh-remote and separate ssh working directory #298 (@GitMensch) +* fix path translation for SSH to Win32 and for extended-remote without executable (attach to process) #323 (@GitMensch) +* fix for race conditions on startup where breakpoints were not hit #304 (@brownts) +* prevent "Not implemented stop reason (assuming exception)" in many cases #316 (@GitMensch), + initial recognition of watchpoints +* fix additional race conditions with setting breakpoints #313 (@brownts) +* fix stack frame expansion in editor via use of the `startFrame` parameter #312 (@brownts) +* allow specification of port/x11port via variable (as numeric string) #265 (@GitMensch) +* Extra debugger arguments now work in all configurations #316, #338 fixing #206 (@GitMensch, @brownts) +* Attaching to local PID now performs initialization prior to attaching #341 fixing #329 (@brownts) + +# 0.25.1 + +* Remove the need for extra trust for debugging workspaces per guidance "for debug extensions" as noted in the [Workspace Trust Extension Guide](https://github.com/microsoft/vscode/issues/120251#issuecomment-825832603) (@GitMensch) +* Fix simple value formatting list parsing with empty string as first argument (@nomtats) +* don't abort if `set target-async` or `cd` fails in attach (brings in line with existing behavior from launch) + +# 0.25.0 + +(released May 2020) + +* Add support for path substitutions (`{"fromPath": "toPath"}`) for GDB and LLDB (@karljs) +* Support up to 65535 threads instead of 256 threads (@ColdenCullen) +* Improve thread names on embedded GDB, makes not all threads always have the same name (with @anshulrouthu) + +# 0.24.0 + +* Added zig as supported language. +* Fix example Debug Microcontroller template +* Implement "Jump to Cursor" to skip instructions +* Fix memory dump for theia + +# 0.23.1 + +Fixes: +* Breakpoints in SSH in other working directories properly resolved +* Undefined/null paths don't crash stacktrace +* Added kotlin to language list + +# 0.23.0 + +(released March 2019) + +* Normalize file paths in stack trace (fixes duplicate opening of files) +* New Examine memory Location UI +* Breakpoints in SSH on windows fixed (@HaronK) +* Project code improvements (@simark) +* Initial configurations contain valueFormatting now (@Yanpas) + +# 0.22.0 + +(released March 2018) + +* Support for using SSH agent +* Support multi-threading (@LeszekSwirski) +* Fixed GDB expansion logic with floats (Marcel Ball) +* Fixed attach to PID template (@gentoo90) + +# 0.21.0 / 0.21.1 / 0.21.2 + +(0.21.2 is pushed without changes to hopefully fix vscode installation) + +* Several fixes to variable pretty printers by @gentoo90 +* Enabled breakpoints for crystal (@faustinoaq) + +# 0.20.0 + +Added support for pretty printers in variable list (by @gentoo90), enable +with `"valuesFormatting": "prettyPrinters"` if you have a pretty printer +to get potentially improved display of variables. diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cf1ab25 --- /dev/null +++ b/LICENSE @@ -0,0 +1,24 @@ +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to diff --git a/README.md b/README.md index d1c5df2..b8f0e34 100644 --- a/README.md +++ b/README.md @@ -1,39 +1,202 @@ -# native-debug +# Debug -#### 介绍 -{**以下是 Gitee 平台说明,您可以替换此简介** -Gitee 是 OSCHINA 推出的基于 Git 的代码托管平台(同时支持 SVN)。专为开发者提供稳定、高效、安全的云端软件开发协作平台 -无论是个人、团队、或是企业,都能够用 Gitee 实现代码托管、项目管理、协作开发。企业项目请看 [https://gitee.com/enterprises](https://gitee.com/enterprises)} +Native VSCode debugger. Supports both GDB and LLDB. -#### 软件架构 -软件架构说明 +## Installation +Press ctrl-p (cmd+p on OS X) and run `ext install webfreak.debug` in visual studio code and install GDB/LLDB. See `Usage` for details on how to set it up. -#### 安装教程 +![Preview](images/preview.png) -1. xxxx -2. xxxx -3. xxxx +## Usage -#### 使用说明 +![Image with red circle around a gear and a red arrow pointing at GDB and LLDB](images/tutorial1.png) -1. xxxx -2. xxxx -3. xxxx +Or if you already have an existing debugger in your project setup you can click "Create Configuration" or use the auto completion instead: -#### 参与贡献 +![Visual studio code debugger launch.json auto completion showing alternative way to create debuggers](images/tutorial1-alt.png) -1. Fork 本仓库 -2. 新建 Feat_xxx 分支 -3. 提交代码 -4. 新建 Pull Request +Open your project and click the debug button in your sidebar. At the top right press +the little gear icon and select GDB or LLDB. It will automatically generate the configuration +you need. +*Note: for LLDB you need to have `lldb-mi` in your PATH* -#### 特技 +If you are on OS X you can add `lldb-mi` to your path using +`ln -s /Applications/Xcode.app/Contents/Developer/usr/bin/lldb-mi /usr/local/bin/lldb-mi` if you have Xcode. -1. 使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md -2. Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) -3. 你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 -4. [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 -5. Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) -6. Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) +![Default config with a red circle around the target](images/tutorial2.png) + +Now you need to change `target` to the application you want to debug relative +to the cwd. (Which is the workspace root by default) + +Additionally you can set `terminal` if you want to run the program in a separate terminal with +support for input. On Windows set it to an empty string (`""`) to enable this feature. On linux +set it to an empty string (`""`) to use the default terminal emulator specified with `x-terminal-emulator` +or specify a custom one. Note that it must support the `-e` argument. + +Before debugging you need to compile your application first, then you can run it using +the green start button in the debug sidebar. For this you could use the `preLaunchTask` +argument vscode allows you to do. Debugging multithreaded applications is currently not +implemented. Adding breakpoints while the program runs will not interrupt it immediately. +For that you need to pause & resume the program once first. However adding breakpoints +while its paused works as expected. + +Extending variables is very limited as it does not support child values of variables. +Watching expressions works partially but the result does not get properly parsed and +it shows the raw output of the command. It will run `data-evaluate-expression` +to check for variables. + +While running you will get a console where you can manually type GDB/LLDB commands or MI +commands prepended with a hyphen `-`. The console shows all output separated +in `stdout` for the application, `stderr` for errors and `log` for log messages. + +Some exceptions/signals like segmentation faults will be catched and displayed but +it does not support for example most D exceptions. + +Support exists for stopping at the entry point of the application. This is controlled +through the `stopAtEntry` setting. This value may be either a boolean or a string. In +the case of a boolean value of `false` (the default), this setting is disabled. In the +case of a boolean value of `true`, if this is a launch configuration and the debugger +supports the `start` (or `exec-run --start` MI feature, more specifically), than this +will be used to run to the entry point of the application. Note that this appears to +work fine for GDB, but LLDB doesn't necessarily seem to adhere to this, even though it may +indicate that it supports this feature. The alternative configuration option for the +`stopAtEntry` setting is to specify a string where the string represents the entry point +itself. In this situation a temporary breakpoint will be set at the specified entry point +and a normal run will occur for a launch configuration. This (setting a temporary +breakpoint) is also the behavior that occurs when the debugger does not support the +`start` feature and the `stopAtEntry` was set to `true`. In that case the entry point will +default to "main". Thus, the most portable way to use this configuration is to explicitly +specify the entry point of the application. In the case of an attach configuration, similar +behavior will occur, however since there is no equivalent of the `start` command for +attaching, a boolean value of `true` for the `stopAtEntry` setting in a launch configuration +will automatically default to an entry point of "main", while a string value for this +setting will be interpreted as the entry point, causing a temporary breakpoint to be set at +that location prior to continuing execution. Note that stopping at the entry point for the +attach configuration assumes that the entry point has not yet been entered at the time of +attach, otherwise this will have no affect. + +### Attaching to existing processes + +Attaching to existing processes currently only works by specifying the PID in the +`launch.json` and setting `request` to `"attach"`. You also need to specify the executable +path for the debugger to find the debug symbols. + +``` +"request": "attach", +"executable": "./bin/executable", +"target": "4285" +``` + +This will attach to PID 4285 which should already run. GDB will pause the program on entering and LLDB will keep it running. + +### Using `gdbserver` for remote debugging (GDB only) + +You can also connect to a gdbserver instance and debug using that. For that modify the +`launch.json` by setting `request` to `"attach"` and `remote` to `true` and specifing the +port and optionally hostname in `target`. + +``` +"request": "attach", +"executable": "./bin/executable", +"target": ":2345", +"cwd": "${workspaceRoot}", +"remote": true +``` + +This will attach to the running process managed by gdbserver on localhost:2345. You might +need to hit the start button in the debug bar at the top first to start the program. + +Control over whether the debugger should continue executing on connect can be configured +by setting `stopAtConnect`. The default value is `false` so that execution will continue +after connecting. + +### Using ssh for debugging on remote + +Debugging using ssh automatically converts all paths between client & server and also optionally +redirects X11 output from the server to the client. +Simply add a `ssh` object in your `launch` request. + +``` +"request": "launch", +"target": "./executable", +"cwd": "${workspaceRoot}", +"ssh": { + "forwardX11": true, + "host": "192.168.178.57", + "cwd": "/home/remoteUser/project/", + "keyfile": "/path/to/.ssh/key", // OR + "password": "password123", + "user": "remoteUser", + "x11host": "localhost", + // x11port may also be specified as string containing only numbers (useful to use configuration variables) + "x11port": 6000, + // Optional, content will be executed on the SSH host before the debugger call. + "bootstrap": "source /home/remoteUser/some-env" +} +``` + +`ssh.sourceFileMap` will be used to trim off local paths and map them to the server. This is +required for basically everything except watched variables or user commands to work. + +For backward compatibility you can also use `cwd` and `ssh.cwd` for the mapping, this is only used +if the newer `ssh.sourceFileMap` is not configured. + +For X11 forwarding to work you first need to enable it in your Display Manager and allow the +connections. To allow connections you can either add an entry for applications or run `xhost +` +in the console while you are debugging and turn it off again when you are done using `xhost -`. + +Because some builds requires one or more environment files to be sourced before running any +command, you can use the `ssh.bootstrap` option to add some extra commands which will be prepended +to the debugger call (using `&&` to join both). + +### Extra Debugger Arguments + +Additional arguments can be supplied to the debugger if needed. These will be added when +the debugger executable (e.g., gdb, lldb-mi, etc.) is launched. Extra debugger arguments +are supplied via the `debugger_args` setting. Note that the behavior of escaping these +options depends on the environment in which the debugger is started. For non-SSH +debugging, the options are passed directly to the application and therefore no escaping is +necessary (other than what is necessary for the JSON configuration). However, as a result +of the options being passed directly to the application, care must be taken to place +switches and switch values as separate entities in `debugger_args`, if they would normally +be separated by a space. For example, supplying the option and value +`-iex "set $foo = \"bar\""` would consist of the following `debugger_args`: +```json +"debugger_args" : ["-iex", "set $foo = \"bar\""] +``` +If `=` is used to associate switches with their values, than the switch and value should +be placed together instead. In fact, the following example shows 4 different ways in +which to specify the same switch and value, using both short and long format, as well as +switch values supplied as a separate parameter or supplied via the `=`: +- ```json + "debugger_args" : ["-iex", "set $foo = \"bar\""] + ``` +- ```json + "debugger_args" : ["-iex=set $foo = \"bar\""] + ``` +- ```json + "debugger_args" : ["--init-eval-command", "set $foo = \"bar\""] + ``` +- ```json + "debugger_args" : ["--init-eval-command=set $foo = \"bar\""] + ``` +Where escaping is really necessary is when running the debugger over SSH. In this case, +the options are not passed directly to the application, but are instead combined with the +application name, joined together with any other options, and sent to the remote system to +be parsed and executed. Thus, depending on the remote system, different escaping may be +necessary. The following shows how the same command as above needs to be escaped +differently based on whether the remote system is a POSIX or a Windows system. +- SSH to Linux machine: + ```json + "debugger_args": ["-iex", "'set $foo = \"bar\"'"] + ``` +- SSH to Windows machine: + ```json + "debugger_args": ["-iex", "\"set $foo = \\\"bar\\\"\""] + ``` +You may need to experiment to find the correct escaping necessary for the command to be +sent to the debugger as you intended. + +## [Issues](https://github.com/WebFreak001/code-debug) diff --git a/images/icon-plain.svg b/images/icon-plain.svg new file mode 100644 index 0000000..d86c021 --- /dev/null +++ b/images/icon-plain.svg @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/icon.png b/images/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..935ec57a9d718898fe21afdd35b67e16ef00db7e GIT binary patch literal 7097 zcmV;q8%E@bP)aa@zQ;l3blh@dRW+H}1? znr?w!=%#Nk7=Pc#_d(xVRi~+Q>sFmQ=ak@XLn25`>WGgf4(N!K(IBHhX$3M22m=BD zKcGo;W`$QESD(5v1IYB6cBtcQIdk#YJtog~q1JOi*zK zbKfoZusjaYI21su^&?0(9w}!ac^E-+Pm5%QLZsLT`Za{+ZRP1dS9)5Y`tWWAShg?* z$c`!3rSkC#nXa# zRsqr$b_Mw+hN1qaha?>z`72&sa@12Ict!!V+8_ce7XfntjYnkg9x4&MjiyA)%Ws#u zyK(m`!19G-(aZONPHu18yE%hiJWcZJ+uhly`xHQ{4Iogb1^FtVxT=}3z#tMMqxj;? z303P2&}f(%6UV2=535>l9VGAw{R7mko~7&rV9>E9k|kl=RWIt5rW-G}~D-vX9n*m-jqH9Oyk zP(camcD@mNlwj%b@gxl%PJGMObPsFQ5GC*hrZ8?qGlq>$CnLipb_3TafL80rtrjbR zpSz^~8u$o>Z)g3oR_7ZrDnWKpAqR7>I#h3fM#F|_k29&0<-MknQ62f}+$pZyDmJ@j z?0h3mC;`AwH2R(l8?%v&44tEe>qC77&}y3!P`LrYL#o$p0g0rbyo{+aaVWxkdLe}1 z;h1h*yM3DjIhXCK)A-J}*7*|2OJ9G*`cucuuGQ^)BTgxSpgX?$L>?Nmo=q95?l!8c z0E-udmf5Qm#o5@JQUN-vJxPe)G3xr#YLRFnMdF7w%pe~n#6Wd3~v`r zTv%(OftPB8ezGg?N z^y3*nW&_(YZa1U?OQ<&^Uz!w+;hyXv ziskFJI^WupUz3z?wy|W-PMi1G!D;kW<4I1jQV zl}cSO3n5lEv{AL`7S@VAk3UVYe}F3WHG(I0#hnr^nVSzzJ2Zz|aXIA%K zygVRLmG&BO=Npi6FQIw&IpU7)*b6hTayf2X?oH|x%Zdkn=9acxHQP@aGLpr+Gt?5( zHbM-dp!Fgk$=)LNPXd=O91A?(0I|FtSH1HW-8Yt$AtO|i(>~-pmL=QWsC^2c)dr!L zf5OvFq%OdfoxgC%NVUXt1c6@pBkw=uYtPO0DS*L&v$Hc&c_VjW=Nk~jQPA=wdv2{? z0n!$B2VQViCU4`e?R*nL%Nr>j>buL1NuYcSgLjJCDX*&HW|?JA>5zZ`gadD+!t%0O z`|!X1?rYU2eDem~$Mby#)snePr@9Y^y#!Gu-=H32o$dc%>Vk;~@s*lVsYU6_T8FHD zo&Wq6=L&AvyvLc&?-$XQ?{mB{Re&7J{3TyoyK4OvAQ341#w9X2Nr-=dY9?PJ&JO!Y zgWNsaw-@nSTUV_sz#A!3kYa%9@~A*~lcuWHr^Y+Kbx;!vrM!ZnEK9!6+C}RMV2IN7 zN}BpP=4339R9014yyi^jFBv}0G~sLF>r%&O=g=z)tzELL00yJaT@j*fob6vME;PI5 z?3157*jtDFIta$I^fim4xn%{=%U4_~kej&smwFDMR4uUdvH2=s*}@p4JZbToo0$^R zoi|5KH2d6Nqam`X?KDBI+Spk#e4NE6zr0Gv<>Df<&&#TG#Q*gjn{BxXi4ZZ&d;M(9 z4=qfkilPV4|J&WPv6YvxvgKAeXjS8Y;ZLRp^0udkPbB!z>s^_tGIfrn5!1TuWyzc zcH3O(y<49zVqJ>L%Spd*w*DKv0X-9_R)Csw0IyR3TQow~ZSSGR!){Q3w^AYj^@8bK zj9z+Q=j)_i)%skDAdbZg+JNyDpmT3Lzq1^?mcx(N%rky?^2yJ=?R227d+`-RfwhJa zKr+;`(l~~ttXrNQ_OF#RG6m4fL@-SP#Q?l-wo0GyHq7j12t$w({_w*dF5fb@w>#7M zPxl^RF_?5@lw)};d$x)ob;NkH&nxwMUi&uPp}O3HPzC~M&}tQ^^orR2y7Xun&ip~c zO%pz~J73Lp{=hcv7}%zr+2^IYO7BzvWDg`l!N05%pstIJirh2uxQt-lOo>tuKHWVn zi8UnL>wH(DlW`gZ9X&0FHP)TVq@>b(JJl8Y`9DpRXa%S@c)(Mr-T95mjmsSfI%*7u zDtd+gN4vd%Dl!zxFzfqNOUl?KC6 zs$PvZKKa*6ZZqerb&a_50SHq7$DQunh&Mj@WjY;G)~~c^muOT-!ZdhEt{+QyU;oyuRF3$ja|Keo;ktp%h{xjyq_oHd*iD#JSB2=Q2~qooxxuZ zf8W?Ad=?R;rIY}Ho)!cQkwELGK4$Ztc^O++zVBPR>x^vLoEQ2HW==vsyCZldlJ72E zV8zjctjPS43M+x7cL61Ww3GrM*wd02NgXks`GYKv0M6{^3j_(R!Wk9Sk$w@8vgUJJvQqL(OE_^Oj{`ZE*_nObVle4l$W0B%+aSC~0g`rZ1u#_H_mO6cWxs<IqMI9{cMjxSrl8#X=$w&Jj{CY?EGpz|!3_k0 z5mC{A;Uux|E?od1F|q@J)fvi;<>%ToIQa;LQ8i@Pcl8oQ73Bxl^s zBe7kS>F*~K`Z|;~)EQPDyK|QFv{=ihl^S^@Hs196+LM;u+dPVo%+!#SdY-hDB7}P) zgWnrBnH|~ZEDqWBGP_QP$F^w6;I{4AedW${rb_DR`oZta%6>R;Dv6PXkz>ZjRUE2g z7r0@=y9Z!f)>(3H-y)((Q^K1xWk}m7c3r+;cAp{yQ)BNadrifu$+*=Yk!{21bjfuF zsX|^}d`W{qlEzVRPjpb5rp@^6ePfxM{$+#8D?;!@^$>i%@FpFahoA_-oP@r$6acVz zL~G5b@M3YH!^gN*Njy1&Znf=9((Fh&O}VwXFbTv~0-Q-t7y2~!)iOEE5x0k)h! z!|D@907z&R&P)9rd+P-I2k>z9Kla;8SzIbE;>h?Eyi#Aq z+LM{4&yC6;5Ii2&OGRm|bD^k!-IooF|^uxIW0Dx#k(`;*(!prEm{Jw^J4ve1=BZv$|VaaX2Gz^aS2jx zHvU>8OIUFRrOgX*gL8;pN`A3yOw54NksOkM*rqi+RRAxOjcmT;dwAu>epLNp3>({tb zmPP;0;AFKSW?Xa^tM^Ul7(<(Cqsq;)QqC3Ju=r!NGyJS;Jk9+4T`oV=UgEtv@IK;O z8f^SuoH_24wbNxNVs*_wYkLKk`E4Pv@+x4yuyq0DRXU#8x{>XVK55gIKPRD|>Gvl$ ztz*OK;}-AxaN;!PB=n_;uOHL9_Ta-K->WWjUA{PTf})CYn)~_lOrJYvGI-_MA94uJ z-BI&{+6ti6>PTC-0_1#mNtBU&o=-9lnasO&2@4G3fzGjjVMlHA`O{YG`ty%IcxHA|3p*bOG~Uiendq-M)B9W2TPmB1?Y7jp!m$g zjc!7}+Wr+2I>yk-g4_0EalP>OF^Kv3$)h&U;oE-UoN1$GSi25%3u|Sv*twFG#}3sp zLajP}*lt(yXZsAac|9{PS1kpQ=ye~~{m@(il2gx+ma++$q(-Y(Zx@@+>np3Wyd9cf zTEZ(kHla-%4bME({gTn`y)x9SGd_Vf*-aDZTde(0kZPm6Bww^PxTkNLsQ5@XFJ}?_n3KNq&91 ztsCmk51_Al5yfXLE=(jbx8D$x{~Q?X=og9#IFNIhBiFB4Ec3Ij@$_nK+hBR{+Evz` z%A{j(C{OpUeR8T!ujlIRVlEUG@Xf_6is~%&p6fG+sOG^O&%e&!j{ay?_d{K}F*GuY z;))6u@6Is0-Z#80k93WvbG2i~#o|IXojb+0tTS%esRWAgrQQ=@>sNr})H5tg`5lsZ zs)%KQ***GNbgKeGW{zKM-e9(#pBfX#ta|qTR~|dW+EbZCH4m{Gat?-d{tM|}*6Qdd z;(If=ZF{~rbHbtmjOoysx&4NabNf~;1@I9H?~R+xQ@#6}nYUl;H-sJ8=a{zsAFkgg zkZ5^%vF$x}>`?#!O^KGuplN{h9UB!mns<#)G7k};(GVRR!qk{J5+ggX_laj1z3Q)g zpL4~mOkQaT?^?(u3|O?F{psMoYD0`dWV7Z>i;bssP!m3!IE_QOIULM2KZwE+mW{mM zG}^2?b&StX9z`!DqoO+T^Pc?}71fCq5B!XW)_vksJN1xB==FE)xzRoac=_#8mM(l6 zMW*9I6Y;4V`L!Z^<_B$I>x?<{Y8}DK2WQax<3E_0g7ZsD`0c-U)UC=Y|2THIR-T{b z`@ZAUFJHn(C_K_N-YEs>9MZz%=lI?ad-?D5f10kXK5>LI1^Fx=If2Pty3w;$gsXBD z=n?v7>)QOSVS5r-ljPU8Bc)qULC!6?&Frt%0?@TZOD1>jrg|Ia3T|+{#Nb^N;ve8t zU5~}}LJ@+Bsw#fH%iNIq{=xm6zM0Rtf*bS=Z|hWBR*|GyviMoUu_RGJ#q%j`J`!+` z;~j>8(z69O=p535DKXvo?Br2Z>+jV%g77AWO{jfWFF94$ptkJ+ICV46V*cRbigIHA z^0rfL)WaS^uWKDC;Fto;eYc#{*B(RY_X751TvCB^)e6ut#QbQN)>Xdxw4_ zj;D!BT9nE1lqb-$7B_7fU#mWmt7V|M&V>d9T8uB)eEzgW1$d^nxnc8SaUqL#?=Zy| zG!$dlcwwCxe)8ZE1pC+aP|C`S~-sOE;#(bm!YyzhuH^e{;&0u)Nv_ zplO}h|L6J)qFuAvvA0s9q5_Ci=D%(|PTd9#PZU|InMYt{J78wL_c}@E>R^w{7Tl)` z%FFoE!F_huwIlm{tyRE>N4{s*V^1+OGK$|Mj$uUh2Mw0<%B>=LwT_^D^V*Kp&u-ml z3TXLw(jzLzFp5=_Y8E!MwEe4qx@fg}LasjnY-w;EcF?wIGn1eF_G~kM236QwJ^3>_ zbiy5HkX&Cv^4ZCwe0K7v)32FY2(}YgI2*0D z!I7s8R{+2;;i#OBz$MOiK0@L5V;)4KDBP;3Fhu~VP0v>00JW@hMsMYwts)2wsGUgF zSMgy;^^E^m4GX0)?lH*MmsbWPxan42N3KZz?z32<<%XVIe8L32= zd8?gRQd!BfTfbmMW^H@?$_J;{yBA>0Ni?E;M>77ycD|rJS1xk@nvZL33MCI7!Q$a# zt-7om^9j|Ysh=O8PM*nwovl9$N3LIE!e<{hG^6=xd>F_7EH=+d(E!xT7M`4%#ggP9 z_$Xfj7Tu4maXde_)(%-&RV5dT3fXhzBA*;PWYMT{w%`T_>WL>bX8$OzD7UzeP@=2g zLSX@$&!1-Xi6iLrwO^%6_v~c%m2Bqr8^Yi=?P(DhNI_W{`*SYy#~=5y>702$^{t8u z9$xneGrA=(C!sGrT80xE5I}xuDF<_}vi{UD{+@ZTp>u%)D83KyKib@e6t;x=>v*lU zDS?%r1NW<5_fHwYb^?5-GFPkWIW_8MAjrt5VAz;7_{tcdhwAnJB$4YV^?QW*+S_W^ z?3xr585va!8@(PseISP9Q{I=0ws9aqq*ChpELyEga?H8DW0o%*i(Y;LguA@0yNf)8 z_%G(Y?oyXL_dJ|a7|y*{ zf;A-YE+N++<)z=df0M3 zUINrT+pTd@0^&E6`u2Bs=Yyw*;xuhrs7wW(@TeS~<4dIOd6LpRc4mWjyo=Koi~;4> zAn)_EC~jg8dXZ9J(1ttk4h1lhnlc>00`6Wb;y#4F?ICuf239LT8p3wRY*L99UV7v{Zw*3-gR!@Cv0 zh*qm1NH-R}oQYrx5aMZ(tZ)<9fRw8#^ZOdD)_OuCFQIWLKuxq-KLRU8fS7<}0s{Bs zh__BAh|MT$=Cat850hNj9WgHLlA_)8O9isUJU4vlpx3l@ + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/images/preview.png b/images/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..dfbcd81b735002d72522ceb61363987b26b0155b GIT binary patch literal 91243 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�m-hu$xNz0>uwA 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�gkWNtT(9+9B^L$`t^(ES+@HoH5E2o03I4> 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 FV1iWpQ;`4w literal 0 HcmV?d00001 diff --git a/images/tutorial1.png b/images/tutorial1.png new file mode 100644 index 0000000000000000000000000000000000000000..73920d374b9370875734abd1024c79d04de192f2 GIT binary patch literal 44078 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 literal 0 HcmV?d00001 diff --git a/images/tutorial2.png b/images/tutorial2.png new file mode 100644 index 0000000000000000000000000000000000000000..2540f0daf1b4ab479e8e94ddeb6642de74656d30 GIT binary patch literal 54388 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 literal 0 HcmV?d00001 diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..416ec04 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,2632 @@ +{ + "name": "debug", + "version": "0.26.0", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "debug", + "version": "0.26.0", + "license": "public domain", + "dependencies": { + "ssh2": "^1.6.0", + "vscode-debugadapter": "^1.45.0", + "vscode-debugprotocol": "^1.45.0" + }, + "devDependencies": { + "@types/mocha": "^5.2.6", + "@types/node": "^11.11.3", + "@types/vscode": "^1.55.0", + "mocha": "^9.1.3", + "tslint": "^5.20.1", + "typescript": "^3.9.3", + "vscode-test": "1.3.0" + }, + "engines": { + "vscode": "^1.55.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", + "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.16.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", + "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.15.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "node_modules/@types/node": { + "version": "11.15.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.54.tgz", + "integrity": "sha512-1RWYiq+5UfozGsU6MwJyFX6BtktcT10XRjvcAQmskCtMcW3tPske88lM/nHv7BQG1w9KBXI1zPGuu5PnNCX14g==", + "dev": true + }, + "node_modules/@types/vscode": { + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.62.0.tgz", + "integrity": "sha512-iGlQJ1w5e3qPUryroO6v4lxg3ql1ztdTCwQW3xEwFawdyPLoeUSv48SYfMwc7kQA7h6ThUqflZIjgKAykeF9oA==", + "dev": true + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "node_modules/agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "dependencies": { + "es6-promisify": "^5.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "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 + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "node_modules/builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/chalk/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/chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "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/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.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": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "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=", + "dev": true + }, + "node_modules/cpu-features": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.2.tgz", + "integrity": "sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "nan": "^2.14.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "deprecated": "Debug versions >=3.2.0 <3.2.7 || >=4 <4.3.1 have a low-severity ReDos regression when used in a Node.js environment. It is recommended you upgrade to 3.2.7 or 4.3.1. (https://github.com/visionmedia/debug/issues/797)", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "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 + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "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/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "bin": { + "flat": "cli.js" + } + }, + "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==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "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/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "engines": { + "node": ">=4.x" + } + }, + "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/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "bin": { + "he": "bin/he" + } + }, + "node_modules/http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "dependencies": { + "agent-base": "4", + "debug": "3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "node_modules/http-proxy-agent/node_modules/debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/http-proxy-agent/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "node_modules/https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "dependencies": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + }, + "engines": { + "node": ">= 4.5.0" + } + }, + "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/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==", + "dev": true, + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "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=", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "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==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "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 + }, + "node_modules/js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/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, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/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 + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "node_modules/mkdirp": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "deprecated": "Legacy versions of mkdirp are no longer supported. Please update to mkdirp 1.x. (Note that the API surface has changed to use Promises in 1.x.)", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "dev": true, + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/mocha/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/mocha/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/mocha/node_modules/debug/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/mocha/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mocha/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/mocha/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 + }, + "node_modules/ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "node_modules/nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "optional": true + }, + "node_modules/nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "dev": true, + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "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==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "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/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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/picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true, + "engines": { + "node": ">=0.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": "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/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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "node_modules/ssh2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.6.0.tgz", + "integrity": "sha512-lxc+uvXqOxyQ99N2M7k5o4pkYDO5GptOTYduWw7hIM41icxvoBcCNHcj+LTKrjkL0vFcAl+qfZekthoSFRJn2Q==", + "hasInstallScript": true, + "dependencies": { + "asn1": "^0.2.4", + "bcrypt-pbkdf": "^1.0.2" + }, + "engines": { + "node": ">=10.16.0" + }, + "optionalDependencies": { + "cpu-features": "0.0.2", + "nan": "^2.15.0" + } + }, + "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, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "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, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-color/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "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==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "bin": { + "tslint": "bin/tslint" + }, + "engines": { + "node": ">=4.8.0" + }, + "peerDependencies": { + "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" + } + }, + "node_modules/tslint/node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tslint/node_modules/tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "peerDependencies": { + "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "node_modules/typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/vscode-debugadapter": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.50.0.tgz", + "integrity": "sha512-KHtwd6uHOqB1C2/1hpKQcD4JY/88QXkieubzKQfT1PTLztnoM53Pz+pTNgH+VXrGDI50BzjLV6YOluPTufUaMQ==", + "dependencies": { + "mkdirp": "^1.0.4", + "vscode-debugprotocol": "1.50.1" + } + }, + "node_modules/vscode-debugadapter/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/vscode-debugprotocol": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.50.1.tgz", + "integrity": "sha512-kIHIipklHnSjBm2KkRqTJLKL2FMZlJl0+/qpJt2y62YOamMNwcxNATnXXRgAwnzKKRMweqp93tJ83UTJ8+O7SQ==" + }, + "node_modules/vscode-test": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz", + "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==", + "dev": true, + "dependencies": { + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.4", + "rimraf": "^2.6.3" + }, + "engines": { + "node": ">=8.9.3" + } + }, + "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, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "dev": true + }, + "node_modules/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, + "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/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, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/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, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/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 + }, + "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/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.0.tgz", + "integrity": "sha512-IF4EOMEV+bfYwOmNxGzSnjR2EmQod7f1UXOpZM3l4i4o4QNwzjtJAu/HxdjHq0aYBvdqMuQEY1eg0nqW9ZPORA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.0" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.15.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz", + "integrity": "sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.0.tgz", + "integrity": "sha512-t8MH41kUQylBtu2+4IQA3atqevA2lRgqA2wyVB/YiWmsDSuylZZuXOUy9ric30hfzauEFfdsuk/eXTRrGrfd0g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.15.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@types/mocha": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-5.2.7.tgz", + "integrity": "sha512-NYrtPht0wGzhwe9+/idPaBB+TqkY9AhTvOLMkThm0IoEfLaiVQZwBwyJ5puCkO3AUCWrmcoePjp2mbFocKy4SQ==", + "dev": true + }, + "@types/node": { + "version": "11.15.54", + "resolved": "https://registry.npmjs.org/@types/node/-/node-11.15.54.tgz", + "integrity": "sha512-1RWYiq+5UfozGsU6MwJyFX6BtktcT10XRjvcAQmskCtMcW3tPske88lM/nHv7BQG1w9KBXI1zPGuu5PnNCX14g==", + "dev": true + }, + "@types/vscode": { + "version": "1.62.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.62.0.tgz", + "integrity": "sha512-iGlQJ1w5e3qPUryroO6v4lxg3ql1ztdTCwQW3xEwFawdyPLoeUSv48SYfMwc7kQA7h6ThUqflZIjgKAykeF9oA==", + "dev": true + }, + "@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true + }, + "agent-base": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", + "dev": true, + "requires": { + "es6-promisify": "^5.0.0" + } + }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "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 + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "camelcase": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz", + "integrity": "sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg==", + "dev": true + }, + "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" + }, + "dependencies": { + "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" + } + } + } + }, + "chokidar": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz", + "integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==", + "dev": true, + "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" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "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": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "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=", + "dev": true + }, + "cpu-features": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.2.tgz", + "integrity": "sha512-/2yieBqvMcRj8McNzkycjW2v3OIUOibBfd2dLEJ0nWts8NobAxwiyw9phVNS6oDL8x8tz9F7uNVFEVpJncQpeA==", + "optional": true, + "requires": { + "nan": "^2.14.1" + } + }, + "debug": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", + "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true + }, + "diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true + }, + "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 + }, + "es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "dev": true + }, + "es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=", + "dev": true, + "requires": { + "es6-promise": "^4.0.3" + } + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "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 + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": 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==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": 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==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "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 + }, + "he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true + }, + "http-proxy-agent": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz", + "integrity": "sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg==", + "dev": true, + "requires": { + "agent-base": "4", + "debug": "3.1.0" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + } + } + }, + "https-proxy-agent": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "dev": true, + "requires": { + "agent-base": "^4.3.0", + "debug": "^3.1.0" + } + }, + "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 + }, + "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==", + "dev": true, + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-core-module": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", + "integrity": "sha512-vd15qHsaqrRL7dtH6QNuy0ndJmRDrS9HAM1CAiSifNUFv4x1a0CCVsj18hJ1mShxIG6T2i1sO78MkP56r0nYRw==", + "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=", + "dev": true + }, + "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 + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "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==", + "dev": true + }, + "is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "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 + }, + "js-yaml": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", + "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==", + "dev": true + }, + "mkdirp": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.4.tgz", + "integrity": "sha512-iG9AK/dJLtJ0XNgTuDbSyNS3zECqDlAhnQW4CsNxBG3LQJBbHmRX1egw39DmtOdCAqY+dKXV+sgPgilNWUKMVw==", + "dev": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mocha": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.1.3.tgz", + "integrity": "sha512-Xcpl9FqXOAYqI3j79pEtHBBnQgVXIhpULjGQa7DVb0Po+VzmSIK9kanAiWLHoRR/dbZ2qpdPshuXr8l1VaHCzw==", + "dev": true, + "requires": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.2", + "debug": "4.3.2", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.1.7", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "3.0.4", + "ms": "2.1.3", + "nanoid": "3.1.25", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.1.5", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "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 + }, + "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" + }, + "dependencies": { + "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 + } + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "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 + } + } + }, + "ms": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz", + "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==", + "dev": true + }, + "nan": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.15.0.tgz", + "integrity": "sha512-8ZtvEnA2c5aYCZYd1cvgdnU6cqwixRoYg70xPLWUws5ORTa/lnw+u4amixRS/Ac5U5mQVgp9pnlSUnbNWFaWZQ==", + "optional": true + }, + "nanoid": { + "version": "3.1.25", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz", + "integrity": "sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "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" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "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 + }, + "picomatch": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz", + "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "requires": { + "picomatch": "^2.2.1" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "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": "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" + } + }, + "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 + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "requires": { + "randombytes": "^2.1.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "ssh2": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/ssh2/-/ssh2-1.6.0.tgz", + "integrity": "sha512-lxc+uvXqOxyQ99N2M7k5o4pkYDO5GptOTYduWw7hIM41icxvoBcCNHcj+LTKrjkL0vFcAl+qfZekthoSFRJn2Q==", + "requires": { + "asn1": "^0.2.4", + "bcrypt-pbkdf": "^1.0.2", + "cpu-features": "0.0.2", + "nan": "^2.15.0" + } + }, + "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, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "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, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "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==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tslint": { + "version": "5.20.1", + "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", + "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "builtin-modules": "^1.1.1", + "chalk": "^2.3.0", + "commander": "^2.12.1", + "diff": "^4.0.1", + "glob": "^7.1.1", + "js-yaml": "^3.13.1", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.1", + "resolve": "^1.3.2", + "semver": "^5.3.0", + "tslib": "^1.8.0", + "tsutils": "^2.29.0" + }, + "dependencies": { + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "tsutils": { + "version": "2.29.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", + "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + } + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" + }, + "typescript": { + "version": "3.9.10", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.9.10.tgz", + "integrity": "sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==", + "dev": true + }, + "vscode-debugadapter": { + "version": "1.50.0", + "resolved": "https://registry.npmjs.org/vscode-debugadapter/-/vscode-debugadapter-1.50.0.tgz", + "integrity": "sha512-KHtwd6uHOqB1C2/1hpKQcD4JY/88QXkieubzKQfT1PTLztnoM53Pz+pTNgH+VXrGDI50BzjLV6YOluPTufUaMQ==", + "requires": { + "mkdirp": "^1.0.4", + "vscode-debugprotocol": "1.50.1" + }, + "dependencies": { + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "vscode-debugprotocol": { + "version": "1.50.1", + "resolved": "https://registry.npmjs.org/vscode-debugprotocol/-/vscode-debugprotocol-1.50.1.tgz", + "integrity": "sha512-kIHIipklHnSjBm2KkRqTJLKL2FMZlJl0+/qpJt2y62YOamMNwcxNATnXXRgAwnzKKRMweqp93tJ83UTJ8+O7SQ==" + }, + "vscode-test": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz", + "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==", + "dev": true, + "requires": { + "http-proxy-agent": "^2.1.0", + "https-proxy-agent": "^2.2.4", + "rimraf": "^2.6.3" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "workerpool": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.1.5.tgz", + "integrity": "sha512-XdKkCK0Zqc6w3iTxLckiuJ81tiD/o5rBE/m+nXpRCB+/Sq4DqkfXZ/x0jW02DG1tGsfUGXbTJyZDP+eu67haSw==", + "dev": true + }, + "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, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "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, + "requires": { + "color-convert": "^2.0.1" + } + }, + "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, + "requires": { + "color-name": "~1.1.4" + } + }, + "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 + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } + }, + "yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true + }, + "yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "requires": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + } + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..79604e0 --- /dev/null +++ b/package.json @@ -0,0 +1,1041 @@ +{ + "name": "debug", + "displayName": "Native Debug", + "description": "GDB, LLDB & Mago-MI Debugger support for VSCode", + "keywords": [ + "gdb", + "lldb", + "mago-mi", + "native", + "debug" + ], + "license": "public domain", + "version": "0.26.0", + "publisher": "webfreak", + "icon": "images/icon.png", + "engines": { + "vscode": "^1.55.0" + }, + "main": "./out/src/frontend/extension", + "activationEvents": [ + "onCommand:code-debug.examineMemoryLocation", + "onCommand:code-debug.getFileNameNoExt", + "onCommand:code-debug.getFileBasenameNoExt" + ], + "categories": [ + "Debuggers" + ], + "repository": { + "type": "git", + "url": "https://github.com/WebFreak001/code-debug.git" + }, + "capabilities": { + "untrustedWorkspaces": { + "supported": true + } + }, + "contributes": { + "commands": [ + { + "command": "code-debug.examineMemoryLocation", + "title": "Code-Debug: Examine memory location" + } + ], + "breakpoints": [ + {"language": "c"}, + {"language": "cpp"}, + {"language": "d"}, + {"language": "objective-c"}, + {"language": "fortran"}, + {"language": "fortran-modern"}, + {"language": "fortran90"}, + {"language": "fortran_free-form"}, + {"language": "fortran_fixed-form"}, + {"language": "rust"}, + {"language": "pascal"}, + {"language": "objectpascal"}, + {"language": "ada"}, + {"language": "nim"}, + {"language": "arm"}, + {"language": "asm"}, + {"language": "vala"}, + {"language": "crystal"}, + {"language": "kotlin"}, + {"language": "zig"} + ], + "debuggers": [ + { + "type": "gdb", + "program": "./out/src/gdb.js", + "runtime": "node", + "label": "GDB", + "languages": [ + "c", + "cpp", + "d", + "objective-c", + "fortran", + "fortran-modern", + "fortran90", + "fortran_free-form", + "fortran_fixed-form", + "rust", + "pascal", + "objectpascal", + "ada", + "nim", + "arm", + "asm", + "vala", + "crystal", + "kotlin", + "zig" + ], + "variables": { + "FileBasenameNoExt": "code-debug.getFileBasenameNoExt", + "FileNameNoExt": "code-debug.getFileNameNoExt" + }, + "configurationAttributes": { + "launch": { + "required": [ + "target", + "cwd" + ], + "properties": { + "target": { + "type": "string", + "description": "Path of executable" + }, + "arguments": { + "type": "string", + "description": "Arguments to append after the executable. You can also use pipes." + }, + "terminal": { + "type": "string", + "description": "Leave this field undefined to keep program output in the vscode console at the bottom. If this is set to empty string the program will spawn in a new console using x-terminal-emulator on linux, otherwise with the specified terminal. On windows setting this to an empty string spawns the program in a console, but no other console is supported." + }, + "cwd": { + "type": "string", + "description": "project path" + }, + "gdbpath": { + "type": "string", + "description": "Path to the gdb executable or the command if in PATH", + "default": "gdb" + }, + "env": { + "type": "object", + "description": "Environment overriding the gdb (and in turn also the process) environment", + "default": null + }, + "debugger_args": { + "type": "array", + "description": "Additional arguments to pass to GDB", + "default": [] + }, + "pathSubstitutions": { + "type": "object", + "description": "Help GDB find your source using path substitutions (GDB `substitute-path)` variable", + "default": { + "": "" + } + }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, + "printCalls": { + "type": "boolean", + "description": "Prints all GDB calls to the console", + "default": false + }, + "showDevDebugOutput": { + "type": "boolean", + "description": "Prints all GDB responses to the console", + "default": false + }, + "autorun": { + "type": "array", + "description": "GDB commands to run when starting to debug", + "default": [] + }, + "stopAtEntry": { + "type": ["boolean", "string"], + "description": "Whether debugger should stop at application entry point", + "default": false + }, + "ssh": { + "required": [ + "host", + "user", + "cwd" + ], + "type": "object", + "description": "If this is set then the extension will connect to an ssh host and run GDB there", + "properties": { + "host": { + "type": "string", + "description": "Remote host name/ip to connect to" + }, + "port": { + "type": ["number", "string"], + "description": "Remote port number", + "default": 22 + }, + "user": { + "type": "string", + "description": "Username to connect as" + }, + "password": { + "type": "string", + "description": "Plain text password (unsafe; if possible use keyfile instead)" + }, + "keyfile": { + "type": "string", + "description": "Absolute path to private key" + }, + "useAgent": { + "type": "boolean", + "description": "Auto-detect the running SSH agent (via SSH_AUTH_SOCK environment variable) and use it to perform authentication", + "default": false + }, + "sourceFileMap": { + "type": "object", + "description": "Mapping of source paths (from GDB on ssh remote) to local (IDE) paths.", + "default": { + "": "" + } + }, + "cwd": { + "type": "string", + "description": "Working directory for the debugger.\nIf `ssh.sourceFileMap` is not set, then this is also the project path on the remote for mapping with `cwd`." + }, + "forwardX11": { + "type": "boolean", + "description": "If true, the server will redirect x11 to the local host", + "default": true + }, + "x11port": { + "type": ["number", "string"], + "description": "Port to redirect X11 data to (by default port = display + 6000)", + "default": 6000 + }, + "x11host": { + "type": "string", + "description": "Hostname/ip to redirect X11 data to", + "default": "localhost" + }, + "remotex11screen": { + "type": "number", + "description": "Screen to start the application on the remote side", + "default": 0 + }, + "bootstrap": { + "type": "string", + "description": "Content will be executed on the SSH host before the debugger call." + } + } + } + } + }, + "attach": { + "required": [ + "target", + "cwd" + ], + "properties": { + "target": { + "type": "string", + "description": "PID of running program or program name or connection arguments (eg :2345) if remote is true" + }, + "remote": { + "type": "boolean", + "description": "If true this will connect to a gdbserver instead of attaching to a PID", + "default": false + }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, + "printCalls": { + "type": "boolean", + "description": "Prints all GDB calls to the console", + "default": false + }, + "showDevDebugOutput": { + "type": "boolean", + "description": "Prints all GDB responses to the console", + "default": false + }, + "executable": { + "type": "string", + "description": "Path of executable for debugging symbols" + }, + "gdbpath": { + "type": "string", + "description": "Path to the gdb executable or the command if in PATH", + "default": "gdb" + }, + "env": { + "type": "object", + "description": "Environment overriding the gdb (and in turn also the process) environment", + "default": null + }, + "debugger_args": { + "type": "array", + "description": "Additional arguments to pass to GDB", + "default": [] + }, + "pathSubstitutions": { + "type": "object", + "description": "Help GDB find your source using path substitutions (GDB `substitute-path)` variable", + "default": { + "": "" + } + }, + "cwd": { + "type": "string", + "description": "project path", + "default": "${workspaceRoot}" + }, + "autorun": { + "type": "array", + "description": "GDB commands to run when starting to debug", + "default": [] + }, + "stopAtConnect": { + "type": "boolean", + "description": "Whether debugger should stop after connecting to target", + "default": false + }, + "stopAtEntry": { + "type": ["boolean", "string"], + "description": "Whether debugger should stop at application entry point", + "default": false + }, + "ssh": { + "required": [ + "host", + "cwd", + "user" + ], + "type": "object", + "description": "If this is set then the extension will connect to an ssh host and run GDB there", + "properties": { + "host": { + "type": "string", + "description": "Remote host name/ip to connect to" + }, + "port": { + "type": ["number", "string"], + "description": "Remote port number", + "default": 22 + }, + "user": { + "type": "string", + "description": "Username to connect as" + }, + "password": { + "type": "string", + "description": "Plain text password (unsafe; if possible use keyfile instead)" + }, + "keyfile": { + "type": "string", + "description": "Absolute path to private key" + }, + "useAgent": { + "type": "boolean", + "description": "Auto-detect the running SSH agent (via SSH_AUTH_SOCK environment variable) and use it to perform authentication", + "default": false + }, + "sourceFileMap": { + "type": "object", + "description": "Mapping of source paths (from GDB on ssh remote) to local (IDE) paths.", + "default": { + "": "" + } + }, + "cwd": { + "type": "string", + "description": "Working directory for the debugger.\nIf `ssh.sourceFileMap` is not set, then this is also the project path on the remote for mapping with `cwd`." + }, + "forwardX11": { + "type": "boolean", + "description": "If true, the server will redirect x11 to the local host", + "default": true + }, + "x11port": { + "type": ["number", "string"], + "description": "Port to redirect X11 data to (by default port = display + 6000)", + "default": 6000 + }, + "x11host": { + "type": "string", + "description": "Hostname/ip to redirect X11 data to", + "default": "localhost" + }, + "remotex11screen": { + "type": "number", + "description": "Screen to start the application on the remote side", + "default": 0 + }, + "bootstrap": { + "type": "string", + "description": "Content will be executed on the SSH host before the debugger call." + } + } + } + } + } + }, + "initialConfigurations": [ + { + "name": "Debug", + "type": "gdb", + "request": "launch", + "target": "./bin/executable", + "cwd": "${workspaceRoot}", + "valuesFormatting": "parseText" + } + ], + "configurationSnippets": [ + { + "label": "GDB: Launch Program", + "description": "Starts the program using gdb", + "body": { + "type": "gdb", + "request": "launch", + "name": "${2:Launch Program}", + "target": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"", + "valuesFormatting": "parseText" + } + }, + { + "label": "GDB: Attach to PID", + "description": "Attaches to a running program pid using gdb", + "body": { + "type": "gdb", + "request": "attach", + "name": "${2:Attach to PID}", + "target": "${1:[PID]}", + "cwd": "^\"\\${workspaceRoot}\"", + "valuesFormatting": "parseText" + } + }, + { + "label": "GDB: Connect to gdbserver", + "description": "Connects to a gdbserver for debugging", + "body": { + "type": "gdb", + "request": "attach", + "name": "${3:Attach to gdbserver}", + "executable": "${1:./bin/executable}", + "target": ":${2:2345}", + "remote": true, + "cwd": "^\"\\${workspaceRoot}\"", + "valuesFormatting": "parseText" + } + }, + { + "label": "GDB: Launch over SSH", + "description": "Remotely starts the program using gdb", + "body": { + "type": "gdb", + "request": "launch", + "name": "${6:Launch Program (SSH)}", + "target": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"", + "ssh": { + "host": "${2:127.0.0.1}", + "cwd": "${3:/tmp/working}", + "keyfile": "${4:/home/my_user/.ssh/id_rsa}", + "user": "${5:remote_user}", + "sourceFileMap": { + "${6:/home/remote_user/project/}": "^\"\\${workspaceRoot}\"" + } + }, + "valuesFormatting": "parseText" + } + }, + { + "label": "GDB: Launch GUI over SSH with X11 forwarding", + "description": "Remotely starts the program using gdb with X11 forwarding", + "body": { + "type": "gdb", + "request": "launch", + "name": "${6:Launch Program (SSH + X11)}", + "target": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"", + "ssh": { + "host": "${2:127.0.0.1}", + "cwd": "${3:/home/remote_user/project/}", + "keyfile": "${4:/home/my_user/.ssh/id_rsa}", + "user": "${5:remote_user}", + "forwardX11": true, + "x11host": "localhost", + "x11port": 6000 + }, + "valuesFormatting": "parseText" + } + }, + { + "label": "GDB: Debug external embedded device", + "description": "Debugs an embedded microcontroller supported by GDB by attaching over extended-remote", + "body": { + "type": "gdb", + "request": "attach", + "name": "${6:Debug Microcontroller}", + "target": "extended-remote ${2:/dev/cu.usbmodem00000000}", + "executable": "${1:./bin/executable.elf}", + "cwd": "^\"\\${workspaceRoot}\"", + "autorun": [ + "monitor tpwr enable", + "monitor swdp_scan", + "attach 1", + "load ${1:./bin/executable.elf}" + ] + }, + "valuesFormatting": "parseText" + } + ] + }, + { + "type": "lldb-mi", + "program": "./out/src/lldb.js", + "runtime": "node", + "label": "LLDB", + "languages": [ + "c", + "cpp", + "d", + "objective-c", + "fortran", + "fortran-modern", + "fortran90", + "fortran_free-form", + "fortran_fixed-form", + "rust", + "pascal", + "objectpascal", + "ada", + "nim", + "arm", + "asm", + "vala", + "crystal", + "kotlin", + "zig" + ], + "variables": { + "FileBasenameNoExt": "code-debug.getFileBasenameNoExt", + "FileNameNoExt": "code-debug.getFileNameNoExt" + }, + "configurationAttributes": { + "launch": { + "required": [ + "target" + ], + "properties": { + "target": { + "type": "string", + "description": "Path of executable" + }, + "arguments": { + "type": "string", + "description": "Arguments to append after the executable" + }, + "cwd": { + "type": "string", + "description": "project path" + }, + "lldbmipath": { + "type": "string", + "description": "Path to the lldb-mi executable or the command if in PATH", + "default": "lldb-mi" + }, + "env": { + "type": "object", + "description": "Environment overriding the lldb-mi (and in turn also the process) environment", + "default": null + }, + "debugger_args": { + "type": "array", + "description": "Additional arguments to pass to LLDB", + "default": [] + }, + "pathSubstitutions": { + "type": "object", + "description": "Help LLDB find your source using path substitutions (LLDB `target.source-map)` variable", + "default": { + "": "" + } + }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, + "printCalls": { + "type": "boolean", + "description": "Prints all lldb calls to the console", + "default": false + }, + "showDevDebugOutput": { + "type": "boolean", + "description": "Prints all lldb responses to the console", + "default": false + }, + "autorun": { + "type": "array", + "description": "lldb commands to run when starting to debug", + "default": [] + }, + "stopAtEntry": { + "type": ["boolean", "string"], + "description": "Whether debugger should stop at application entry point", + "default": false + }, + "ssh": { + "required": [ + "host", + "cwd", + "user" + ], + "type": "object", + "description": "If this is set then the extension will connect to an ssh host and run lldb there", + "properties": { + "host": { + "type": "string", + "description": "Remote host name/ip to connect to" + }, + "port": { + "type": ["number", "string"], + "description": "Remote port number", + "default": 22 + }, + "user": { + "type": "string", + "description": "Username to connect as" + }, + "password": { + "type": "string", + "description": "Plain text password (unsafe; if possible use keyfile instead)" + }, + "keyfile": { + "type": "string", + "description": "Absolute path to private key" + }, + "useAgent": { + "type": "boolean", + "description": "Auto-detect the running SSH agent (via SSH_AUTH_SOCK environment variable) and use it to perform authentication", + "default": false + }, + "sourceFileMap": { + "type": "object", + "description": "Mapping of source paths (from GDB on ssh remote) to local (IDE) paths.", + "default": { + "": "" + } + }, + "cwd": { + "type": "string", + "description": "Working directory for the debugger.\nIf `ssh.sourceFileMap` is not set, then this is also the project path on the remote for mapping with `cwd`." + }, + "forwardX11": { + "type": "boolean", + "description": "If true, the server will redirect x11 to the local host", + "default": true + }, + "x11host": { + "type": "string", + "description": "Hostname/ip to redirect X11 data to", + "default": "localhost" + }, + "x11port": { + "type": ["number", "string"], + "description": "Port to redirect X11 data to (by default port = display + 6000)", + "default": 6000 + }, + "remotex11screen": { + "type": "number", + "description": "Screen to start the application on the remote side", + "default": 0 + }, + "bootstrap": { + "type": "string", + "description": "Content will be executed on the SSH host before the debugger call." + } + } + } + } + }, + "attach": { + "required": [ + "target" + ], + "properties": { + "target": { + "type": "string", + "description": "PID of running program or program name" + }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, + "printCalls": { + "type": "boolean", + "description": "Prints all LLDB calls to the console", + "default": false + }, + "showDevDebugOutput": { + "type": "boolean", + "description": "Prints all LLDB responses to the console", + "default": false + }, + "executable": { + "type": "string", + "description": "Path of executable for debugging symbols" + }, + "lldbmipath": { + "type": "string", + "description": "Path to the lldb-mi executable or the command if in PATH", + "default": "lldb-mi" + }, + "env": { + "type": "object", + "description": "Environment overriding the lldb-mi (and in turn also the process) environment", + "default": null + }, + "debugger_args": { + "type": "array", + "description": "Additional arguments to pass to LLDB", + "default": [] + }, + "pathSubstitutions": { + "type": "object", + "description": "Help LLDB find your source using path substitutions (LLDB `target.source-map)` variable", + "default": { + "": "" + } + }, + "cwd": { + "type": "string", + "description": "project path", + "default": "${workspaceRoot}" + }, + "autorun": { + "type": "array", + "description": "lldb commands to run when starting to debug", + "default": [] + }, + "stopAtConnect": { + "type": "boolean", + "description": "Whether debugger should stop after connecting to target", + "default": false + }, + "stopAtEntry": { + "type": ["boolean", "string"], + "description": "Whether debugger should stop at application entry point", + "default": false + } + } + } + }, + "initialConfigurations": [ + { + "name": "Debug", + "type": "lldb-mi", + "request": "launch", + "target": "./bin/executable", + "cwd": "${workspaceRoot}", + "valuesFormatting": "parseText" + } + ], + "configurationSnippets": [ + { + "label": "LLDB: Launch Program", + "description": "Starts the program using lldb-mi", + "body": { + "type": "lldb-mi", + "request": "launch", + "name": "${2:Launch Program}", + "target": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"", + "valuesFormatting": "parseText" + } + }, + { + "label": "LLDB: Attach to PID", + "description": "Attaches to a running program pid using lldb-mi", + "body": { + "type": "lldb-mi", + "request": "attach", + "name": "${2:Attach to PID}", + "target": "${1:[PID]}", + "cwd": "^\"\\${workspaceRoot}\"", + "valuesFormatting": "parseText" + } + }, + { + "label": "LLDB: Launch over SSH", + "description": "Remotely starts the program using lldb-mi", + "body": { + "type": "lldb-mi", + "request": "launch", + "name": "${6:Launch Program (SSH)}", + "target": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"", + "ssh": { + "host": "${2:127.0.0.1}", + "cwd": "${3:/home/remote_user/project/}", + "keyfile": "${4:/home/my_user/.ssh/id_rsa}", + "user": "${5:remote_user}" + }, + "valuesFormatting": "parseText" + } + }, + { + "label": "LLDB: Launch GUI over SSH with X11 forwarding", + "description": "Remotely starts the program using lldb-mi with X11 forwarding", + "body": { + "type": "lldb-mi", + "request": "launch", + "name": "${6:Launch Program (SSH + X11)}", + "target": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"", + "ssh": { + "host": "${2:127.0.0.1}", + "cwd": "${3:/home/remote_user/project/}", + "keyfile": "${4:/home/my_user/.ssh/id_rsa}", + "user": "${5:remote_user}", + "forwardX11": true, + "x11host": "localhost", + "x11port": 6000 + }, + "valuesFormatting": "parseText" + } + } + ] + }, + { + "type": "mago-mi", + "program": "./out/src/mago.js", + "runtime": "node", + "label": "Mago-MI", + "variables": { + "FileBasenameNoExt": "code-debug.getFileBasenameNoExt", + "FileNameNoExt": "code-debug.getFileNameNoExt" + }, + "configurationAttributes": { + "launch": { + "required": [ + "target" + ], + "properties": { + "target": { + "type": "string", + "description": "Path of executable" + }, + "arguments": { + "type": "string", + "description": "Arguments to append after the executable" + }, + "cwd": { + "type": "string", + "description": "project path" + }, + "magomipath": { + "type": "string", + "description": "Path to the mago-mi executable or the command if in PATH", + "default": "mago-mi" + }, + "env": { + "type": "object", + "description": "Environment overriding the mago-mi (and in turn also the process) environment", + "default": null + }, + "debugger_args": { + "type": "array", + "description": "Additional arguments to pass to mago", + "default": [] + }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, + "printCalls": { + "type": "boolean", + "description": "Prints all mago calls to the console", + "default": false + }, + "showDevDebugOutput": { + "type": "boolean", + "description": "Prints all mago responses to the console", + "default": false + }, + "autorun": { + "type": "array", + "description": "mago commands to run when starting to debug", + "default": [] + } + } + }, + "attach": { + "required": [ + "target" + ], + "properties": { + "target": { + "type": "string", + "description": "PID of running program or program name" + }, + "valuesFormatting": { + "type": "string", + "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any", + "default": "parseText", + "enum": [ + "disabled", + "parseText", + "prettyPrinters" + ] + }, + "printCalls": { + "type": "boolean", + "description": "Prints all mago calls to the console", + "default": false + }, + "showDevDebugOutput": { + "type": "boolean", + "description": "Prints all mago responses to the console", + "default": false + }, + "executable": { + "type": "string", + "description": "Path of executable for debugging symbols" + }, + "magomipath": { + "type": "string", + "description": "Path to the mago-mi executable or the command if in PATH", + "default": "mago-mi" + }, + "env": { + "type": "object", + "description": "Environment overriding the mago-mi (and in turn also the process) environment", + "default": null + }, + "debugger_args": { + "type": "array", + "description": "Additional arguments to pass to mago", + "default": [] + }, + "cwd": { + "type": "string", + "description": "project path", + "default": "${workspaceRoot}" + }, + "autorun": { + "type": "array", + "description": "mago commands to run when starting to debug", + "default": [] + }, + "stopAtConnect": { + "type": "boolean", + "description": "Whether debugger should stop after connecting to target", + "default": false + } + } + } + }, + "initialConfigurations": [ + { + "name": "Debug", + "type": "mago-mi", + "request": "launch", + "target": "./bin/executable", + "cwd": "${workspaceRoot}", + "valuesFormatting": "parseText" + } + ], + "configurationSnippets": [ + { + "label": "Mago: Launch Program", + "description": "Starts the program using mago-mi", + "body": { + "type": "mago-mi", + "request": "launch", + "name": "${2:Launch Program}", + "target": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"", + "valuesFormatting": "parseText" + } + }, + { + "label": "Mago: Attach to PID", + "description": "Attaches to a running program pid using mago-mi", + "body": { + "type": "mago-mi", + "request": "attach", + "name": "${2:Attach to PID}", + "target": "${1:[PID]}", + "cwd": "^\"\\${workspaceRoot}\"", + "valuesFormatting": "parseText" + } + } + ] + } + ] + }, + "scripts": { + "vscode:prepublish": "tsc -p ./", + "compile": "tsc -watch -p ./" + }, + "dependencies": { + "ssh2": "^1.6.0", + "vscode-debugadapter": "^1.45.0", + "vscode-debugprotocol": "^1.45.0" + }, + "devDependencies": { + "@types/mocha": "^5.2.6", + "@types/node": "^11.11.3", + "@types/vscode": "^1.55.0", + "mocha": "^9.1.3", + "tslint": "^5.20.1", + "typescript": "^3.9.3", + "vscode-test": "1.3.0" + }, + "__metadata": { + "id": "2fd22b8e-b3b8-4e7f-9a28-a5e2d1bdd0d4", + "publisherDisplayName": "WebFreak", + "publisherId": "e054f80a-50f9-4d80-85c8-6ff87eef6c35" + } +} diff --git a/src/backend/backend.ts b/src/backend/backend.ts new file mode 100644 index 0000000..10532a4 --- /dev/null +++ b/src/backend/backend.ts @@ -0,0 +1,165 @@ +import { MINode } from "./mi_parse"; +import { DebugProtocol } from "vscode-debugprotocol/lib/debugProtocol"; + +export type ValuesFormattingMode = "disabled" | "parseText" | "prettyPrinters"; + +export interface Breakpoint { + file?: string; + line?: number; + raw?: string; + condition: string; + countCondition?: string; +} + +export interface Thread { + id: number; + targetId: string; + name?: string; +} + +export interface Stack { + level: number; + address: string; + function: string; + fileName: string; + file: string; + line: number; +} + +export interface Variable { + name: string; + valueStr: string; + type: string; + raw?: any; +} + +export interface SSHArguments { + forwardX11: boolean; + host: string; + keyfile: string; + password: string; + useAgent: boolean; + cwd: string; + port: number; + user: string; + remotex11screen: number; + x11port: number; + x11host: string; + bootstrap: string; + sourceFileMap: { [index: string]: string }; +} + +export interface IBackend { + load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable; + ssh(args: SSHArguments, cwd: string, target: string, procArgs: string, separateConsole: string, attach: boolean): Thenable; + attach(cwd: string, executable: string, target: string): Thenable; + connect(cwd: string, executable: string, target: string): Thenable; + start(runToStart: boolean): Thenable; + stop(); + detach(); + interrupt(): Thenable; + continue(): Thenable; + next(): Thenable; + step(): Thenable; + stepOut(): Thenable; + loadBreakPoints(breakpoints: Breakpoint[]): Thenable<[boolean, Breakpoint][]>; + addBreakPoint(breakpoint: Breakpoint): Thenable<[boolean, Breakpoint]>; + removeBreakPoint(breakpoint: Breakpoint): Thenable; + clearBreakPoints(source?: string): Thenable; + getThreads(): Thenable; + getStack(startFrame: number, maxLevels: number, thread: number): Thenable; + getStackVariables(thread: number, frame: number): Thenable; + evalExpression(name: string, thread: number, frame: number): Thenable; + isReady(): boolean; + changeVariable(name: string, rawValue: string): Thenable; + examineMemory(from: number, to: number): Thenable; +} + +export class VariableObject { + name: string; + exp: string; + numchild: number; + type: string; + value: string; + threadId: string; + frozen: boolean; + dynamic: boolean; + displayhint: string; + hasMore: boolean; + id: number; + constructor(node: any) { + this.name = MINode.valueOf(node, "name"); + this.exp = MINode.valueOf(node, "exp"); + this.numchild = parseInt(MINode.valueOf(node, "numchild")); + this.type = MINode.valueOf(node, "type"); + this.value = MINode.valueOf(node, "value"); + this.threadId = MINode.valueOf(node, "thread-id"); + this.frozen = !!MINode.valueOf(node, "frozen"); + this.dynamic = !!MINode.valueOf(node, "dynamic"); + this.displayhint = MINode.valueOf(node, "displayhint"); + // TODO: use has_more when it's > 0 + this.hasMore = !!MINode.valueOf(node, "has_more"); + } + + public applyChanges(node: MINode) { + this.value = MINode.valueOf(node, "value"); + if (!!MINode.valueOf(node, "type_changed")) { + this.type = MINode.valueOf(node, "new_type"); + } + this.dynamic = !!MINode.valueOf(node, "dynamic"); + this.displayhint = MINode.valueOf(node, "displayhint"); + this.hasMore = !!MINode.valueOf(node, "has_more"); + } + + public isCompound(): boolean { + return this.numchild > 0 || + this.value === "{...}" || + (this.dynamic && (this.displayhint === "array" || this.displayhint === "map")); + } + + public toProtocolVariable(): DebugProtocol.Variable { + const res: DebugProtocol.Variable = { + name: this.exp, + evaluateName: this.name, + value: (this.value === void 0) ? "" : this.value, + type: this.type, + variablesReference: this.id + }; + return res; + } +} + +// from https://gist.github.com/justmoon/15511f92e5216fa2624b#gistcomment-1928632 +export interface MIError extends Error { + readonly name: string; + readonly message: string; + readonly source: string; +} +export interface MIErrorConstructor { + new (message: string, source: string): MIError; + readonly prototype: MIError; +} + +export const MIError: MIErrorConstructor = class MIError { + readonly name: string; + readonly message: string; + readonly source: string; + public constructor(message: string, source: string) { + Object.defineProperty(this, 'name', { + get: () => (this.constructor as any).name, + }); + Object.defineProperty(this, 'message', { + get: () => message, + }); + Object.defineProperty(this, 'source', { + get: () => source, + }); + Error.captureStackTrace(this, this.constructor); + } + + public toString() { + return `${this.message} (from ${this.source})`; + } +}; +Object.setPrototypeOf(MIError as any, Object.create(Error.prototype)); +MIError.prototype.constructor = MIError; diff --git a/src/backend/gdb_expansion.ts b/src/backend/gdb_expansion.ts new file mode 100644 index 0000000..143e6d5 --- /dev/null +++ b/src/backend/gdb_expansion.ts @@ -0,0 +1,258 @@ +import { MINode } from "./mi_parse"; + +const resultRegex = /^([a-zA-Z_\-][a-zA-Z0-9_\-]*|\[\d+\])\s*=\s*/; +const variableRegex = /^[a-zA-Z_\-][a-zA-Z0-9_\-]*/; +const errorRegex = /^\<.+?\>/; +const referenceStringRegex = /^(0x[0-9a-fA-F]+\s*)"/; +const referenceRegex = /^0x[0-9a-fA-F]+/; +const cppReferenceRegex = /^@0x[0-9a-fA-F]+/; +const nullpointerRegex = /^0x0+\b/; +const charRegex = /^(\d+) ['"]/; +const numberRegex = /^\d+(\.\d+)?/; +const pointerCombineChar = "."; + +export function isExpandable(value: string): number { + let match; + value = value.trim(); + if (value.length == 0) return 0; + else if (value.startsWith("{...}")) return 2; // lldb string/array + else if (value[0] == '{') return 1; // object + else if (value.startsWith("true")) return 0; + else if (value.startsWith("false")) return 0; + else if (match = nullpointerRegex.exec(value)) return 0; + else if (match = referenceStringRegex.exec(value)) return 0; + else if (match = referenceRegex.exec(value)) return 2; // reference + else if (match = charRegex.exec(value)) return 0; + else if (match = numberRegex.exec(value)) return 0; + else if (match = variableRegex.exec(value)) return 0; + else if (match = errorRegex.exec(value)) return 0; + else return 0; +} + +export function expandValue(variableCreate: Function, value: string, root: string = "", extra: any = undefined): any { + const parseCString = () => { + value = value.trim(); + if (value[0] != '"' && value[0] != '\'') + return ""; + let stringEnd = 1; + let inString = true; + const charStr = value[0]; + let remaining = value.substr(1); + let escaped = false; + while (inString) { + if (escaped) + escaped = false; + else if (remaining[0] == '\\') + escaped = true; + else if (remaining[0] == charStr) + inString = false; + + remaining = remaining.substr(1); + stringEnd++; + } + const str = value.substr(0, stringEnd).trim(); + value = value.substr(stringEnd).trim(); + return str; + }; + + const stack = [root]; + let parseValue, parseCommaResult, parseCommaValue, parseResult, createValue; + let variable = ""; + + const getNamespace = (variable) => { + let namespace = ""; + let prefix = ""; + stack.push(variable); + stack.forEach(name => { + prefix = ""; + if (name != "") { + if (name.startsWith("[")) + namespace = namespace + name; + else { + if (namespace) { + while (name.startsWith("*")) { + prefix += "*"; + name = name.substr(1); + } + namespace = namespace + pointerCombineChar + name; + } else + namespace = name; + } + } + }); + stack.pop(); + return prefix + namespace; + }; + + const parseTupleOrList = () => { + value = value.trim(); + if (value[0] != '{') + return undefined; + const oldContent = value; + value = value.substr(1).trim(); + if (value[0] == '}') { + value = value.substr(1).trim(); + return []; + } + if (value.startsWith("...")) { + value = value.substr(3).trim(); + if (value[0] == '}') { + value = value.substr(1).trim(); + return "<...>"; + } + } + const eqPos = value.indexOf("="); + const newValPos1 = value.indexOf("{"); + const newValPos2 = value.indexOf(","); + let newValPos = newValPos1; + if (newValPos2 != -1 && newValPos2 < newValPos1) + newValPos = newValPos2; + if (newValPos != -1 && eqPos > newValPos || eqPos == -1) { // is value list + const values = []; + stack.push("[0]"); + let val = parseValue(); + stack.pop(); + values.push(createValue("[0]", val)); + const remaining = value; + let i = 0; + while (true) { + stack.push("[" + (++i) + "]"); + if (!(val = parseCommaValue())) { + stack.pop(); + break; + } + stack.pop(); + values.push(createValue("[" + i + "]", val)); + } + value = value.substr(1).trim(); // } + return values; + } + + let result = parseResult(true); + if (result) { + const results = []; + results.push(result); + while (result = parseCommaResult(true)) + results.push(result); + value = value.substr(1).trim(); // } + return results; + } + + return undefined; + }; + + const parsePrimitive = () => { + let primitive: any; + let match; + value = value.trim(); + if (value.length == 0) + primitive = undefined; + else if (value.startsWith("true")) { + primitive = "true"; + value = value.substr(4).trim(); + } else if (value.startsWith("false")) { + primitive = "false"; + value = value.substr(5).trim(); + } else if (match = nullpointerRegex.exec(value)) { + primitive = ""; + value = value.substr(match[0].length).trim(); + } else if (match = referenceStringRegex.exec(value)) { + value = value.substr(match[1].length).trim(); + primitive = parseCString(); + } else if (match = referenceRegex.exec(value)) { + primitive = "*" + match[0]; + value = value.substr(match[0].length).trim(); + } else if (match = cppReferenceRegex.exec(value)) { + primitive = match[0]; + value = value.substr(match[0].length).trim(); + } else if (match = charRegex.exec(value)) { + primitive = match[1]; + value = value.substr(match[0].length - 1); + primitive += " " + parseCString(); + } else if (match = numberRegex.exec(value)) { + primitive = match[0]; + value = value.substr(match[0].length).trim(); + } else if (match = variableRegex.exec(value)) { + primitive = match[0]; + value = value.substr(match[0].length).trim(); + } else if (match = errorRegex.exec(value)) { + primitive = match[0]; + value = value.substr(match[0].length).trim(); + } else { + primitive = value; + } + return primitive; + }; + + parseValue = () => { + value = value.trim(); + if (value[0] == '"') + return parseCString(); + else if (value[0] == '{') + return parseTupleOrList(); + else + return parsePrimitive(); + }; + + parseResult = (pushToStack: boolean = false) => { + value = value.trim(); + const variableMatch = resultRegex.exec(value); + if (!variableMatch) + return undefined; + value = value.substr(variableMatch[0].length).trim(); + const name = variable = variableMatch[1]; + if (pushToStack) + stack.push(variable); + const val = parseValue(); + if (pushToStack) + stack.pop(); + return createValue(name, val); + }; + + createValue = (name, val) => { + let ref = 0; + if (typeof val == "object") { + ref = variableCreate(val); + val = "Object"; + } else if (typeof val == "string" && val.startsWith("*0x")) { + if (extra && MINode.valueOf(extra, "arg") == "1") { + ref = variableCreate(getNamespace("*(" + name), { arg: true }); + val = ""; + } else { + ref = variableCreate(getNamespace("*" + name)); + val = "Object@" + val; + } + } else if (typeof val == "string" && val.startsWith("@0x")) { + ref = variableCreate(getNamespace("*&" + name.substr)); + val = "Ref" + val; + } else if (typeof val == "string" && val.startsWith("<...>")) { + ref = variableCreate(getNamespace(name)); + val = "..."; + } + return { + name: name, + value: val, + variablesReference: ref + }; + }; + + parseCommaValue = () => { + value = value.trim(); + if (value[0] != ',') + return undefined; + value = value.substr(1).trim(); + return parseValue(); + }; + + parseCommaResult = (pushToStack: boolean = false) => { + value = value.trim(); + if (value[0] != ',') + return undefined; + value = value.substr(1).trim(); + return parseResult(pushToStack); + }; + + + value = value.trim(); + return parseValue(); +} diff --git a/src/backend/linux/console.ts b/src/backend/linux/console.ts new file mode 100644 index 0000000..464d697 --- /dev/null +++ b/src/backend/linux/console.ts @@ -0,0 +1,21 @@ +import * as ChildProcess from "child_process"; +import * as fs from "fs"; + +export function spawnTerminalEmulator(preferedEmulator: string): Thenable { + return new Promise((resolve, reject) => { + const ttyFileOutput = "/tmp/vscode-gdb-tty-0" + Math.floor(Math.random() * 100000000).toString(36); + ChildProcess.spawn(preferedEmulator || "x-terminal-emulator", ["-e", "sh -c \"tty > " + ttyFileOutput + " && sleep 4294967294\""]); + let it = 0; + const interval = setInterval(() => { + if (fs.existsSync(ttyFileOutput)) { + clearInterval(interval); + const tty = fs.readFileSync(ttyFileOutput).toString("utf8"); + fs.unlinkSync(ttyFileOutput); + return resolve(tty); + } + it++; + if (it > 500) + reject(); + }, 10); + }); +} diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts new file mode 100644 index 0000000..47b666a --- /dev/null +++ b/src/backend/mi2/mi2.ts @@ -0,0 +1,888 @@ +import { Breakpoint, IBackend, Thread, Stack, SSHArguments, Variable, VariableObject, MIError } from "../backend"; +import * as ChildProcess from "child_process"; +import { EventEmitter } from "events"; +import { parseMI, MINode } from '../mi_parse'; +import * as linuxTerm from '../linux/console'; +import * as net from "net"; +import * as fs from "fs"; +import * as path from "path"; +import { Client } from "ssh2"; + +export function escape(str: string) { + return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\""); +} + +const nonOutput = /^(?:\d*|undefined)[\*\+\=]|[\~\@\&\^]/; +const gdbMatch = /(?:\d*|undefined)\(gdb\)/; +const numRegex = /\d+/; + +function couldBeOutput(line: string) { + if (nonOutput.exec(line)) + return false; + return true; +} + +const trace = false; + +export class MI2 extends EventEmitter implements IBackend { + constructor(public application: string, public preargs: string[], public extraargs: string[], procEnv: any, public extraCommands: string[] = []) { + super(); + + if (procEnv) { + const env = {}; + // Duplicate process.env so we don't override it + for (const key in process.env) + if (process.env.hasOwnProperty(key)) + env[key] = process.env[key]; + + // Overwrite with user specified variables + for (const key in procEnv) { + if (procEnv.hasOwnProperty(key)) { + if (procEnv === null) + delete env[key]; + else + env[key] = procEnv[key]; + } + } + this.procEnv = env; + } + } + + load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable { + if (!path.isAbsolute(target)) + target = path.join(cwd, target); + return new Promise((resolve, reject) => { + this.isSSH = false; + const args = this.preargs.concat(this.extraargs || []); + this.process = ChildProcess.spawn(this.application, args, { cwd: cwd, env: this.procEnv }); + this.process.stdout.on("data", this.stdout.bind(this)); + this.process.stderr.on("data", this.stderr.bind(this)); + this.process.on("exit", (() => { this.emit("quit"); }).bind(this)); + this.process.on("error", ((err) => { this.emit("launcherror", err); }).bind(this)); + const promises = this.initCommands(target, cwd); + if (procArgs && procArgs.length) + promises.push(this.sendCommand("exec-arguments " + procArgs)); + if (process.platform == "win32") { + if (separateConsole !== undefined) + promises.push(this.sendCommand("gdb-set new-console on")); + Promise.all(promises).then(() => { + this.emit("debug-ready"); + resolve(undefined); + }, reject); + } else { + if (separateConsole !== undefined) { + linuxTerm.spawnTerminalEmulator(separateConsole).then(tty => { + promises.push(this.sendCommand("inferior-tty-set " + tty)); + Promise.all(promises).then(() => { + this.emit("debug-ready"); + resolve(undefined); + }, reject); + }); + } else { + Promise.all(promises).then(() => { + this.emit("debug-ready"); + resolve(undefined); + }, reject); + } + } + }); + } + + ssh(args: SSHArguments, cwd: string, target: string, procArgs: string, separateConsole: string, attach: boolean): Thenable { + return new Promise((resolve, reject) => { + this.isSSH = true; + this.sshReady = false; + this.sshConn = new Client(); + + if (separateConsole !== undefined) + this.log("stderr", "WARNING: Output to terminal emulators are not supported over SSH"); + + if (args.forwardX11) { + this.sshConn.on("x11", (info, accept, reject) => { + const xserversock = new net.Socket(); + xserversock.on("error", (err) => { + this.log("stderr", "Could not connect to local X11 server! Did you enable it in your display manager?\n" + err); + }); + xserversock.on("connect", () => { + const xclientsock = accept(); + xclientsock.pipe(xserversock).pipe(xclientsock); + }); + xserversock.connect(args.x11port, args.x11host); + }); + } + + const connectionArgs: any = { + host: args.host, + port: args.port, + username: args.user + }; + + if (args.useAgent) { + connectionArgs.agent = process.env.SSH_AUTH_SOCK; + } else if (args.keyfile) { + if (require("fs").existsSync(args.keyfile)) + connectionArgs.privateKey = require("fs").readFileSync(args.keyfile); + else { + this.log("stderr", "SSH key file does not exist!"); + this.emit("quit"); + reject(); + return; + } + } else { + connectionArgs.password = args.password; + } + + this.sshConn.on("ready", () => { + this.log("stdout", "Running " + this.application + " over ssh..."); + const execArgs: any = {}; + if (args.forwardX11) { + execArgs.x11 = { + single: false, + screen: args.remotex11screen + }; + } + let sshCMD = this.application + " " + this.preargs.concat(this.extraargs || []).join(" "); + if (args.bootstrap) sshCMD = args.bootstrap + " && " + sshCMD; + this.sshConn.exec(sshCMD, execArgs, (err, stream) => { + if (err) { + this.log("stderr", "Could not run " + this.application + "(" + sshCMD +") over ssh!"); + if (err === undefined) { + err = "" + } + this.log("stderr", err.toString()); + this.emit("quit"); + reject(); + return; + } + this.sshReady = true; + this.stream = stream; + stream.on("data", this.stdout.bind(this)); + stream.stderr.on("data", this.stderr.bind(this)); + stream.on("exit", (() => { + this.emit("quit"); + this.sshConn.end(); + }).bind(this)); + const promises = this.initCommands(target, cwd, attach); + promises.push(this.sendCommand("environment-cd \"" + escape(cwd) + "\"")); + if (attach) { + // Attach to local process + promises.push(this.sendCommand("target-attach " + target)); + } else if (procArgs && procArgs.length) + promises.push(this.sendCommand("exec-arguments " + procArgs)); + Promise.all(promises).then(() => { + this.emit("debug-ready"); + resolve(undefined); + }, reject); + }); + }).on("error", (err) => { + this.log("stderr", "Error running " + this.application + " over ssh!"); + if (err === undefined) { + err = "" + } + this.log("stderr", err.toString()); + this.emit("quit"); + reject(); + }).connect(connectionArgs); + }); + } + + protected initCommands(target: string, cwd: string, attach: boolean = false) { + // We need to account for the possibility of the path type used by the debugger being different + // than the path type where the extension is running (e.g., SSH from Linux to Windows machine). + // Since the CWD is expected to be an absolute path in the debugger's environment, we can test + // that to determine the path type used by the debugger and use the result of that test to + // select the correct API to check whether the target path is an absolute path. + const debuggerPath = path.posix.isAbsolute(cwd) ? path.posix : path.win32; + + if (!debuggerPath.isAbsolute(target)) + target = debuggerPath.join(cwd, target); + + const cmds = [ + this.sendCommand("gdb-set target-async on", true), + new Promise(resolve => { + this.sendCommand("list-features").then(done => { + this.features = done.result("features"); + resolve(undefined); + }, () => { + // Default to no supported features on error + this.features = []; + resolve(undefined); + }); + }), + this.sendCommand("environment-directory \"" + escape(cwd) + "\"", true) + ]; + if (!attach) + cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\"")); + if (this.prettyPrint) + cmds.push(this.sendCommand("enable-pretty-printing")); + for (let cmd of this.extraCommands) { + cmds.push(this.sendCommand(cmd)); + } + + return cmds; + } + + attach(cwd: string, executable: string, target: string): Thenable { + return new Promise((resolve, reject) => { + let args = []; + if (executable && !path.isAbsolute(executable)) + executable = path.join(cwd, executable); + args = this.preargs.concat(this.extraargs || []); + this.process = ChildProcess.spawn(this.application, args, { cwd: cwd, env: this.procEnv }); + this.process.stdout.on("data", this.stdout.bind(this)); + this.process.stderr.on("data", this.stderr.bind(this)); + this.process.on("exit", (() => { this.emit("quit"); }).bind(this)); + this.process.on("error", ((err) => { this.emit("launcherror", err); }).bind(this)); + const promises = this.initCommands(target, cwd, true); + if (target.startsWith("extended-remote")) { + promises.push(this.sendCommand("target-select " + target)); + if (executable) + promises.push(this.sendCommand("file-symbol-file \"" + escape(executable) + "\"")); + } else { + // Attach to local process + if (executable) + promises.push(this.sendCommand("file-exec-and-symbols \"" + escape(executable) + "\"")); + promises.push(this.sendCommand("target-attach " + target)); + } + Promise.all(promises).then(() => { + this.emit("debug-ready"); + resolve(undefined); + }, reject); + }); + } + + connect(cwd: string, executable: string, target: string): Thenable { + return new Promise((resolve, reject) => { + let args = []; + if (executable && !path.isAbsolute(executable)) + executable = path.join(cwd, executable); + args = this.preargs.concat(this.extraargs || []); + if (executable) + args = args.concat([executable]); + this.process = ChildProcess.spawn(this.application, args, { cwd: cwd, env: this.procEnv }); + this.process.stdout.on("data", this.stdout.bind(this)); + this.process.stderr.on("data", this.stderr.bind(this)); + this.process.on("exit", (() => { this.emit("quit"); }).bind(this)); + this.process.on("error", ((err) => { this.emit("launcherror", err); }).bind(this)); + const promises = this.initCommands(target, cwd, true); + promises.push(this.sendCommand("target-select remote " + target)); + Promise.all(promises).then(() => { + this.emit("debug-ready"); + resolve(undefined); + }, reject); + }); + } + + stdout(data) { + if (trace) + this.log("stderr", "stdout: " + data); + if (typeof data == "string") + this.buffer += data; + else + this.buffer += data.toString("utf8"); + const end = this.buffer.lastIndexOf('\n'); + if (end != -1) { + this.onOutput(this.buffer.substr(0, end)); + this.buffer = this.buffer.substr(end + 1); + } + if (this.buffer.length) { + if (this.onOutputPartial(this.buffer)) { + this.buffer = ""; + } + } + } + + stderr(data) { + if (typeof data == "string") + this.errbuf += data; + else + this.errbuf += data.toString("utf8"); + const end = this.errbuf.lastIndexOf('\n'); + if (end != -1) { + this.onOutputStderr(this.errbuf.substr(0, end)); + this.errbuf = this.errbuf.substr(end + 1); + } + if (this.errbuf.length) { + this.logNoNewLine("stderr", this.errbuf); + this.errbuf = ""; + } + } + + onOutputStderr(lines) { + lines = lines.split('\n'); + lines.forEach(line => { + this.log("stderr", line); + }); + } + + onOutputPartial(line) { + if (couldBeOutput(line)) { + this.logNoNewLine("stdout", line); + return true; + } + return false; + } + + onOutput(lines) { + lines = lines.split('\n'); + lines.forEach(line => { + if (couldBeOutput(line)) { + if (!gdbMatch.exec(line)) + this.log("stdout", line); + } else { + const parsed = parseMI(line); + if (this.debugOutput) + this.log("log", "GDB -> App: " + JSON.stringify(parsed)); + let handled = false; + if (parsed.token !== undefined) { + if (this.handlers[parsed.token]) { + this.handlers[parsed.token](parsed); + delete this.handlers[parsed.token]; + handled = true; + } + } + if (!handled && parsed.resultRecords && parsed.resultRecords.resultClass == "error") { + this.log("stderr", parsed.result("msg") || line); + } + if (parsed.outOfBandRecord) { + parsed.outOfBandRecord.forEach(record => { + if (record.isStream) { + this.log(record.type, record.content); + } else { + if (record.type == "exec") { + this.emit("exec-async-output", parsed); + if (record.asyncClass == "running") + this.emit("running", parsed); + else if (record.asyncClass == "stopped") { + const reason = parsed.record("reason"); + if (reason === undefined) { + if (trace) + this.log("stderr", "stop (no reason given)"); + // attaching to a process stops, but does not provide a reason + // also python generated interrupt seems to only produce this + this.emit("step-other", parsed); + } else { + if (trace) + this.log("stderr", "stop: " + reason); + switch (reason) { + case "breakpoint-hit": + this.emit("breakpoint", parsed); + break; + case "watchpoint-trigger": + case "read-watchpoint-trigger": + case "access-watchpoint-trigger": + this.emit("watchpoint", parsed); + break; + case "function-finished": + // identical result -> send step-end + // this.emit("step-out-end", parsed); + // break; + case "location-reached": + case "end-stepping-range": + this.emit("step-end", parsed); + break; + case "watchpoint-scope": + case "solib-event": + case "syscall-entry": + case "syscall-return": + // TODO: inform the user + this.emit("step-end", parsed); + break; + case "fork": + case "vfork": + case "exec": + // TODO: inform the user, possibly add second inferiour + this.emit("step-end", parsed); + break; + case "signal-received": + this.emit("signal-stop", parsed); + break; + case "exited-normally": + this.emit("exited-normally", parsed); + break; + case "exited": // exit with error code != 0 + this.log("stderr", "Program exited with code " + parsed.record("exit-code")); + this.emit("exited-normally", parsed); + break; + // case "exited-signalled": // consider handling that explicit possible + // this.log("stderr", "Program exited because of signal " + parsed.record("signal")); + // this.emit("stoped", parsed); + // break; + + default: + this.log("console", "Not implemented stop reason (assuming exception): " + reason); + this.emit("stopped", parsed); + break; + } + } + } else + this.log("log", JSON.stringify(parsed)); + } else if (record.type == "notify") { + if (record.asyncClass == "thread-created") { + this.emit("thread-created", parsed); + } else if (record.asyncClass == "thread-exited") { + this.emit("thread-exited", parsed); + } + } + } + }); + handled = true; + } + if (parsed.token == undefined && parsed.resultRecords == undefined && parsed.outOfBandRecord.length == 0) + handled = true; + if (!handled) + this.log("log", "Unhandled: " + JSON.stringify(parsed)); + } + }); + } + + start(runToStart: boolean): Thenable { + const options: string[] = []; + if (runToStart) + options.push("--start"); + const startCommand: string = ["exec-run"].concat(options).join(" "); + return new Promise((resolve, reject) => { + this.log("console", "Running executable"); + this.sendCommand(startCommand).then((info) => { + if (info.resultRecords.resultClass == "running") + resolve(undefined); + else + reject(); + }, reject); + }); + } + + stop() { + if (this.isSSH) { + const proc = this.stream; + const to = setTimeout(() => { + proc.signal("KILL"); + }, 1000); + this.stream.on("exit", function (code) { + clearTimeout(to); + }); + this.sendRaw("-gdb-exit"); + } else { + const proc = this.process; + const to = setTimeout(() => { + process.kill(-proc.pid); + }, 1000); + this.process.on("exit", function (code) { + clearTimeout(to); + }); + this.sendRaw("-gdb-exit"); + } + } + + detach() { + const proc = this.process; + const to = setTimeout(() => { + process.kill(-proc.pid); + }, 1000); + this.process.on("exit", function (code) { + clearTimeout(to); + }); + this.sendRaw("-target-detach"); + } + + interrupt(): Thenable { + if (trace) + this.log("stderr", "interrupt"); + return new Promise((resolve, reject) => { + this.sendCommand("exec-interrupt").then((info) => { + resolve(info.resultRecords.resultClass == "done"); + }, reject); + }); + } + + continue(reverse: boolean = false): Thenable { + if (trace) + this.log("stderr", "continue"); + return new Promise((resolve, reject) => { + this.sendCommand("exec-continue" + (reverse ? " --reverse" : "")).then((info) => { + resolve(info.resultRecords.resultClass == "running"); + }, reject); + }); + } + + next(reverse: boolean = false): Thenable { + if (trace) + this.log("stderr", "next"); + return new Promise((resolve, reject) => { + this.sendCommand("exec-next" + (reverse ? " --reverse" : "")).then((info) => { + resolve(info.resultRecords.resultClass == "running"); + }, reject); + }); + } + + step(reverse: boolean = false): Thenable { + if (trace) + this.log("stderr", "step"); + return new Promise((resolve, reject) => { + this.sendCommand("exec-step" + (reverse ? " --reverse" : "")).then((info) => { + resolve(info.resultRecords.resultClass == "running"); + }, reject); + }); + } + + stepOut(reverse: boolean = false): Thenable { + if (trace) + this.log("stderr", "stepOut"); + return new Promise((resolve, reject) => { + this.sendCommand("exec-finish" + (reverse ? " --reverse" : "")).then((info) => { + resolve(info.resultRecords.resultClass == "running"); + }, reject); + }); + } + + goto(filename: string, line: number): Thenable { + if (trace) + this.log("stderr", "goto"); + return new Promise((resolve, reject) => { + const target: string = '"' + (filename ? escape(filename) + ":" : "") + line + '"'; + this.sendCommand("break-insert -t " + target).then(() => { + this.sendCommand("exec-jump " + target).then((info) => { + resolve(info.resultRecords.resultClass == "running"); + }, reject); + }, reject); + }); + } + + changeVariable(name: string, rawValue: string): Thenable { + if (trace) + this.log("stderr", "changeVariable"); + return this.sendCommand("gdb-set var " + name + "=" + rawValue); + } + + loadBreakPoints(breakpoints: Breakpoint[]): Thenable<[boolean, Breakpoint][]> { + if (trace) + this.log("stderr", "loadBreakPoints"); + const promisses = []; + breakpoints.forEach(breakpoint => { + promisses.push(this.addBreakPoint(breakpoint)); + }); + return Promise.all(promisses); + } + + setBreakPointCondition(bkptNum, condition): Thenable { + if (trace) + this.log("stderr", "setBreakPointCondition"); + return this.sendCommand("break-condition " + bkptNum + " " + condition); + } + + setEntryBreakPoint(entryPoint: string): Thenable { + return this.sendCommand("break-insert -t -f " + entryPoint); + } + + addBreakPoint(breakpoint: Breakpoint): Thenable<[boolean, Breakpoint]> { + if (trace) + this.log("stderr", "addBreakPoint"); + return new Promise((resolve, reject) => { + if (this.breakpoints.has(breakpoint)) + return resolve([false, undefined]); + let location = ""; + if (breakpoint.countCondition) { + if (breakpoint.countCondition[0] == ">") + location += "-i " + numRegex.exec(breakpoint.countCondition.substr(1))[0] + " "; + else { + const match = numRegex.exec(breakpoint.countCondition)[0]; + if (match.length != breakpoint.countCondition.length) { + this.log("stderr", "Unsupported break count expression: '" + breakpoint.countCondition + "'. Only supports 'X' for breaking once after X times or '>X' for ignoring the first X breaks"); + location += "-t "; + } else if (parseInt(match) != 0) + location += "-t -i " + parseInt(match) + " "; + } + } + if (breakpoint.raw) + location += '"' + escape(breakpoint.raw) + '"'; + else + location += '"' + escape(breakpoint.file) + ":" + breakpoint.line + '"'; + this.sendCommand("break-insert -f " + location).then((result) => { + if (result.resultRecords.resultClass == "done") { + const bkptNum = parseInt(result.result("bkpt.number")); + const newBrk = { + file: breakpoint.file ? breakpoint.file : result.result("bkpt.file"), + raw: breakpoint.raw, + line: parseInt(result.result("bkpt.line")), + condition: breakpoint.condition + }; + if (breakpoint.condition) { + this.setBreakPointCondition(bkptNum, breakpoint.condition).then((result) => { + if (result.resultRecords.resultClass == "done") { + this.breakpoints.set(newBrk, bkptNum); + resolve([true, newBrk]); + } else { + resolve([false, undefined]); + } + }, reject); + } else { + this.breakpoints.set(newBrk, bkptNum); + resolve([true, newBrk]); + } + } else { + reject(result); + } + }, reject); + }); + } + + removeBreakPoint(breakpoint: Breakpoint): Thenable { + if (trace) + this.log("stderr", "removeBreakPoint"); + return new Promise((resolve, reject) => { + if (!this.breakpoints.has(breakpoint)) + return resolve(false); + this.sendCommand("break-delete " + this.breakpoints.get(breakpoint)).then((result) => { + if (result.resultRecords.resultClass == "done") { + this.breakpoints.delete(breakpoint); + resolve(true); + } else resolve(false); + }); + }); + } + + clearBreakPoints(source?: string): Thenable { + if (trace) + this.log("stderr", "clearBreakPoints"); + return new Promise((resolve, reject) => { + const promises = []; + const breakpoints = this.breakpoints; + this.breakpoints = new Map(); + breakpoints.forEach((k, index) => { + if (index.file === source) { + promises.push(this.sendCommand("break-delete " + k).then((result) => { + if (result.resultRecords.resultClass == "done") resolve(true); + else resolve(false); + })); + } else { + this.breakpoints.set(index, k); + } + }); + Promise.all(promises).then(resolve, reject); + }); + } + + async getThreads(): Promise { + if (trace) this.log("stderr", "getThreads"); + + const command = "thread-info"; + const result = await this.sendCommand(command); + const threads = result.result("threads"); + const ret: Thread[] = []; + return threads.map(element => { + const ret: Thread = { + id: parseInt(MINode.valueOf(element, "id")), + targetId: MINode.valueOf(element, "target-id") + }; + + ret.name = MINode.valueOf(element, "details") + || undefined; + + return ret; + }); + } + + async getStack(startFrame: number, maxLevels: number, thread: number): Promise { + if (trace) this.log("stderr", "getStack"); + + const options: string[] = []; + + if (thread != 0) + options.push("--thread " + thread); + + const depth: number = (await this.sendCommand(["stack-info-depth"].concat(options).join(" "))).result("depth").valueOf(); + const lowFrame: number = startFrame ? startFrame : 0; + const highFrame: number = (maxLevels ? Math.min(depth, lowFrame + maxLevels) : depth) - 1; + + if (highFrame < lowFrame) + return []; + + options.push(lowFrame.toString()); + options.push(highFrame.toString()); + + const result = await this.sendCommand(["stack-list-frames"].concat(options).join(" ")); + const stack = result.result("stack"); + return stack.map(element => { + const level = MINode.valueOf(element, "@frame.level"); + const addr = MINode.valueOf(element, "@frame.addr"); + const func = MINode.valueOf(element, "@frame.func"); + const filename = MINode.valueOf(element, "@frame.file"); + let file: string = MINode.valueOf(element, "@frame.fullname"); + if (file) { + if (this.isSSH) + file = path.posix.normalize(file); + else + file = path.normalize(file); + } + + let line = 0; + const lnstr = MINode.valueOf(element, "@frame.line"); + if (lnstr) + line = parseInt(lnstr); + const from = parseInt(MINode.valueOf(element, "@frame.from")); + return { + address: addr, + fileName: filename, + file: file, + function: func || from, + level: level, + line: line + }; + }); + } + + async getStackVariables(thread: number, frame: number): Promise { + if (trace) + this.log("stderr", "getStackVariables"); + + const result = await this.sendCommand(`stack-list-variables --thread ${thread} --frame ${frame} --simple-values`); + const variables = result.result("variables"); + const ret: Variable[] = []; + for (const element of variables) { + const key = MINode.valueOf(element, "name"); + const value = MINode.valueOf(element, "value"); + const type = MINode.valueOf(element, "type"); + ret.push({ + name: key, + valueStr: value, + type: type, + raw: element + }); + } + return ret; + } + + examineMemory(from: number, length: number): Thenable { + if (trace) + this.log("stderr", "examineMemory"); + return new Promise((resolve, reject) => { + this.sendCommand("data-read-memory-bytes 0x" + from.toString(16) + " " + length).then((result) => { + resolve(result.result("memory[0].contents")); + }, reject); + }); + } + + async evalExpression(name: string, thread: number, frame: number): Promise { + if (trace) + this.log("stderr", "evalExpression"); + + let command = "data-evaluate-expression "; + if (thread != 0) { + command += `--thread ${thread} --frame ${frame} `; + } + command += name; + + return await this.sendCommand(command); + } + + async varCreate(expression: string, name: string = "-", frame: string = "@"): Promise { + if (trace) + this.log("stderr", "varCreate"); + const res = await this.sendCommand(`var-create ${this.quote(name)} ${frame} "${expression}"`); + return new VariableObject(res.result("")); + } + + async varEvalExpression(name: string): Promise { + if (trace) + this.log("stderr", "varEvalExpression"); + return this.sendCommand(`var-evaluate-expression ${this.quote(name)}`); + } + + async varListChildren(name: string): Promise { + if (trace) + this.log("stderr", "varListChildren"); + //TODO: add `from` and `to` arguments + const res = await this.sendCommand(`var-list-children --all-values ${this.quote(name)}`); + const children = res.result("children") || []; + const omg: VariableObject[] = children.map(child => new VariableObject(child[1])); + return omg; + } + + async varUpdate(name: string = "*"): Promise { + if (trace) + this.log("stderr", "varUpdate"); + return this.sendCommand(`var-update --all-values ${this.quote(name)}`); + } + + async varAssign(name: string, rawValue: string): Promise { + if (trace) + this.log("stderr", "varAssign"); + return this.sendCommand(`var-assign ${this.quote(name)} ${rawValue}`); + } + + logNoNewLine(type: string, msg: string) { + this.emit("msg", type, msg); + } + + log(type: string, msg: string) { + this.emit("msg", type, msg[msg.length - 1] == '\n' ? msg : (msg + "\n")); + } + + sendUserInput(command: string, threadId: number = 0, frameLevel: number = 0): Thenable { + if (command.startsWith("-")) { + return this.sendCommand(command.substr(1)); + } else { + return this.sendCliCommand(command, threadId, frameLevel); + } + } + + sendRaw(raw: string) { + if (this.printCalls) + this.log("log", raw); + if (this.isSSH) + this.stream.write(raw + "\n"); + else + this.process.stdin.write(raw + "\n"); + } + + sendCliCommand(command: string, threadId: number = 0, frameLevel: number = 0): Thenable { + let miCommand = "interpreter-exec "; + if (threadId != 0) { + miCommand += `--thread ${threadId} --frame ${frameLevel} `; + } + miCommand += `console "${command.replace(/[\\"']/g, '\\$&')}"`; + return this.sendCommand(miCommand); + } + + sendCommand(command: string, suppressFailure: boolean = false): Thenable { + const sel = this.currentToken++; + return new Promise((resolve, reject) => { + this.handlers[sel] = (node: MINode) => { + if (node && node.resultRecords && node.resultRecords.resultClass === "error") { + if (suppressFailure) { + this.log("stderr", `WARNING: Error executing command '${command}'`); + resolve(node); + } else + reject(new MIError(node.result("msg") || "Internal error", command)); + } else + resolve(node); + }; + this.sendRaw(sel + "-" + command); + }); + } + + isReady(): boolean { + return this.isSSH ? this.sshReady : !!this.process; + } + + protected quote(text: string): string { + // only escape if text contains non-word or non-path characters such as whitespace or quotes + return /^-|[^\w\d\/_\-\.]/g.test(text) ? ('"' + escape(text) + '"') : text; + } + + prettyPrint: boolean = true; + printCalls: boolean; + debugOutput: boolean; + features: string[]; + public procEnv: any; + protected isSSH: boolean; + protected sshReady: boolean; + protected currentToken: number = 1; + protected handlers: { [index: number]: (info: MINode) => any } = {}; + protected breakpoints: Map = new Map(); + protected buffer: string; + protected errbuf: string; + protected process: ChildProcess.ChildProcess; + protected stream; + protected sshConn; +} diff --git a/src/backend/mi2/mi2lldb.ts b/src/backend/mi2/mi2lldb.ts new file mode 100644 index 0000000..514f891 --- /dev/null +++ b/src/backend/mi2/mi2lldb.ts @@ -0,0 +1,72 @@ +import { MI2, escape } from "./mi2"; +import { Breakpoint } from "../backend"; +import * as ChildProcess from "child_process"; +import * as path from "path"; + +export class MI2_LLDB extends MI2 { + protected initCommands(target: string, cwd: string, attach: boolean = false) { + // We need to account for the possibility of the path type used by the debugger being different + // than the path type where the extension is running (e.g., SSH from Linux to Windows machine). + // Since the CWD is expected to be an absolute path in the debugger's environment, we can test + // that to determine the path type used by the debugger and use the result of that test to + // select the correct API to check whether the target path is an absolute path. + const debuggerPath = path.posix.isAbsolute(cwd) ? path.posix : path.win32; + + if (!debuggerPath.isAbsolute(target)) + target = debuggerPath.join(cwd, target); + + const cmds = [ + this.sendCommand("gdb-set target-async on"), + new Promise(resolve => { + this.sendCommand("list-features").then(done => { + this.features = done.result("features"); + resolve(undefined); + }, err => { + this.features = []; + resolve(undefined); + }); + }) + ]; + if (!attach) + cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\"")); + for (let cmd of this.extraCommands) { + cmds.push(this.sendCliCommand(cmd)); + } + return cmds; + } + + attach(cwd: string, executable: string, target: string): Thenable { + return new Promise((resolve, reject) => { + const args = this.preargs.concat(this.extraargs || []); + this.process = ChildProcess.spawn(this.application, args, { cwd: cwd, env: this.procEnv }); + this.process.stdout.on("data", this.stdout.bind(this)); + this.process.stderr.on("data", this.stderr.bind(this)); + this.process.on("exit", (() => { this.emit("quit"); }).bind(this)); + this.process.on("error", ((err) => { this.emit("launcherror", err); }).bind(this)); + const promises = this.initCommands(target, cwd, true); + promises.push(this.sendCommand("file-exec-and-symbols \"" + escape(executable) + "\"")); + promises.push(this.sendCommand("target-attach " + target)); + Promise.all(promises).then(() => { + this.emit("debug-ready"); + resolve(undefined); + }, reject); + }); + } + + setBreakPointCondition(bkptNum, condition): Thenable { + return this.sendCommand("break-condition " + bkptNum + " \"" + escape(condition) + "\" 1"); + } + + goto(filename: string, line: number): Thenable { + return new Promise((resolve, reject) => { + // LLDB parses the file differently than GDB... + // GDB doesn't allow quoting only the file but only the whole argument + // LLDB doesn't allow quoting the whole argument but rather only the file + const target: string = (filename ? '"' + escape(filename) + '":' : "") + line; + this.sendCliCommand("jump " + target).then(() => { + this.emit("step-other", null); + resolve(true); + }, reject); + }); + } +} diff --git a/src/backend/mi2/mi2mago.ts b/src/backend/mi2/mi2mago.ts new file mode 100644 index 0000000..78e9f25 --- /dev/null +++ b/src/backend/mi2/mi2mago.ts @@ -0,0 +1,45 @@ +import { MI2_LLDB } from "./mi2lldb"; +import { Stack } from "../backend"; +import { MINode } from "../mi_parse"; + +export class MI2_Mago extends MI2_LLDB { + getStack(startFrame: number, maxLevels: number, thread: number): Promise { + return new Promise((resolve, reject) => { + const command = "stack-list-frames"; + this.sendCommand(command).then((result) => { + const stack = result.resultRecords.results; + const ret: Stack[] = []; + const remaining = []; + const addToStack = (element) => { + const level = MINode.valueOf(element, "frame.level"); + const addr = MINode.valueOf(element, "frame.addr"); + const func = MINode.valueOf(element, "frame.func"); + const filename = MINode.valueOf(element, "file"); + const file = MINode.valueOf(element, "fullname"); + let line = 0; + const lnstr = MINode.valueOf(element, "line"); + if (lnstr) + line = parseInt(lnstr); + const from = parseInt(MINode.valueOf(element, "from")); + ret.push({ + address: addr, + fileName: filename || "", + file: file || "", + function: func || from || "", + level: level, + line: line + }); + }; + stack.forEach(element => { + if (element) + if (element[0] == "stack") { + addToStack(element[1]); + } else remaining.push(element); + }); + if (remaining.length) + addToStack(remaining); + resolve(ret); + }, reject); + }); + } +} diff --git a/src/backend/mi_parse.ts b/src/backend/mi_parse.ts new file mode 100644 index 0000000..1bdd9be --- /dev/null +++ b/src/backend/mi_parse.ts @@ -0,0 +1,313 @@ +export interface MIInfo { + token: number; + outOfBandRecord: { isStream: boolean, type: string, asyncClass: string, output: [string, any][], content: string }[]; + resultRecords: { resultClass: string, results: [string, any][] }; +} + +const octalMatch = /^[0-7]{3}/; +function parseString(str: string): string { + const ret = new Buffer(str.length * 4); + let bufIndex = 0; + + if (str[0] != '"' || str[str.length - 1] != '"') + throw new Error("Not a valid string"); + str = str.slice(1, -1); + let escaped = false; + for (let i = 0; i < str.length; i++) { + if (escaped) { + let m; + if (str[i] == '\\') + bufIndex += ret.write('\\', bufIndex); + else if (str[i] == '"') + bufIndex += ret.write('"', bufIndex); + else if (str[i] == '\'') + bufIndex += ret.write('\'', bufIndex); + else if (str[i] == 'n') + bufIndex += ret.write('\n', bufIndex); + else if (str[i] == 'r') + bufIndex += ret.write('\r', bufIndex); + else if (str[i] == 't') + bufIndex += ret.write('\t', bufIndex); + else if (str[i] == 'b') + bufIndex += ret.write('\b', bufIndex); + else if (str[i] == 'f') + bufIndex += ret.write('\f', bufIndex); + else if (str[i] == 'v') + bufIndex += ret.write('\v', bufIndex); + else if (str[i] == '0') + bufIndex += ret.write('\0', bufIndex); + else if (m = octalMatch.exec(str.substr(i))) { + ret.writeUInt8(parseInt(m[0], 8), bufIndex++); + i += 2; + } else + bufIndex += ret.write(str[i], bufIndex); + escaped = false; + } else { + if (str[i] == '\\') + escaped = true; + else if (str[i] == '"') + throw new Error("Not a valid string"); + else + bufIndex += ret.write(str[i], bufIndex); + } + } + return ret.slice(0, bufIndex).toString("utf8"); +} + +export class MINode implements MIInfo { + token: number; + outOfBandRecord: { isStream: boolean, type: string, asyncClass: string, output: [string, any][], content: string }[]; + resultRecords: { resultClass: string, results: [string, any][] }; + + constructor(token: number, info: { isStream: boolean, type: string, asyncClass: string, output: [string, any][], content: string }[], result: { resultClass: string, results: [string, any][] }) { + this.token = token; + this.outOfBandRecord = info; + this.resultRecords = result; + } + + record(path: string): any { + if (!this.outOfBandRecord) + return undefined; + return MINode.valueOf(this.outOfBandRecord[0].output, path); + } + + result(path: string): any { + if (!this.resultRecords) + return undefined; + return MINode.valueOf(this.resultRecords.results, path); + } + + static valueOf(start: any, path: string): any { + if (!start) + return undefined; + const pathRegex = /^\.?([a-zA-Z_\-][a-zA-Z0-9_\-]*)/; + const indexRegex = /^\[(\d+)\](?:$|\.)/; + path = path.trim(); + if (!path) + return start; + let current = start; + do { + let target = pathRegex.exec(path); + if (target) { + path = path.substr(target[0].length); + if (current.length && typeof current != "string") { + const found = []; + for (const element of current) { + if (element[0] == target[1]) { + found.push(element[1]); + } + } + if (found.length > 1) { + current = found; + } else if (found.length == 1) { + current = found[0]; + } else return undefined; + } else return undefined; + } else if (path[0] == '@') { + current = [current]; + path = path.substr(1); + } else { + target = indexRegex.exec(path); + if (target) { + path = path.substr(target[0].length); + const i = parseInt(target[1]); + if (current.length && typeof current != "string" && i >= 0 && i < current.length) { + current = current[i]; + } else if (i == 0) { + } else return undefined; + } else return undefined; + } + path = path.trim(); + } while (path); + return current; + } +} + +const tokenRegex = /^\d+/; +const outOfBandRecordRegex = /^(?:(\d*|undefined)([\*\+\=])|([\~\@\&]))/; +const resultRecordRegex = /^(\d*)\^(done|running|connected|error|exit)/; +const newlineRegex = /^\r\n?/; +const endRegex = /^\(gdb\)\r\n?/; +const variableRegex = /^([a-zA-Z_\-][a-zA-Z0-9_\-]*)/; +const asyncClassRegex = /^[^,\r\n]+/; + +export function parseMI(output: string): MINode { + /* + output ==> + ( + exec-async-output = [ token ] "*" ("stopped" | others) ( "," variable "=" (const | tuple | list) )* \n + status-async-output = [ token ] "+" ("stopped" | others) ( "," variable "=" (const | tuple | list) )* \n + notify-async-output = [ token ] "=" ("stopped" | others) ( "," variable "=" (const | tuple | list) )* \n + console-stream-output = "~" c-string \n + target-stream-output = "@" c-string \n + log-stream-output = "&" c-string \n + )* + [ + [ token ] "^" ("done" | "running" | "connected" | "error" | "exit") ( "," variable "=" (const | tuple | list) )* \n + ] + "(gdb)" \n + */ + + let token = undefined; + const outOfBandRecord = []; + let resultRecords = undefined; + + const asyncRecordType = { + "*": "exec", + "+": "status", + "=": "notify" + }; + const streamRecordType = { + "~": "console", + "@": "target", + "&": "log" + }; + + const parseCString = () => { + if (output[0] != '"') + return ""; + let stringEnd = 1; + let inString = true; + let remaining = output.substr(1); + let escaped = false; + while (inString) { + if (escaped) + escaped = false; + else if (remaining[0] == '\\') + escaped = true; + else if (remaining[0] == '"') + inString = false; + + remaining = remaining.substr(1); + stringEnd++; + } + let str; + try { + str = parseString(output.substr(0, stringEnd)); + } catch (e) { + str = output.substr(0, stringEnd); + } + output = output.substr(stringEnd); + return str; + }; + + let parseValue, parseCommaResult, parseCommaValue, parseResult; + + const parseTupleOrList = () => { + if (output[0] != '{' && output[0] != '[') + return undefined; + const oldContent = output; + const canBeValueList = output[0] == '['; + output = output.substr(1); + if (output[0] == '}' || output[0] == ']') { + output = output.substr(1); // ] or } + return []; + } + if (canBeValueList) { + let value = parseValue(); + if (value !== undefined) { // is value list + const values = []; + values.push(value); + const remaining = output; + while ((value = parseCommaValue()) !== undefined) + values.push(value); + output = output.substr(1); // ] + return values; + } + } + let result = parseResult(); + if (result) { + const results = []; + results.push(result); + while (result = parseCommaResult()) + results.push(result); + output = output.substr(1); // } + return results; + } + output = (canBeValueList ? '[' : '{') + output; + return undefined; + }; + + parseValue = () => { + if (output[0] == '"') + return parseCString(); + else if (output[0] == '{' || output[0] == '[') + return parseTupleOrList(); + else + return undefined; + }; + + parseResult = () => { + const variableMatch = variableRegex.exec(output); + if (!variableMatch) + return undefined; + output = output.substr(variableMatch[0].length + 1); + const variable = variableMatch[1]; + return [variable, parseValue()]; + }; + + parseCommaValue = () => { + if (output[0] != ',') + return undefined; + output = output.substr(1); + return parseValue(); + }; + + parseCommaResult = () => { + if (output[0] != ',') + return undefined; + output = output.substr(1); + return parseResult(); + }; + + let match = undefined; + + while (match = outOfBandRecordRegex.exec(output)) { + output = output.substr(match[0].length); + if (match[1] && token === undefined && match[1] !== "undefined") { + token = parseInt(match[1]); + } + + if (match[2]) { + const classMatch = asyncClassRegex.exec(output); + output = output.substring(classMatch[0].length); + const asyncRecord = { + isStream: false, + type: asyncRecordType[match[2]], + asyncClass: classMatch[0], + output: [] + }; + let result; + while (result = parseCommaResult()) + asyncRecord.output.push(result); + outOfBandRecord.push(asyncRecord); + } else if (match[3]) { + const streamRecord = { + isStream: true, + type: streamRecordType[match[3]], + content: parseCString() + }; + outOfBandRecord.push(streamRecord); + } + + output = output.replace(newlineRegex, ""); + } + + if (match = resultRecordRegex.exec(output)) { + output = output.substr(match[0].length); + if (match[1] && token === undefined) { + token = parseInt(match[1]); + } + resultRecords = { + resultClass: match[2], + results: [] + }; + let result; + while (result = parseCommaResult()) + resultRecords.results.push(result); + + output = output.replace(newlineRegex, ""); + } + + return new MINode(token, outOfBandRecord || [], resultRecords); +} diff --git a/src/frontend/extension.ts b/src/frontend/extension.ts new file mode 100644 index 0000000..19fc6f9 --- /dev/null +++ b/src/frontend/extension.ts @@ -0,0 +1,175 @@ +import * as vscode from "vscode"; +import * as net from "net"; +import * as fs from "fs"; +import * as path from "path"; +import * as os from "os"; + +export function activate(context: vscode.ExtensionContext) { + context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider("debugmemory", new MemoryContentProvider())); + context.subscriptions.push(vscode.commands.registerCommand("code-debug.examineMemoryLocation", examineMemory)); + context.subscriptions.push(vscode.commands.registerCommand("code-debug.getFileNameNoExt", () => { + if (!vscode.window.activeTextEditor || !vscode.window.activeTextEditor.document || !vscode.window.activeTextEditor.document.fileName) { + vscode.window.showErrorMessage("No editor with valid file name active"); + return; + } + const fileName = vscode.window.activeTextEditor.document.fileName; + const ext = path.extname(fileName); + return fileName.substr(0, fileName.length - ext.length); + })); + context.subscriptions.push(vscode.commands.registerCommand("code-debug.getFileBasenameNoExt", () => { + if (!vscode.window.activeTextEditor || !vscode.window.activeTextEditor.document || !vscode.window.activeTextEditor.document.fileName) { + vscode.window.showErrorMessage("No editor with valid file name active"); + return; + } + const fileName = path.basename(vscode.window.activeTextEditor.document.fileName); + const ext = path.extname(fileName); + return fileName.substr(0, fileName.length - ext.length); + })); +} + +const memoryLocationRegex = /^0x[0-9a-f]+$/; + +function getMemoryRange(range: string) { + if (!range) + return undefined; + range = range.replace(/\s+/g, "").toLowerCase(); + let index; + if ((index = range.indexOf("+")) != -1) { + const from = range.substr(0, index); + let length = range.substr(index + 1); + if (!memoryLocationRegex.exec(from)) + return undefined; + if (memoryLocationRegex.exec(length)) + length = parseInt(length.substr(2), 16).toString(); + return "from=" + encodeURIComponent(from) + "&length=" + encodeURIComponent(length); + } else if ((index = range.indexOf("-")) != -1) { + const from = range.substr(0, index); + const to = range.substr(index + 1); + if (!memoryLocationRegex.exec(from)) + return undefined; + if (!memoryLocationRegex.exec(to)) + return undefined; + return "from=" + encodeURIComponent(from) + "&to=" + encodeURIComponent(to); + } else if (memoryLocationRegex.exec(range)) + return "at=" + encodeURIComponent(range); + else return undefined; +} + +function examineMemory() { + const socketlists = path.join(os.tmpdir(), "code-debug-sockets"); + if (!fs.existsSync(socketlists)) { + if (process.platform == "win32") + return vscode.window.showErrorMessage("This command is not available on windows"); + else + return vscode.window.showErrorMessage("No debugging sessions available"); + } + fs.readdir(socketlists, (err, files) => { + if (err) { + if (process.platform == "win32") + return vscode.window.showErrorMessage("This command is not available on windows"); + else + return vscode.window.showErrorMessage("No debugging sessions available"); + } + const pickedFile = (file) => { + vscode.window.showInputBox({ placeHolder: "Memory Location or Range", validateInput: range => getMemoryRange(range) === undefined ? "Range must either be in format 0xF00-0xF01, 0xF100+32 or 0xABC154" : "" }).then(range => { + vscode.window.showTextDocument(vscode.Uri.parse("debugmemory://" + file + "?" + getMemoryRange(range))); + }); + }; + if (files.length == 1) + pickedFile(files[0]); + else if (files.length > 0) + vscode.window.showQuickPick(files, { placeHolder: "Running debugging instance" }).then(file => pickedFile(file)); + else if (process.platform == "win32") + return vscode.window.showErrorMessage("This command is not available on windows"); + else + vscode.window.showErrorMessage("No debugging sessions available"); + }); +} + +class MemoryContentProvider implements vscode.TextDocumentContentProvider { + provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): Thenable { + return new Promise((resolve, reject) => { + const conn = net.connect(path.join(os.tmpdir(), "code-debug-sockets", uri.authority.toLowerCase())); + let from, to; + let highlightAt = -1; + const splits = uri.query.split("&"); + if (splits[0].split("=")[0] == "at") { + const loc = parseInt(splits[0].split("=")[1].substr(2), 16); + highlightAt = 64; + from = Math.max(loc - 64, 0); + to = Math.max(loc + 768, 0); + } else if (splits[0].split("=")[0] == "from") { + from = parseInt(splits[0].split("=")[1].substr(2), 16); + if (splits[1].split("=")[0] == "to") { + to = parseInt(splits[1].split("=")[1].substr(2), 16); + } else if (splits[1].split("=")[0] == "length") { + to = from + parseInt(splits[1].split("=")[1]); + } else return reject("Invalid Range"); + } else return reject("Invalid Range"); + if (to < from) + return reject("Negative Range"); + conn.write("examineMemory " + JSON.stringify([from, to - from + 1])); + conn.once("data", data => { + let formattedCode = " 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n"; + var index: number = from; + const hexString = data.toString(); + let x = 0; + let asciiLine = ""; + let byteNo = 0; + for (let i = 0; i < hexString.length; i += 2) { + if (x == 0) { + var addr = index.toString(16); + while (addr.length < 16) addr = '0' + addr; + formattedCode += addr + " "; + } + index++; + + const digit = hexString.substr(i, 2); + const digitNum = parseInt(digit, 16); + if (digitNum >= 32 && digitNum <= 126) + asciiLine += String.fromCharCode(digitNum); + else + asciiLine += "."; + + if (highlightAt == byteNo) { + formattedCode = formattedCode.slice(0, -1) + "[" + digit + "]"; + } else { + formattedCode += digit + " "; + } + + if (x == 7) + formattedCode += " "; + + if (++x >= 16) { + formattedCode += " " + asciiLine + "\n"; + x = 0; + asciiLine = ""; + } + byteNo++; + } + if (x > 0) { + for (let i = 0; i <= 16 - x; i++) { + formattedCode += " "; + } + if (x >= 8) + formattedCode = formattedCode.slice(0, -2); + else + formattedCode = formattedCode.slice(0, -1); + formattedCode += asciiLine; + } + resolve(center("Memory Range from 0x" + from.toString(16) + " to 0x" + to.toString(16), 84) + "\n\n" + formattedCode); + conn.destroy(); + }); + }); + } +} + +function center(str: string, width: number): string { + var left = true; + while (str.length < width) { + if (left) str = ' ' + str; + else str = str + ' '; + left = !left; + } + return str; +} diff --git a/src/gdb.ts b/src/gdb.ts new file mode 100644 index 0000000..6934e43 --- /dev/null +++ b/src/gdb.ts @@ -0,0 +1,173 @@ +import { MI2DebugSession, RunCommand } from './mibase'; +import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { MI2, escape } from "./backend/mi2/mi2"; +import { SSHArguments, ValuesFormattingMode } from './backend/backend'; + +export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { + cwd: string; + target: string; + gdbpath: string; + env: any; + debugger_args: string[]; + pathSubstitutions: { [index: string]: string }; + arguments: string; + terminal: string; + autorun: string[]; + stopAtEntry: boolean | string; + ssh: SSHArguments; + valuesFormatting: ValuesFormattingMode; + printCalls: boolean; + showDevDebugOutput: boolean; +} + +export interface AttachRequestArguments extends DebugProtocol.AttachRequestArguments { + cwd: string; + target: string; + gdbpath: string; + env: any; + debugger_args: string[]; + pathSubstitutions: { [index: string]: string }; + executable: string; + remote: boolean; + autorun: string[]; + stopAtConnect: boolean; + stopAtEntry: boolean | string; + ssh: SSHArguments; + valuesFormatting: ValuesFormattingMode; + printCalls: boolean; + showDevDebugOutput: boolean; +} + +class GDBDebugSession extends MI2DebugSession { + protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { + response.body.supportsGotoTargetsRequest = true; + response.body.supportsHitConditionalBreakpoints = true; + response.body.supportsConfigurationDoneRequest = true; + response.body.supportsConditionalBreakpoints = true; + response.body.supportsFunctionBreakpoints = true; + response.body.supportsEvaluateForHovers = true; + response.body.supportsSetVariable = true; + response.body.supportsStepBack = true; + this.sendResponse(response); + } + + protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { + this.miDebugger = new MI2(args.gdbpath || "gdb", ["-q", "--interpreter=mi2"], args.debugger_args, args.env); + this.setPathSubstitutions(args.pathSubstitutions); + this.initDebugger(); + this.quit = false; + this.attached = false; + this.initialRunCommand = RunCommand.RUN; + this.isSSH = false; + this.started = false; + this.crashed = false; + this.setValuesFormattingMode(args.valuesFormatting); + this.miDebugger.printCalls = !!args.printCalls; + this.miDebugger.debugOutput = !!args.showDevDebugOutput; + this.stopAtEntry = args.stopAtEntry; + if (args.ssh !== undefined) { + if (args.ssh.forwardX11 === undefined) + args.ssh.forwardX11 = true; + if (args.ssh.port === undefined) + args.ssh.port = 22; + if (args.ssh.x11port === undefined) + args.ssh.x11port = 6000; + if (args.ssh.x11host === undefined) + args.ssh.x11host = "localhost"; + if (args.ssh.remotex11screen === undefined) + args.ssh.remotex11screen = 0; + this.isSSH = true; + this.setSourceFileMap(args.ssh.sourceFileMap, args.ssh.cwd, args.cwd); + this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments, args.terminal, false).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }, err => { + this.sendErrorResponse(response, 102, `Failed to SSH: ${err.toString()}`); + }); + } else { + this.miDebugger.load(args.cwd, args.target, args.arguments, args.terminal).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }, err => { + this.sendErrorResponse(response, 103, `Failed to load MI Debugger: ${err.toString()}`); + }); + } + } + + protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void { + this.miDebugger = new MI2(args.gdbpath || "gdb", ["-q", "--interpreter=mi2"], args.debugger_args, args.env); + this.setPathSubstitutions(args.pathSubstitutions); + this.initDebugger(); + this.quit = false; + this.attached = !args.remote; + this.initialRunCommand = !!args.stopAtConnect ? RunCommand.NONE : RunCommand.CONTINUE; + this.isSSH = false; + this.setValuesFormattingMode(args.valuesFormatting); + this.miDebugger.printCalls = !!args.printCalls; + this.miDebugger.debugOutput = !!args.showDevDebugOutput; + this.stopAtEntry = args.stopAtEntry; + if (args.ssh !== undefined) { + if (args.ssh.forwardX11 === undefined) + args.ssh.forwardX11 = true; + if (args.ssh.port === undefined) + args.ssh.port = 22; + if (args.ssh.x11port === undefined) + args.ssh.x11port = 6000; + if (args.ssh.x11host === undefined) + args.ssh.x11host = "localhost"; + if (args.ssh.remotex11screen === undefined) + args.ssh.remotex11screen = 0; + this.isSSH = true; + this.setSourceFileMap(args.ssh.sourceFileMap, args.ssh.cwd, args.cwd); + this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, "", undefined, true).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }, err => { + this.sendErrorResponse(response, 102, `Failed to SSH: ${err.toString()}`); + }); + } else { + if (args.remote) { + this.miDebugger.connect(args.cwd, args.executable, args.target).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }, err => { + this.sendErrorResponse(response, 102, `Failed to attach: ${err.toString()}`); + }); + } else { + this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }, err => { + this.sendErrorResponse(response, 101, `Failed to attach: ${err.toString()}`); + }); + } + } + } + + // Add extra commands for source file path substitution in GDB-specific syntax + protected setPathSubstitutions(substitutions: { [index: string]: string }): void { + if (substitutions) { + Object.keys(substitutions).forEach(source => { + this.miDebugger.extraCommands.push("gdb-set substitute-path \"" + escape(source) + "\" \"" + escape(substitutions[source]) + "\""); + }) + } + } +} + +DebugSession.run(GDBDebugSession); diff --git a/src/lldb.ts b/src/lldb.ts new file mode 100644 index 0000000..9c4a979 --- /dev/null +++ b/src/lldb.ts @@ -0,0 +1,126 @@ +import { MI2DebugSession, RunCommand } from './mibase'; +import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { MI2_LLDB } from "./backend/mi2/mi2lldb"; +import { SSHArguments, ValuesFormattingMode } from './backend/backend'; + +export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { + cwd: string; + target: string; + lldbmipath: string; + env: any; + debugger_args: string[]; + pathSubstitutions: { [index: string]: string }; + arguments: string; + autorun: string[]; + stopAtEntry: boolean | string; + ssh: SSHArguments; + valuesFormatting: ValuesFormattingMode; + printCalls: boolean; + showDevDebugOutput: boolean; +} + +export interface AttachRequestArguments extends DebugProtocol.AttachRequestArguments { + cwd: string; + target: string; + lldbmipath: string; + env: any; + debugger_args: string[]; + pathSubstitutions: { [index: string]: string }; + executable: string; + autorun: string[]; + stopAtConnect: boolean; + stopAtEntry: boolean | string; + valuesFormatting: ValuesFormattingMode; + printCalls: boolean; + showDevDebugOutput: boolean; +} + +class LLDBDebugSession extends MI2DebugSession { + protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { + response.body.supportsGotoTargetsRequest = true; + response.body.supportsHitConditionalBreakpoints = true; + response.body.supportsConfigurationDoneRequest = true; + response.body.supportsConditionalBreakpoints = true; + response.body.supportsFunctionBreakpoints = true; + response.body.supportsEvaluateForHovers = true; + this.sendResponse(response); + } + + protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { + this.miDebugger = new MI2_LLDB(args.lldbmipath || "lldb-mi", [], args.debugger_args, args.env); + this.setPathSubstitutions(args.pathSubstitutions); + this.initDebugger(); + this.quit = false; + this.attached = false; + this.initialRunCommand = RunCommand.RUN; + this.isSSH = false; + this.started = false; + this.crashed = false; + this.setValuesFormattingMode(args.valuesFormatting); + this.miDebugger.printCalls = !!args.printCalls; + this.miDebugger.debugOutput = !!args.showDevDebugOutput; + this.stopAtEntry = args.stopAtEntry; + if (args.ssh !== undefined) { + if (args.ssh.forwardX11 === undefined) + args.ssh.forwardX11 = true; + if (args.ssh.port === undefined) + args.ssh.port = 22; + if (args.ssh.x11port === undefined) + args.ssh.x11port = 6000; + if (args.ssh.x11host === undefined) + args.ssh.x11host = "localhost"; + if (args.ssh.remotex11screen === undefined) + args.ssh.remotex11screen = 0; + this.isSSH = true; + this.setSourceFileMap(args.ssh.sourceFileMap, args.ssh.cwd, args.cwd); + this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments, undefined, false).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }); + } else { + this.miDebugger.load(args.cwd, args.target, args.arguments, undefined).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }); + } + } + + protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void { + this.miDebugger = new MI2_LLDB(args.lldbmipath || "lldb-mi", [], args.debugger_args, args.env); + this.setPathSubstitutions(args.pathSubstitutions); + this.initDebugger(); + this.quit = false; + this.attached = true; + this.initialRunCommand = !!args.stopAtConnect ? RunCommand.NONE : RunCommand.CONTINUE; + this.isSSH = false; + this.setValuesFormattingMode(args.valuesFormatting); + this.miDebugger.printCalls = !!args.printCalls; + this.miDebugger.debugOutput = !!args.showDevDebugOutput; + this.stopAtEntry = args.stopAtEntry; + this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }); + } + + // Add extra commands for source file path substitution in LLDB-specific syntax + protected setPathSubstitutions(substitutions: { [index: string]: string }): void { + if (substitutions) { + Object.keys(substitutions).forEach(source => { + this.miDebugger.extraCommands.push("settings append target.source-map " + source + " " + substitutions[source]); + }) + } + } +} + +DebugSession.run(LLDBDebugSession); diff --git a/src/mago.ts b/src/mago.ts new file mode 100644 index 0000000..387138d --- /dev/null +++ b/src/mago.ts @@ -0,0 +1,93 @@ +import { MI2DebugSession, RunCommand } from './mibase'; +import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { MI2_Mago } from "./backend/mi2/mi2mago"; +import { SSHArguments, ValuesFormattingMode } from './backend/backend'; + +export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { + cwd: string; + target: string; + magomipath: string; + env: any; + debugger_args: string[]; + arguments: string; + autorun: string[]; + valuesFormatting: ValuesFormattingMode; + printCalls: boolean; + showDevDebugOutput: boolean; +} + +export interface AttachRequestArguments extends DebugProtocol.AttachRequestArguments { + cwd: string; + target: string; + magomipath: string; + env: any; + debugger_args: string[]; + executable: string; + autorun: string[]; + stopAtConnect: boolean; + valuesFormatting: ValuesFormattingMode; + printCalls: boolean; + showDevDebugOutput: boolean; +} + +class MagoDebugSession extends MI2DebugSession { + public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) { + super(debuggerLinesStartAt1, isServer); + } + + protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { + response.body.supportsHitConditionalBreakpoints = true; + response.body.supportsConfigurationDoneRequest = true; + response.body.supportsConditionalBreakpoints = true; + response.body.supportsFunctionBreakpoints = true; + response.body.supportsEvaluateForHovers = true; + this.sendResponse(response); + } + + getThreadID() { + return 0; + } + + protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { + this.miDebugger = new MI2_Mago(args.magomipath || "mago-mi", ["-q"], args.debugger_args, args.env); + this.initDebugger(); + this.quit = false; + this.attached = false; + this.initialRunCommand = RunCommand.RUN; + this.isSSH = false; + this.started = false; + this.crashed = false; + this.setValuesFormattingMode(args.valuesFormatting); + this.miDebugger.printCalls = !!args.printCalls; + this.miDebugger.debugOutput = !!args.showDevDebugOutput; + this.miDebugger.load(args.cwd, args.target, args.arguments, undefined).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }); + } + + protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void { + this.miDebugger = new MI2_Mago(args.magomipath || "mago-mi", [], args.debugger_args, args.env); + this.initDebugger(); + this.quit = false; + this.attached = true; + this.initialRunCommand = !!args.stopAtConnect ? RunCommand.NONE : RunCommand.CONTINUE; + this.isSSH = false; + this.setValuesFormattingMode(args.valuesFormatting); + this.miDebugger.printCalls = !!args.printCalls; + this.miDebugger.debugOutput = !!args.showDevDebugOutput; + this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { + if (args.autorun) + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); + this.sendResponse(response); + }); + } +} + +DebugSession.run(MagoDebugSession); diff --git a/src/mibase.ts b/src/mibase.ts new file mode 100644 index 0000000..7836263 --- /dev/null +++ b/src/mibase.ts @@ -0,0 +1,763 @@ +import * as DebugAdapter from 'vscode-debugadapter'; +import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, ThreadEvent, OutputEvent, ContinuedEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; +import { DebugProtocol } from 'vscode-debugprotocol'; +import { Breakpoint, IBackend, Variable, VariableObject, ValuesFormattingMode, MIError } from './backend/backend'; +import { MINode } from './backend/mi_parse'; +import { expandValue, isExpandable } from './backend/gdb_expansion'; +import { MI2 } from './backend/mi2/mi2'; +import { posix } from "path"; +import * as systemPath from "path"; +import * as net from "net"; +import * as os from "os"; +import * as fs from "fs"; + +class ExtendedVariable { + constructor(public name, public options) { + } +} + +export enum RunCommand { CONTINUE, RUN, NONE } + +const STACK_HANDLES_START = 1000; +const VAR_HANDLES_START = 512 * 256 + 1000; + +export class MI2DebugSession extends DebugSession { + protected variableHandles = new Handles(VAR_HANDLES_START); + protected variableHandlesReverse: { [id: string]: number } = {}; + protected useVarObjects: boolean; + protected quit: boolean; + protected attached: boolean; + protected initialRunCommand: RunCommand; + protected stopAtEntry: boolean | string; + protected isSSH: boolean; + protected sourceFileMap: Map; + protected started: boolean; + protected crashed: boolean; + protected miDebugger: MI2; + protected commandServer: net.Server; + protected serverPath: string; + + public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) { + super(debuggerLinesStartAt1, isServer); + } + + protected initDebugger() { + this.miDebugger.on("launcherror", this.launchError.bind(this)); + this.miDebugger.on("quit", this.quitEvent.bind(this)); + this.miDebugger.on("exited-normally", this.quitEvent.bind(this)); + this.miDebugger.on("stopped", this.stopEvent.bind(this)); + this.miDebugger.on("msg", this.handleMsg.bind(this)); + this.miDebugger.on("breakpoint", this.handleBreakpoint.bind(this)); + this.miDebugger.on("watchpoint", this.handleBreak.bind(this)); // consider to parse old/new, too (otherwise it is in the console only) + this.miDebugger.on("step-end", this.handleBreak.bind(this)); + // this.miDebugger.on("step-out-end", this.handleBreak.bind(this)); // was combined into step-end + this.miDebugger.on("step-other", this.handleBreak.bind(this)); + this.miDebugger.on("signal-stop", this.handlePause.bind(this)); + this.miDebugger.on("thread-created", this.threadCreatedEvent.bind(this)); + this.miDebugger.on("thread-exited", this.threadExitedEvent.bind(this)); + this.miDebugger.once("debug-ready", (() => this.sendEvent(new InitializedEvent()))); + try { + this.commandServer = net.createServer(c => { + c.on("data", data => { + const rawCmd = data.toString(); + const spaceIndex = rawCmd.indexOf(" "); + let func = rawCmd; + let args = []; + if (spaceIndex != -1) { + func = rawCmd.substr(0, spaceIndex); + args = JSON.parse(rawCmd.substr(spaceIndex + 1)); + } + Promise.resolve(this.miDebugger[func].apply(this.miDebugger, args)).then(data => { + c.write(data.toString()); + }); + }); + }); + this.commandServer.on("error", err => { + if (process.platform != "win32") + this.handleMsg("stderr", "Code-Debug WARNING: Utility Command Server: Error in command socket " + err.toString() + "\nCode-Debug WARNING: The examine memory location command won't work"); + }); + if (!fs.existsSync(systemPath.join(os.tmpdir(), "code-debug-sockets"))) + fs.mkdirSync(systemPath.join(os.tmpdir(), "code-debug-sockets")); + this.commandServer.listen(this.serverPath = systemPath.join(os.tmpdir(), "code-debug-sockets", ("Debug-Instance-" + Math.floor(Math.random() * 36 * 36 * 36 * 36).toString(36)).toLowerCase())); + } catch (e) { + if (process.platform != "win32") + this.handleMsg("stderr", "Code-Debug WARNING: Utility Command Server: Failed to start " + e.toString() + "\nCode-Debug WARNING: The examine memory location command won't work"); + } + } + + protected setValuesFormattingMode(mode: ValuesFormattingMode) { + switch (mode) { + case "disabled": + this.useVarObjects = true; + this.miDebugger.prettyPrint = false; + break; + case "prettyPrinters": + this.useVarObjects = true; + this.miDebugger.prettyPrint = true; + break; + case "parseText": + default: + this.useVarObjects = false; + this.miDebugger.prettyPrint = false; + } + } + + protected handleMsg(type: string, msg: string) { + if (type == "target") + type = "stdout"; + if (type == "log") + type = "stderr"; + this.sendEvent(new OutputEvent(msg, type)); + } + + protected handleBreakpoint(info: MINode) { + const event = new StoppedEvent("breakpoint", parseInt(info.record("thread-id"))); + (event as DebugProtocol.StoppedEvent).body.allThreadsStopped = info.record("stopped-threads") == "all"; + this.sendEvent(event); + } + + protected handleBreak(info?: MINode) { + const event = new StoppedEvent("step", info ? parseInt(info.record("thread-id")) : 1); + (event as DebugProtocol.StoppedEvent).body.allThreadsStopped = info ? info.record("stopped-threads") == "all" : true; + this.sendEvent(event); + } + + protected handlePause(info: MINode) { + const event = new StoppedEvent("user request", parseInt(info.record("thread-id"))); + (event as DebugProtocol.StoppedEvent).body.allThreadsStopped = info.record("stopped-threads") == "all"; + this.sendEvent(event); + } + + protected stopEvent(info: MINode) { + if (!this.started) + this.crashed = true; + if (!this.quit) { + const event = new StoppedEvent("exception", parseInt(info.record("thread-id"))); + (event as DebugProtocol.StoppedEvent).body.allThreadsStopped = info.record("stopped-threads") == "all"; + this.sendEvent(event); + } + } + + protected threadCreatedEvent(info: MINode) { + this.sendEvent(new ThreadEvent("started", info.record("id"))); + } + + protected threadExitedEvent(info: MINode) { + this.sendEvent(new ThreadEvent("exited", info.record("id"))); + } + + protected quitEvent() { + this.quit = true; + this.sendEvent(new TerminatedEvent()); + + if (this.serverPath) + fs.unlink(this.serverPath, (err) => { + console.error("Failed to unlink debug server"); + }); + } + + protected launchError(err: any) { + this.handleMsg("stderr", "Could not start debugger process, does the program exist in filesystem?\n"); + this.handleMsg("stderr", err.toString() + "\n"); + this.quitEvent(); + } + + protected disconnectRequest(response: DebugProtocol.DisconnectResponse, args: DebugProtocol.DisconnectArguments): void { + if (this.attached) + this.miDebugger.detach(); + else + this.miDebugger.stop(); + this.commandServer.close(); + this.commandServer = undefined; + this.sendResponse(response); + } + + protected async setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): Promise { + try { + if (this.useVarObjects) { + let name = args.name; + if (args.variablesReference >= VAR_HANDLES_START) { + const parent = this.variableHandles.get(args.variablesReference) as VariableObject; + name = `${parent.name}.${name}`; + } + + const res = await this.miDebugger.varAssign(name, args.value); + response.body = { + value: res.result("value") + }; + } else { + await this.miDebugger.changeVariable(args.name, args.value); + response.body = { + value: args.value + }; + } + this.sendResponse(response); + } catch (err) { + this.sendErrorResponse(response, 11, `Could not continue: ${err}`); + } + } + + protected setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void { + const all = []; + args.breakpoints.forEach(brk => { + all.push(this.miDebugger.addBreakPoint({ raw: brk.name, condition: brk.condition, countCondition: brk.hitCondition })); + }); + Promise.all(all).then(brkpoints => { + const finalBrks = []; + brkpoints.forEach(brkp => { + if (brkp[0]) + finalBrks.push({ line: brkp[1].line }); + }); + response.body = { + breakpoints: finalBrks + }; + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 10, msg.toString()); + }); + } + + protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void { + this.miDebugger.clearBreakPoints(args.source.path).then(() => { + let path = args.source.path; + if (this.isSSH) { + // convert local path to ssh path + if (path.indexOf("\\") != -1) + path = path.replace(/\\/g, "/").toLowerCase(); + // ideCWD is the local path, gdbCWD is the ssh path, both had the replacing \ -> / done up-front + for (let [ideCWD, gdbCWD] of this.sourceFileMap) { + if (path.startsWith(ideCWD)) { + path = posix.relative(ideCWD, path); + path = posix.join(gdbCWD, path); // we combined a guaranteed path with relative one (works with GDB both on GNU/Linux and Win32) + break; + } + } + } + const all = args.breakpoints.map(brk => { + return this.miDebugger.addBreakPoint({ file: path, line: brk.line, condition: brk.condition, countCondition: brk.hitCondition }); + }); + Promise.all(all).then(brkpoints => { + const finalBrks = []; + brkpoints.forEach(brkp => { + // TODO: Currently all breakpoints returned are marked as verified, + // which leads to verified breakpoints on a broken lldb. + if (brkp[0]) + finalBrks.push(new DebugAdapter.Breakpoint(true, brkp[1].line)); + }); + response.body = { + breakpoints: finalBrks + }; + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 9, msg.toString()); + }); + }, msg => { + this.sendErrorResponse(response, 9, msg.toString()); + }); + } + + protected threadsRequest(response: DebugProtocol.ThreadsResponse): void { + if (!this.miDebugger) { + this.sendResponse(response); + return; + } + this.miDebugger.getThreads().then(threads => { + response.body = { + threads: [] + }; + for (const thread of threads) { + let threadName = thread.name || thread.targetId || ""; + response.body.threads.push(new Thread(thread.id, thread.id + ":" + threadName)); + } + this.sendResponse(response); + }).catch(error => { + this.sendErrorResponse(response, 17, `Could not get threads: ${error}`); + }); + } + + // Supports 65535 threads. + protected threadAndLevelToFrameId(threadId: number, level: number) { + return level << 16 | threadId; + } + protected frameIdToThreadAndLevel(frameId: number) { + return [frameId & 0xffff, frameId >> 16]; + } + + protected stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): void { + this.miDebugger.getStack(args.startFrame, args.levels, args.threadId).then(stack => { + const ret: StackFrame[] = []; + stack.forEach(element => { + let source = undefined; + let path = element.file; + if (path) { + if (this.isSSH) { + // convert ssh path to local path + if (path.indexOf("\\") != -1) + path = path.replace(/\\/g, "/").toLowerCase(); + // ideCWD is the local path, gdbCWD is the ssh path, both had the replacing \ -> / done up-front + for (let [ideCWD, gdbCWD] of this.sourceFileMap) { + if (path.startsWith(gdbCWD)) { + path = posix.relative(gdbCWD, path); // only operates on "/" paths + path = systemPath.resolve(ideCWD, path); // will do the conversion to "\" on Win32 + break; + } + } + } else if (process.platform === "win32") { + if (path.startsWith("\\cygdrive\\") || path.startsWith("/cygdrive/")) { + path = path[10] + ":" + path.substr(11); // replaces /cygdrive/c/foo/bar.txt with c:/foo/bar.txt + } + } + source = new Source(element.fileName, path); + } + + ret.push(new StackFrame( + this.threadAndLevelToFrameId(args.threadId, element.level), + element.function + "@" + element.address, + source, + element.line, + 0)); + }); + response.body = { + stackFrames: ret + }; + this.sendResponse(response); + }, err => { + this.sendErrorResponse(response, 12, `Failed to get Stack Trace: ${err.toString()}`); + }); + } + + protected configurationDoneRequest(response: DebugProtocol.ConfigurationDoneResponse, args: DebugProtocol.ConfigurationDoneArguments): void { + const promises: Thenable[] = []; + let entryPoint: string | undefined = undefined; + let runToStart: boolean = false; + // Setup temporary breakpoint for the entry point if needed. + switch (this.initialRunCommand) { + case RunCommand.CONTINUE: + case RunCommand.NONE: + if (typeof this.stopAtEntry == 'boolean' && this.stopAtEntry) + entryPoint = "main"; // sensible default + else if (typeof this.stopAtEntry == 'string') + entryPoint = this.stopAtEntry; + break; + case RunCommand.RUN: + if (typeof this.stopAtEntry == 'boolean' && this.stopAtEntry) { + if (this.miDebugger.features.includes("exec-run-start-option")) + runToStart = true; + else + entryPoint = "main"; // sensible fallback + } else if (typeof this.stopAtEntry == 'string') + entryPoint = this.stopAtEntry; + break; + default: + throw new Error('Unhandled run command: ' + RunCommand[this.initialRunCommand]); + } + if (entryPoint) + promises.push(this.miDebugger.setEntryBreakPoint(entryPoint)); + switch (this.initialRunCommand) { + case RunCommand.CONTINUE: + promises.push(this.miDebugger.continue().then(() => { + // Some debuggers will provide an out-of-band status that they are stopped + // when attaching (e.g., gdb), so the client assumes we are stopped and gets + // confused if we start running again on our own. + // + // If we don't send this event, the client may start requesting data (such as + // stack frames, local variables, etc.) since they believe the target is + // stopped. Furthermore the client may not be indicating the proper status + // to the user (may indicate stopped when the target is actually running). + this.sendEvent(new ContinuedEvent(1, true)); + })); + break; + case RunCommand.RUN: + promises.push(this.miDebugger.start(runToStart).then(() => { + this.started = true; + if (this.crashed) + this.handlePause(undefined); + })); + break; + case RunCommand.NONE: + // Not all debuggers seem to provide an out-of-band status that they are stopped + // when attaching (e.g., lldb), so the client assumes we are running and gets + // confused when we don't actually run or continue. Therefore, we'll force a + // stopped event to be sent to the client (just in case) to synchronize the state. + const event: DebugProtocol.StoppedEvent = new StoppedEvent("pause", 1); + event.body.description = "paused on attach"; + event.body.allThreadsStopped = true; + this.sendEvent(event); + break; + default: + throw new Error('Unhandled run command: ' + RunCommand[this.initialRunCommand]); + } + Promise.all(promises).then(() => { + this.sendResponse(response); + }).catch(err => { + this.sendErrorResponse(response, 18, `Could not run/continue: ${err.toString()}`); + }); + } + + protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void { + const scopes = new Array(); + scopes.push(new Scope("Local", STACK_HANDLES_START + (parseInt(args.frameId as any) || 0), false)); + + response.body = { + scopes: scopes + }; + this.sendResponse(response); + } + + protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise { + const variables: DebugProtocol.Variable[] = []; + let id: number | string | VariableObject | ExtendedVariable; + if (args.variablesReference < VAR_HANDLES_START) { + id = args.variablesReference - STACK_HANDLES_START; + } else { + id = this.variableHandles.get(args.variablesReference); + } + + const createVariable = (arg, options?) => { + if (options) + return this.variableHandles.create(new ExtendedVariable(arg, options)); + else + return this.variableHandles.create(arg); + }; + + const findOrCreateVariable = (varObj: VariableObject): number => { + let id: number; + if (this.variableHandlesReverse.hasOwnProperty(varObj.name)) { + id = this.variableHandlesReverse[varObj.name]; + } else { + id = createVariable(varObj); + this.variableHandlesReverse[varObj.name] = id; + } + return varObj.isCompound() ? id : 0; + }; + + if (typeof id == "number") { + let stack: Variable[]; + try { + const [threadId, level] = this.frameIdToThreadAndLevel(id); + stack = await this.miDebugger.getStackVariables(threadId, level); + for (const variable of stack) { + if (this.useVarObjects) { + try { + const varObjName = `var_${id}_${variable.name}`; + let varObj: VariableObject; + try { + const changes = await this.miDebugger.varUpdate(varObjName); + const changelist = changes.result("changelist"); + changelist.forEach((change) => { + const name = MINode.valueOf(change, "name"); + const vId = this.variableHandlesReverse[name]; + const v = this.variableHandles.get(vId) as any; + v.applyChanges(change); + }); + const varId = this.variableHandlesReverse[varObjName]; + varObj = this.variableHandles.get(varId) as any; + } catch (err) { + if (err instanceof MIError && err.message == "Variable object not found") { + varObj = await this.miDebugger.varCreate(variable.name, varObjName); + const varId = findOrCreateVariable(varObj); + varObj.exp = variable.name; + varObj.id = varId; + } else { + throw err; + } + } + variables.push(varObj.toProtocolVariable()); + } catch (err) { + variables.push({ + name: variable.name, + value: `<${err}>`, + variablesReference: 0 + }); + } + } else { + if (variable.valueStr !== undefined) { + let expanded = expandValue(createVariable, `{${variable.name}=${variable.valueStr})`, "", variable.raw); + if (expanded) { + if (typeof expanded[0] == "string") + expanded = [ + { + name: "", + value: prettyStringArray(expanded), + variablesReference: 0 + } + ]; + variables.push(expanded[0]); + } + } else + variables.push({ + name: variable.name, + type: variable.type, + value: "", + variablesReference: createVariable(variable.name) + }); + } + } + response.body = { + variables: variables + }; + this.sendResponse(response); + } catch (err) { + this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`); + } + } else if (typeof id == "string") { + // Variable members + let variable; + try { + // TODO: this evals on an (effectively) unknown thread for multithreaded programs. + variable = await this.miDebugger.evalExpression(JSON.stringify(id), 0, 0); + try { + let expanded = expandValue(createVariable, variable.result("value"), id, variable); + if (!expanded) { + this.sendErrorResponse(response, 2, `Could not expand variable`); + } else { + if (typeof expanded[0] == "string") + expanded = [ + { + name: "", + value: prettyStringArray(expanded), + variablesReference: 0 + } + ]; + response.body = { + variables: expanded + }; + this.sendResponse(response); + } + } catch (e) { + this.sendErrorResponse(response, 2, `Could not expand variable: ${e}`); + } + } catch (err) { + this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`); + } + } else if (typeof id == "object") { + if (id instanceof VariableObject) { + // Variable members + let children: VariableObject[]; + try { + children = await this.miDebugger.varListChildren(id.name); + const vars = children.map(child => { + const varId = findOrCreateVariable(child); + child.id = varId; + return child.toProtocolVariable(); + }); + + response.body = { + variables: vars + }; + this.sendResponse(response); + } catch (err) { + this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`); + } + } else if (id instanceof ExtendedVariable) { + const varReq = id; + if (varReq.options.arg) { + const strArr = []; + let argsPart = true; + let arrIndex = 0; + const submit = () => { + response.body = { + variables: strArr + }; + this.sendResponse(response); + }; + const addOne = async () => { + // TODO: this evals on an (effectively) unknown thread for multithreaded programs. + const variable = await this.miDebugger.evalExpression(JSON.stringify(`${varReq.name}+${arrIndex})`), 0, 0); + try { + const expanded = expandValue(createVariable, variable.result("value"), varReq.name, variable); + if (!expanded) { + this.sendErrorResponse(response, 15, `Could not expand variable`); + } else { + if (typeof expanded == "string") { + if (expanded == "") { + if (argsPart) + argsPart = false; + else + return submit(); + } else if (expanded[0] != '"') { + strArr.push({ + name: "[err]", + value: expanded, + variablesReference: 0 + }); + return submit(); + } + strArr.push({ + name: `[${(arrIndex++)}]`, + value: expanded, + variablesReference: 0 + }); + addOne(); + } else { + strArr.push({ + name: "[err]", + value: expanded, + variablesReference: 0 + }); + submit(); + } + } + } catch (e) { + this.sendErrorResponse(response, 14, `Could not expand variable: ${e}`); + } + }; + addOne(); + } else + this.sendErrorResponse(response, 13, `Unimplemented variable request options: ${JSON.stringify(varReq.options)}`); + } else { + response.body = { + variables: id + }; + this.sendResponse(response); + } + } else { + response.body = { + variables: variables + }; + this.sendResponse(response); + } + } + + protected pauseRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void { + this.miDebugger.interrupt().then(done => { + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 3, `Could not pause: ${msg}`); + }); + } + + protected reverseContinueRequest(response: DebugProtocol.ReverseContinueResponse, args: DebugProtocol.ReverseContinueArguments): void { + this.miDebugger.continue(true).then(done => { + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 2, `Could not continue: ${msg}`); + }); + } + + protected continueRequest(response: DebugProtocol.ContinueResponse, args: DebugProtocol.ContinueArguments): void { + this.miDebugger.continue().then(done => { + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 2, `Could not continue: ${msg}`); + }); + } + + protected stepBackRequest(response: DebugProtocol.StepBackResponse, args: DebugProtocol.StepBackArguments): void { + this.miDebugger.step(true).then(done => { + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 4, `Could not step back: ${msg} - Try running 'target record-full' before stepping back`); + }); + } + + protected stepInRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void { + this.miDebugger.step().then(done => { + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 4, `Could not step in: ${msg}`); + }); + } + + protected stepOutRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void { + this.miDebugger.stepOut().then(done => { + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 5, `Could not step out: ${msg}`); + }); + } + + protected nextRequest(response: DebugProtocol.NextResponse, args: DebugProtocol.NextArguments): void { + this.miDebugger.next().then(done => { + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 6, `Could not step over: ${msg}`); + }); + } + + protected evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments): void { + const [threadId, level] = this.frameIdToThreadAndLevel(args.frameId); + if (args.context == "watch" || args.context == "hover") { + this.miDebugger.evalExpression(args.expression, threadId, level).then((res) => { + response.body = { + variablesReference: 0, + result: res.result("value") + }; + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 7, msg.toString()); + }); + } else { + this.miDebugger.sendUserInput(args.expression, threadId, level).then(output => { + if (typeof output == "undefined") + response.body = { + result: "", + variablesReference: 0 + }; + else + response.body = { + result: JSON.stringify(output), + variablesReference: 0 + }; + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 8, msg.toString()); + }); + } + } + + protected gotoTargetsRequest(response: DebugProtocol.GotoTargetsResponse, args: DebugProtocol.GotoTargetsArguments): void { + this.miDebugger.goto(args.source.path, args.line).then(done => { + response.body = { + targets: [{ + id: 1, + label: args.source.name, + column: args.column, + line : args.line + }] + }; + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 16, `Could not jump: ${msg}`); + }); + } + + protected gotoRequest(response: DebugProtocol.GotoResponse, args: DebugProtocol.GotoArguments): void { + this.sendResponse(response); + } + + private addSourceFileMapEntry(gdbCWD :string, ideCWD : string): void { + // if it looks like a Win32 path convert to "/"-style for comparisions and to all-lower-case + if (ideCWD.indexOf("\\") != -1) + ideCWD = ideCWD.replace(/\\/g, "/").toLowerCase(); + if (!ideCWD.endsWith("/")) + ideCWD = ideCWD + "/" + // ensure that we only replace complete paths + if (gdbCWD.indexOf("\\") != -1) + gdbCWD = gdbCWD.replace(/\\/g, "/").toLowerCase(); + if (!gdbCWD.endsWith("/")) + gdbCWD = gdbCWD + "/" + this.sourceFileMap.set(ideCWD, gdbCWD); + } + + protected setSourceFileMap(configMap: { [index: string]: string }, fallbackGDB :string, fallbackIDE : string): void { + this.sourceFileMap = new Map(); + if (configMap === undefined) { + this.addSourceFileMapEntry(fallbackGDB, fallbackIDE); + } else { + for (let [gdbPath, localPath] of Object.entries(configMap)) { + this.addSourceFileMapEntry(gdbPath, localPath); + } + } + } + +} + +function prettyStringArray(strings) { + if (typeof strings == "object") { + if (strings.length !== undefined) + return strings.join(", "); + else + return JSON.stringify(strings); + } else return strings; +} diff --git a/src/test/runTest.ts b/src/test/runTest.ts new file mode 100644 index 0000000..76dfd38 --- /dev/null +++ b/src/test/runTest.ts @@ -0,0 +1,24 @@ +import * as path from 'path'; + +import { runTests } from 'vscode-test'; + +async function main() { + try { + // The folder containing the Extension Manifest package.json + // Passed to `--extensionDevelopmentPath` + const extensionDevelopmentPath = path.resolve(__dirname, '../../'); + + // The path to the extension test runner script + // Passed to --extensionTestsPath + const extensionTestsPath = path.resolve(__dirname, './suite/index'); + + // Download VS Code, unzip it and run the integration test + await runTests({ extensionDevelopmentPath, extensionTestsPath }); + } catch (err) { + console.error(err); + console.error('Failed to run tests'); + process.exit(1); + } +} + +main(); \ No newline at end of file diff --git a/src/test/suite/gdb_expansion.test.ts b/src/test/suite/gdb_expansion.test.ts new file mode 100644 index 0000000..ff81ac6 --- /dev/null +++ b/src/test/suite/gdb_expansion.test.ts @@ -0,0 +1,306 @@ +import * as assert from 'assert'; +import { expandValue, isExpandable } from '../../backend/gdb_expansion'; + +suite("GDB Value Expansion", () => { + const variableCreate = (variable) => { return { expanded: variable }; }; + test("Various values", () => { + assert.strictEqual(isExpandable(`false`), 0); + assert.equal(expandValue(variableCreate, `false`), "false"); + assert.strictEqual(isExpandable(`5`), 0); + assert.equal(expandValue(variableCreate, `5`), "5"); + assert.strictEqual(isExpandable(`"hello world!"`), 0); + assert.equal(expandValue(variableCreate, `"hello world!"`), `"hello world!"`); + assert.strictEqual(isExpandable(`0x7fffffffe956 "foobar"`), 0); + assert.equal(expandValue(variableCreate, `0x7fffffffe956 "foobar"`), `"foobar"`); + assert.strictEqual(isExpandable(`0x0`), 0); + assert.equal(expandValue(variableCreate, `0x0`), ""); + assert.strictEqual(isExpandable(`0x000000`), 0); + assert.equal(expandValue(variableCreate, `0x000000`), ""); + assert.strictEqual(isExpandable(`{...}`), 2); + assert.equal(expandValue(variableCreate, `{...}`), "<...>"); + assert.strictEqual(isExpandable(`0x00abc`), 2); + assert.equal(expandValue(variableCreate, `0x007ffff7ecb480`), "*0x007ffff7ecb480"); + assert.strictEqual(isExpandable(`{a = b, c = d}`), 1); + assert.deepEqual(expandValue(variableCreate, `{a = b, c = d}`), [ + { + name: "a", + value: "b", + variablesReference: 0 + }, { + name: "c", + value: "d", + variablesReference: 0 + }]); + assert.strictEqual(isExpandable(`{[0] = 0x400730 "foo", [1] = 0x400735 "bar"}`), 1); + assert.deepEqual(expandValue(variableCreate, `{[0] = 0x400730 "foo", [1] = 0x400735 "bar"}`), [ + { + name: "[0]", + value: "\"foo\"", + variablesReference: 0 + }, { + name: "[1]", + value: "\"bar\"", + variablesReference: 0 + }]); + assert.strictEqual(isExpandable(`{{a = b}}`), 1); + assert.deepEqual(expandValue(variableCreate, `{{a = b}}`), [ + { + name: "[0]", + value: "Object", + variablesReference: { + expanded: [ + { + name: "a", + value: "b", + variablesReference: 0 + } + ] + } + } + ]); + assert.deepEqual(expandValue(variableCreate, `{1, 2, 3, 4}`), [ + { + name: "[0]", + value: "1", + variablesReference: 0 + }, { + name: "[1]", + value: "2", + variablesReference: 0 + }, { + name: "[2]", + value: "3", + variablesReference: 0 + }, { + name: "[3]", + value: "4", + variablesReference: 0 + }]); + }); + test("Error values", () => { + assert.strictEqual(isExpandable(``), 0); + assert.equal(expandValue(variableCreate, ``), ""); + }); + test("Nested values", () => { + assert.strictEqual(isExpandable(`{a = {b = e}, c = d}`), 1); + assert.deepEqual(expandValue(variableCreate, `{a = {b = e}, c = d}`), [ + { + name: "a", + value: "Object", + variablesReference: { + expanded: [ + { + name: "b", + value: "e", + variablesReference: 0 + } + ] + } + }, { + name: "c", + value: "d", + variablesReference: 0 + }]); + }); + test("Simple node", () => { + assert.strictEqual(isExpandable(`{a = false, b = 5, c = 0x0, d = "foobar"}`), 1); + const variables = expandValue(variableCreate, `{a = false, b = 5, c = 0x0, d = "foobar"}`); + assert.equal(variables.length, 4); + assert.equal(variables[0].name, "a"); + assert.equal(variables[0].value, "false"); + assert.equal(variables[1].name, "b"); + assert.equal(variables[1].value, "5"); + assert.equal(variables[2].name, "c"); + assert.equal(variables[2].value, ""); + assert.equal(variables[3].name, "d"); + assert.equal(variables[3].value, `"foobar"`); + }); + test("Complex node", () => { + const node = `{quit = false, _views = {{view = 0x7ffff7ece1e8, renderer = 0x7ffff7eccc50, world = 0x7ffff7ece480}}, deltaTimer = {_flagStarted = false, _timeStart = {length = 0}, _timeMeasured = {length = 0}}, _start = {callbacks = 0x0}, _stop = {callbacks = 0x0}}`; + assert.strictEqual(isExpandable(node), 1); + const variables = expandValue(variableCreate, node); + assert.deepEqual(variables, [ + { + name: "quit", + value: "false", + variablesReference: 0 + }, + { + name: "_views", + value: "Object", + variablesReference: { + expanded: [ + { + name: "[0]", + value: "Object", + variablesReference: { + expanded: [ + { + name: "view", + value: "Object@*0x7ffff7ece1e8", + variablesReference: { expanded: "*_views[0].view" } + }, + { + name: "renderer", + value: "Object@*0x7ffff7eccc50", + variablesReference: { expanded: "*_views[0].renderer" } + }, + { + name: "world", + value: "Object@*0x7ffff7ece480", + variablesReference: { expanded: "*_views[0].world" } + } + ] + } + } + ] + } + }, + { + name: "deltaTimer", + value: "Object", + variablesReference: { + expanded: [ + { + name: "_flagStarted", + value: "false", + variablesReference: 0 + }, + { + name: "_timeStart", + value: "Object", + variablesReference: { + expanded: [ + { + name: "length", + value: "0", + variablesReference: 0 + } + ] + } + }, + { + name: "_timeMeasured", + value: "Object", + variablesReference: { + expanded: [ + { + name: "length", + value: "0", + variablesReference: 0 + } + ] + } + } + ] + } + }, + { + name: "_start", + value: "Object", + variablesReference: { + expanded: [ + { + name: "callbacks", + value: "", + variablesReference: 0 + } + ] + } + }, + { + name: "_stop", + value: "Object", + variablesReference: { + expanded: [ + { + name: "callbacks", + value: "", + variablesReference: 0 + } + ] + } + } + ]); + }); + test("Simple node with errors", () => { + const node = `{_enableMipMaps = false, _minFilter = , _magFilter = , _wrapX = , _wrapY = , _inMode = 6408, _mode = 6408, _id = 1, _width = 1024, _height = 1024}`; + assert.strictEqual(isExpandable(node), 1); + const variables = expandValue(variableCreate, node); + assert.deepEqual(variables, [ + { + name: "_enableMipMaps", + value: "false", + variablesReference: 0 + }, + { + name: "_minFilter", + value: "", + variablesReference: 0 + }, + { + name: "_magFilter", + value: "", + variablesReference: 0 + }, + { + name: "_wrapX", + value: "", + variablesReference: 0 + }, + { + name: "_wrapY", + value: "", + variablesReference: 0 + }, + { + name: "_inMode", + value: "6408", + variablesReference: 0 + }, + { + name: "_mode", + value: "6408", + variablesReference: 0 + }, + { + name: "_id", + value: "1", + variablesReference: 0 + }, + { + name: "_width", + value: "1024", + variablesReference: 0 + }, + { + name: "_height", + value: "1024", + variablesReference: 0 + } + ]); + }); + test("lldb strings", () => { + const node = `{ name = {...} }`; + assert.strictEqual(isExpandable(node), 1); + const variables = expandValue(variableCreate, node); + assert.deepEqual(variables, [ + { + name: "name", + value: "...", + variablesReference: { expanded: "name" } + } + ]); + }); + test("float values", () => { + const node = `{ intval1 = 123, floatval1 = 123.456, intval2 = 3, floatval2 = 234.45 }`; + const variables = expandValue(variableCreate, node); + + assert.deepEqual(variables, [ + { name: "intval1", value: "123", variablesReference: 0 }, + { name: "floatval1", value: "123.456", variablesReference: 0 }, + { name: "intval2", value: "3", variablesReference: 0 }, + { name: "floatval2", value: "234.45", variablesReference: 0 } + ]); + }); +}); diff --git a/src/test/suite/index.ts b/src/test/suite/index.ts new file mode 100644 index 0000000..45ff4b8 --- /dev/null +++ b/src/test/suite/index.ts @@ -0,0 +1,37 @@ +import * as path from 'path'; +import * as Mocha from 'mocha'; +import * as glob from 'glob'; + +export function run(): Promise { + // Create the mocha test + const mocha = new Mocha({ + ui: 'tdd', + useColors: true + }); + + const testsRoot = path.resolve(__dirname, '..'); + + return new Promise((c, e) => { + glob('**/**.test.js', { cwd: testsRoot }, (err, files) => { + if (err) { + return e(err); + } + + // Add files to the test suite + files.forEach(f => mocha.addFile(path.resolve(testsRoot, f))); + + try { + // Run the mocha test + mocha.run(failures => { + if (failures > 0) { + e(new Error(`${failures} tests failed.`)); + } else { + c(); + } + }); + } catch (err) { + e(err); + } + }); + }); +} \ No newline at end of file diff --git a/src/test/suite/mi_parse.test.ts b/src/test/suite/mi_parse.test.ts new file mode 100644 index 0000000..8bf7a89 --- /dev/null +++ b/src/test/suite/mi_parse.test.ts @@ -0,0 +1,207 @@ +import * as assert from 'assert'; +import { parseMI, MINode } from '../../backend/mi_parse'; + +suite("MI Parse", () => { + test("Very simple out of band record", () => { + const parsed = parseMI(`*stopped`); + assert.ok(parsed); + assert.strictEqual(parsed.token, undefined); + assert.strictEqual(parsed.outOfBandRecord.length, 1); + assert.strictEqual(parsed.outOfBandRecord[0].isStream, false); + assert.strictEqual(parsed.outOfBandRecord[0].asyncClass, "stopped"); + assert.strictEqual(parsed.outOfBandRecord[0].output.length, 0); + assert.strictEqual(parsed.resultRecords, undefined); + }); + test("Simple out of band record", () => { + const parsed = parseMI(`4=thread-exited,id="3",group-id="i1"`); + assert.ok(parsed); + assert.equal(parsed.token, 4); + assert.equal(parsed.outOfBandRecord.length, 1); + assert.equal(parsed.outOfBandRecord[0].isStream, false); + assert.equal(parsed.outOfBandRecord[0].asyncClass, "thread-exited"); + assert.equal(parsed.outOfBandRecord[0].output.length, 2); + assert.deepEqual(parsed.outOfBandRecord[0].output[0], ["id", "3"]); + assert.deepEqual(parsed.outOfBandRecord[0].output[1], ["group-id", "i1"]); + assert.equal(parsed.resultRecords, undefined); + }); + test("Console stream output with new line", () => { + const parsed = parseMI(`~"[Thread 0x7fffe993a700 (LWP 11002) exited]\\n"`); + assert.ok(parsed); + assert.equal(parsed.token, undefined); + assert.equal(parsed.outOfBandRecord.length, 1); + assert.equal(parsed.outOfBandRecord[0].isStream, true); + assert.equal(parsed.outOfBandRecord[0].content, "[Thread 0x7fffe993a700 (LWP 11002) exited]\n"); + assert.equal(parsed.resultRecords, undefined); + }); + test("Unicode", () => { + let parsed = parseMI(`~"[Depuraci\\303\\263n de hilo usando libthread_db enabled]\\n"`); + assert.ok(parsed); + assert.equal(parsed.token, undefined); + assert.equal(parsed.outOfBandRecord.length, 1); + assert.equal(parsed.outOfBandRecord[0].isStream, true); + assert.equal(parsed.outOfBandRecord[0].content, "[Depuración de hilo usando libthread_db enabled]\n"); + assert.equal(parsed.resultRecords, undefined); + parsed = parseMI(`~"4\\t std::cout << \\"\\345\\245\\275\\345\\245\\275\\345\\255\\246\\344\\271\\240\\357\\274\\214\\345\\244\\251\\345\\244\\251\\345\\220\\221\\344\\270\\212\\" << std::endl;\\n"`); + assert.ok(parsed); + assert.equal(parsed.token, undefined); + assert.equal(parsed.outOfBandRecord.length, 1); + assert.equal(parsed.outOfBandRecord[0].isStream, true); + assert.equal(parsed.outOfBandRecord[0].content, `4\t std::cout << "好好学习,天天向上" << std::endl;\n`); + assert.equal(parsed.resultRecords, undefined); + }); + test("Empty line", () => { + const parsed = parseMI(``); + assert.ok(parsed); + assert.equal(parsed.token, undefined); + assert.equal(parsed.outOfBandRecord.length, 0); + assert.equal(parsed.resultRecords, undefined); + }); + test("'(gdb)' line", () => { + const parsed = parseMI(`(gdb)`); + assert.ok(parsed); + assert.equal(parsed.token, undefined); + assert.equal(parsed.outOfBandRecord.length, 0); + assert.equal(parsed.resultRecords, undefined); + }); + test("Simple result record", () => { + const parsed = parseMI(`1^running`); + assert.ok(parsed); + assert.equal(parsed.token, 1); + assert.equal(parsed.outOfBandRecord.length, 0); + assert.notEqual(parsed.resultRecords, undefined); + assert.equal(parsed.resultRecords.resultClass, "running"); + assert.equal(parsed.resultRecords.results.length, 0); + }); + test("Advanced out of band record (Breakpoint hit)", () => { + const parsed = parseMI(`*stopped,reason="breakpoint-hit",disp="keep",bkptno="1",frame={addr="0x00000000004e807f",func="D main",args=[{name="args",value="..."}],file="source/app.d",fullname="/path/to/source/app.d",line="157"},thread-id="1",stopped-threads="all",core="0"`); + assert.ok(parsed); + assert.equal(parsed.token, undefined); + assert.equal(parsed.outOfBandRecord.length, 1); + assert.equal(parsed.outOfBandRecord[0].isStream, false); + assert.equal(parsed.outOfBandRecord[0].asyncClass, "stopped"); + assert.equal(parsed.outOfBandRecord[0].output.length, 7); + assert.deepEqual(parsed.outOfBandRecord[0].output[0], ["reason", "breakpoint-hit"]); + assert.deepEqual(parsed.outOfBandRecord[0].output[1], ["disp", "keep"]); + assert.deepEqual(parsed.outOfBandRecord[0].output[2], ["bkptno", "1"]); + const frame = [ + ["addr", "0x00000000004e807f"], + ["func", "D main"], + ["args", [[["name", "args"], ["value", "..."]]]], + ["file", "source/app.d"], + ["fullname", "/path/to/source/app.d"], + ["line", "157"] + ]; + assert.deepEqual(parsed.outOfBandRecord[0].output[3], ["frame", frame]); + assert.deepEqual(parsed.outOfBandRecord[0].output[4], ["thread-id", "1"]); + assert.deepEqual(parsed.outOfBandRecord[0].output[5], ["stopped-threads", "all"]); + assert.deepEqual(parsed.outOfBandRecord[0].output[6], ["core", "0"]); + assert.equal(parsed.resultRecords, undefined); + }); + test("Advanced result record", () => { + const parsed = parseMI(`2^done,asm_insns=[src_and_asm_line={line="134",file="source/app.d",fullname="/path/to/source/app.d",line_asm_insn=[{address="0x00000000004e7da4",func-name="_Dmain",offset="0",inst="push %rbp"},{address="0x00000000004e7da5",func-name="_Dmain",offset="1",inst="mov %rsp,%rbp"}]}]`); + assert.ok(parsed); + assert.equal(parsed.token, 2); + assert.equal(parsed.outOfBandRecord.length, 0); + assert.notEqual(parsed.resultRecords, undefined); + assert.equal(parsed.resultRecords.resultClass, "done"); + assert.equal(parsed.resultRecords.results.length, 1); + const asmInsns = [ + "asm_insns", + [ + [ + "src_and_asm_line", + [ + ["line", "134"], + ["file", "source/app.d"], + ["fullname", "/path/to/source/app.d"], + [ + "line_asm_insn", + [ + [ + ["address", "0x00000000004e7da4"], + ["func-name", "_Dmain"], + ["offset", "0"], + ["inst", "push %rbp"] + ], + [ + ["address", "0x00000000004e7da5"], + ["func-name", "_Dmain"], + ["offset", "1"], + ["inst", "mov %rsp,%rbp"] + ] + ] + ] + ] + ] + ] + ]; + assert.deepEqual(parsed.resultRecords.results[0], asmInsns); + assert.equal(parsed.result("asm_insns.src_and_asm_line.line_asm_insn[1].address"), "0x00000000004e7da5"); + }); + test("valueof children", () => { + const obj = [ + [ + "frame", + [ + ["level", "0"], + ["addr", "0x0000000000435f70"], + ["func", "D main"], + ["file", "source/app.d"], + ["fullname", "/path/to/source/app.d"], + ["line", "5"] + ] + ], + [ + "frame", + [ + ["level", "1"], + ["addr", "0x00000000004372d3"], + ["func", "rt.dmain2._d_run_main()"] + ] + ], + [ + "frame", + [ + ["level", "2"], + ["addr", "0x0000000000437229"], + ["func", "rt.dmain2._d_run_main()"] + ] + ] + ]; + + assert.equal(MINode.valueOf(obj[0], "@frame.level"), "0"); + assert.equal(MINode.valueOf(obj[0], "@frame.addr"), "0x0000000000435f70"); + assert.equal(MINode.valueOf(obj[0], "@frame.func"), "D main"); + assert.equal(MINode.valueOf(obj[0], "@frame.file"), "source/app.d"); + assert.equal(MINode.valueOf(obj[0], "@frame.fullname"), "/path/to/source/app.d"); + assert.equal(MINode.valueOf(obj[0], "@frame.line"), "5"); + + assert.equal(MINode.valueOf(obj[1], "@frame.level"), "1"); + assert.equal(MINode.valueOf(obj[1], "@frame.addr"), "0x00000000004372d3"); + assert.equal(MINode.valueOf(obj[1], "@frame.func"), "rt.dmain2._d_run_main()"); + assert.equal(MINode.valueOf(obj[1], "@frame.file"), undefined); + assert.equal(MINode.valueOf(obj[1], "@frame.fullname"), undefined); + assert.equal(MINode.valueOf(obj[1], "@frame.line"), undefined); + }); + test("empty string values", () => { + const parsed = parseMI(`15^done,register-names=["r0","pc","","xpsr","","control"]`); + const result = parsed.result('register-names'); + assert.deepEqual(result, ["r0", "pc", "", "xpsr", "", "control"]); + }); + test("empty string value first and last", () => { + const parsed = parseMI(`15^done,register-names=["","r0","pc","","xpsr","","control",""]`); + const result = parsed.result('register-names'); + assert.deepEqual(result, ["","r0","pc","","xpsr","","control", ""]); + }); + test("empty array values", () => { + const parsed = parseMI(`15^done,foo={x=[],y="y"}`); + assert.deepEqual(parsed.result('foo.x'), []); + assert.equal(parsed.result('foo.y'), "y"); + }); + test("empty object values", () => { + // GDB may send {} as empty array + const parsed = parseMI(`15^done,foo={x={},y="y"}`); + assert.deepEqual(parsed.result('foo.x'), []); + assert.equal(parsed.result('foo.y'), "y"); + }); +}); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..915ff8f --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es6", + "outDir": "out", + "lib": [ + "es6" + ], + "sourceMap": true, + "rootDir": ".", + "plugins": [ + { + "name": "tslint-language-service" + } + ] + }, + "exclude": [ + "node_modules", + ".vscode-test" + ] +} diff --git a/tslint.json b/tslint.json new file mode 100644 index 0000000..b1ea9a1 --- /dev/null +++ b/tslint.json @@ -0,0 +1,38 @@ +{ + "defaultSeverity": "error", + "extends": "tslint:recommended", + "rules": { + "no-null-keyword": true, + "indent": [true, "tabs"], + /* Rules in tslint:recommended that we don't follow yet. */ + "array-type": false, + "arrow-parens": false, + "arrow-return-shorthand": false, + "ban-types": false, + "class-name": false, + "comment-format": false, + "curly": false, + "interface-name": false, + "max-classes-per-file": false, + "max-line-length": false, + "member-access": false, + "member-ordering": false, + "no-angle-bracket-type-assertion": false, + "no-bitwise": false, + "no-conditional-assignment": false, + "no-consecutive-blank-lines": false, + "no-empty": false, + "no-shadowed-variable": false, + "no-unnecessary-initializer": false, + "object-literal-shorthand": false, + "object-literal-sort-keys": false, + "one-variable-per-declaration": false, + "only-arrow-functions": false, + "ordered-imports": false, + "quotemark": false, + "radix": false, + "space-before-function-paren": false, + "trailing-comma": false, + "triple-equals": false + } +} From fd7d8ee1642b6e29e84667daefd4083c0771af45 Mon Sep 17 00:00:00 2001 From: Haoyang Date: Fri, 9 Sep 2022 17:22:12 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E5=8F=8D=E5=90=91?= =?UTF-8?q?=E8=B0=83=E8=AF=95=E7=9A=84=E7=95=8C=E9=9D=A2=E6=8C=89=E9=92=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Haoyang --- package.json | 29 ++++++++++++++++++++++- src/backend/mi2/mi2.ts | 31 ++++++++++++++++++++++++- src/frontend/extension.ts | 48 ++++++++++++++++++++++++++++++++------- src/mibase.ts | 39 +++++++++++++++++++++++++++++-- 4 files changed, 135 insertions(+), 12 deletions(-) diff --git a/package.json b/package.json index 79604e0..1cf66b9 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,12 @@ }, "main": "./out/src/frontend/extension", "activationEvents": [ + "onDebug", "onCommand:code-debug.examineMemoryLocation", "onCommand:code-debug.getFileNameNoExt", - "onCommand:code-debug.getFileBasenameNoExt" + "onCommand:code-debug.getFileBasenameNoExt", + "onCommand:code-debug.startRecord", + "onCommand:code-debug.stopRecord" ], "categories": [ "Debuggers" @@ -39,8 +42,32 @@ { "command": "code-debug.examineMemoryLocation", "title": "Code-Debug: Examine memory location" + }, + { + "command": "code-debug.startRecord", + "title": "Code-Debug: Start reverse debugging", + "icon":"$(debug-start)" + }, + { + "command": "code-debug.stopRecord", + "title": "Code-Debug: Stop reverse debugging", + "icon":"$(debug-stop)" } ], + "menus": { + "editor/title": [ + { + "command": "code-debug.startRecord", + "when": "inDebugMode && debugState == stopped && debugType == 'gdb' && code-debug.enableStartRecord", + "group": "navigation" + }, + { + "command": "code-debug.stopRecord", + "when": "inDebugMode && debugState == stopped && debugType == 'gdb' && !code-debug.enableStartRecord", + "group": "navigation" + } + ] + }, "breakpoints": [ {"language": "c"}, {"language": "cpp"}, diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 47b666a..81cce1f 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -351,9 +351,12 @@ export class MI2 extends EventEmitter implements IBackend { } else { if (record.type == "exec") { this.emit("exec-async-output", parsed); - if (record.asyncClass == "running") + if (record.asyncClass == "running") { + this.status = 'running'; this.emit("running", parsed); + } else if (record.asyncClass == "stopped") { + this.status = 'stopped'; const reason = parsed.record("reason"); if (reason === undefined) { if (trace) @@ -762,6 +765,30 @@ export class MI2 extends EventEmitter implements IBackend { }); } + record(): Thenable { + if (trace) + this.log("stderr", "record"); + + return new Promise((resolve, reject) => { + + if (this.status != 'stopped') { + resolve(this.isRecord ? {result:'0', oldValue:'1'} : { result:'0', oldValue:'0'}); + this.log("stderr", `WARNING: The program is ${this.status} and cannot ${this.isRecord ? 'stop' : 'start'} reverse debugging.`); + return; + } + + this.isRecord = !this.isRecord; + this.sendCliCommand(this.isRecord ? "record" : "record stop").then((result) => { + if (result.resultRecords.resultClass == "done") { + resolve(this.isRecord ? {result:'1', oldValue:'0'} : { result:'1', oldValue:'1'}); + } + else { + this.isRecord = !this.isRecord; //restore + resolve(this.isRecord ? {result:'0', oldValue:'1'} : { result:'0', oldValue:'0'}); + } + }, reject); + }); + } async evalExpression(name: string, thread: number, frame: number): Promise { if (trace) this.log("stderr", "evalExpression"); @@ -870,6 +897,8 @@ export class MI2 extends EventEmitter implements IBackend { return /^-|[^\w\d\/_\-\.]/g.test(text) ? ('"' + escape(text) + '"') : text; } + isRecord:boolean = false; + status: 'running' | 'stopped' | 'none' = 'none'; prettyPrint: boolean = true; printCalls: boolean; debugOutput: boolean; diff --git a/src/frontend/extension.ts b/src/frontend/extension.ts index 19fc6f9..4cc7f26 100644 --- a/src/frontend/extension.ts +++ b/src/frontend/extension.ts @@ -16,6 +16,8 @@ export function activate(context: vscode.ExtensionContext) { const ext = path.extname(fileName); return fileName.substr(0, fileName.length - ext.length); })); + context.subscriptions.push(vscode.commands.registerCommand("code-debug.startRecord", handleRecord)); + context.subscriptions.push(vscode.commands.registerCommand("code-debug.stopRecord", handleRecord)); context.subscriptions.push(vscode.commands.registerCommand("code-debug.getFileBasenameNoExt", () => { if (!vscode.window.activeTextEditor || !vscode.window.activeTextEditor.document || !vscode.window.activeTextEditor.document.fileName) { vscode.window.showErrorMessage("No editor with valid file name active"); @@ -25,6 +27,10 @@ export function activate(context: vscode.ExtensionContext) { const ext = path.extname(fileName); return fileName.substr(0, fileName.length - ext.length); })); + + vscode.debug.onDidStartDebugSession(()=>{ + vscode.commands.executeCommand('setContext', 'code-debug.enableStartRecord', true); + }); } const memoryLocationRegex = /^0x[0-9a-f]+$/; @@ -55,7 +61,7 @@ function getMemoryRange(range: string) { else return undefined; } -function examineMemory() { +function execCmd(func:any){ const socketlists = path.join(os.tmpdir(), "code-debug-sockets"); if (!fs.existsSync(socketlists)) { if (process.platform == "win32") @@ -70,15 +76,11 @@ function examineMemory() { else return vscode.window.showErrorMessage("No debugging sessions available"); } - const pickedFile = (file) => { - vscode.window.showInputBox({ placeHolder: "Memory Location or Range", validateInput: range => getMemoryRange(range) === undefined ? "Range must either be in format 0xF00-0xF01, 0xF100+32 or 0xABC154" : "" }).then(range => { - vscode.window.showTextDocument(vscode.Uri.parse("debugmemory://" + file + "?" + getMemoryRange(range))); - }); - }; + if (files.length == 1) - pickedFile(files[0]); + func(files[0]); else if (files.length > 0) - vscode.window.showQuickPick(files, { placeHolder: "Running debugging instance" }).then(file => pickedFile(file)); + vscode.window.showQuickPick(files, { placeHolder: "Running debugging instance" }).then(file => func(file)); else if (process.platform == "win32") return vscode.window.showErrorMessage("This command is not available on windows"); else @@ -86,6 +88,36 @@ function examineMemory() { }); } +function examineMemory() { + const pickedFile = (file) => { + vscode.window.showInputBox({ placeHolder: "Memory Location or Range", validateInput: range => getMemoryRange(range) === undefined ? "Range must either be in format 0xF00-0xF01, 0xF100+32 or 0xABC154" : "" }).then(range => { + vscode.window.showTextDocument(vscode.Uri.parse("debugmemory://" + file + "?" + getMemoryRange(range))); + }); + }; + execCmd(pickedFile); +} + +function handleRecord() { + const record = (file) => { + const conn = net.connect(path.join(os.tmpdir(), "code-debug-sockets", file)); + conn.write("record"); + conn.once("data", data => { + if (data){ + let ret = JSON.parse(data.toString()); + if (ret && ret.result == '1'){ + console.log('successful to satrt reverse debugging.'); + } + else { + vscode.window.showErrorMessage(`Failed to ${ret.oldValue == '1' ? 'stop' : 'start'} reverse debugging`); + } + vscode.commands.executeCommand('setContext', 'code-debug.enableStartRecord', ret.oldValue == '1' ? true : false); + } + conn.destroy(); + }); + }; + execCmd(record); +} + class MemoryContentProvider implements vscode.TextDocumentContentProvider { provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): Thenable { return new Promise((resolve, reject) => { diff --git a/src/mibase.ts b/src/mibase.ts index 7836263..5ca012e 100644 --- a/src/mibase.ts +++ b/src/mibase.ts @@ -41,7 +41,7 @@ export class MI2DebugSession extends DebugSession { super(debuggerLinesStartAt1, isServer); } - protected initDebugger() { + protected async initDebugger() { this.miDebugger.on("launcherror", this.launchError.bind(this)); this.miDebugger.on("quit", this.quitEvent.bind(this)); this.miDebugger.on("exited-normally", this.quitEvent.bind(this)); @@ -57,6 +57,10 @@ export class MI2DebugSession extends DebugSession { this.miDebugger.on("thread-exited", this.threadExitedEvent.bind(this)); this.miDebugger.once("debug-ready", (() => this.sendEvent(new InitializedEvent()))); try { + const socketlists = systemPath.join(os.tmpdir(), "code-debug-sockets"); + if (fs.existsSync(socketlists)) { + await cleanInvalidSocketPath(socketlists); + } this.commandServer = net.createServer(c => { c.on("data", data => { const rawCmd = data.toString(); @@ -68,7 +72,7 @@ export class MI2DebugSession extends DebugSession { args = JSON.parse(rawCmd.substr(spaceIndex + 1)); } Promise.resolve(this.miDebugger[func].apply(this.miDebugger, args)).then(data => { - c.write(data.toString()); + c.write(data instanceof Object ? JSON.stringify(data).toString() : data.toString()); }); }); }); @@ -761,3 +765,34 @@ function prettyStringArray(strings) { return JSON.stringify(strings); } else return strings; } + +async function cleanInvalidSocketPath(socketlists:string){ + return new Promise((resolve, reject) => { + fs.readdir(socketlists, (err, files) => { + if (!err) { + if (files.length == 0) resolve(''); + files.forEach((file)=>{ + try { + const conn = net.connect(systemPath.join(socketlists, file)); + conn.setTimeout(200); + conn.on('error',()=>{ + fs.unlink(systemPath.join(socketlists, file), (err) => { + if (err) + console.error("Failed to unlink invalid debug server"); + resolve(''); + }); + }); + } + catch{ + fs.unlink(systemPath.join(socketlists, file), (err) => { + if (err) + console.error("Failed to unlink invalid debug server"); + resolve(''); + }); + } + }) + } + resolve(''); + }); + }); +}