├── .github └── workflows │ ├── node.js.yml │ └── scorecard.yml ├── CODEOWNERS ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE.txt ├── README.md ├── security.md ├── tcf ├── .gitignore ├── LICENSE.txt ├── README.md ├── package-lock.json ├── package.json └── tsconfig.json ├── tests ├── .eslintrc.json ├── .gitignore ├── nyc.config.js ├── package-lock.json ├── package.json ├── src │ └── test │ │ ├── test-bad-service.pcap │ │ ├── test-mismatched-token.pcap │ │ ├── test-small-token-style.pcap │ │ ├── unit │ │ ├── badservice.ts │ │ ├── disassembly.ts │ │ ├── jsonverify.ts │ │ ├── suite.ts │ │ ├── tokenmismatch.ts │ │ └── tokenstyle.ts │ │ └── unitTest.ts └── tsconfig.json └── vscode-tcf-debug ├── .eslintrc.json ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── docs ├── manual.md ├── vscode-debug-info.png └── vscode-install-vsix.png ├── package-lock.json ├── package.json ├── src ├── asyncDebugSession.ts ├── debugProvider.ts ├── extension.ts ├── lifetimeDebugSession.ts ├── loader.ts ├── mocksocket.ts ├── pcap.ts ├── proxy.ts ├── repl.ts ├── schema │ └── TCFLaunchRequestArguments.json ├── tcf-all.ts ├── tcf.ts ├── tcf │ ├── breakpoints.ts │ ├── contextquery.ts │ ├── diagnostics.ts │ ├── disassembly.ts │ ├── error.ts │ ├── expressions.ts │ ├── linenumbers.ts │ ├── locator.ts │ ├── memory.ts │ ├── registers.ts │ ├── runcontrol.ts │ ├── schema │ │ ├── BreakpointData.json │ │ ├── BreakpointStatus.json │ │ ├── ContextSuspendedData.json │ │ ├── DisassemblyCapability.json │ │ ├── DisassemblyLine.json │ │ ├── ExpressionsContextData.json │ │ ├── InstanceStatusData.json │ │ ├── MemoryResult.json │ │ ├── PieceValue.json │ │ ├── RegistersContextData.json │ │ ├── TCFCodeAreaLineNumbers.json │ │ ├── TCFContextData.json │ │ ├── TCFContextDataStackTrace.json │ │ ├── TCFError.json │ │ ├── TCFStateData.json │ │ ├── TCFSymbolContextData.json │ │ └── ValueProperties.json │ ├── stacktrace.ts │ ├── symbols.ts │ ├── tcfproto.ts │ ├── tcfutils.ts │ └── validators │ │ ├── validate-BreakpointData.d.ts │ │ ├── validate-BreakpointData.js │ │ ├── validate-BreakpointStatus.d.ts │ │ ├── validate-BreakpointStatus.js │ │ ├── validate-ContextSuspendedData.d.ts │ │ ├── validate-ContextSuspendedData.js │ │ ├── validate-DisassemblyCapability.d.ts │ │ ├── validate-DisassemblyCapability.js │ │ ├── validate-DisassemblyLine.d.ts │ │ ├── validate-DisassemblyLine.js │ │ ├── validate-ExpressionsContextData.d.ts │ │ ├── validate-ExpressionsContextData.js │ │ ├── validate-InstanceStatusData.d.ts │ │ ├── validate-InstanceStatusData.js │ │ ├── validate-MemoryResult.d.ts │ │ ├── validate-MemoryResult.js │ │ ├── validate-PieceValue.d.ts │ │ ├── validate-PieceValue.js │ │ ├── validate-RegistersContextData.d.ts │ │ ├── validate-RegistersContextData.js │ │ ├── validate-TCFCodeAreaLineNumbers.d.ts │ │ ├── validate-TCFCodeAreaLineNumbers.js │ │ ├── validate-TCFContextData.d.ts │ │ ├── validate-TCFContextData.js │ │ ├── validate-TCFContextDataStackTrace.d.ts │ │ ├── validate-TCFContextDataStackTrace.js │ │ ├── validate-TCFError.d.ts │ │ ├── validate-TCFError.js │ │ ├── validate-TCFStateData.d.ts │ │ ├── validate-TCFStateData.js │ │ ├── validate-TCFSymbolContextData.d.ts │ │ ├── validate-TCFSymbolContextData.js │ │ ├── validate-ValueProperties.d.ts │ │ └── validate-ValueProperties.js ├── tcfclient.ts ├── types.ts ├── validators │ ├── validate-TCFLaunchRequestArguments.d.ts │ └── validate-TCFLaunchRequestArguments.js └── variables │ ├── array.ts │ ├── composite.ts │ ├── helper.ts │ ├── pointer.ts │ ├── primitive.ts │ ├── raw.ts │ ├── symbol.ts │ └── types.ts └── tsconfig.json /.github/workflows/node.js.yml: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2023 Intel Corporation 3 | # SPDX-License-Identifier: MIT 4 | # 5 | name: Build extension 6 | on: [push] 7 | permissions: 8 | contents: read 9 | id-token: write 10 | attestations: write 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | steps: 16 | - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 17 | - name: Build tcf 18 | run: | 19 | cd tcf 20 | npm ci 21 | npm run compile 22 | npm pack 23 | - name: Build vscode-tcf-debug 24 | run: | 25 | cd vscode-tcf-debug 26 | npm ci 27 | npm run lint 28 | npm run package 29 | npm pack 30 | - name: Save VSIX 31 | uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v3.0 32 | with: 33 | name: vscode-tcf-debug.vsix 34 | path: vscode-tcf-debug/*vsix 35 | - name: Attest Build Provenance 36 | uses: actions/attest-build-provenance@897ed5eab6ed058a474202017ada7f40bfa52940 # v1.0.0 37 | with: 38 | subject-path: 'vscode-tcf-debug/vscode-tcf-debug.vsix' 39 | - name: Run tests 40 | run: | 41 | cd tests 42 | npm ci 43 | npm run compile 44 | npm run unittest 45 | -------------------------------------------------------------------------------- /.github/workflows/scorecard.yml: -------------------------------------------------------------------------------- 1 | # This workflow uses actions that are not certified by GitHub. They are provided 2 | # by a third-party and are governed by separate terms of service, privacy 3 | # policy, and support documentation. 4 | 5 | name: Scorecard supply-chain security 6 | on: 7 | # For Branch-Protection check. Only the default branch is supported. See 8 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection 9 | branch_protection_rule: 10 | # To guarantee Maintained check is occasionally updated. See 11 | # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained 12 | schedule: 13 | # Weekly on Saturdays 14 | - cron: '30 1 * * 6' 15 | push: 16 | branches: [ "main" ] 17 | 18 | # Declare default permissions as read only. 19 | permissions: read-all 20 | 21 | jobs: 22 | analysis: 23 | name: Scorecard analysis 24 | runs-on: ubuntu-latest 25 | permissions: 26 | # Needed to upload the results to code-scanning dashboard. 27 | security-events: write 28 | # Needed to publish results and get a badge (see publish_results below). 29 | id-token: write 30 | # Uncomment the permissions below if installing in a private repository. 31 | # contents: read 32 | # actions: read 33 | 34 | steps: 35 | - name: "Checkout code" 36 | uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 37 | with: 38 | persist-credentials: false 39 | 40 | - name: "Run analysis" 41 | uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1 42 | with: 43 | results_file: results.sarif 44 | results_format: sarif 45 | # (Optional) "write" PAT token. Uncomment the `repo_token` line below if: 46 | # - you want to enable the Branch-Protection check on a *public* repository, or 47 | # - you are installing Scorecard on a *private* repository 48 | # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat. 49 | # repo_token: ${{ secrets.SCORECARD_TOKEN }} 50 | 51 | # Public repositories: 52 | # - Publish results to OpenSSF REST API for easy access by consumers 53 | # - Allows the repository to include the Scorecard badge. 54 | # - See https://github.com/ossf/scorecard-action#publishing-results. 55 | # For private repositories: 56 | # - `publish_results` will always be set to `false`, regardless 57 | # of the value entered here. 58 | publish_results: true 59 | 60 | # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF 61 | # format to the repository Actions tab. 62 | - name: "Upload artifact" 63 | uses: actions/upload-artifact@v4.6.0 64 | # uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20 65 | with: 66 | name: "SARIF file" 67 | path: results.sarif 68 | retention-days: 5 69 | overwrite: true 70 | 71 | # Upload the results to GitHub's code scanning dashboard. 72 | - name: "Upload to code-scanning" 73 | uses: github/codeql-action/upload-sarif@1b1aada464948af03b950897e5eb522f92603cc2 # v3.24.9 74 | with: 75 | sarif_file: results.sarif 76 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @AliceStoian @ovidiuostoia 2 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | We as members, contributors, and leaders pledge to make participation in our 6 | community a harassment-free experience for everyone, regardless of age, body 7 | size, visible or invisible disability, ethnicity, sex characteristics, gender 8 | identity and expression, level of experience, education, socio-economic status, 9 | nationality, personal appearance, race, caste, color, religion, or sexual 10 | identity and orientation. 11 | 12 | We pledge to act and interact in ways that contribute to an open, welcoming, 13 | diverse, inclusive, and healthy community. 14 | 15 | ## Our Standards 16 | 17 | Examples of behavior that contributes to a positive environment for our 18 | community include: 19 | 20 | * Demonstrating empathy and kindness toward other people 21 | * Being respectful of differing opinions, viewpoints, and experiences 22 | * Giving and gracefully accepting constructive feedback 23 | * Accepting responsibility and apologizing to those affected by our mistakes, 24 | and learning from the experience 25 | * Focusing on what is best not just for us as individuals, but for the overall 26 | community 27 | 28 | Examples of unacceptable behavior include: 29 | 30 | * The use of sexualized language or imagery, and sexual attention or advances of 31 | any kind 32 | * Trolling, insulting or derogatory comments, and personal or political attacks 33 | * Public or private harassment 34 | * Publishing others' private information, such as a physical or email address, 35 | without their explicit permission 36 | * Other conduct which could reasonably be considered inappropriate in a 37 | professional setting 38 | 39 | ## Enforcement Responsibilities 40 | 41 | Community leaders are responsible for clarifying and enforcing our standards of 42 | acceptable behavior and will take appropriate and fair corrective action in 43 | response to any behavior that they deem inappropriate, threatening, offensive, 44 | or harmful. 45 | 46 | Community leaders have the right and responsibility to remove, edit, or reject 47 | comments, commits, code, wiki edits, issues, and other contributions that are 48 | not aligned to this Code of Conduct, and will communicate reasons for moderation 49 | decisions when appropriate. 50 | 51 | ## Scope 52 | 53 | This Code of Conduct applies within all community spaces, and also applies when 54 | an individual is officially representing the community in public spaces. 55 | Examples of representing our community include using an official e-mail address, 56 | posting via an official social media account, or acting as an appointed 57 | representative at an online or offline event. 58 | 59 | ## Enforcement 60 | 61 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 62 | reported to the community leaders responsible for enforcement at 63 | CommunityCodeOfConduct AT intel DOT com. 64 | All complaints will be reviewed and investigated promptly and fairly. 65 | 66 | All community leaders are obligated to respect the privacy and security of the 67 | reporter of any incident. 68 | 69 | ## Enforcement Guidelines 70 | 71 | Community leaders will follow these Community Impact Guidelines in determining 72 | the consequences for any action they deem in violation of this Code of Conduct: 73 | 74 | ### 1. Correction 75 | 76 | **Community Impact**: Use of inappropriate language or other behavior deemed 77 | unprofessional or unwelcome in the community. 78 | 79 | **Consequence**: A private, written warning from community leaders, providing 80 | clarity around the nature of the violation and an explanation of why the 81 | behavior was inappropriate. A public apology may be requested. 82 | 83 | ### 2. Warning 84 | 85 | **Community Impact**: A violation through a single incident or series of 86 | actions. 87 | 88 | **Consequence**: A warning with consequences for continued behavior. No 89 | interaction with the people involved, including unsolicited interaction with 90 | those enforcing the Code of Conduct, for a specified period of time. This 91 | includes avoiding interactions in community spaces as well as external channels 92 | like social media. Violating these terms may lead to a temporary or permanent 93 | ban. 94 | 95 | ### 3. Temporary Ban 96 | 97 | **Community Impact**: A serious violation of community standards, including 98 | sustained inappropriate behavior. 99 | 100 | **Consequence**: A temporary ban from any sort of interaction or public 101 | communication with the community for a specified period of time. No public or 102 | private interaction with the people involved, including unsolicited interaction 103 | with those enforcing the Code of Conduct, is allowed during this period. 104 | Violating these terms may lead to a permanent ban. 105 | 106 | ### 4. Permanent Ban 107 | 108 | **Community Impact**: Demonstrating a pattern of violation of community 109 | standards, including sustained inappropriate behavior, harassment of an 110 | individual, or aggression toward or disparagement of classes of individuals. 111 | 112 | **Consequence**: A permanent ban from any sort of public interaction within the 113 | community. 114 | 115 | ## Attribution 116 | 117 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 118 | version 2.1, available at 119 | [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. 120 | 121 | Community Impact Guidelines were inspired by 122 | [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. 123 | 124 | For answers to common questions about this code of conduct, see the FAQ at 125 | [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at 126 | [https://www.contributor-covenant.org/translations][translations]. 127 | 128 | [homepage]: https://www.contributor-covenant.org 129 | [v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html 130 | [Mozilla CoC]: https://github.com/mozilla/diversity 131 | [FAQ]: https://www.contributor-covenant.org/faq 132 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | ### License 4 | 5 | vscode-tcf-debug is licensed under the terms in [LICENSE](./LICENSE.txt). By contributing to the project, you agree to the license and copyright terms therein and release your contribution under these terms. 6 | 7 | ### Sign your work 8 | 9 | Please use the sign-off line at the end of the patch. Your signature certifies that you wrote the patch or otherwise have the right to pass it on as an open-source patch. The rules are pretty simple: if you can certify 10 | the below (from [developercertificate.org](http://developercertificate.org/)): 11 | 12 | ``` 13 | Developer Certificate of Origin 14 | Version 1.1 15 | 16 | Copyright (C) 2004, 2006 The Linux Foundation and its contributors. 17 | 660 York Street, Suite 102, 18 | San Francisco, CA 94110 USA 19 | 20 | Everyone is permitted to copy and distribute verbatim copies of this 21 | license document, but changing it is not allowed. 22 | 23 | Developer's Certificate of Origin 1.1 24 | 25 | By making a contribution to this project, I certify that: 26 | 27 | (a) The contribution was created in whole or in part by me and I 28 | have the right to submit it under the open source license 29 | indicated in the file; or 30 | 31 | (b) The contribution is based upon previous work that, to the best 32 | of my knowledge, is covered under an appropriate open source 33 | license and I have the right under that license to submit that 34 | work with modifications, whether created in whole or in part 35 | by me, under the same open source license (unless I am 36 | permitted to submit under a different license), as indicated 37 | in the file; or 38 | 39 | (c) The contribution was provided directly to me by some other 40 | person who certified (a), (b) or (c) and I have not modified 41 | it. 42 | 43 | (d) I understand and agree that this project and the contribution 44 | are public and that a record of the contribution (including all 45 | personal information I submit with it, including my sign-off) is 46 | maintained indefinitely and may be redistributed consistent with 47 | this project or the open source license(s) involved. 48 | ``` 49 | 50 | Then you just add a line to every git commit message: 51 | 52 | Signed-off-by: Joe Smith 53 | 54 | Use your real name (sorry, no pseudonyms or anonymous contributions.) 55 | 56 | If you set your `user.name` and `user.email` git configs, you can sign your 57 | commit automatically with `git commit -s`. 58 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2022, 2023 Intel Corporation 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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 OR COPYRIGHT HOLDERS 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. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Visual Studio Code Target Communication Framework (TCF) Debugger Extension 2 | 3 | This extension allows debugging via Target Communication Framework (TCF) from Visual Studio Code. 4 | 5 | Manage breakpoints, resume after breakpoint hit, see the call stack and variables. 6 | 7 | More details in the [extension README](./vscode-tcf-debug/README.md) 8 | -------------------------------------------------------------------------------- /security.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | Intel is committed to rapidly addressing security vulnerabilities affecting our customers and providing clear guidance on the solution, impact, severity and mitigation. 3 | 4 | ## Reporting a Vulnerability 5 | Please report any security vulnerabilities in this project utilizing the guidelines [here](https://www.intel.com/content/www/us/en/security-center/vulnerability-handling-guidelines.html). 6 | -------------------------------------------------------------------------------- /tcf/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.vsix 3 | out/ 4 | -------------------------------------------------------------------------------- /tcf/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2022, 2023 Intel Corporation 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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 OR COPYRIGHT HOLDERS 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. 8 | -------------------------------------------------------------------------------- /tcf/README.md: -------------------------------------------------------------------------------- 1 | # Building 2 | 3 | Run `npm pack` to create the package .tgz file. 4 | 5 | -------------------------------------------------------------------------------- /tcf/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@intel/tcf", 3 | "version": "0.2.8", 4 | "description": "TCF client library.", 5 | "main": "./out/tcf-all.js", 6 | "types": "./out/tcf-all.d.ts", 7 | "files": [ 8 | "/out" 9 | ], 10 | "scripts": { 11 | "precompile": "mkdir src && cp -R ../vscode-tcf-debug/src/tcf src/ && cp ../vscode-tcf-debug/src/tcf*.ts src && cp ../vscode-tcf-debug/src/pcap.ts src && cp ../vscode-tcf-debug/src/mocksocket.ts src && cp -R ../vscode-tcf-debug/src/variables src/variables", 12 | "compile": "tsc -p ./" 13 | }, 14 | "author": "ebold", 15 | "contributors": [ 16 | { 17 | "name": "ebold", 18 | "email": "emilian.bold@intel.com" 19 | }, 20 | { 21 | "name": "oostoia", 22 | "email": "ovidiu.ostoia@intel.com" 23 | }, 24 | { 25 | "name": "alicesto", 26 | "email": "alice.stoian@intel.com" 27 | } 28 | ], 29 | "license": "MIT", 30 | "private": "true", 31 | "devDependencies": { 32 | "@types/mocha": "^10.0.6", 33 | "@types/node": "20.x", 34 | "@typescript-eslint/eslint-plugin": "^6.13.2", 35 | "@typescript-eslint/parser": "^6.13.2", 36 | "eslint": "^8.55.0", 37 | "mocha": "^10.8.2", 38 | "typescript": "^5.3.3" 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tcf/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2022", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2022" 8 | ], 9 | "declaration": true, 10 | "declarationMap": true, 11 | "sourceMap": true, 12 | "rootDir": "src", 13 | "strict": true /* enable all strict type-checking options */ 14 | /* Additional Checks */ 15 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 16 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 17 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /tests/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module" 7 | }, 8 | "plugins": [ 9 | "@typescript-eslint" 10 | ], 11 | "rules": { 12 | "@typescript-eslint/naming-convention": "warn", 13 | "@typescript-eslint/semi": "warn", 14 | "curly": "warn", 15 | "eqeqeq": "warn", 16 | "no-throw-literal": "warn", 17 | "semi": "off", 18 | "no-console": "error" 19 | }, 20 | "ignorePatterns": [ 21 | "out", 22 | "dist", 23 | "**/*.d.ts" 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /tests/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out/ 3 | .nyc_output 4 | coverage -------------------------------------------------------------------------------- /tests/nyc.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | 'use strict'; 6 | const path = require('path'); 7 | 8 | module.exports = { 9 | // "extends": "@istanbuljs/nyc-config-typescript", 10 | "cwd": path.resolve(__dirname, "../"), 11 | "all": true, 12 | // "check-coverage": true, 13 | "include": [ 14 | "**/vscode-tcf-debug/**/*.js", 15 | "**/vscode-tcf-debug/**/*.ts", 16 | ], 17 | "exclude": [ 18 | "**/test/**", 19 | "**/vscode-tcf-debug/node_modules/**", 20 | //Instambul doesn't seem to detect the validators usage properly (probably because they are pure JS and not TS files) 21 | "**/vscode-tcf-debug/**/validators/*", 22 | ], 23 | "excludeNodeModules": false 24 | }; -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tests", 3 | "description": "TCF tests", 4 | "displayName": "Public Tests", 5 | "publisher": "Intel", 6 | "version": "0.2.8", 7 | "license": "MIT", 8 | "engines": { 9 | "vscode": "^1.79.0" 10 | }, 11 | "author": "ebold", 12 | "contributors": [ 13 | { 14 | "name": "ebold", 15 | "email": "emilian.bold@intel.com" 16 | }, 17 | { 18 | "name": "oostoia", 19 | "email": "ovidiu.ostoia@intel.com" 20 | }, 21 | { 22 | "name": "alicesto", 23 | "email": "alice.stoian@intel.com" 24 | } 25 | ], 26 | "scripts": { 27 | "compile": "tsc -p ./", 28 | "watch": "tsc -watch -p ./", 29 | "lint": "eslint src --ext ts", 30 | "preunittest": "npm run compile", 31 | "unittest": "npx mocha ./out/test/unit/suite", 32 | "coverage": "npx nyc --temp-dir tests/.nyc_output --silent npx mocha ./out/test/unit/suite && npx nyc --temp-dir tests/.nyc_output report --reporter=cobertura --reporter=text --report-dir tests/coverage" 33 | }, 34 | "devDependencies": { 35 | "@types/mocha": "^10.0.6", 36 | "@types/node": "20.x", 37 | "@typescript-eslint/eslint-plugin": "^6.1.0", 38 | "@typescript-eslint/parser": "^6.0.0", 39 | "eslint": "^8.46.0", 40 | "mocha": "^10.8.2", 41 | "nyc": "^15.1.0", 42 | "typescript": "^5.1.6" 43 | }, 44 | "dependencies": { 45 | "@vscode/debugadapter": "^1.61.0", 46 | "@vscode/debugprotocol": "^1.61.0", 47 | "vscode-tcf-debug": "file:../vscode-tcf-debug" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /tests/src/test/test-bad-service.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-tcf-debug/7f689cc85043a869f136ea9f0a606ee14fc6dcd9/tests/src/test/test-bad-service.pcap -------------------------------------------------------------------------------- /tests/src/test/test-mismatched-token.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-tcf-debug/7f689cc85043a869f136ea9f0a606ee14fc6dcd9/tests/src/test/test-mismatched-token.pcap -------------------------------------------------------------------------------- /tests/src/test/test-small-token-style.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-tcf-debug/7f689cc85043a869f136ea9f0a606ee14fc6dcd9/tests/src/test/test-small-token-style.pcap -------------------------------------------------------------------------------- /tests/src/test/unit/badservice.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | /* eslint-disable no-console */ 6 | import assert = require("assert"); 7 | import { TestTCFClient } from "../unitTest"; 8 | import { ipv4Header, pcapAppend, pcapCreate, PCAP_LOCALHOST, PCAP_OTHER_HOST, HelloLocatorEvent, SmallCommandStamper, SimpleCommandStamper, GetContextRunControlCommand, SimpleCommand, QueryCommand, join } from "vscode-tcf-debug/out/tcf-all"; 9 | 10 | export async function createEmptyPcap(output: string, tokenGen: SimpleCommandStamper) { 11 | const END_OF_PACKET_MARKER = Uint8Array.from([3, 1]); 12 | 13 | const outFD = pcapCreate(output); 14 | 15 | //we send Hello 16 | let packet = new HelloLocatorEvent().toBuffer(); 17 | pcapAppend(outFD, 18 | Buffer.concat( 19 | [ipv4Header(packet, PCAP_LOCALHOST, PCAP_OTHER_HOST), 20 | packet, 21 | ]), 22 | ); 23 | 24 | //should receive a reply 25 | packet = new HelloLocatorEvent(["ContextQuery", "Locator"]).toBuffer(); 26 | pcapAppend(outFD, 27 | Buffer.concat( 28 | [ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), 29 | packet, 30 | ]), 31 | ); 32 | 33 | 34 | //next a query 35 | let command: SimpleCommand = new QueryCommand("*"); 36 | let token = tokenGen.createToken(command); 37 | packet = command.toBuffer(token); 38 | pcapAppend(outFD, 39 | Buffer.concat( 40 | [ipv4Header(packet, PCAP_LOCALHOST, PCAP_OTHER_HOST), 41 | packet, 42 | ]), 43 | ); 44 | 45 | packet = join([ 46 | Buffer.from("R"), 47 | Buffer.from(token), // "ContextQuery/0/query/*"), 48 | Buffer.from([]), //error report 49 | Buffer.from(JSON.stringify([])), //not list of IDs, to avoid some more commands 50 | ]); 51 | pcapAppend(outFD, 52 | Buffer.concat( 53 | [ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), 54 | packet, 55 | Buffer.from([0]), 56 | Buffer.from(END_OF_PACKET_MARKER)]), 57 | ); 58 | 59 | await outFD.close(); 60 | } 61 | 62 | export function badServiceSuite() { 63 | it("Reject unsupported service", async function () { 64 | // await createEmptyPcap("src/test/test-bad-service.pcap", new SmallCommandStamper()); 65 | 66 | const t = new TestTCFClient(); 67 | t.playback("src/test/test-bad-service.pcap"); 68 | t.connect("localhost", 123); 69 | 70 | try { 71 | await t.sendCommand(new GetContextRunControlCommand("someContext")); 72 | } catch (e) { 73 | assert.ok(e instanceof Error); 74 | assert.equal((e as Error).message, "Service RunControl not supported by remote TCF"); 75 | } finally { 76 | t.disconnect(); 77 | } 78 | }); 79 | } -------------------------------------------------------------------------------- /tests/src/test/unit/disassembly.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | /* eslint-disable no-console */ 6 | import { TCFDebugSession, TCFLaunchRequestArguments } from "vscode-tcf-debug/out/debugProvider"; 7 | import { DebugProtocol } from "@vscode/debugprotocol"; 8 | import { Source } from "@vscode/debugadapter"; 9 | import assert = require("assert"); 10 | import { TinyDAP } from "../unitTest"; 11 | 12 | export function disassemblySuite(playbackFile: string, file: string, line: number, handler: ((i: DebugProtocol.DisassembledInstruction[] | undefined) => void)) { 13 | let afterCleanup: (() => void)[] = []; 14 | 15 | it("Disassemble", async function () { 16 | this.timeout(130 * 1000); //bump mocha timeout on playback 17 | const session = new TCFDebugSession(); 18 | const dap = new TinyDAP(session); 19 | afterCleanup.push(function () { 20 | //disconnect (and indirectly close socket) at the end 21 | if (session) { 22 | session.handleMessage({ 23 | command: 'disconnect', 24 | seq: 10000, //just a seq number, should be big enough 25 | type: 'request' 26 | } as DebugProtocol.DisconnectRequest); 27 | } 28 | }); 29 | 30 | const initializedPromise = dap.forEvent('initialized'); 31 | 32 | await dap.send({ 33 | arguments: { 34 | breakpointPrefix: "", 35 | host: "127.0.0.1", 36 | // record: playbackFile, 37 | playback: playbackFile, 38 | // debugTCFMessages: true 39 | } as TCFLaunchRequestArguments, 40 | command: 'launch', 41 | seq: 0,// doesn't matter, will be replaced 42 | type: 'request' 43 | } as DebugProtocol.LaunchRequest); 44 | 45 | await initializedPromise; 46 | 47 | console.log("\nawaiting on setBreakpoints"); 48 | await dap.send({ 49 | command: 'setBreakpoints', 50 | type: 'request', 51 | arguments: { 52 | source: new Source(file, file), 53 | lines: [line] 54 | } 55 | } as DebugProtocol.SetBreakpointsRequest); 56 | 57 | console.log("\nawaiting on configurationDone"); 58 | await dap.send({ 59 | command: 'configurationDone', 60 | type: 'request', 61 | } as DebugProtocol.ConfigurationDoneRequest); 62 | 63 | // //await breakpointPromise; 64 | console.log("\nawaiting on stoppedPromise"); 65 | const stoppedData = await dap.forEvent('stopped'); 66 | const threadId = (stoppedData as DebugProtocol.StoppedEvent).body.threadId; 67 | console.log(JSON.stringify(stoppedData)); 68 | 69 | // //NOTE: waterfall is threads->stacktrace->Scope->Variables ... Variables 70 | 71 | console.log("\nWaiting on threads"); 72 | const threads = await dap.send({ 73 | command: 'threads', 74 | type: 'request', 75 | } as DebugProtocol.ThreadsRequest); 76 | console.log(JSON.stringify(threads)); 77 | 78 | console.log("\nWaiting on stack traces"); 79 | const stacktraces = await dap.send({ 80 | command: 'stackTrace', 81 | type: 'request', 82 | arguments: { 83 | threadId: threadId 84 | } 85 | } as DebugProtocol.StackTraceRequest); 86 | console.log(JSON.stringify(stacktraces)); 87 | 88 | const stackFrames = (stacktraces as DebugProtocol.StackTraceResponse).body.stackFrames; 89 | 90 | console.log(`Stack frames ${JSON.stringify(stackFrames)}`); 91 | 92 | const frameId = stackFrames[0].id; 93 | const memoryReference = stackFrames[0].instructionPointerReference; 94 | 95 | console.log("\nWaiting on scopes"); 96 | const scopes = await dap.send({ 97 | command: 'scopes', 98 | type: 'request', 99 | arguments: { 100 | frameId 101 | } 102 | } as DebugProtocol.ScopesRequest); 103 | console.log(JSON.stringify(scopes)); 104 | 105 | const localVarsReference = (scopes as DebugProtocol.ScopesResponse).body.scopes[0].variablesReference; 106 | 107 | console.log("\nAwaiting variables response"); 108 | const variableResponse = await dap.send({ 109 | command: 'variables', 110 | type: 'request', 111 | arguments: { 112 | variablesReference: localVarsReference 113 | } 114 | } as DebugProtocol.VariablesRequest); 115 | 116 | console.log("Got variable response"); 117 | const variables = (variableResponse as DebugProtocol.VariablesResponse).body.variables; 118 | console.log(variables); 119 | 120 | console.log("\nWaiting on disassemble"); 121 | const disassembleResponse = await dap.send({ 122 | command: 'disassemble', 123 | type: 'request', 124 | arguments: { 125 | memoryReference: memoryReference, 126 | offset: 0, 127 | instructionOffset: -100, 128 | instructionCount: 200 129 | } 130 | } as DebugProtocol.DisassembleRequest); 131 | console.log(JSON.stringify(disassembleResponse)); 132 | 133 | console.log("Got disassemble response"); 134 | const instructions = (disassembleResponse as DebugProtocol.DisassembleResponse).body?.instructions; 135 | handler(instructions); 136 | }); 137 | 138 | after(function () { 139 | afterCleanup.forEach(x => x()); 140 | }); 141 | } -------------------------------------------------------------------------------- /tests/src/test/unit/jsonverify.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import assert = require("assert"); 6 | import { asTCFContextData } from "vscode-tcf-debug/out/tcf-all"; 7 | import * as validateTCFContextData from 'vscode-tcf-debug/out/tcf/validators/validate-TCFContextData.js'; 8 | 9 | export function jsonSchemaTest() { 10 | it('Should propagate validator error', function () { 11 | 12 | const badObject = { 13 | /* eslint-disable @typescript-eslint/naming-convention */ 14 | ID: "10", 15 | ParentID: 42 //should be string 16 | /* eslint-enable */ 17 | }; 18 | 19 | //validate manually 20 | const valid = validateTCFContextData(badObject); 21 | assert.equal(false, valid); 22 | const errors = (validateTCFContextData as any).errors; 23 | 24 | assert.notEqual(undefined, errors, "Errors should exists"); 25 | 26 | //validate with the helper as- function 27 | try { 28 | asTCFContextData(badObject); 29 | assert.fail("Should not get this far"); 30 | } catch (e) { 31 | //expected to get an error 32 | const cause = (e as Error).cause; 33 | 34 | assert.notEqual(undefined, cause, "Validation cause should be propagated"); 35 | assert.deepEqual(errors, cause, "The same validation error should be wrapped in the JSON validation error"); 36 | } 37 | }); 38 | } 39 | -------------------------------------------------------------------------------- /tests/src/test/unit/suite.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { badServiceSuite } from "./badservice"; 6 | import { jsonSchemaTest } from "./jsonverify"; 7 | import { tokenMismatchSuite } from "./tokenmismatch"; 8 | import { tokenStyleSuite } from "./tokenstyle"; 9 | 10 | describe("Tests", function () { 11 | describe("JSON validators", jsonSchemaTest.bind(this)); 12 | describe("Mismatch", tokenMismatchSuite.bind(this)); 13 | describe("Token style", tokenStyleSuite.bind(this)); 14 | describe("Unsupported service", badServiceSuite.bind(this)); 15 | }); -------------------------------------------------------------------------------- /tests/src/test/unit/tokenmismatch.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | /* eslint-disable no-console */ 6 | import { TCFDebugSession, TCFLaunchRequestArguments } from "vscode-tcf-debug/out/debugProvider"; 7 | import { DebugProtocol } from "@vscode/debugprotocol"; 8 | import assert = require("assert"); 9 | import { TinyDAP } from "../unitTest"; 10 | import { ipv4Header, pcapAppend, pcapCreate, PCAP_LOCALHOST, PCAP_OTHER_HOST, HelloLocatorEvent, QueryCommand, join, SetBreakpointsCommand, SimpleCommand, SimpleCommandStamper, DebugCommandStamper } from "vscode-tcf-debug/out/tcf-all"; 11 | 12 | export async function createPcapWithMismatchedToken(output: string, tokenGen: SimpleCommandStamper) { 13 | const END_OF_PACKET_MARKER = Uint8Array.from([3, 1]); 14 | 15 | const outFD = pcapCreate(output); 16 | 17 | //we send Hello 18 | let packet = new HelloLocatorEvent().toBuffer(); 19 | pcapAppend(outFD, 20 | Buffer.concat( 21 | [ipv4Header(packet, PCAP_LOCALHOST, PCAP_OTHER_HOST), 22 | packet, 23 | ]), 24 | ); 25 | 26 | //should receive a reply 27 | packet = new HelloLocatorEvent(["RunControl", "ContextQuery", "Locator"]).toBuffer(); 28 | pcapAppend(outFD, 29 | Buffer.concat( 30 | [ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), 31 | packet, 32 | ]), 33 | ); 34 | //next a query 35 | let command : SimpleCommand = new QueryCommand("*"); 36 | let token = tokenGen.createToken(command); 37 | packet = command.toBuffer(token); 38 | pcapAppend(outFD, 39 | Buffer.concat( 40 | [ipv4Header(packet, PCAP_LOCALHOST, PCAP_OTHER_HOST), 41 | packet, 42 | ]), 43 | ); 44 | 45 | packet = join([ 46 | Buffer.from("R"), 47 | Buffer.from(token), // "ContextQuery/0/query/*"), 48 | Buffer.from([]), //error report 49 | Buffer.from(JSON.stringify([])), //not list of IDs, to avoid some more commands 50 | ]); 51 | pcapAppend(outFD, 52 | Buffer.concat( 53 | [ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), 54 | packet, 55 | Buffer.from([0]), 56 | Buffer.from(END_OF_PACKET_MARKER)]), 57 | ); 58 | 59 | //handshake finished, add breakpoints 60 | command = new SetBreakpointsCommand([]); 61 | token = tokenGen.createToken(command); 62 | packet = command.toBuffer(token); 63 | pcapAppend(outFD, 64 | Buffer.concat( 65 | [ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), 66 | packet, 67 | ]), 68 | ); 69 | 70 | //breakpoint reply 71 | packet = join([ 72 | Buffer.from("R"), 73 | Buffer.from(token), // "Breakpoints/0/set/0"), 74 | Buffer.from([]), //error report 75 | Buffer.from([]), 76 | ]); 77 | pcapAppend(outFD, 78 | Buffer.concat( 79 | [ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), 80 | packet, 81 | Buffer.from([0]), 82 | Buffer.from(END_OF_PACKET_MARKER)]), 83 | ); 84 | 85 | // let's put a reply with an unexpected token 86 | packet = join([ 87 | Buffer.from("R"), 88 | Buffer.from("SomeService/1/someCommand"), //bad token 89 | Buffer.from([]), //error report 90 | Buffer.from("hey") 91 | ]); 92 | pcapAppend(outFD, 93 | Buffer.concat( 94 | [ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), 95 | packet, 96 | Buffer.from([0]), 97 | Buffer.from(END_OF_PACKET_MARKER)]), 98 | ); 99 | 100 | await outFD.close(); 101 | } 102 | 103 | export function tokenMismatchSuite() { 104 | let afterCleanup: (() => void)[] = []; 105 | 106 | it("Mismatched token in reply", async function () { 107 | // await createPcapWithMismatchedToken("src/test/test-mismatched-token.pcap", new DebugCommandStamper()); 108 | 109 | this.timeout(30 * 1000); //bump mocha timeout on playback 110 | const session = new TCFDebugSession(); 111 | const dap = new TinyDAP(session); 112 | afterCleanup.push(function () { 113 | //disconnect (and indirectly close socket) at the end 114 | if (session) { 115 | session.handleMessage({ 116 | command: 'disconnect', 117 | seq: 10000, //just a seq number, should be big enough 118 | type: 'request' 119 | } as DebugProtocol.DisconnectRequest); 120 | } 121 | }); 122 | 123 | const initializedPromise = dap.forEvent('initialized'); 124 | 125 | await dap.send({ 126 | arguments: { 127 | breakpointPrefix: "", 128 | host: "127.0.0.1", 129 | playback: "src/test/test-mismatched-token.pcap", 130 | playbackFlag: { 131 | consumeEventsRepliesEagerly: true 132 | }, 133 | internal: { 134 | commandToken: "debug" 135 | } 136 | // debugTCFMessages: true 137 | } as TCFLaunchRequestArguments, 138 | command: 'launch', 139 | seq: 0,// doesn't matter, will be replaced 140 | type: 'request' 141 | } as DebugProtocol.LaunchRequest); 142 | 143 | await initializedPromise; 144 | 145 | const outputPromise = dap.forEvent('output'); 146 | console.log("\nawaiting on console output"); 147 | const out = await outputPromise; 148 | 149 | console.log("out is"); 150 | console.log(out); 151 | assert.ok(out.body.output.includes("No command with this token")); 152 | }); 153 | 154 | after(function () { 155 | afterCleanup.forEach(x => x()); 156 | }); 157 | } -------------------------------------------------------------------------------- /tests/src/test/unit/tokenstyle.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | /* eslint-disable no-console */ 6 | import { TCFDebugSession, TCFLaunchRequestArguments } from "vscode-tcf-debug/out/debugProvider"; 7 | import { DebugProtocol } from "@vscode/debugprotocol"; 8 | import assert = require("assert"); 9 | import { TinyDAP } from "../unitTest"; 10 | import { ipv4Header, pcapAppend, pcapCreate, PCAP_LOCALHOST, PCAP_OTHER_HOST, HelloLocatorEvent, QueryCommand, join, SetBreakpointsCommand, SimpleCommand, SmallCommandStamper } from "vscode-tcf-debug/out/tcf-all"; 11 | import { createPcapWithMismatchedToken } from "./tokenmismatch"; 12 | 13 | export function tokenStyleSuite() { 14 | let afterCleanup: (() => void)[] = []; 15 | 16 | it("Plain token style", async function () { 17 | // await createPcapWithMismatchedToken("src/test/test-small-token-style.pcap", new SmallCommandStamper()); 18 | 19 | this.timeout(30 * 1000); //bump mocha timeout on playback 20 | const session = new TCFDebugSession(); 21 | const dap = new TinyDAP(session); 22 | afterCleanup.push(function () { 23 | //disconnect (and indirectly close socket) at the end 24 | if (session) { 25 | session.handleMessage({ 26 | command: 'disconnect', 27 | seq: 10000, //just a seq number, should be big enough 28 | type: 'request' 29 | } as DebugProtocol.DisconnectRequest); 30 | } 31 | }); 32 | 33 | const initializedPromise = dap.forEvent('initialized'); 34 | 35 | await dap.send({ 36 | arguments: { 37 | breakpointPrefix: "", 38 | host: "127.0.0.1", 39 | playback: "src/test/test-small-token-style.pcap", 40 | playbackFlag: { 41 | consumeEventsRepliesEagerly: true 42 | } 43 | // debugTCFMessages: true 44 | } as TCFLaunchRequestArguments, 45 | command: 'launch', 46 | seq: 0,// doesn't matter, will be replaced 47 | type: 'request' 48 | } as DebugProtocol.LaunchRequest); 49 | 50 | await initializedPromise; 51 | 52 | //just happy if it gets this far 53 | }); 54 | 55 | after(function () { 56 | afterCleanup.forEach(x => x()); 57 | }); 58 | } -------------------------------------------------------------------------------- /tests/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2022", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2022" 8 | ], 9 | "sourceMap": true, 10 | "rootDir": "src", 11 | "declaration": true, 12 | "strict": true /* enable all strict type-checking options */ 13 | /* Additional Checks */ 14 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 15 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 16 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /vscode-tcf-debug/.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "root": true, 3 | "parser": "@typescript-eslint/parser", 4 | "parserOptions": { 5 | "ecmaVersion": 6, 6 | "sourceType": "module", 7 | "project": "./tsconfig.json" 8 | }, 9 | "plugins": [ 10 | "@typescript-eslint" 11 | ], 12 | "rules": { 13 | "@typescript-eslint/no-floating-promises": [ 14 | "error" 15 | ], 16 | "@typescript-eslint/naming-convention": "warn", 17 | "@typescript-eslint/semi": "warn", 18 | "curly": "warn", 19 | "eqeqeq": "warn", 20 | "no-throw-literal": "warn", 21 | "semi": "off" 22 | }, 23 | "ignorePatterns": [ 24 | "out", 25 | "dist", 26 | "**/*.d.ts" 27 | ] 28 | } 29 | -------------------------------------------------------------------------------- /vscode-tcf-debug/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.vsix 3 | out/ 4 | -------------------------------------------------------------------------------- /vscode-tcf-debug/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | 5 | { 6 | "name": "Run TCF Extension", 7 | "type": "extensionHost", 8 | "request": "launch", 9 | "args": [ 10 | "--profile-temp", 11 | "--extensionDevelopmentPath=${workspaceFolder}" 12 | ], 13 | "outFiles": [ 14 | "${workspaceFolder}/out/**/*.js" 15 | ], 16 | "preLaunchTask": "npm: watch" 17 | }, 18 | { 19 | "name": "TCF Extension Tests", 20 | "type": "extensionHost", 21 | "request": "launch", 22 | "args": [ 23 | "--extensionDevelopmentPath=${workspaceFolder}", 24 | "--extensionTestsPath=${workspaceFolder}/out/test/suite/index" 25 | ], 26 | "outFiles": [ 27 | "${workspaceFolder}/out/test/**/*.js" 28 | ], 29 | "preLaunchTask": "${defaultBuildTask}" 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /vscode-tcf-debug/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "type": "npm", 6 | "script": "watch", 7 | "problemMatcher": "$tsc-watch", 8 | "isBackground": true, 9 | "presentation": { 10 | "reveal": "never" 11 | }, 12 | "group": { 13 | "kind": "build", 14 | "isDefault": true 15 | } 16 | } 17 | ] 18 | } -------------------------------------------------------------------------------- /vscode-tcf-debug/.vscodeignore: -------------------------------------------------------------------------------- 1 | .vscode/** 2 | .vscode-test/** 3 | src/** 4 | .gitignore 5 | .yarnrc 6 | vsc-extension-quickstart.md 7 | **/tsconfig.json 8 | **/.eslintrc.json 9 | **/*.map 10 | **/*.ts 11 | *pcap 12 | out/test/** 13 | docs -------------------------------------------------------------------------------- /vscode-tcf-debug/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Release notes 2 | 3 | ### 0.2.8 4 | 5 | * Fix source file not found when TCFCodeAreaLineNumbers.File has absolute path 6 | * Maintenance 7 | 8 | ### 0.2.7 9 | 10 | * Shows CPU registers in the `Registers` scope. 11 | Note that previously local variables *stored* in registers were 12 | showed in that scope. Now CPU registers are showed while 13 | all local variables are grouped together. The local variables 14 | stored in registers have a different presentation hint which 15 | VSCode may use to show them slightly differently. 16 | * Supports instruction level granularity in step over. 17 | * Loads fewer stack trace items based on the optional `stackTraceDepth` launch config. 18 | This massively reduces the number of messages (and time) it takes to load a stack trace 19 | with the disadvantage of loading only part of it. 20 | This disadvantage will be fixed in the future once `supportsDelayedStackTraceLoading` is 21 | implemented. 22 | 23 | ### 0.2.6 24 | * Adds generic dynamic import service loader 25 | * Fallback to RunControl if ContextQuery is unavailable during initial handshake 26 | * Refactors toBuffer, introduces some constants and cleans up invocations 27 | 28 | ### 0.2.5 29 | * Print an error to the user if a mismatched reply is sent by a non-compliant tcf agent 30 | * Improvements to our unit tests structure and added code coverage 31 | 32 | ### 0.2.4 33 | 34 | * Adds disassembly support for stack trace 35 | * Slightly faster stack trace loading (if CodeArea is present in stack context) 36 | 37 | ### 0.2.3 38 | 39 | * Validates all TCF responses in order to be complaint with TCF specs 40 | * Fixes watch variable functionality when frameId is 0 41 | * Maintenance 42 | 43 | ### 0.2.2 44 | 45 | * Adds `watch` functionality for local variables 46 | * Validates all forms of input 47 | * Validates all JSONs sent by the TCF agent 48 | 49 | ### 0.2.1 50 | 51 | * Shows only relevant sub-variables for C++ class instance variables 52 | * Shows breakpoint verified state 53 | * Adds configuration to disable executing the path mapper function 54 | * Shows hints in debug console during TCF playback to avoid confusing the run with an actual execution 55 | * Adds basic update check. No update is actually done, just a message shown if different version found 56 | 57 | ### 0.2.0 58 | 59 | * Step Over, Step Into, Step Out works 60 | * Loads subvariables better (eg. a struct inside a struct) 61 | * Shows 64bit integers 62 | * Adds optional `timeout` configuration parameter 63 | * Requires at least VSCode version 1.79 64 | 65 | ### 0.1.1 66 | 67 | * Fixes breakpoint handling when there's multiple source files 68 | * Shows stack in usual reversed order 69 | * Fixes stack source path 70 | 71 | ### 0.1.0 72 | 73 | * Breakpoints 74 | - Inlined code warning for breakpoints 75 | * Call stack with functioning jump to source 76 | * Primitive variables, arrays and structs 77 | -------------------------------------------------------------------------------- /vscode-tcf-debug/LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (C) 2022, 2023 Intel Corporation 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | 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 OR COPYRIGHT HOLDERS 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. 8 | -------------------------------------------------------------------------------- /vscode-tcf-debug/README.md: -------------------------------------------------------------------------------- 1 | # Visual Studio Code Target Communication Framework (TCF) Debugger Extension 2 | 3 | This extension allows debugging via Target Communication Framework (TCF) from Visual Studio Code. 4 | 5 | Manage breakpoints, resume after breakpoint hit, see the call stack and variables. 6 | 7 | ## Requirements 8 | 9 | No dependencies. The extension only requires Visual Studio Code. 10 | 11 | Read the full [manual](./docs/manual.md) or just follow the steps below. 12 | 13 | ## Installation 14 | 15 | Download and install the `.VSIX` file. (Note that if you download a `.tgz` file the 16 | `.vsix` is probably inside the `.tgz` archive). 17 | 18 | ``` 19 | File Edit Selection View Go Run Terminal Help 20 | -──────────────────────────── 21 | 📃 Extensions ↻ [···] ⬅️ 1. Press here 22 | 🔎 ┌────────────────────────────┐ 23 | 🐞 │Views │ 24 | |🧩 │Check for Extension Updates │ 25 | ⚙️ ├────────────────────────────┤ 26 | 📺 │Install from VSIX... │ ⬅️2. Then here 27 | 🏁 └────────────────────────────┘ 28 | 29 | ``` 30 | 31 | ## Configuration 32 | 33 | A configuration of type `tcf` will auto-complete when you edit `launch.json`. 34 | 35 | Note that the extension will connect to the TCF port so the debugged application must already be running (locally or remote) and the TCF port must be accessible. In practice you will have a local debugger running so you always connect to the local debugger TCF agent, 36 | ie. to `localhost`. 37 | 38 | Your local `launch.json` should work with the plain `tcf` configuration which connects by default to `localhost`: 39 | 40 | ```JSON 41 | "configurations": [ 42 | { 43 | "type": "tcf", 44 | "request": "launch", 45 | "name": "Debug program" 46 | } 47 | ] 48 | ``` 49 | 50 | but you can also manually configure the following parameters (default values shown): 51 | 52 | 53 | ``` 54 | { 55 | "host": "127.0.0.1", // or any other hostname you want to connect to 56 | "port": 1534, //or any other port where a TCF agent is listening 57 | 58 | "record": undefined, // use any file path here to write a log of all the TCF messages (useful for bug reports and playback) 59 | "playback": undefined, //use a pre-existing TCF recording to simulate a debugging session (this is obviously brittle and requires you to run close to the same commands) 60 | 61 | "timeout": 10000 //debug commands timeout in milliseconds (this may be useful for connection to very slow machines) 62 | 63 | "debugTCFMessages": false //toggle to true to see in the debug console the TCF messages being sent / received (for internal use generally) 64 | 65 | "type": "tcf", 66 | "request": "launch", 67 | "name": "Debug program" 68 | } 69 | ``` 70 | 71 | ## Release Notes 72 | 73 | ### 0.2.8 74 | 75 | * Fix source file not found when TCFCodeAreaLineNumbers.File has absolute path 76 | * Maintenance 77 | 78 | ### 0.2.7 79 | 80 | * Shows CPU registers in the `Registers` scope. 81 | Note that previously local variables *stored* in registers were 82 | showed in that scope. Now CPU registers are showed while 83 | all local variables are grouped together. The local variables 84 | stored in registers have a different presentation hint which 85 | VSCode may use to show them slightly differently. 86 | * Supports instruction level granularity in step over. 87 | * Loads fewer stack trace items based on the optional `stackTraceDepth` launch config. 88 | This massively reduces the number of messages (and time) it takes to load a stack trace 89 | with the disadvantage of loading only part of it. 90 | This disadvantage will be fixed in the future once `supportsDelayedStackTraceLoading` is 91 | implemented. 92 | 93 | ### 0.2.6 94 | * Adds generic dynamic import service loader 95 | * Fallback to RunControl if ContextQuery is unavailable during initial handshake 96 | * Refactors toBuffer, introduces some constants and cleans up invocations 97 | 98 | ### 0.2.5 99 | * Print an error to the user if a mismatched reply is sent by a non-compliant tcf agent 100 | * Improvements to our unit tests structure and added code coverage 101 | 102 | ### 0.2.4 103 | 104 | * Adds disassembly support for stack trace 105 | * Slightly faster stack trace loading (if CodeArea is present in stack context) 106 | 107 | ### 0.2.3 108 | 109 | * Validates all TCF responses in order to be complaint with TCF specs 110 | * Fixes watch variable functionality when frameId is 0 111 | * Maintenance 112 | 113 | ### 0.2.2 114 | 115 | * Adds `watch` functionality for local variables 116 | * Validates all forms of input 117 | * Validates all JSONs sent by the TCF agent 118 | 119 | ### 0.2.1 120 | 121 | * Shows only relevant sub-variables for C++ class instance variables 122 | * Shows breakpoint verified state 123 | * Adds configuration to disable executing the path mapper function 124 | * Shows hints in debug console during TCF playback to avoid confusing the run with an actual execution 125 | * Adds basic update check. No update is actually done, just a message shown if different version found 126 | 127 | ### 0.2.0 128 | 129 | * Step Over, Step Into, Step Out works 130 | * Loads subvariables better (eg. a struct inside a struct) 131 | * Shows 64bit integers 132 | * Adds optional `timeout` configuration parameter 133 | * Requires at least VSCode version 1.79 134 | 135 | ### 0.1.1 136 | 137 | * Fixes breakpoint handling when there's multiple source files 138 | * Shows stack in usual reversed order 139 | * Fixes stack source path 140 | 141 | ### 0.1.0 142 | 143 | * Breakpoints 144 | - Inlined code warning for breakpoints 145 | * Call stack with functioning jump to source 146 | * Primitive variables, arrays and structs 147 | 148 | 149 | ## NOTICE 150 | 151 | This product's `.VSIX` file bundles `@vscode/debugadapter` and `@vscode/debugprotocol` which are both under the same MIT license: 152 | 153 | ``` 154 | Copyright (c) Microsoft Corporation 155 | 156 | All rights reserved. 157 | 158 | MIT License 159 | 160 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 161 | 162 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 163 | 164 | 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 OR COPYRIGHT HOLDERS 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. 165 | 166 | ``` 167 | -------------------------------------------------------------------------------- /vscode-tcf-debug/docs/manual.md: -------------------------------------------------------------------------------- 1 | # TCF Debugging Visual Studio Code Extension Manual 2 | 3 | ## Preface 4 | 5 | ### What is the TCF Debugging Extension? 6 | 7 | The Target Communication Framework (TCF) debugging extension allows developers to debug from Visual Studio Code a binary running on a TCF-aware debugger. 8 | 9 | The extension uses the TCF protocol to communicate with the debugger. You may notice a `Starting TCF agent` or similar message showing up early when your debugger starts. 10 | 11 | ### Bug Reporting 12 | 13 | If the manual is incorrect, or unclear about a topic or if you think it needs more details please report an issue. 14 | 15 | ## Getting Started 16 | 17 | ### Installation 18 | 19 | The extension has to be manually installed from a `.vsix` file. You will not find it in the Visual Studio Marketplace yet. 20 | 21 | #### Downloading the Extension 22 | 23 | The extension can be downloaded from the GitHub Releases page. 24 | 25 | Under the `Assets` link, download the `vscode-tcf-debug.vsix` file. 26 | 27 | #### Installing in Visual Studio Code 28 | 29 | Once you have the `.vsix` file, go to Visual Studio Code, pick the Extensions sidebar, press the `...` (three dots) button, and select `Install from VSIX...` 30 | 31 | ![Screenshot with VSCode Install from VSIX](vscode-install-vsix.png) 32 | 33 | ##### Visual Studio Code Remote Development 34 | 35 | If you are using Visual Studio Code using a Remote Window make sure to install the extension on the remote machine. 36 | 37 | Visual Studio Code will generally do this by default when you pick `Install from VSIX...` but if you have the extension locally installed you may have 38 | to go into the Extensions sidebar, find the TCF extension and click `Install in (your remote name)...` 39 | 40 | ### Configuring Your Project 41 | 42 | Visual Studio Code debugging is tied to the `launch.json` file (see [the Visual Studio Code documentation](https://code.visualstudio.com/docs/editor/debugging)). The TCF debugging extension is no exception. 43 | 44 | You will have to create a `launch.json` file either manually or from on of the editor hints. Once you have the file you can use code completion to get something similar to this empty configuration file: 45 | 46 | ```json 47 | { 48 | "version": "0.2.0", 49 | "configurations": [], 50 | } 51 | ``` 52 | 53 | Next you need to configure the TCF debugging extension itself. 54 | 55 | Inside the `configurations` section you can trigger again code completion and you will get a list of all the debugging types your Visual Studio Code installation supports. 56 | 57 | Among them you should find the `TCF Debug: Launch` item which will generate the plain configuration with the type `tcf`: 58 | 59 | ```json 60 | "configurations": [ 61 | { 62 | "type": "tcf", 63 | "request": "launch", 64 | "name": "Debug TCF program" 65 | } 66 | ] 67 | ``` 68 | 69 | This empty configuration should be usually enough. 70 | 71 | You can also manually configure the following parameters which will also auto complete (default values shown): 72 | 73 | ``` 74 | { 75 | "host": "127.0.0.1", // or any other hostname you want to connect to 76 | "port": 1534, //or any other port where a TCF agent is listening 77 | 78 | "record": undefined, // use any file path here to write a log of all the TCF messages (useful for bug reports and playback) 79 | "playback": undefined, //use a pre-existing TCF recording to simulate a debugging session (this is obviously brittle and requires you to run close to the same commands) 80 | 81 | "timeout": 10000 //debug commands timeout in milliseconds (this may be useful for connection to very slow machines) 82 | 83 | "debugTCFMessages": false //toggle to true to see in the debug console the TCF messages being sent / received (for internal use generally) 84 | 85 | "pathMapper": "return function (path, context) { return path; }" //custom Javascript function providing a file path mapper from VSCode path to debuggee path; defaults to identity function. 86 | } 87 | ``` 88 | 89 | ### Launching Your Project 90 | 91 | Note that since the extension just connects to (the TCF port provided by) the debugger, the debugged binary must *already be running* (locally or remote) and the TCF port must be accessible. 92 | 93 | In practice you will have a local debugger running but if you are connecting to a remote machine, you may have to configure the `host` and `port` parameters (see previous section). 94 | 95 | ### Start Debugging 96 | 97 | Once you have: 98 | 99 | 1. the extension installed 100 | 2. your project configured in `launch.json` 101 | 3. the binary running 102 | 4. through a (TCF aware) debugger 103 | 104 | you can start debugging from Visual Studio Code. 105 | 106 | This can be done using the normal Visual Studio Code `Run | Start Debugging` menu item or by pressing `F5`. 107 | 108 | After starting a new debug session you will see messages in the Visual Studio Code Debug Console. You will also see your breakpoints, the call stack as well as stack variables. 109 | 110 | ![Visual Studio Code breakpoints, call stack and variables](vscode-debug-info.png) 111 | 112 | Congratulations! If you got this far you have a well configured and functioning debugging extension. 113 | 114 | ## Internals 115 | 116 | This section will explain how the extension itself is implemented. If you only need the extension to debug your own binaries, you can freely ignore it. 117 | 118 | ### Architecture 119 | 120 | The extension is essentially a bidirectional adapter between [Debug Adapter Protocol](https://microsoft.github.io/debug-adapter-protocol/) and [Target Communication Framework](https://wiki.eclipse.org/TCF). 121 | 122 | All the TCF logic is in the `src/tcf` folder, `src/tcf.ts` and `src/tcfclient.ts`. 123 | 124 | TCF *commands* are implemented by subclassing `SimpleCommand` (from `tcfutils.ts`): 125 | 126 | * serialization is done by `toBuffer` 127 | 128 | * response de-serialization is done by `result` 129 | 130 | * each command has a `service` name, `command` and `arguments` plus an unique message `token`. 131 | 132 | `tcf.ts` tries to provide more lower level things while `tcfclient.ts` provides helper-like methods more easily used from the DAP side. 133 | 134 | ### Supported Visual Studio Code Versions 135 | 136 | Since the extension has no major release yet, it will generally work with the latest Visual Studio Code. And thus we'll update [engines.vscode](https://code.visualstudio.com/api/references/extension-manifest) quite liberally. 137 | 138 | Once a major public release exists, we may revisit and support older Visual Studio Code versions. 139 | 140 | ### Resources 141 | 142 | VSCode: 143 | 144 | * https://code.visualstudio.com/api/extension-guides/debugger-extension 145 | 146 | * https://code.visualstudio.com/api/references/vscode-api#debug 147 | 148 | TCF: 149 | 150 | * https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Specification.html 151 | 152 | * https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Services.html 153 | 154 | DAP: 155 | 156 | * https://microsoft.github.io/debug-adapter-protocol/overview 157 | 158 | * https://microsoft.github.io/debug-adapter-protocol/specification 159 | -------------------------------------------------------------------------------- /vscode-tcf-debug/docs/vscode-debug-info.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-tcf-debug/7f689cc85043a869f136ea9f0a606ee14fc6dcd9/vscode-tcf-debug/docs/vscode-debug-info.png -------------------------------------------------------------------------------- /vscode-tcf-debug/docs/vscode-install-vsix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/intel/vscode-tcf-debug/7f689cc85043a869f136ea9f0a606ee14fc6dcd9/vscode-tcf-debug/docs/vscode-install-vsix.png -------------------------------------------------------------------------------- /vscode-tcf-debug/src/extension.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import * as vscode from 'vscode'; 6 | import { TCFDebugSession } from './debugProvider'; 7 | import { LoggingDebugSession } from '@vscode/debugadapter'; 8 | import { DebugProtocol } from '@vscode/debugprotocol'; 9 | import { PathLoader } from './loader'; 10 | 11 | export interface ActivateHook { 12 | activate(context: vscode.ExtensionContext): void; 13 | } 14 | 15 | export function activate(context: vscode.ExtensionContext) { 16 | void (vscode.window.showInformationMessage('TCF debugging extension is enabled.')); 17 | 18 | // debug-provider 19 | context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider('tcf', new TCFConfigurationProvider())); 20 | context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('tcf', new TCFDebugAdapterFactory())); 21 | 22 | //temporary migration message 23 | context.subscriptions.push(vscode.debug.registerDebugAdapterDescriptorFactory('vpu', new VPURenameDebugAdapterFactory())); 24 | 25 | //this is handy because it can be used in launch.json to be expanded via ${command:timestamp} in eg. record pcap paths 26 | context.subscriptions.push(vscode.commands.registerCommand('timestamp', () => { 27 | return new Date().toISOString() 28 | .replaceAll(":", "-"); //Windows does not like `:` in paths 29 | })); 30 | 31 | new PathLoader("./").get("extension-postactivate") 32 | .then(h => { 33 | if (h !== undefined) { 34 | h.activate(context); 35 | } 36 | }).catch(e => { 37 | //ignore 38 | }); 39 | } 40 | 41 | export class VPURenameDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory { 42 | 43 | createDebugAdapterDescriptor(_session: vscode.DebugSession): vscode.ProviderResult { 44 | return new vscode.DebugAdapterInlineImplementation(new VPUDummyDebugSession()); 45 | } 46 | } 47 | 48 | export class VPUDummyDebugSession extends LoggingDebugSession { 49 | 50 | protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { 51 | this.sendErrorResponse(response, 0, "Extension configuration moved from `vpu` to `tcf`. Please edit your launch.json file"); 52 | } 53 | } 54 | 55 | export class TCFDebugAdapterFactory implements vscode.DebugAdapterDescriptorFactory { 56 | 57 | createDebugAdapterDescriptor(_session: vscode.DebugSession): vscode.ProviderResult { 58 | //By default, path mapper execution is *enabled*. The workspace is already trusted so a default 'false' value only ruins the debugging experience. 59 | const pathMapperConfigDefault = vscode.workspace.getConfiguration("tcf").inspect("executePathMapper")?.defaultValue ?? true; 60 | const pathMapperConfig = vscode.workspace.getConfiguration("tcf").get('executePathMapper', pathMapperConfigDefault); 61 | 62 | const enablePathMapper = 63 | //technically, isTrusted is always true since a debugging extension will not be enabled in an untrusted workspace 64 | vscode.workspace.isTrusted 65 | && pathMapperConfig === true; 66 | return new vscode.DebugAdapterInlineImplementation(new TCFDebugSession(enablePathMapper)); 67 | } 68 | } 69 | 70 | export class TCFConfigurationProvider implements vscode.DebugConfigurationProvider { 71 | 72 | /** 73 | * Massage a debug configuration just before a debug session is being launched, 74 | * e.g. add all missing attributes to the debug configuration. 75 | */ 76 | resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration, token?: vscode.CancellationToken): vscode.ProviderResult { 77 | 78 | // if launch.json is missing or empty 79 | if (!config.type && !config.request && !config.name) { 80 | const editor = vscode.window.activeTextEditor; 81 | if (editor && (editor.document.languageId === 'cpp' || editor.document.languageId === 'c')) { 82 | config.type = 'tcf'; 83 | config.name = 'Launch'; 84 | config.request = 'launch'; 85 | } 86 | } 87 | 88 | return config; 89 | } 90 | } 91 | 92 | export function deactivate() { 93 | // handled by context.subscriptions 94 | } 95 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/loader.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | // This file provides a basic service loader for Typescript. 6 | // Why would one need such a thing? To have dynamic features based 7 | // on the mere presence of some source code files in the package. 8 | 9 | /** 10 | * A service loader interface 11 | */ 12 | export interface Loader { 13 | /** 14 | * Dynamically load service by name 15 | * @param name service name 16 | */ 17 | get(name: string): Promise; 18 | } 19 | 20 | /** 21 | * A service loader restricted to a single folder subpath 22 | */ 23 | export class PathLoader implements Loader { 24 | prefix: string; 25 | cache: Map = new Map(); 26 | 27 | constructor(pathPrefix: string) { 28 | this.prefix = pathPrefix; 29 | } 30 | 31 | async get(name: string): Promise { 32 | if (!name.match("^[a-zA-Z-]+$")) { 33 | throw new Error("Only single word accepted for service"); 34 | } 35 | 36 | let s = this.cache.get(name); 37 | if (s !== undefined) { 38 | return s ?? undefined; //we return the known null as undefined 39 | } 40 | 41 | try { 42 | const module = await import(`${this.prefix}/${name}`); 43 | const provider = module.default as T; 44 | 45 | this.cache.set(name, provider); 46 | 47 | return provider; 48 | } catch (e) { 49 | this.cache.set(name, null); 50 | 51 | this.error(e, name); 52 | return undefined; 53 | } 54 | } 55 | 56 | /** 57 | * handle error `e` in subclass 58 | */ 59 | protected error(e: any, name: string) { 60 | console.log(name); 61 | console.log(e); 62 | } 63 | 64 | } 65 | 66 | /** 67 | * Helper class to map a service. Best for factories. 68 | */ 69 | export class MappedLoader implements Loader { 70 | service: Loader; 71 | mapper: (service: T) => U; 72 | 73 | cache: Map = new Map(); 74 | constructor(service: Loader, mapper: (service: T) => U) { 75 | this.service = service; 76 | this.mapper = mapper; 77 | } 78 | 79 | async get(name: string): Promise { 80 | let c = this.cache.get(name); 81 | if (c !== undefined) { 82 | return c ?? undefined; //we return the known null as undefined 83 | } 84 | 85 | const s = await this.service.get(name); 86 | if (s === undefined) { 87 | this.cache.set(name, null); 88 | return undefined; 89 | } 90 | 91 | const o = this.mapper(s); 92 | this.cache.set(name, o); 93 | return o; 94 | } 95 | 96 | /** 97 | * Call argument for each loaded service 98 | * @param f 99 | */ 100 | forEach(f: (value: U) => void): void { 101 | this.cache.forEach(x => { 102 | //we skip services we couldn't load 103 | if (x !== null) { 104 | f(x); 105 | } 106 | }); 107 | } 108 | } -------------------------------------------------------------------------------- /vscode-tcf-debug/src/proxy.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | /* eslint no-console: "off" */ 6 | import * as net from "net"; 7 | import { EMPTY_BUFFER, TCF_END_OF_PACKET_MARKER, ipv4Header, pcapAppend, pcapClose, pcapCreate } from "./tcf-all"; 8 | 9 | const PORT = 1535; 10 | const OTHER_PORT = 1534; 11 | const OTHER_HOST = "127.0.0.1"; 12 | 13 | const PCAP_LOCALHOST = [127, 0, 0, 1]; 14 | const PCAP_OTHER_HOST = [127, 0, 0, 2]; 15 | 16 | const pcapFile = pcapCreate("proxy.pcap"); 17 | 18 | var server = net.createServer(function (socket) { 19 | console.log(`Proxy connection open, forwarding to ${OTHER_HOST}:${OTHER_PORT}`); 20 | 21 | const proxy = new net.Socket(); 22 | proxy.setKeepAlive(true); 23 | proxy.setNoDelay(true); 24 | proxy.connect(OTHER_PORT, OTHER_HOST); 25 | 26 | { 27 | let prevData = EMPTY_BUFFER; 28 | proxy.on('data', data => { 29 | console.log("Proxy got"); 30 | console.log(data.toString()); 31 | 32 | socket.write(data); 33 | 34 | { 35 | prevData = Buffer.concat([prevData, data]); 36 | 37 | while (true) { 38 | const eom = prevData.indexOf(TCF_END_OF_PACKET_MARKER); 39 | if (eom !== -1) { 40 | const packet = prevData.subarray(0, eom); 41 | prevData = prevData.subarray(eom + 2); 42 | 43 | pcapAppend(pcapFile, Buffer.concat([ipv4Header(packet, PCAP_OTHER_HOST, PCAP_LOCALHOST), packet, TCF_END_OF_PACKET_MARKER])); 44 | } else { 45 | //this buffer has no EOM, we stil need to receive more data 46 | return; 47 | } 48 | } 49 | } 50 | }); 51 | } 52 | proxy.on('error', err => { 53 | console.log("Forwarded connection error: App <----> This proxy <-- here --> actual TCF agent"); 54 | console.log(err); 55 | console.log("Disconnecting"); 56 | socket.end(); 57 | console.log("Closing pcap file"); 58 | pcapFile.close() 59 | .catch(e => console.log(e)); 60 | }); 61 | 62 | { 63 | let prevData = EMPTY_BUFFER; 64 | socket.on('data', data => { 65 | console.log("Got"); 66 | console.log(data.toJSON()); 67 | console.log(data.toString()); 68 | proxy.write(data); 69 | { 70 | prevData = Buffer.concat([prevData, data]); 71 | 72 | while (true) { 73 | const eom = prevData.indexOf(TCF_END_OF_PACKET_MARKER); 74 | if (eom !== -1) { 75 | const packet = prevData.subarray(0, eom); 76 | prevData = prevData.subarray(eom + 2); 77 | 78 | //note the reverted IP addresses 79 | pcapAppend(pcapFile, Buffer.concat([ipv4Header(packet, PCAP_LOCALHOST, PCAP_OTHER_HOST), packet, TCF_END_OF_PACKET_MARKER])); 80 | } else { 81 | //this buffer has no EOM, we stil need to receive more data 82 | return; 83 | } 84 | } 85 | } 86 | }); 87 | } 88 | socket.on('error', err => { 89 | console.log("Direct connection error: App <-- here --> This proxy <----> actual TCF agent"); 90 | console.log(err); 91 | 92 | proxy.end(); 93 | 94 | console.log("Closing pcap file"); 95 | pcapFile.close() 96 | .catch(e => console.log(e)); 97 | }); 98 | }); 99 | 100 | console.log(`Starting TCF proxy on port ${PORT}`); 101 | server.listen(PORT, '127.0.0.1'); 102 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/repl.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { DebugProtocol } from "@vscode/debugprotocol"; 6 | import { TCFClient } from "./tcfclient"; 7 | import { TCFLogger } from "./tcf"; 8 | 9 | export interface Repl { 10 | evaluateRequest(response: DebugProtocol.EvaluateResponse, args: DebugProtocol.EvaluateArguments, request?: DebugProtocol.Request | undefined): Promise; 11 | handledEvent(service: string, event: string, datas: Buffer[]): boolean; 12 | disconnect(): void; 13 | } 14 | 15 | export interface ReplProvider { 16 | create(client: TCFClient, logger: TCFLogger): Repl; 17 | } -------------------------------------------------------------------------------- /vscode-tcf-debug/src/schema/TCFLaunchRequestArguments.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "__restart": { 5 | "description": "Arbitrary data from the previous, restarted session.\nThe data is sent as the `restart` attribute of the `terminated` event.\nThe client should leave the data intact." 6 | }, 7 | "breakpointPrefix": { 8 | "type": "string" 9 | }, 10 | "debugTCFMessages": { 11 | "description": "Show TCF messages in the debug console", 12 | "type": "boolean" 13 | }, 14 | "host": { 15 | "default": "localhost", 16 | "description": "(Remote) TCF agent host", 17 | "type": "string" 18 | }, 19 | "internal": { 20 | "properties": { 21 | "commandToken": { 22 | "default": "default", 23 | "description": "Normally TCF command tokens are very terse identifiers which make manually reading the TCF messages hard.\nIf this property is set to `debug` a more verbose command token is used which makes the reply easier to\nunderstand.", 24 | "enum": [ 25 | "debug", 26 | "default" 27 | ], 28 | "type": "string" 29 | }, 30 | "debugTCFMessages": { 31 | "description": "Show TCF messages in the debug console", 32 | "type": "boolean" 33 | } 34 | }, 35 | "type": "object" 36 | }, 37 | "noDebug": { 38 | "description": "If true, the launch request should launch the program without enabling debugging.", 39 | "type": "boolean" 40 | }, 41 | "pathMapper": { 42 | "default": "return function (path, context) { return path; }", 43 | "description": "A Javascript function to map a local path to the debugger path", 44 | "type": "string" 45 | }, 46 | "playback": { 47 | "description": "File path with recorded TCF message which will be used to replay TCF messages (host and port will be ignored)", 48 | "type": "string" 49 | }, 50 | "playbackFlag": { 51 | "properties": { 52 | "consumeEventsRepliesEagerly": { 53 | "description": "The mock socket is not strict about ordering. Most replies are delayed until\na command actually comes in. This is designed to accomodate timing variations in how\nthe user / code may invoke commands.\n\nIf this flag is `true` it consumes events and replies eagerly. This may break\nmost scenarios but may also be preferable in other situations (eg. specific tests).", 54 | "type": "boolean" 55 | } 56 | }, 57 | "type": "object" 58 | }, 59 | "port": { 60 | "default": 1534, 61 | "description": "TCF connection port", 62 | "type": "number" 63 | }, 64 | "record": { 65 | "description": "File path where TCF messages will be recorded into", 66 | "type": "string" 67 | }, 68 | "stackTraceDepth": { 69 | "description": "Maximum number of stack frames that a stackTrace can have. Unlimited, if not defined.", 70 | "type": "number" 71 | }, 72 | "timeout": { 73 | "default": 10000, 74 | "description": "Debug commands timeout (milliseconds)", 75 | "type": "number" 76 | } 77 | }, 78 | "type": "object" 79 | } 80 | 81 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf-all.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | export * from './tcf'; 6 | export * from './tcfclient'; 7 | export * from './pcap'; 8 | 9 | export * from './tcf/tcfutils'; 10 | 11 | export * from './tcf/breakpoints'; 12 | export * from './tcf/contextquery'; 13 | export * from './tcf/expressions'; 14 | export * from './tcf/linenumbers'; 15 | export * from './tcf/locator'; 16 | export * from './tcf/memory'; 17 | export * from './tcf/runcontrol'; 18 | export * from './tcf/symbols'; 19 | 20 | export * from './variables/types'; 21 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/breakpoints.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { asStringArray, parseEmptyResponse, PromiseError, PromiseSuccess, SimpleCommand, validateJSON, ValidatingCommand } from './tcfutils'; 6 | import * as validateBreakpointStatus from './validators/validate-BreakpointStatus'; 7 | import * as validateBreakpointData from './validators/validate-BreakpointData'; 8 | 9 | export function asBreakpointData(result: any): BreakpointData { 10 | return validateJSON(result, validateBreakpointData) as BreakpointData; //type assertion OK 11 | } 12 | 13 | export function asBreakpointStatus(result: any): BreakpointStatus { 14 | return validateJSON(result, validateBreakpointStatus) as BreakpointStatus; //type assertion OK 15 | } 16 | 17 | abstract class BreakpointsCommand extends SimpleCommand { 18 | constructor() { 19 | super(); 20 | } 21 | 22 | service(): string { 23 | return "Breakpoints"; 24 | } 25 | 26 | debugDescription(tokenID : number): string { 27 | return `${this.service()}/${tokenID}`; 28 | } 29 | 30 | } 31 | 32 | abstract class BreakpointsValidatingCommand extends ValidatingCommand { 33 | constructor() { 34 | super(); 35 | } 36 | 37 | service(): string { 38 | return "Breakpoints"; 39 | } 40 | 41 | debugDescription(tokenID : number): string { 42 | return `${this.service()}/${tokenID}`; 43 | } 44 | 45 | } 46 | 47 | /** 48 | * A command with not response to parse. 49 | */ 50 | abstract class BreakpointsEmptyCommand extends BreakpointsCommand { 51 | 52 | override result(responseAll: Buffer[], success: PromiseSuccess, error: PromiseError): void { 53 | parseEmptyResponse(responseAll, success, error); 54 | } 55 | } 56 | 57 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Breakpoints.html#CmdSet 58 | /* eslint-disable @typescript-eslint/naming-convention */ 59 | enum BreakpointType { 60 | Software = "Software", 61 | Hardware = "Hardware", 62 | Auto = "Auto" 63 | } 64 | /* eslint-enable */ 65 | 66 | /* eslint-disable @typescript-eslint/naming-convention */ 67 | export interface BreakpointData { 68 | ID: string; 69 | Enabled: boolean; 70 | File?: string; 71 | Line?: number; 72 | BreakpointType?: BreakpointType; 73 | //TODO: ... and many more properties 74 | } 75 | /* eslint-enable */ 76 | 77 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Breakpoints.html#CmdSet 78 | export class SetBreakpointsCommand extends BreakpointsEmptyCommand { 79 | args: BreakpointData[]; 80 | 81 | constructor(args: BreakpointData[]) { 82 | super(); 83 | this.args = args; 84 | } 85 | 86 | debugDescription(tokenID : number): string { 87 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.argumentsHash(); 88 | } 89 | 90 | command(): string { 91 | return "set"; 92 | } 93 | 94 | arguments() { 95 | return this.args; 96 | } 97 | 98 | private argumentsHash(): number { 99 | return this.args.reduce((partialHash: number, data: BreakpointData, index: number, arr: BreakpointData[]) => { 100 | return Math.imul(31, partialHash) + this.dataHash(data); 101 | }, 0); 102 | } 103 | 104 | private dataHash(data: BreakpointData): number { 105 | let h = 0; 106 | if (data.File) { 107 | for (let i = 0; i < data.File.length; i++) { 108 | const c = data.File.charCodeAt(i); 109 | h = Math.imul(31, h) + c | 0; 110 | } 111 | } 112 | h = h + (data.Line || 0); 113 | return h; 114 | } 115 | 116 | } 117 | 118 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Breakpoints.html#CmdAdd 119 | export class AddBreakpointsCommand extends BreakpointsEmptyCommand { 120 | breakpoint: BreakpointData; 121 | 122 | constructor(breakpoint: BreakpointData) { 123 | super(); 124 | this.breakpoint = breakpoint; 125 | } 126 | 127 | debugDescription(tokenID : number): string { 128 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.breakpoint.ID; 129 | } 130 | 131 | command(): string { 132 | return "add"; 133 | } 134 | 135 | arguments() { 136 | return this.breakpoint; 137 | } 138 | 139 | } 140 | 141 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Breakpoints.html#CmdRemove 142 | export class RemoveBreakpointsCommand extends BreakpointsEmptyCommand { 143 | ids: string[]; 144 | 145 | constructor(breakpointIds: string[]) { 146 | super(); 147 | this.ids = breakpointIds; 148 | } 149 | 150 | debugDescription(tokenID : number): string { 151 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.ids.join("+"); 152 | } 153 | 154 | command(): string { 155 | return "remove"; 156 | } 157 | 158 | arguments() { 159 | return this.ids; 160 | } 161 | 162 | } 163 | 164 | /* eslint-disable @typescript-eslint/naming-convention */ 165 | export interface BreakpointStatus { 166 | Instances?: InstanceStatusData[] | null; 167 | Error?: string; 168 | File?: string; 169 | Line?: number; 170 | Column?: number; 171 | } 172 | /* eslint-enable */ 173 | 174 | /* eslint-disable @typescript-eslint/naming-convention */ 175 | export interface InstanceStatusData { 176 | Error?: string; 177 | BreakpointType?: string; 178 | LocationContext?: string; 179 | MemoryContext?: string; 180 | Address?: number | string; //seems to be deserialized as number... 181 | HitCount?: number; 182 | Size?: number; 183 | ConditionError?: string; 184 | } 185 | /* eslint-enable */ 186 | 187 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Breakpoints.html#CmdGetIDs 188 | //NOTE: This will return IDs set by *all* clients. The client should know its own breakpoint IDs. 189 | export class GetIDsBreakpointsCommand extends BreakpointsValidatingCommand { 190 | constructor() { 191 | super(); 192 | } 193 | 194 | debugDescription(tokenID : number): string { 195 | return super.debugDescription(tokenID) + "/" + this.command(); 196 | } 197 | 198 | command(): string { 199 | return "getIDs"; 200 | } 201 | 202 | arguments() { 203 | return undefined; 204 | } 205 | 206 | override cast(json: any): string[] { 207 | return asStringArray(json); 208 | } 209 | 210 | } 211 | 212 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Breakpoints.html#CmdGetProperties 213 | export class GetPropertiesBreakpointsCommand extends BreakpointsValidatingCommand { 214 | breakpointID: string; 215 | 216 | constructor(breakpointID: string) { 217 | super(); 218 | this.breakpointID = breakpointID; 219 | } 220 | 221 | debugDescription(tokenID : number): string { 222 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.arguments(); 223 | } 224 | 225 | command(): string { 226 | return "getProperties"; 227 | } 228 | 229 | arguments() { 230 | return this.breakpointID; 231 | } 232 | 233 | override cast(json: any): BreakpointData { 234 | return asBreakpointData(json); 235 | } 236 | } 237 | 238 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Breakpoints.html#CmdGetStatus 239 | export class GetStatusBreakpointsCommand extends BreakpointsValidatingCommand { 240 | breakpointID: string; 241 | 242 | constructor(breakpointID: string) { 243 | super(); 244 | this.breakpointID = breakpointID; 245 | } 246 | 247 | debugDescription(tokenID : number): string { 248 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.arguments(); 249 | } 250 | 251 | command(): string { 252 | return "getStatus"; 253 | } 254 | 255 | arguments() { 256 | return this.breakpointID; 257 | } 258 | 259 | override cast(json: any): BreakpointStatus { 260 | return asBreakpointStatus(json); 261 | } 262 | } 263 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/contextquery.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { ValidatingCommand, asStringArray } from './tcfutils'; 6 | 7 | export const CONTEXT_QUERY_SERVICE = "ContextQuery"; 8 | 9 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Context%20Query.html#CmdQuery 10 | export class QueryCommand extends ValidatingCommand { 11 | query: string; 12 | 13 | constructor(q: string) { 14 | super(); 15 | this.query = q; 16 | } 17 | 18 | debugDescription(tokenID: number): string { 19 | return `${this.service()}/${tokenID}` + "/" + this.command() + "/" + this.query; 20 | } 21 | 22 | service(): string { 23 | return CONTEXT_QUERY_SERVICE; 24 | } 25 | 26 | command(): string { 27 | return "query"; 28 | } 29 | 30 | arguments() { 31 | return this.query; 32 | } 33 | 34 | override cast(json: any): string[] { 35 | return asStringArray(json); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/diagnostics.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { ValidatingCommand, asString } from './tcfutils'; 6 | 7 | abstract class DiagnosticsCommand extends ValidatingCommand { 8 | constructor() { 9 | super(); 10 | } 11 | 12 | debugDescription(tokenID: number): string { 13 | return `${this.service()}/${tokenID}`; 14 | } 15 | 16 | service(): string { 17 | return "Diagnostics"; 18 | } 19 | } 20 | 21 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Diagnostics.html#CmdEcho 22 | export class EchoDiagnosticsCommand extends DiagnosticsCommand { 23 | command(): string { 24 | return "echo"; 25 | } 26 | 27 | arguments() { 28 | return "hello world"; //can be anything really 29 | } 30 | 31 | override cast(json: any): string { 32 | return asString(json); 33 | } 34 | } -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/disassembly.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { ValidatingCommand, asNullableArray, toBuffer, validateJSON } from './tcfutils'; 6 | import * as validateDisassemblyLine from './validators/validate-DisassemblyLine'; 7 | import * as validateDisassemblyCapability from './validators/validate-DisassemblyCapability'; 8 | 9 | abstract class DisassemblyCommand extends ValidatingCommand { 10 | 11 | constructor() { 12 | super(); 13 | } 14 | 15 | service(): string { 16 | return "Disassembly"; 17 | 18 | } 19 | 20 | debugDescription(tokenID: number): string { 21 | return `${this.service()}/${tokenID}`; 22 | } 23 | 24 | } 25 | 26 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Disassembly.html#CmdGetCapabilities 27 | /* eslint-disable @typescript-eslint/naming-convention */ 28 | export interface DisassemblyCapability { 29 | ISA?: string; 30 | Simplified?: boolean; 31 | PseudoInstruction?: boolean; 32 | OpcodeValue?: boolean; 33 | } 34 | /* eslint-enable */ 35 | 36 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Disassembly.html#CmdGetCapabilities 37 | export class GetCapabilitiesDisassemblyCommand extends DisassemblyCommand { 38 | contextID: string; 39 | 40 | constructor(contextID: string) { 41 | super(); 42 | this.contextID = contextID; 43 | } 44 | 45 | cast(json: any): DisassemblyCapability[] | null { 46 | return asNullableArray(json, asDisassemblyCapability); 47 | } 48 | 49 | command(): string { 50 | return "getCapabilities"; 51 | } 52 | 53 | arguments() { 54 | return this.contextID; 55 | } 56 | 57 | } 58 | 59 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Disassembly.html#CmdDisassemble 60 | /* eslint-disable @typescript-eslint/naming-convention */ 61 | export interface DisassemblyLine { 62 | ISA?: string, //The spec doesn't mention this as optional, but in practice it is 63 | Address: number, 64 | Size: number, 65 | Instruction: DisassemblyInstructionField[] | null, 66 | OpcodeValue?: string //The spec doesn't mention this as optional, but in practice it is 67 | } 68 | 69 | export enum DisassemblyInstructionFieldTypes { 70 | string = "String", 71 | register = "Register", 72 | address = "Address", 73 | displacement = "Displacement", 74 | immediate = "Immediate" 75 | } 76 | 77 | export interface DisassemblyInstructionField { 78 | Type: string, // usually one of the DisassemblyInstructionFieldTypes values 79 | Text: string, 80 | Value?: number, 81 | AddressSpace?: string //context id 82 | } 83 | 84 | export interface DisassemblyParameters { 85 | ISA: string, //TODO: are these optional? 86 | Simplified: boolean, 87 | PseudoInstructions: boolean, 88 | OpcodeValue: boolean 89 | } 90 | /* eslint-enable */ 91 | 92 | function asDisassemblyLine(json: any): DisassemblyLine { 93 | return validateJSON(json, validateDisassemblyLine) as DisassemblyLine; //type assertion OK 94 | } 95 | 96 | function asDisassemblyCapability(json: any): DisassemblyCapability { 97 | return validateJSON(json, validateDisassemblyCapability) as DisassemblyCapability; //type assertion OK 98 | } 99 | 100 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Disassembly.html#CmdDisassemble 101 | export class DisassembleDisassemblyCommand extends DisassemblyCommand { 102 | contextID: string; 103 | startLocation: number; 104 | size: number; 105 | params: DisassemblyParameters; 106 | 107 | constructor(contextID: string, startLocation: number, size: number, params: DisassemblyParameters) { 108 | super(); 109 | this.contextID = contextID; 110 | this.startLocation = startLocation; 111 | this.size = size; 112 | this.params = params; 113 | } 114 | 115 | cast(json: any): DisassemblyLine[] | null { 116 | return asNullableArray(json, asDisassemblyLine); 117 | } 118 | 119 | command(): string { 120 | return "disassemble"; 121 | } 122 | 123 | arguments() { 124 | return undefined; 125 | } 126 | 127 | toBuffer(token: string): Buffer { 128 | return toBuffer(["C", token, this.service(), this.command(), JSON.stringify(this.contextID), JSON.stringify(this.startLocation), JSON.stringify(this.size), JSON.stringify(this.params)]); 129 | } 130 | 131 | } -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/error.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import * as validateTCFError from './validators/validate-TCFError'; 6 | 7 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Error%20Report%20Format.html 8 | /* eslint-disable @typescript-eslint/naming-convention */ 9 | export interface TCFError { 10 | Code: number, 11 | Time?: number, 12 | Service?: string, 13 | Format?: string, 14 | Params?: any[], 15 | Severity?: number, 16 | AltCode?: number, 17 | AltOrg?: string, 18 | CausedBy?: TCFError 19 | } 20 | /* esline-enable */ 21 | 22 | export function asTCFError(result: any): TCFError { 23 | const validResult = validateTCFError(result); 24 | if (!validResult) { 25 | //this one is pretty odd... the error itself not validating? 26 | //still, it's not a good JSON 27 | throw new SyntaxError("JSON did not validate"); 28 | } 29 | return result as TCFError; //type assertion OK 30 | } 31 | 32 | /* eslint-disable @typescript-eslint/naming-convention */ 33 | export enum TCFErrorCodes { 34 | OTHER = 1, 35 | JSON_SYNTAX, 36 | PROTOCOL, 37 | BUFFER_OVERFLOW, 38 | CHANNEL_CLOSED, 39 | COMMAND_CANCELLED, 40 | UNKNOWN_PEER, 41 | BASE64, 42 | EOF, 43 | ALREADY_STOPPED, 44 | ALREADY_EXITED, 45 | ALREADY_RUNNING, 46 | ALREADY_ATTACHED, 47 | IS_RUNNING, 48 | INV_DATA_SIZE, 49 | INV_CONTEXT, 50 | INV_ADDRESS, 51 | INV_EXPRESSION, 52 | INV_FORMAT, 53 | INV_NUMBER, 54 | INV_DWARF, 55 | SYM_NOT_FOUND, 56 | UNSUPPORTED, 57 | INV_DATA_TYPE, 58 | INV_COMMAND, 59 | } 60 | /* eslint-enable */ -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/linenumbers.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { ValidatingCommand, asNullableArray, toBuffer, validateJSON } from './tcfutils'; 6 | import * as validateTCFCodeAreaLineNumbers from './validators/validate-TCFCodeAreaLineNumbers'; 7 | 8 | abstract class LineNumbersCommand extends ValidatingCommand { 9 | 10 | constructor() { 11 | super(); 12 | } 13 | 14 | service(): string { 15 | return "LineNumbers"; 16 | } 17 | 18 | debugDescription(tokenID: number): string { 19 | return `${this.service()}/${tokenID}`; 20 | } 21 | 22 | } 23 | 24 | /* eslint-disable @typescript-eslint/naming-convention */ 25 | export interface TCFCodeAreaLineNumbers { 26 | SLine?: number, 27 | SCol?: number, 28 | SAddr?: number, 29 | ELine?: number, 30 | ECol?: number, 31 | EAddr?: number 32 | NAddr?: number, 33 | File?: string 34 | Dir?: string, 35 | ISA?: number, 36 | IsStmt?: boolean, 37 | BasicBlock?: boolean, 38 | PrologueEnd?: boolean, 39 | EpilogueBegin?: boolean, 40 | OpIndex?: number, 41 | Discriminator?: number, 42 | NStmtAddr?: number 43 | } 44 | /* eslint-enable */ 45 | 46 | function asTCFCodeAreaLineNumbers(json: any) { 47 | return validateJSON(json, validateTCFCodeAreaLineNumbers) as TCFCodeAreaLineNumbers; //type assertion OK 48 | } 49 | 50 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Line%20Numbers.html#CmdMapToSource 51 | export class MapToSourceLineNumbersCommand extends LineNumbersCommand { 52 | contextID: string; 53 | startAddress: number; 54 | endAddress: number; 55 | 56 | constructor(contextID: string, startAddress: number, endAddress: number) { 57 | super(); 58 | this.contextID = contextID; 59 | this.startAddress = startAddress; 60 | this.endAddress = endAddress; 61 | } 62 | 63 | debugDescription(tokenID: number): string { 64 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + [this.contextID, this.startAddress, this.endAddress].map(x => "" + x).join("+"); 65 | } 66 | 67 | command(): string { 68 | return "mapToSource"; 69 | } 70 | 71 | arguments() { 72 | return undefined; 73 | } 74 | 75 | toBuffer(token: string): Buffer { 76 | return toBuffer(["C", token, this.service(), this.command(), JSON.stringify(this.contextID), JSON.stringify(this.startAddress), JSON.stringify(this.endAddress)]); 77 | } 78 | 79 | override cast(json: any): TCFCodeAreaLineNumbers[] | null { 80 | return asNullableArray(json, asTCFCodeAreaLineNumbers); 81 | } 82 | } 83 | 84 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Line%20Numbers.html#CmdMapToMemory 85 | export class MapToMemoryLineNumbersCommand extends LineNumbersCommand { 86 | contextID: string; 87 | file: string; 88 | line: number; 89 | column: number; 90 | 91 | constructor(contextID: string, file: string, line: number, column: number) { 92 | super(); 93 | this.contextID = contextID; 94 | this.file = file; 95 | this.line = line; 96 | this.column = column; 97 | } 98 | 99 | debugDescription(tokenID: number): string { 100 | //file expressly removed from token. too noisy 101 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + [this.contextID, this.line, this.column].map(x => "" + x).join("+"); 102 | } 103 | 104 | command(): string { 105 | return "mapToMemory"; 106 | } 107 | 108 | arguments() { 109 | return undefined; 110 | } 111 | 112 | toBuffer(token: string): Buffer { 113 | return toBuffer(["C", token, this.service(), this.command(), JSON.stringify(this.contextID), JSON.stringify(this.file), JSON.stringify(this.line), JSON.stringify(this.column)]); 114 | } 115 | 116 | override cast(json: any): TCFCodeAreaLineNumbers[] | null { 117 | return asNullableArray(json, asTCFCodeAreaLineNumbers); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/locator.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { SimpleCommand, SimpleEvent, asStringNullableArray, responseLengthAbout } from './tcfutils'; 6 | 7 | abstract class LocatorCommand extends SimpleCommand { 8 | constructor() { 9 | super(); 10 | } 11 | 12 | service(): string { 13 | return "Locator"; 14 | } 15 | 16 | debugDescription(tokenID: number): string { 17 | return `${this.service()}/${tokenID}`; 18 | } 19 | 20 | } 21 | 22 | abstract class LocatorEvent extends SimpleEvent { 23 | service(): string { 24 | return "Locator"; 25 | } 26 | } 27 | 28 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Locator.html 29 | export class HelloLocatorEvent extends LocatorEvent { 30 | 31 | services: string[]; 32 | 33 | constructor(services: string[] = ["Locator"]) { //list of our services. we barely know... locator! 34 | super(); 35 | this.services = services; 36 | } 37 | 38 | event(): string { 39 | return "Hello"; 40 | } 41 | 42 | data() { 43 | return this.services; 44 | } 45 | } 46 | 47 | export function parseHelloLocatorEvent(response: Buffer[]): string[] | null { 48 | if (!responseLengthAbout(1, response)) { 49 | throw new SyntaxError(`Response should have one JSON array, got ${response.length} buffers`); 50 | } 51 | 52 | const supportedServices = asStringNullableArray(JSON.parse(response[0].toString())); //may throw validation error 53 | return supportedServices; 54 | } -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/memory.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { PromiseError, PromiseSuccess, SimpleCommand, ValidatingCommand, asString, asStringNullableArray, handleError, handleErrorBuffer, responseLengthAbout, toBuffer, validateJSON } from "./tcfutils"; 6 | import * as validateMemoryResult from './validators/validate-MemoryResult'; 7 | 8 | abstract class MemoryCommand extends SimpleCommand { 9 | constructor() { 10 | super(); 11 | } 12 | 13 | service(): string { 14 | return "Memory"; 15 | } 16 | 17 | debugDescription(tokenID: number): string { 18 | return `${this.service()}/${tokenID}`; 19 | } 20 | 21 | } 22 | 23 | abstract class MemoryValidatingCommand extends ValidatingCommand { 24 | constructor() { 25 | super(); 26 | } 27 | 28 | service(): string { 29 | return "Memory"; 30 | } 31 | 32 | debugDescription(tokenID: number): string { 33 | return `${this.service()}/${tokenID}`; 34 | } 35 | 36 | } 37 | 38 | 39 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Memory.html#CmdGetChildren 40 | export class GetChildrenMemoryCommand extends MemoryValidatingCommand { 41 | parentContextID: string | null; 42 | 43 | constructor(parentContextID: string | null) { 44 | super(); 45 | this.parentContextID = parentContextID; 46 | } 47 | 48 | command(): string { 49 | return "getChildren"; 50 | } 51 | 52 | arguments() { 53 | return this.parentContextID; 54 | } 55 | 56 | override cast(json: any): string[] | null { 57 | return asStringNullableArray(json); 58 | } 59 | } 60 | 61 | export interface MemoryErrorAddress { 62 | addr: number, 63 | size: number, 64 | stat: number, 65 | msg: any 66 | } 67 | 68 | export interface MemoryResult { 69 | base64: string, 70 | errorAddresses: MemoryErrorAddress[] | null 71 | } 72 | 73 | export function asMemoryResult(result: any): MemoryResult { 74 | return validateJSON(result, validateMemoryResult) as MemoryResult; //type assertion OK 75 | } 76 | 77 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Memory.html#CmdGetMemory 78 | export class GetMemoryCommand extends MemoryCommand { 79 | contextID: string; 80 | address: number; 81 | wordSize: number; 82 | byteCount: number; 83 | mode: number; 84 | 85 | constructor(contextID: string, address: number, wordSize: number, byteCount: number, mode: number = 0) { 86 | super(); 87 | this.contextID = contextID; 88 | this.address = address; 89 | this.wordSize = wordSize; 90 | this.byteCount = byteCount; 91 | this.mode = mode; 92 | } 93 | 94 | command(): string { 95 | return "get"; 96 | } 97 | 98 | arguments() { 99 | return undefined; 100 | } 101 | 102 | toBuffer(token: string): Buffer { 103 | return toBuffer(["C", token, this.service(), this.command(), 104 | JSON.stringify(this.contextID), JSON.stringify(this.address), JSON.stringify(this.wordSize), 105 | JSON.stringify(this.byteCount), JSON.stringify(this.mode)], undefined); 106 | } 107 | 108 | result(responseAll: Buffer[], success: PromiseSuccess, error: PromiseError): void { 109 | parseMemoryResponse(responseAll, success, error); 110 | } 111 | } 112 | 113 | export function parseMemoryResponse(responseAll: Buffer[], success: PromiseSuccess, error: PromiseError): void { 114 | const [response, resultError, errorAddresses, ...etc] = responseAll; 115 | 116 | if (handleErrorBuffer(resultError, error)) { 117 | return; 118 | } 119 | 120 | if (!responseLengthAbout(0, etc)) { 121 | console.log(`Response should have a single JSON, got ${response.length} buffers`); 122 | } 123 | 124 | try { 125 | success(asMemoryResult({ 126 | base64: asString(JSON.parse(response.toString())), 127 | errorAddresses: JSON.parse(errorAddresses.toString()) as MemoryErrorAddress[] //type assertion OK 128 | })); //base64 string 129 | } catch (e) { 130 | handleError(e, error); 131 | } 132 | } 133 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/registers.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { ValidatingCommand, asNullable, asString, asStringNullableArray, validateJSON } from "./tcfutils"; 6 | import * as validateRegistersContextData from './validators/validate-RegistersContextData'; 7 | 8 | abstract class RegistersValidatingCommand extends ValidatingCommand { 9 | constructor() { 10 | super(); 11 | } 12 | 13 | service(): string { 14 | return "Registers"; 15 | } 16 | 17 | debugDescription(tokenID: number): string { 18 | return `${this.service()}/${tokenID}`; 19 | } 20 | 21 | } 22 | 23 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Registers.html#CmdGetContext 24 | export interface RegistersContextData { 25 | /* eslint-disable @typescript-eslint/naming-convention */ 26 | ID: string, 27 | ParentID?: string, 28 | ProcessID?: string, 29 | Name?: string, 30 | Description?: string, 31 | Size?: number, 32 | Readable?: boolean, 33 | ReadOnce?: boolean, 34 | //and many more other fields... 35 | Role?: string 36 | /* eslint-enable */ 37 | } 38 | 39 | export function asRegistersContextData(result: any): RegistersContextData { 40 | return validateJSON(result, validateRegistersContextData) as RegistersContextData; //type assertion OK 41 | } 42 | 43 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Registers.html#CmdGetContext 44 | export class GetContextRegistersCommand extends RegistersValidatingCommand { 45 | contextID: string; 46 | 47 | constructor(contextID: string) { 48 | super(); 49 | this.contextID = contextID; 50 | } 51 | 52 | debugDescription(tokenID: number): string { 53 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.contextID; 54 | } 55 | 56 | command(): string { 57 | return "getContext"; 58 | } 59 | 60 | arguments() { 61 | return this.contextID; 62 | } 63 | 64 | override cast(json: any): RegistersContextData | null { 65 | return asNullable(json, asRegistersContextData); 66 | } 67 | } 68 | 69 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Registers.html#CmdGetChildren 70 | export class GetChildrenRegistersCommand extends RegistersValidatingCommand { 71 | parentContextID: string; 72 | 73 | constructor(parentContextID: string) { 74 | super(); 75 | this.parentContextID = parentContextID; 76 | } 77 | 78 | debugDescription(tokenID: number): string { 79 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.arguments(); 80 | } 81 | 82 | command(): string { 83 | return "getChildren"; 84 | } 85 | 86 | arguments() { 87 | return this.parentContextID; 88 | } 89 | 90 | override cast(json: any): string[] | null { 91 | return asStringNullableArray(json); 92 | } 93 | } 94 | 95 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Registers.html#CmdGetRegister 96 | export class GetRegistersCommand extends RegistersValidatingCommand { 97 | contextID: string; 98 | 99 | constructor(contextID: string) { 100 | super(); 101 | this.contextID = contextID; 102 | } 103 | 104 | debugDescription(tokenID: number): string { 105 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.arguments(); 106 | } 107 | 108 | command(): string { 109 | return "get"; 110 | } 111 | 112 | arguments() { 113 | return this.contextID; 114 | } 115 | 116 | override cast(json: any): Buffer { 117 | const s = asString(json); //validates 118 | return Buffer.from(s, "base64"); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/BreakpointData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "BreakpointType": { 5 | "enum": [ 6 | "Auto", 7 | "Hardware", 8 | "Software" 9 | ], 10 | "type": "string" 11 | }, 12 | "Enabled": { 13 | "type": "boolean" 14 | }, 15 | "File": { 16 | "type": "string" 17 | }, 18 | "ID": { 19 | "type": "string" 20 | }, 21 | "Line": { 22 | "type": "number" 23 | } 24 | }, 25 | "required": [ 26 | "Enabled", 27 | "ID" 28 | ], 29 | "type": "object" 30 | } 31 | 32 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/BreakpointStatus.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "InstanceStatusData": { 5 | "properties": { 6 | "Address": { 7 | "type": [ 8 | "string", 9 | "number" 10 | ] 11 | }, 12 | "BreakpointType": { 13 | "type": "string" 14 | }, 15 | "ConditionError": { 16 | "type": "string" 17 | }, 18 | "Error": { 19 | "type": "string" 20 | }, 21 | "HitCount": { 22 | "type": "number" 23 | }, 24 | "LocationContext": { 25 | "type": "string" 26 | }, 27 | "MemoryContext": { 28 | "type": "string" 29 | }, 30 | "Size": { 31 | "type": "number" 32 | } 33 | }, 34 | "type": "object" 35 | } 36 | }, 37 | "properties": { 38 | "Column": { 39 | "type": "number" 40 | }, 41 | "Error": { 42 | "type": "string" 43 | }, 44 | "File": { 45 | "type": "string" 46 | }, 47 | "Instances": { 48 | "anyOf": [ 49 | { 50 | "items": { 51 | "$ref": "#/definitions/InstanceStatusData" 52 | }, 53 | "type": "array" 54 | }, 55 | { 56 | "type": "null" 57 | } 58 | ] 59 | }, 60 | "Line": { 61 | "type": "number" 62 | } 63 | }, 64 | "type": "object" 65 | } 66 | 67 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/ContextSuspendedData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "StateData": { 5 | "properties": { 6 | "BPs": { 7 | "items": { 8 | "type": "string" 9 | }, 10 | "type": "array" 11 | }, 12 | "CPU": { 13 | "type": "string" 14 | }, 15 | "Context": { 16 | "type": "string" 17 | }, 18 | "FuncCall": { 19 | "type": "boolean" 20 | }, 21 | "PCError": { 22 | "additionalProperties": true, 23 | "properties": {}, 24 | "type": "object" 25 | }, 26 | "Reversing": { 27 | "type": "boolean" 28 | }, 29 | "Signal": { 30 | "type": "number" 31 | }, 32 | "SignalDescription": { 33 | "type": "string" 34 | }, 35 | "SignalName": { 36 | "type": "string" 37 | }, 38 | "StateName": { 39 | "type": "string" 40 | }, 41 | "StepError": { 42 | "additionalProperties": true, 43 | "properties": {}, 44 | "type": "object" 45 | } 46 | }, 47 | "type": "object" 48 | } 49 | }, 50 | "properties": { 51 | "data": { 52 | "anyOf": [ 53 | { 54 | "$ref": "#/definitions/StateData" 55 | }, 56 | { 57 | "type": "null" 58 | } 59 | ] 60 | }, 61 | "id": { 62 | "type": "string" 63 | }, 64 | "pc": { 65 | "type": "number" 66 | }, 67 | "reason": { 68 | "type": "string" 69 | } 70 | }, 71 | "required": [ 72 | "data", 73 | "id", 74 | "pc", 75 | "reason" 76 | ], 77 | "type": "object" 78 | } 79 | 80 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/DisassemblyCapability.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "ISA": { 5 | "type": "string" 6 | }, 7 | "OpcodeValue": { 8 | "type": "boolean" 9 | }, 10 | "PseudoInstruction": { 11 | "type": "boolean" 12 | }, 13 | "Simplified": { 14 | "type": "boolean" 15 | } 16 | }, 17 | "type": "object" 18 | } 19 | 20 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/DisassemblyLine.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "DisassemblyInstructionField": { 5 | "properties": { 6 | "AddressSpace": { 7 | "type": "string" 8 | }, 9 | "Text": { 10 | "type": "string" 11 | }, 12 | "Type": { 13 | "type": "string" 14 | }, 15 | "Value": { 16 | "type": "number" 17 | } 18 | }, 19 | "required": [ 20 | "Text", 21 | "Type" 22 | ], 23 | "type": "object" 24 | } 25 | }, 26 | "properties": { 27 | "Address": { 28 | "type": "number" 29 | }, 30 | "ISA": { 31 | "type": "string" 32 | }, 33 | "Instruction": { 34 | "anyOf": [ 35 | { 36 | "items": { 37 | "$ref": "#/definitions/DisassemblyInstructionField" 38 | }, 39 | "type": "array" 40 | }, 41 | { 42 | "type": "null" 43 | } 44 | ] 45 | }, 46 | "OpcodeValue": { 47 | "type": "string" 48 | }, 49 | "Size": { 50 | "type": "number" 51 | } 52 | }, 53 | "required": [ 54 | "Address", 55 | "Instruction", 56 | "Size" 57 | ], 58 | "type": "object" 59 | } 60 | 61 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/ExpressionsContextData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "CanAssign": { 5 | "type": "boolean" 6 | }, 7 | "Class": { 8 | "type": "number" 9 | }, 10 | "Expression": { 11 | "type": "string" 12 | }, 13 | "HasFuncCall": { 14 | "type": "boolean" 15 | }, 16 | "ID": { 17 | "type": "string" 18 | }, 19 | "ParentID": { 20 | "type": "string" 21 | }, 22 | "Size": { 23 | "type": "number" 24 | }, 25 | "SymbolID": { 26 | "type": "string" 27 | }, 28 | "Type": { 29 | "type": "string" 30 | } 31 | }, 32 | "required": [ 33 | "ID" 34 | ], 35 | "type": "object" 36 | } 37 | 38 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/InstanceStatusData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "Address": { 5 | "type": [ 6 | "string", 7 | "number" 8 | ] 9 | }, 10 | "BreakpointType": { 11 | "type": "string" 12 | }, 13 | "ConditionError": { 14 | "type": "string" 15 | }, 16 | "Error": { 17 | "type": "string" 18 | }, 19 | "HitCount": { 20 | "type": "number" 21 | }, 22 | "LocationContext": { 23 | "type": "string" 24 | }, 25 | "MemoryContext": { 26 | "type": "string" 27 | }, 28 | "Size": { 29 | "type": "number" 30 | } 31 | }, 32 | "type": "object" 33 | } 34 | 35 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/MemoryResult.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "MemoryErrorAddress": { 5 | "properties": { 6 | "addr": { 7 | "type": "number" 8 | }, 9 | "msg": {}, 10 | "size": { 11 | "type": "number" 12 | }, 13 | "stat": { 14 | "type": "number" 15 | } 16 | }, 17 | "required": [ 18 | "addr", 19 | "msg", 20 | "size", 21 | "stat" 22 | ], 23 | "type": "object" 24 | } 25 | }, 26 | "properties": { 27 | "base64": { 28 | "type": "string" 29 | }, 30 | "errorAddresses": { 31 | "anyOf": [ 32 | { 33 | "items": { 34 | "$ref": "#/definitions/MemoryErrorAddress" 35 | }, 36 | "type": "array" 37 | }, 38 | { 39 | "type": "null" 40 | } 41 | ] 42 | } 43 | }, 44 | "required": [ 45 | "base64", 46 | "errorAddresses" 47 | ], 48 | "type": "object" 49 | } 50 | 51 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/PieceValue.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "Size": { 5 | "type": "number" 6 | }, 7 | "Value": { 8 | "type": "string" 9 | } 10 | }, 11 | "required": [ 12 | "Size" 13 | ], 14 | "type": "object" 15 | } 16 | 17 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/RegistersContextData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "Description": { 5 | "type": "string" 6 | }, 7 | "ID": { 8 | "type": "string" 9 | }, 10 | "Name": { 11 | "type": "string" 12 | }, 13 | "ParentID": { 14 | "type": "string" 15 | }, 16 | "ProcessID": { 17 | "type": "string" 18 | }, 19 | "ReadOnce": { 20 | "type": "boolean" 21 | }, 22 | "Readable": { 23 | "type": "boolean" 24 | }, 25 | "Role": { 26 | "type": "string" 27 | }, 28 | "Size": { 29 | "type": "number" 30 | } 31 | }, 32 | "required": [ 33 | "ID" 34 | ], 35 | "type": "object" 36 | } 37 | 38 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/TCFCodeAreaLineNumbers.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "BasicBlock": { 5 | "type": "boolean" 6 | }, 7 | "Dir": { 8 | "type": "string" 9 | }, 10 | "Discriminator": { 11 | "type": "number" 12 | }, 13 | "EAddr": { 14 | "type": "number" 15 | }, 16 | "ECol": { 17 | "type": "number" 18 | }, 19 | "ELine": { 20 | "type": "number" 21 | }, 22 | "EpilogueBegin": { 23 | "type": "boolean" 24 | }, 25 | "File": { 26 | "type": "string" 27 | }, 28 | "ISA": { 29 | "type": "number" 30 | }, 31 | "IsStmt": { 32 | "type": "boolean" 33 | }, 34 | "NAddr": { 35 | "type": "number" 36 | }, 37 | "NStmtAddr": { 38 | "type": "number" 39 | }, 40 | "OpIndex": { 41 | "type": "number" 42 | }, 43 | "PrologueEnd": { 44 | "type": "boolean" 45 | }, 46 | "SAddr": { 47 | "type": "number" 48 | }, 49 | "SCol": { 50 | "type": "number" 51 | }, 52 | "SLine": { 53 | "type": "number" 54 | } 55 | }, 56 | "type": "object" 57 | } 58 | 59 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/TCFContextData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "properties": { 4 | "CPUGroup": { 5 | "type": "string" 6 | }, 7 | "CanCount": { 8 | "type": "number" 9 | }, 10 | "CanDetach": { 11 | "type": "boolean" 12 | }, 13 | "CanResume": { 14 | "type": "number" 15 | }, 16 | "CanSuspend": { 17 | "type": "boolean" 18 | }, 19 | "CanTerminate": { 20 | "type": "boolean" 21 | }, 22 | "HasState": { 23 | "type": "boolean" 24 | }, 25 | "ID": { 26 | "type": "string" 27 | }, 28 | "IsContainer": { 29 | "type": "boolean" 30 | }, 31 | "Name": { 32 | "type": "string" 33 | }, 34 | "ParentID": { 35 | "type": "string" 36 | }, 37 | "ProcessID": { 38 | "type": "string" 39 | }, 40 | "RCGroup": { 41 | "type": "string" 42 | }, 43 | "RegAccessTypes": { 44 | "items": { 45 | "type": "string" 46 | }, 47 | "type": "array" 48 | }, 49 | "SymbolsGroup": { 50 | "type": "string" 51 | }, 52 | "WordSize": { 53 | "type": "number" 54 | } 55 | }, 56 | "required": [ 57 | "ID" 58 | ], 59 | "type": "object" 60 | } 61 | 62 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/TCFContextDataStackTrace.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "TCFCodeAreaLineNumbers": { 5 | "properties": { 6 | "BasicBlock": { 7 | "type": "boolean" 8 | }, 9 | "Dir": { 10 | "type": "string" 11 | }, 12 | "Discriminator": { 13 | "type": "number" 14 | }, 15 | "EAddr": { 16 | "type": "number" 17 | }, 18 | "ECol": { 19 | "type": "number" 20 | }, 21 | "ELine": { 22 | "type": "number" 23 | }, 24 | "EpilogueBegin": { 25 | "type": "boolean" 26 | }, 27 | "File": { 28 | "type": "string" 29 | }, 30 | "ISA": { 31 | "type": "number" 32 | }, 33 | "IsStmt": { 34 | "type": "boolean" 35 | }, 36 | "NAddr": { 37 | "type": "number" 38 | }, 39 | "NStmtAddr": { 40 | "type": "number" 41 | }, 42 | "OpIndex": { 43 | "type": "number" 44 | }, 45 | "PrologueEnd": { 46 | "type": "boolean" 47 | }, 48 | "SAddr": { 49 | "type": "number" 50 | }, 51 | "SCol": { 52 | "type": "number" 53 | }, 54 | "SLine": { 55 | "type": "number" 56 | } 57 | }, 58 | "type": "object" 59 | } 60 | }, 61 | "properties": { 62 | "ArgsAddr": { 63 | "type": "number" 64 | }, 65 | "ArgsCnt": { 66 | "type": "number" 67 | }, 68 | "CodeArea": { 69 | "$ref": "#/definitions/TCFCodeAreaLineNumbers" 70 | }, 71 | "FP": { 72 | "type": "number" 73 | }, 74 | "FuncID": { 75 | "type": "string" 76 | }, 77 | "ID": { 78 | "type": "string" 79 | }, 80 | "IP": { 81 | "type": "number" 82 | }, 83 | "Index": { 84 | "type": "number" 85 | }, 86 | "Name": { 87 | "type": "string" 88 | }, 89 | "ParentID": { 90 | "type": "string" 91 | }, 92 | "ProcessID": { 93 | "type": "string" 94 | }, 95 | "RP": { 96 | "type": "number" 97 | }, 98 | "TopFrame": { 99 | "type": "boolean" 100 | }, 101 | "Walk": { 102 | "type": "boolean" 103 | } 104 | }, 105 | "required": [ 106 | "ID" 107 | ], 108 | "type": "object" 109 | } 110 | 111 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/TCFError.json: -------------------------------------------------------------------------------- 1 | { 2 | "$ref": "#/definitions/TCFError", 3 | "$schema": "http://json-schema.org/draft-07/schema#", 4 | "definitions": { 5 | "TCFError": { 6 | "properties": { 7 | "AltCode": { 8 | "type": "number" 9 | }, 10 | "AltOrg": { 11 | "type": "string" 12 | }, 13 | "CausedBy": { 14 | "$ref": "#/definitions/TCFError" 15 | }, 16 | "Code": { 17 | "type": "number" 18 | }, 19 | "Format": { 20 | "type": "string" 21 | }, 22 | "Params": { 23 | "items": {}, 24 | "type": "array" 25 | }, 26 | "Service": { 27 | "type": "string" 28 | }, 29 | "Severity": { 30 | "type": "number" 31 | }, 32 | "Time": { 33 | "type": "number" 34 | } 35 | }, 36 | "required": [ 37 | "Code" 38 | ], 39 | "type": "object" 40 | } 41 | } 42 | } 43 | 44 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/TCFStateData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "StateData": { 5 | "properties": { 6 | "BPs": { 7 | "items": { 8 | "type": "string" 9 | }, 10 | "type": "array" 11 | }, 12 | "CPU": { 13 | "type": "string" 14 | }, 15 | "Context": { 16 | "type": "string" 17 | }, 18 | "FuncCall": { 19 | "type": "boolean" 20 | }, 21 | "PCError": { 22 | "additionalProperties": true, 23 | "properties": {}, 24 | "type": "object" 25 | }, 26 | "Reversing": { 27 | "type": "boolean" 28 | }, 29 | "Signal": { 30 | "type": "number" 31 | }, 32 | "SignalDescription": { 33 | "type": "string" 34 | }, 35 | "SignalName": { 36 | "type": "string" 37 | }, 38 | "StateName": { 39 | "type": "string" 40 | }, 41 | "StepError": { 42 | "additionalProperties": true, 43 | "properties": {}, 44 | "type": "object" 45 | } 46 | }, 47 | "type": "object" 48 | } 49 | }, 50 | "properties": { 51 | "data": { 52 | "anyOf": [ 53 | { 54 | "$ref": "#/definitions/StateData" 55 | }, 56 | { 57 | "type": "null" 58 | } 59 | ] 60 | }, 61 | "lastStateReason": { 62 | "type": [ 63 | "null", 64 | "string" 65 | ] 66 | }, 67 | "pc": { 68 | "type": "number" 69 | }, 70 | "suspended": { 71 | "type": "boolean" 72 | } 73 | }, 74 | "required": [ 75 | "data", 76 | "lastStateReason", 77 | "pc", 78 | "suspended" 79 | ], 80 | "type": "object" 81 | } 82 | 83 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/TCFSymbolContextData.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "TCFSymbolClass": { 5 | "enum": [ 6 | 0, 7 | 1, 8 | 2, 9 | 3, 10 | 4, 11 | 5, 12 | 6, 13 | 7, 14 | 8, 15 | 9 16 | ], 17 | "type": "number" 18 | } 19 | }, 20 | "properties": { 21 | "Address": { 22 | "type": "number" 23 | }, 24 | "BaseTypeID": { 25 | "type": [ 26 | "null", 27 | "string" 28 | ] 29 | }, 30 | "Class": { 31 | "$ref": "#/definitions/TCFSymbolClass" 32 | }, 33 | "ContainerID": { 34 | "type": [ 35 | "null", 36 | "string" 37 | ] 38 | }, 39 | "Flags": { 40 | "type": "number" 41 | }, 42 | "ID": { 43 | "type": "string" 44 | }, 45 | "Length": { 46 | "type": "number" 47 | }, 48 | "Name": { 49 | "type": [ 50 | "null", 51 | "string" 52 | ] 53 | }, 54 | "Offset": { 55 | "type": "number" 56 | }, 57 | "OwnerID": { 58 | "type": "string" 59 | }, 60 | "Register": { 61 | "type": "string" 62 | }, 63 | "Size": { 64 | "type": "number" 65 | }, 66 | "TypeClass": { 67 | "enum": [ 68 | 0, 69 | 1, 70 | 10, 71 | 2, 72 | 3, 73 | 4, 74 | 5, 75 | 6, 76 | 7, 77 | 8, 78 | 9 79 | ], 80 | "type": "number" 81 | }, 82 | "TypeID": { 83 | "type": "string" 84 | }, 85 | "UpdatePolicy": { 86 | "type": "number" 87 | }, 88 | "Value": { 89 | "type": "string" 90 | } 91 | }, 92 | "required": [ 93 | "Class", 94 | "ID" 95 | ], 96 | "type": "object" 97 | } 98 | 99 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/schema/ValueProperties.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "http://json-schema.org/draft-07/schema#", 3 | "definitions": { 4 | "PieceValue": { 5 | "properties": { 6 | "Size": { 7 | "type": "number" 8 | }, 9 | "Value": { 10 | "type": "string" 11 | } 12 | }, 13 | "required": [ 14 | "Size" 15 | ], 16 | "type": "object" 17 | } 18 | }, 19 | "properties": { 20 | "Address": { 21 | "type": "number" 22 | }, 23 | "BigEndian": { 24 | "type": "boolean" 25 | }, 26 | "BinaryScale": { 27 | "type": "number" 28 | }, 29 | "BitStride": { 30 | "type": "number" 31 | }, 32 | "Class": { 33 | "enum": [ 34 | 0, 35 | 1, 36 | 2, 37 | 3, 38 | 4, 39 | 5, 40 | 6, 41 | 7, 42 | 8, 43 | 9 44 | ], 45 | "type": "number" 46 | }, 47 | "DecimalScale": { 48 | "type": "number" 49 | }, 50 | "ImplicitPointer": { 51 | "type": "boolean" 52 | }, 53 | "Pieces": { 54 | "items": { 55 | "$ref": "#/definitions/PieceValue" 56 | }, 57 | "type": "array" 58 | }, 59 | "Register": { 60 | "type": "string" 61 | }, 62 | "Symbol": { 63 | "type": "string" 64 | }, 65 | "Type": { 66 | "type": "string" 67 | } 68 | }, 69 | "type": "object" 70 | } 71 | 72 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/stacktrace.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { TCFCodeAreaLineNumbers } from './linenumbers'; 6 | import { asNullableArray, asStringNullableArray, handleError, handleErrorBuffer, PromiseError, PromiseSuccess, SimpleCommand, validateJSON, ValidatingCommand, toBuffer } from './tcfutils'; 7 | import * as validateTCFContextDataStackTrace from './validators/validate-TCFContextDataStackTrace'; 8 | 9 | const DEFAULT_STACKTRACE_RANGE = 20; 10 | 11 | abstract class StackTraceCommand extends SimpleCommand { 12 | constructor() { 13 | super(); 14 | } 15 | 16 | service(): string { 17 | return "StackTrace"; 18 | } 19 | 20 | debugDescription(tokenID: number): string { 21 | return `${this.service()}/${tokenID}`; 22 | } 23 | 24 | } 25 | 26 | abstract class StackTraceValidatingCommand extends ValidatingCommand { 27 | constructor() { 28 | super(); 29 | } 30 | 31 | service(): string { 32 | return "StackTrace"; 33 | } 34 | 35 | debugDescription(tokenID: number): string { 36 | return `${this.service()}/${tokenID}`; 37 | } 38 | 39 | } 40 | 41 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Stack%20Trace.html#CmdGetChildren 42 | export class GetChildrenStackTraceCommand extends StackTraceValidatingCommand { 43 | parentContextId: string; 44 | 45 | constructor(parentContextId: string) { 46 | super(); 47 | this.parentContextId = parentContextId; 48 | } 49 | 50 | debugDescription(tokenID: number): string { 51 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.arguments(); 52 | } 53 | 54 | command(): string { 55 | return "getChildren"; 56 | } 57 | 58 | arguments(): string { 59 | return this.parentContextId; 60 | } 61 | 62 | override cast(json: any): string[] | null { 63 | return asStringNullableArray(json); 64 | } 65 | } 66 | 67 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Stack%20Trace.html#CmdGetChildrenRange 68 | export class GetChildrenRangeStackTraceCommand extends StackTraceValidatingCommand { 69 | parentContextId: string; 70 | startRange: number; 71 | endRange: number; 72 | 73 | constructor(parentcontextId: string, start: number = 0, end: number = DEFAULT_STACKTRACE_RANGE - 1) { 74 | super(); 75 | this.parentContextId = parentcontextId; 76 | this.startRange = start; 77 | this.endRange = end; 78 | } 79 | 80 | debugDescription(tokenID: number): string { 81 | return `${super.debugDescription(tokenID)}/${this.command()}/${this.parentContextId}-${this.startRange}:${this.endRange}`; 82 | } 83 | 84 | command(): string { 85 | return "getChildrenRange"; 86 | } 87 | 88 | arguments(): any { 89 | return undefined; //custom serialization 90 | } 91 | 92 | override cast(json: any): string[] | null { 93 | return asStringNullableArray(json); 94 | } 95 | 96 | toBuffer(token: string): Buffer { 97 | return toBuffer(["C", token, this.service(), this.command(), JSON.stringify(this.parentContextId), JSON.stringify(this.startRange), JSON.stringify(this.endRange)]); 98 | } 99 | 100 | } 101 | 102 | 103 | /* eslint-disable @typescript-eslint/naming-convention */ 104 | export interface TCFContextDataStackTrace { 105 | ID: string, 106 | ParentID?: string, 107 | ProcessID?: string, 108 | Name?: string, 109 | TopFrame?: boolean, 110 | Index?: number, 111 | Walk?: boolean, 112 | FP?: number, 113 | RP?: number, 114 | IP?: number, 115 | ArgsCnt?: number, 116 | ArgsAddr?: number, 117 | CodeArea?: TCFCodeAreaLineNumbers, 118 | FuncID?: string 119 | } 120 | /* eslint-enable */ 121 | 122 | function asTCFContextDataStackTrace(json: any) { 123 | return validateJSON(json, validateTCFContextDataStackTrace) as TCFContextDataStackTrace; //type assertion OK 124 | } 125 | 126 | function asTCFContextDataStackTraceNullableArray(result: any): TCFContextDataStackTrace[] | null { 127 | return asNullableArray(result, asTCFContextDataStackTrace); 128 | } 129 | 130 | //see https://download.eclipse.org/tools/tcf/tcf-docs/TCF%20Service%20-%20Stack%20Trace.html#CmdGetContext 131 | export class GetContextStackTraceCommand extends StackTraceCommand { 132 | contextIDs: string[]; 133 | 134 | constructor(contextIDs: string[]) { 135 | super(); 136 | this.contextIDs = contextIDs; 137 | } 138 | 139 | debugDescription(tokenID: number): string { 140 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.arguments().join("+"); 141 | } 142 | 143 | command(): string { 144 | return "getContext"; 145 | } 146 | 147 | arguments(): string[] { 148 | return this.contextIDs; 149 | } 150 | 151 | result(responseAll: Buffer[], success: PromiseSuccess, error: PromiseError): void /* TCFContextDataStackTrace[] */ { 152 | //error and response are REVERSED! 153 | const [response, resultError, ...misc] = responseAll; 154 | 155 | if (!handleErrorBuffer(resultError, error)) { 156 | try { 157 | success(asTCFContextDataStackTraceNullableArray(JSON.parse(response.toString())) ?? []); 158 | } catch (e) { 159 | handleError(e, error); 160 | } 161 | } 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/symbols.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { asString, asStringNullableArray, toBuffer, validateJSON, ValidatingCommand } from './tcfutils'; 6 | import * as validateTCFSymbolContextData from './validators/validate-TCFSymbolContextData'; 7 | 8 | abstract class SymbolsCommand extends ValidatingCommand { 9 | constructor() { 10 | super(); 11 | } 12 | 13 | service(): string { 14 | return "Symbols"; 15 | } 16 | 17 | debugDescription(tokenID: number): string { 18 | return `${this.service()}/${tokenID}`; 19 | } 20 | } 21 | 22 | //returns string 23 | export class FindByAddrSymbolsCommand extends SymbolsCommand { 24 | contextID: string; 25 | address: number; 26 | 27 | constructor(contextID: string, address: number) { 28 | super(); 29 | this.contextID = contextID; 30 | this.address = address; 31 | } 32 | 33 | debugDescription(tokenID: number): string { 34 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.contextID + "+" + this.address; 35 | } 36 | 37 | command(): string { 38 | return "findByAddr"; 39 | } 40 | 41 | arguments() { 42 | return undefined; 43 | } 44 | 45 | toBuffer(token: string): Buffer { 46 | return toBuffer(["C", token, this.service(), this.command(), JSON.stringify(this.contextID), JSON.stringify(this.address)]); 47 | } 48 | 49 | override cast(json: any): string { 50 | return asString(json); 51 | } 52 | } 53 | 54 | /* eslint-disable @typescript-eslint/naming-convention */ 55 | export enum TCFSymbolClass { 56 | unknown, 57 | value, 58 | reference, 59 | function, 60 | type, 61 | comp_unit, 62 | block, 63 | namespace, 64 | variant_part, 65 | variant 66 | } 67 | /* eslint-enable */ 68 | 69 | /* eslint-disable @typescript-eslint/naming-convention */ 70 | export enum TCFTypeClass { 71 | unknown, 72 | cardinal, 73 | integer, 74 | real, 75 | pointer, 76 | array, 77 | composite, 78 | enumeration, 79 | function, 80 | member_pointer, 81 | complex 82 | } 83 | /* eslint-enable */ 84 | 85 | /* eslint-disable @typescript-eslint/naming-convention */ 86 | export interface TCFSymbolContextData { 87 | ID: string, 88 | OwnerID?: string, 89 | UpdatePolicy?: number, 90 | Name?: string | null, 91 | TypeClass?: TCFTypeClass, 92 | TypeID?: string, 93 | BaseTypeID?: string | null, 94 | //IndexTypeID?: string | null, 95 | ContainerID?: string | null, 96 | Size?: number, 97 | Length?: number, //array length 98 | //LowerBound?: number, 99 | //UpperBound?: number, 100 | //BitStride?: number, 101 | Offset?: number, 102 | Address?: number, 103 | Value?: string, //base64 string 104 | //BigEndian?: boolean, 105 | Register?: string, 106 | Flags?: number, 107 | Class: TCFSymbolClass 108 | } 109 | /* eslint-enable */ 110 | 111 | function asTCFSymbolContextData(json: any): TCFSymbolContextData { 112 | return validateJSON(json, validateTCFSymbolContextData) as TCFSymbolContextData; //type assertion OK 113 | } 114 | 115 | //returns TCFSymbolContextData 116 | export class GetContextSymbolsCommand extends SymbolsCommand { 117 | contextID: string; 118 | 119 | constructor(contextID: string) { 120 | super(); 121 | this.contextID = contextID; 122 | } 123 | 124 | debugDescription(tokenID: number): string { 125 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.contextID; 126 | } 127 | 128 | command(): string { 129 | return "getContext"; 130 | } 131 | 132 | arguments() { 133 | return this.contextID; 134 | } 135 | 136 | override cast(json: any): TCFSymbolContextData { 137 | return asTCFSymbolContextData(json); 138 | } 139 | 140 | } 141 | 142 | /** 143 | * Get struct children. 144 | */ 145 | export class GetChildrenSymbolsCommand extends SymbolsCommand { 146 | contextID: string; 147 | 148 | constructor(contextID: string) { 149 | super(); 150 | this.contextID = contextID; 151 | } 152 | 153 | debugDescription(tokenID: number): string { 154 | return super.debugDescription(tokenID) + "/" + this.command() + "/" + this.contextID; 155 | } 156 | 157 | command(): string { 158 | return "getChildren"; 159 | } 160 | 161 | arguments() { 162 | return this.contextID; 163 | } 164 | 165 | override cast(json: any): string[] | null { 166 | return asStringNullableArray(json); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/tcfproto.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2022, 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | 6 | /** 7 | * Note that normally a TCF command has a `token` too. That token is not part of the command though, 8 | * it is just a serialization identifier. As such it is excluded from this interface. This may not 9 | * be the best idea if we add command de-serialization since the token will have to be represented 10 | * somehow. 11 | */ 12 | export interface TCFCommand { 13 | service(): string; 14 | command(): string; 15 | arguments(): any; 16 | } 17 | 18 | export interface TCFResult { 19 | token(): string; 20 | data(): any; 21 | } 22 | 23 | export interface TCFEvent { 24 | service(): string; 25 | event(): string; 26 | data(): any; 27 | } 28 | 29 | export interface TCFFlowControl { 30 | congestion(): number; 31 | } 32 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-BreakpointData.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-BreakpointData.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = validate20; 3 | module.exports.default = validate20; 4 | const schema22 = {"$schema":"http://json-schema.org/draft-07/schema#","properties":{"BreakpointType":{"enum":["Auto","Hardware","Software"],"type":"string"},"Enabled":{"type":"boolean"},"File":{"type":"string"},"ID":{"type":"string"},"Line":{"type":"number"}},"required":["Enabled","ID"],"type":"object"}; 5 | 6 | function validate20(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){ 7 | let vErrors = null; 8 | let errors = 0; 9 | if(errors === 0){ 10 | if(data && typeof data == "object" && !Array.isArray(data)){ 11 | let missing0; 12 | if(((data.Enabled === undefined) && (missing0 = "Enabled")) || ((data.ID === undefined) && (missing0 = "ID"))){ 13 | validate20.errors = [{instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: missing0},message:"must have required property '"+missing0+"'"}]; 14 | return false; 15 | } 16 | else { 17 | if(data.BreakpointType !== undefined){ 18 | let data0 = data.BreakpointType; 19 | const _errs1 = errors; 20 | if(typeof data0 !== "string"){ 21 | validate20.errors = [{instancePath:instancePath+"/BreakpointType",schemaPath:"#/properties/BreakpointType/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 22 | return false; 23 | } 24 | if(!(((data0 === "Auto") || (data0 === "Hardware")) || (data0 === "Software"))){ 25 | validate20.errors = [{instancePath:instancePath+"/BreakpointType",schemaPath:"#/properties/BreakpointType/enum",keyword:"enum",params:{allowedValues: schema22.properties.BreakpointType.enum},message:"must be equal to one of the allowed values"}]; 26 | return false; 27 | } 28 | var valid0 = _errs1 === errors; 29 | } 30 | else { 31 | var valid0 = true; 32 | } 33 | if(valid0){ 34 | if(data.Enabled !== undefined){ 35 | const _errs3 = errors; 36 | if(typeof data.Enabled !== "boolean"){ 37 | validate20.errors = [{instancePath:instancePath+"/Enabled",schemaPath:"#/properties/Enabled/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}]; 38 | return false; 39 | } 40 | var valid0 = _errs3 === errors; 41 | } 42 | else { 43 | var valid0 = true; 44 | } 45 | if(valid0){ 46 | if(data.File !== undefined){ 47 | const _errs5 = errors; 48 | if(typeof data.File !== "string"){ 49 | validate20.errors = [{instancePath:instancePath+"/File",schemaPath:"#/properties/File/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 50 | return false; 51 | } 52 | var valid0 = _errs5 === errors; 53 | } 54 | else { 55 | var valid0 = true; 56 | } 57 | if(valid0){ 58 | if(data.ID !== undefined){ 59 | const _errs7 = errors; 60 | if(typeof data.ID !== "string"){ 61 | validate20.errors = [{instancePath:instancePath+"/ID",schemaPath:"#/properties/ID/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 62 | return false; 63 | } 64 | var valid0 = _errs7 === errors; 65 | } 66 | else { 67 | var valid0 = true; 68 | } 69 | if(valid0){ 70 | if(data.Line !== undefined){ 71 | let data4 = data.Line; 72 | const _errs9 = errors; 73 | if(!((typeof data4 == "number") && (isFinite(data4)))){ 74 | validate20.errors = [{instancePath:instancePath+"/Line",schemaPath:"#/properties/Line/type",keyword:"type",params:{type: "number"},message:"must be number"}]; 75 | return false; 76 | } 77 | var valid0 = _errs9 === errors; 78 | } 79 | else { 80 | var valid0 = true; 81 | } 82 | } 83 | } 84 | } 85 | } 86 | } 87 | } 88 | else { 89 | validate20.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}]; 90 | return false; 91 | } 92 | } 93 | validate20.errors = vErrors; 94 | return errors === 0; 95 | } 96 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-BreakpointStatus.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-ContextSuspendedData.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-DisassemblyCapability.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-DisassemblyCapability.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = validate20; 3 | module.exports.default = validate20; 4 | const schema22 = {"$schema":"http://json-schema.org/draft-07/schema#","properties":{"ISA":{"type":"string"},"OpcodeValue":{"type":"boolean"},"PseudoInstruction":{"type":"boolean"},"Simplified":{"type":"boolean"}},"type":"object"}; 5 | 6 | function validate20(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){ 7 | let vErrors = null; 8 | let errors = 0; 9 | if(errors === 0){ 10 | if(data && typeof data == "object" && !Array.isArray(data)){ 11 | if(data.ISA !== undefined){ 12 | const _errs1 = errors; 13 | if(typeof data.ISA !== "string"){ 14 | validate20.errors = [{instancePath:instancePath+"/ISA",schemaPath:"#/properties/ISA/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 15 | return false; 16 | } 17 | var valid0 = _errs1 === errors; 18 | } 19 | else { 20 | var valid0 = true; 21 | } 22 | if(valid0){ 23 | if(data.OpcodeValue !== undefined){ 24 | const _errs3 = errors; 25 | if(typeof data.OpcodeValue !== "boolean"){ 26 | validate20.errors = [{instancePath:instancePath+"/OpcodeValue",schemaPath:"#/properties/OpcodeValue/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}]; 27 | return false; 28 | } 29 | var valid0 = _errs3 === errors; 30 | } 31 | else { 32 | var valid0 = true; 33 | } 34 | if(valid0){ 35 | if(data.PseudoInstruction !== undefined){ 36 | const _errs5 = errors; 37 | if(typeof data.PseudoInstruction !== "boolean"){ 38 | validate20.errors = [{instancePath:instancePath+"/PseudoInstruction",schemaPath:"#/properties/PseudoInstruction/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}]; 39 | return false; 40 | } 41 | var valid0 = _errs5 === errors; 42 | } 43 | else { 44 | var valid0 = true; 45 | } 46 | if(valid0){ 47 | if(data.Simplified !== undefined){ 48 | const _errs7 = errors; 49 | if(typeof data.Simplified !== "boolean"){ 50 | validate20.errors = [{instancePath:instancePath+"/Simplified",schemaPath:"#/properties/Simplified/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}]; 51 | return false; 52 | } 53 | var valid0 = _errs7 === errors; 54 | } 55 | else { 56 | var valid0 = true; 57 | } 58 | } 59 | } 60 | } 61 | } 62 | else { 63 | validate20.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}]; 64 | return false; 65 | } 66 | } 67 | validate20.errors = vErrors; 68 | return errors === 0; 69 | } 70 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-DisassemblyLine.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-ExpressionsContextData.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-ExpressionsContextData.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = validate20; 3 | module.exports.default = validate20; 4 | const schema22 = {"$schema":"http://json-schema.org/draft-07/schema#","properties":{"CanAssign":{"type":"boolean"},"Class":{"type":"number"},"Expression":{"type":"string"},"HasFuncCall":{"type":"boolean"},"ID":{"type":"string"},"ParentID":{"type":"string"},"Size":{"type":"number"},"SymbolID":{"type":"string"},"Type":{"type":"string"}},"required":["ID"],"type":"object"}; 5 | 6 | function validate20(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){ 7 | let vErrors = null; 8 | let errors = 0; 9 | if(errors === 0){ 10 | if(data && typeof data == "object" && !Array.isArray(data)){ 11 | let missing0; 12 | if((data.ID === undefined) && (missing0 = "ID")){ 13 | validate20.errors = [{instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: missing0},message:"must have required property '"+missing0+"'"}]; 14 | return false; 15 | } 16 | else { 17 | if(data.CanAssign !== undefined){ 18 | const _errs1 = errors; 19 | if(typeof data.CanAssign !== "boolean"){ 20 | validate20.errors = [{instancePath:instancePath+"/CanAssign",schemaPath:"#/properties/CanAssign/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}]; 21 | return false; 22 | } 23 | var valid0 = _errs1 === errors; 24 | } 25 | else { 26 | var valid0 = true; 27 | } 28 | if(valid0){ 29 | if(data.Class !== undefined){ 30 | let data1 = data.Class; 31 | const _errs3 = errors; 32 | if(!((typeof data1 == "number") && (isFinite(data1)))){ 33 | validate20.errors = [{instancePath:instancePath+"/Class",schemaPath:"#/properties/Class/type",keyword:"type",params:{type: "number"},message:"must be number"}]; 34 | return false; 35 | } 36 | var valid0 = _errs3 === errors; 37 | } 38 | else { 39 | var valid0 = true; 40 | } 41 | if(valid0){ 42 | if(data.Expression !== undefined){ 43 | const _errs5 = errors; 44 | if(typeof data.Expression !== "string"){ 45 | validate20.errors = [{instancePath:instancePath+"/Expression",schemaPath:"#/properties/Expression/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 46 | return false; 47 | } 48 | var valid0 = _errs5 === errors; 49 | } 50 | else { 51 | var valid0 = true; 52 | } 53 | if(valid0){ 54 | if(data.HasFuncCall !== undefined){ 55 | const _errs7 = errors; 56 | if(typeof data.HasFuncCall !== "boolean"){ 57 | validate20.errors = [{instancePath:instancePath+"/HasFuncCall",schemaPath:"#/properties/HasFuncCall/type",keyword:"type",params:{type: "boolean"},message:"must be boolean"}]; 58 | return false; 59 | } 60 | var valid0 = _errs7 === errors; 61 | } 62 | else { 63 | var valid0 = true; 64 | } 65 | if(valid0){ 66 | if(data.ID !== undefined){ 67 | const _errs9 = errors; 68 | if(typeof data.ID !== "string"){ 69 | validate20.errors = [{instancePath:instancePath+"/ID",schemaPath:"#/properties/ID/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 70 | return false; 71 | } 72 | var valid0 = _errs9 === errors; 73 | } 74 | else { 75 | var valid0 = true; 76 | } 77 | if(valid0){ 78 | if(data.ParentID !== undefined){ 79 | const _errs11 = errors; 80 | if(typeof data.ParentID !== "string"){ 81 | validate20.errors = [{instancePath:instancePath+"/ParentID",schemaPath:"#/properties/ParentID/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 82 | return false; 83 | } 84 | var valid0 = _errs11 === errors; 85 | } 86 | else { 87 | var valid0 = true; 88 | } 89 | if(valid0){ 90 | if(data.Size !== undefined){ 91 | let data6 = data.Size; 92 | const _errs13 = errors; 93 | if(!((typeof data6 == "number") && (isFinite(data6)))){ 94 | validate20.errors = [{instancePath:instancePath+"/Size",schemaPath:"#/properties/Size/type",keyword:"type",params:{type: "number"},message:"must be number"}]; 95 | return false; 96 | } 97 | var valid0 = _errs13 === errors; 98 | } 99 | else { 100 | var valid0 = true; 101 | } 102 | if(valid0){ 103 | if(data.SymbolID !== undefined){ 104 | const _errs15 = errors; 105 | if(typeof data.SymbolID !== "string"){ 106 | validate20.errors = [{instancePath:instancePath+"/SymbolID",schemaPath:"#/properties/SymbolID/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 107 | return false; 108 | } 109 | var valid0 = _errs15 === errors; 110 | } 111 | else { 112 | var valid0 = true; 113 | } 114 | if(valid0){ 115 | if(data.Type !== undefined){ 116 | const _errs17 = errors; 117 | if(typeof data.Type !== "string"){ 118 | validate20.errors = [{instancePath:instancePath+"/Type",schemaPath:"#/properties/Type/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 119 | return false; 120 | } 121 | var valid0 = _errs17 === errors; 122 | } 123 | else { 124 | var valid0 = true; 125 | } 126 | } 127 | } 128 | } 129 | } 130 | } 131 | } 132 | } 133 | } 134 | } 135 | } 136 | else { 137 | validate20.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}]; 138 | return false; 139 | } 140 | } 141 | validate20.errors = vErrors; 142 | return errors === 0; 143 | } 144 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-InstanceStatusData.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-InstanceStatusData.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = validate20; 3 | module.exports.default = validate20; 4 | const schema22 = {"$schema":"http://json-schema.org/draft-07/schema#","properties":{"Address":{"type":["string","number"]},"BreakpointType":{"type":"string"},"ConditionError":{"type":"string"},"Error":{"type":"string"},"HitCount":{"type":"number"},"LocationContext":{"type":"string"},"MemoryContext":{"type":"string"},"Size":{"type":"number"}},"type":"object"}; 5 | 6 | function validate20(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){ 7 | let vErrors = null; 8 | let errors = 0; 9 | if(errors === 0){ 10 | if(data && typeof data == "object" && !Array.isArray(data)){ 11 | if(data.Address !== undefined){ 12 | let data0 = data.Address; 13 | const _errs1 = errors; 14 | if((typeof data0 !== "string") && (!((typeof data0 == "number") && (isFinite(data0))))){ 15 | validate20.errors = [{instancePath:instancePath+"/Address",schemaPath:"#/properties/Address/type",keyword:"type",params:{type: schema22.properties.Address.type},message:"must be string,number"}]; 16 | return false; 17 | } 18 | var valid0 = _errs1 === errors; 19 | } 20 | else { 21 | var valid0 = true; 22 | } 23 | if(valid0){ 24 | if(data.BreakpointType !== undefined){ 25 | const _errs3 = errors; 26 | if(typeof data.BreakpointType !== "string"){ 27 | validate20.errors = [{instancePath:instancePath+"/BreakpointType",schemaPath:"#/properties/BreakpointType/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 28 | return false; 29 | } 30 | var valid0 = _errs3 === errors; 31 | } 32 | else { 33 | var valid0 = true; 34 | } 35 | if(valid0){ 36 | if(data.ConditionError !== undefined){ 37 | const _errs5 = errors; 38 | if(typeof data.ConditionError !== "string"){ 39 | validate20.errors = [{instancePath:instancePath+"/ConditionError",schemaPath:"#/properties/ConditionError/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 40 | return false; 41 | } 42 | var valid0 = _errs5 === errors; 43 | } 44 | else { 45 | var valid0 = true; 46 | } 47 | if(valid0){ 48 | if(data.Error !== undefined){ 49 | const _errs7 = errors; 50 | if(typeof data.Error !== "string"){ 51 | validate20.errors = [{instancePath:instancePath+"/Error",schemaPath:"#/properties/Error/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 52 | return false; 53 | } 54 | var valid0 = _errs7 === errors; 55 | } 56 | else { 57 | var valid0 = true; 58 | } 59 | if(valid0){ 60 | if(data.HitCount !== undefined){ 61 | let data4 = data.HitCount; 62 | const _errs9 = errors; 63 | if(!((typeof data4 == "number") && (isFinite(data4)))){ 64 | validate20.errors = [{instancePath:instancePath+"/HitCount",schemaPath:"#/properties/HitCount/type",keyword:"type",params:{type: "number"},message:"must be number"}]; 65 | return false; 66 | } 67 | var valid0 = _errs9 === errors; 68 | } 69 | else { 70 | var valid0 = true; 71 | } 72 | if(valid0){ 73 | if(data.LocationContext !== undefined){ 74 | const _errs11 = errors; 75 | if(typeof data.LocationContext !== "string"){ 76 | validate20.errors = [{instancePath:instancePath+"/LocationContext",schemaPath:"#/properties/LocationContext/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 77 | return false; 78 | } 79 | var valid0 = _errs11 === errors; 80 | } 81 | else { 82 | var valid0 = true; 83 | } 84 | if(valid0){ 85 | if(data.MemoryContext !== undefined){ 86 | const _errs13 = errors; 87 | if(typeof data.MemoryContext !== "string"){ 88 | validate20.errors = [{instancePath:instancePath+"/MemoryContext",schemaPath:"#/properties/MemoryContext/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 89 | return false; 90 | } 91 | var valid0 = _errs13 === errors; 92 | } 93 | else { 94 | var valid0 = true; 95 | } 96 | if(valid0){ 97 | if(data.Size !== undefined){ 98 | let data7 = data.Size; 99 | const _errs15 = errors; 100 | if(!((typeof data7 == "number") && (isFinite(data7)))){ 101 | validate20.errors = [{instancePath:instancePath+"/Size",schemaPath:"#/properties/Size/type",keyword:"type",params:{type: "number"},message:"must be number"}]; 102 | return false; 103 | } 104 | var valid0 = _errs15 === errors; 105 | } 106 | else { 107 | var valid0 = true; 108 | } 109 | } 110 | } 111 | } 112 | } 113 | } 114 | } 115 | } 116 | } 117 | else { 118 | validate20.errors = [{instancePath,schemaPath:"#/type",keyword:"type",params:{type: "object"},message:"must be object"}]; 119 | return false; 120 | } 121 | } 122 | validate20.errors = vErrors; 123 | return errors === 0; 124 | } 125 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-MemoryResult.d.ts: -------------------------------------------------------------------------------- 1 | export = validate20; 2 | declare function validate20(data: any, { instancePath, parentData, parentDataProperty, rootData }?: { 3 | instancePath?: string; 4 | parentData: any; 5 | parentDataProperty: any; 6 | rootData?: any; 7 | }): boolean; 8 | declare namespace validate20 { 9 | export { validate20 as default }; 10 | } 11 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/tcf/validators/validate-MemoryResult.js: -------------------------------------------------------------------------------- 1 | "use strict"; 2 | module.exports = validate20; 3 | module.exports.default = validate20; 4 | const schema22 = {"$schema":"http://json-schema.org/draft-07/schema#","definitions":{"MemoryErrorAddress":{"properties":{"addr":{"type":"number"},"msg":{},"size":{"type":"number"},"stat":{"type":"number"}},"required":["addr","msg","size","stat"],"type":"object"}},"properties":{"base64":{"type":"string"},"errorAddresses":{"anyOf":[{"items":{"$ref":"#/definitions/MemoryErrorAddress"},"type":"array"},{"type":"null"}]}},"required":["base64","errorAddresses"],"type":"object"}; 5 | const schema23 = {"properties":{"addr":{"type":"number"},"msg":{},"size":{"type":"number"},"stat":{"type":"number"}},"required":["addr","msg","size","stat"],"type":"object"}; 6 | 7 | function validate20(data, {instancePath="", parentData, parentDataProperty, rootData=data}={}){ 8 | let vErrors = null; 9 | let errors = 0; 10 | if(errors === 0){ 11 | if(data && typeof data == "object" && !Array.isArray(data)){ 12 | let missing0; 13 | if(((data.base64 === undefined) && (missing0 = "base64")) || ((data.errorAddresses === undefined) && (missing0 = "errorAddresses"))){ 14 | validate20.errors = [{instancePath,schemaPath:"#/required",keyword:"required",params:{missingProperty: missing0},message:"must have required property '"+missing0+"'"}]; 15 | return false; 16 | } 17 | else { 18 | if(data.base64 !== undefined){ 19 | const _errs1 = errors; 20 | if(typeof data.base64 !== "string"){ 21 | validate20.errors = [{instancePath:instancePath+"/base64",schemaPath:"#/properties/base64/type",keyword:"type",params:{type: "string"},message:"must be string"}]; 22 | return false; 23 | } 24 | var valid0 = _errs1 === errors; 25 | } 26 | else { 27 | var valid0 = true; 28 | } 29 | if(valid0){ 30 | if(data.errorAddresses !== undefined){ 31 | let data1 = data.errorAddresses; 32 | const _errs3 = errors; 33 | const _errs4 = errors; 34 | let valid1 = false; 35 | const _errs5 = errors; 36 | if(errors === _errs5){ 37 | if(Array.isArray(data1)){ 38 | var valid2 = true; 39 | const len0 = data1.length; 40 | for(let i0=0; i0 { 19 | if (this.children === undefined) { 20 | await this.loadChildren(); 21 | } 22 | return this.children ?? []; 23 | } 24 | 25 | async loadChildren() { 26 | if (!this.type.BaseTypeID) { 27 | return; //no known element type? 28 | } 29 | const baseTypeDetails = await this.helper.sendCommand(new GetContextSymbolsCommand(this.type.BaseTypeID)); 30 | 31 | const symbolDetails = this.type; //TODO: Or do we need symbolDetails? 32 | const size = symbolDetails.Size; 33 | const length = symbolDetails.Length; //TODO: This has to be done lazily otherwise large arrays will take all the RAM 34 | if (!size || !length) { 35 | return; //TODO: log? 36 | } 37 | const elementSize = size / length; 38 | 39 | let children = []; 40 | for (let i = 0; i < length; i++) { 41 | const self = this; 42 | const valueProvider = new class implements RawValueProvider { 43 | async value(): Promise { 44 | const value = await self.valueProvider.value(); 45 | const elementBytes = value?.subarray(i * elementSize, (i + 1) * elementSize); 46 | return elementBytes; 47 | } 48 | isBigEndian(): boolean { 49 | return self.valueProvider.isBigEndian(); 50 | } 51 | }(); 52 | 53 | const nameProvider = new class implements NameProvider { 54 | name() { 55 | return `[${i}]`; 56 | } 57 | }(); 58 | 59 | const v = this.helper.createVariable(baseTypeDetails, undefined, nameProvider, valueProvider); //TODO: do array elements even have symbols? 60 | 61 | if (v !== undefined) { 62 | children.push(v); 63 | } 64 | } 65 | this.children = children; 66 | } 67 | 68 | async displayValue(): Promise { 69 | 70 | return "[...]"; //TODO: What should an array display for value? First N elements? 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/variables/composite.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { GetChildrenSymbolsCommand, GetContextSymbolsCommand, TCFSymbolContextData } from "../tcf-all"; 6 | import { AbstractVariable, ClientVariable, NameProvider, RawValueProvider, VariableHelper } from "./types"; 7 | 8 | export class CompositeVariable extends AbstractVariable { 9 | private children: ClientVariable[] | undefined = undefined; 10 | helper: VariableHelper; 11 | 12 | _displayValue: string | undefined; 13 | loadedValue: boolean = false; 14 | symbol: TCFSymbolContextData; 15 | 16 | constructor(type: TCFSymbolContextData, symbolDetails: TCFSymbolContextData, helper: VariableHelper, nameProvider: NameProvider, valueProvider: RawValueProvider) { 17 | super(type, symbolDetails, nameProvider, valueProvider); 18 | this.symbol = symbolDetails; 19 | this.helper = helper; 20 | } 21 | 22 | async getChildren(): Promise { 23 | if (this.children === undefined) { 24 | await this.loadChildren(); 25 | } 26 | return this.children ?? []; 27 | } 28 | 29 | async loadChildren() { 30 | //NOTE: In theory we could get the struct fields via GetChildrenExpressionCommand but it doesn't seem to work with any argument... 31 | const structFields = await this.helper.sendCommand(new GetChildrenSymbolsCommand(this.symbol.ID)) || []; //or value.properties.Symbol? 32 | let children = []; 33 | 34 | for (const structField of structFields) { 35 | const fieldContext = await this.helper.sendCommand(new GetContextSymbolsCommand(structField)); 36 | let typeContext: TCFSymbolContextData | undefined = undefined; 37 | 38 | if (fieldContext.TypeID) { 39 | try { 40 | typeContext = await this.helper.sendCommand(new GetContextSymbolsCommand(fieldContext.TypeID)); 41 | } catch (e) { 42 | console.error(`Could not load struct field type: ${e}`); 43 | //XXX: normally we should have a type, but let's allow an undefined and handle it futher down 44 | } 45 | } 46 | 47 | if (!typeContext) { 48 | //TODO: This should not be allowed... but older tests do need it since this was the initial (wrong) behavior 49 | //TODO: Rewrite test (and particularly re-record pcap) for the broken test 50 | console.log("Struct field has no (loadable) type. Reusing parent struct type."); 51 | typeContext = fieldContext; 52 | //continue; 53 | } 54 | 55 | const self = this; 56 | const valueProvider = new class implements RawValueProvider { 57 | async value(): Promise { 58 | if (fieldContext.Offset === undefined || fieldContext.Size === undefined) { 59 | //TODO: also fallback to name being the index? 60 | return undefined; 61 | } 62 | const value = await self.valueProvider.value(); 63 | const elementBytes = value?.subarray(fieldContext.Offset, fieldContext.Offset + fieldContext.Size); 64 | return elementBytes; 65 | } 66 | isBigEndian(): boolean { 67 | return self.valueProvider.isBigEndian(); 68 | } 69 | }(); 70 | 71 | const nameProvider = new class implements NameProvider { 72 | name(): string | undefined { 73 | //TODO: name could be index c.type.Name || `${variableName}[${i}]` 74 | return fieldContext.Name ?? typeContext?.Name ?? undefined; 75 | } 76 | 77 | }(); 78 | 79 | //fieldContext is a symbol data structure, not a type data structure... 80 | const v = this.helper.createVariable(typeContext, fieldContext, nameProvider, valueProvider); 81 | if (v !== undefined && nameProvider.name() !== undefined) { 82 | children.push(v); 83 | } 84 | 85 | console.log(`Field ${JSON.stringify(fieldContext)}`); 86 | } 87 | 88 | this.children = children; 89 | } 90 | 91 | async displayValue(): Promise { 92 | if (!this.loadedValue) { 93 | this.loadedValue = true; 94 | this._displayValue = await this.loadValue(); 95 | } 96 | return this._displayValue; 97 | } 98 | 99 | async loadValue(): Promise { 100 | let structChildren = await this.getChildren(); 101 | 102 | let chunks = []; 103 | //load first 3 fields into struct display value 104 | for (let i = 0; i < Math.min(3, structChildren.length); i++) { 105 | chunks.push(`[${structChildren[i].name()}]`); 106 | chunks.push("="); 107 | 108 | chunks.push(await structChildren[i].displayValue()); //TODO: this could recurse very deeply or even infinitely! 109 | } 110 | return chunks.join(" "); 111 | } 112 | 113 | } 114 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/variables/helper.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { SimpleCommand, TCFSymbolClass, TCFSymbolContextData, TCFTypeClass } from "../tcf-all"; 6 | import { ArrayVariable } from "./array"; 7 | import { CompositeVariable } from "./composite"; 8 | import { PointerVariable } from "./pointer"; 9 | import { PrimitiveVariable } from "./primitive"; 10 | import { RawVariable } from "./raw"; 11 | import { SYM_FLAG_TYPEDEF, SYM_FLAG_TYPE_PARAMETER } from "./symbol"; 12 | import { ClientVariable, NameProvider, RawValueProvider, VariableHelper } from "./types"; 13 | 14 | export interface Logger { 15 | log(message: string): void; 16 | } 17 | 18 | export abstract class DefaultVariableHelper implements VariableHelper, Logger { 19 | abstract sendCommand(c: SimpleCommand): Promise; 20 | 21 | createVariable(typeDetails: TCFSymbolContextData, symbolDetails: TCFSymbolContextData | undefined, nameProvider: NameProvider, valueProvider: RawValueProvider): ClientVariable | undefined { 22 | if (this.shouldFilter(typeDetails, symbolDetails)) { 23 | return undefined; 24 | } 25 | 26 | switch (typeDetails.TypeClass) { 27 | case TCFTypeClass.integer: 28 | case TCFTypeClass.cardinal: 29 | case TCFTypeClass.real: 30 | return new PrimitiveVariable(typeDetails, symbolDetails, nameProvider, valueProvider, this); 31 | case TCFTypeClass.pointer: 32 | return new PointerVariable(typeDetails, symbolDetails, nameProvider, valueProvider, this); 33 | case TCFTypeClass.composite: 34 | if (symbolDetails) { 35 | return new CompositeVariable(typeDetails, symbolDetails, this, nameProvider, valueProvider); 36 | } else { 37 | return undefined; 38 | } 39 | case TCFTypeClass.array: 40 | return new ArrayVariable(typeDetails, this, nameProvider, valueProvider); 41 | case TCFTypeClass.enumeration: 42 | case TCFTypeClass.function: 43 | this.log(`Function/enum variable ${JSON.stringify(typeDetails)} ${JSON.stringify(symbolDetails)}`); 44 | return undefined; 45 | default: 46 | return new RawVariable(typeDetails, symbolDetails, [], nameProvider, valueProvider); 47 | } 48 | } 49 | 50 | private shouldFilter(typeDetails: TCFSymbolContextData, symbolDetails: TCFSymbolContextData | undefined): boolean { 51 | if (symbolDetails) { 52 | switch (symbolDetails.Class) { 53 | case TCFSymbolClass.value: 54 | case TCFSymbolClass.reference: 55 | //what we expect 56 | break; 57 | case TCFSymbolClass.type: 58 | case TCFSymbolClass.block: 59 | case TCFSymbolClass.comp_unit: 60 | case TCFSymbolClass.function: 61 | case TCFSymbolClass.namespace: 62 | //a type symbol isn't a very practical variable to display, so we don't 63 | return true; 64 | default: 65 | break; 66 | } 67 | } 68 | 69 | return false; 70 | } 71 | 72 | abstract log(message: string): void; 73 | } 74 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/variables/pointer.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import assert = require("assert"); 6 | import { GetContextSymbolsCommand, TCFSymbolContextData, TCFTypeClass } from "../tcf-all"; 7 | import { AbstractVariable, ClientVariable, FixedNameProvider, NameProvider, RawValueProvider, UndefinedRawValueProvider, VariableHelper } from "./types"; 8 | 9 | export class PointerVariable extends AbstractVariable { 10 | private children: ClientVariable[] | undefined = undefined; 11 | helper: VariableHelper; 12 | 13 | _displayValue: string | undefined; 14 | loadedValue: boolean = false; 15 | 16 | constructor(type: TCFSymbolContextData, symbolDetails: TCFSymbolContextData | undefined, nameProvider: NameProvider, valueProvider: RawValueProvider, helper: VariableHelper) { 17 | super(type, symbolDetails, nameProvider, valueProvider); 18 | this.helper = helper; 19 | } 20 | 21 | async getChildren() { 22 | if (this.children === undefined) { 23 | await this.loadChildren(); 24 | } 25 | return this.children ?? []; 26 | } 27 | 28 | async loadChildren() { 29 | if (this.type.BaseTypeID) { 30 | //XXX: it looks like we would need to recurse here, eg. we could have a pointer to a pointer to a struct, etc. 31 | const baseTypeDetails = await this.helper.sendCommand(new GetContextSymbolsCommand(this.type.BaseTypeID)); 32 | // How to load the symbol for the pointed data? 33 | // It may not even be a symbol but just a memory region. 34 | // const symbolDetails = await this.helper.sendCommand(new GetContextSymbolsCommand(...) 35 | // or perhaps this.sendCommand(new EvaluateExpressionCommand(varName+"."+this.type.Name)) ? 36 | 37 | baseTypeDetails.Name = baseTypeDetails.Name + "*"; //TODO: marking this as a pointer type. Normally we should return the full list of types upstream and the client decides how to present it in the UI 38 | 39 | const v = this.helper.createVariable(baseTypeDetails, undefined /* no symbol data */, new FixedNameProvider("*"), new UndefinedRawValueProvider()); 40 | if (v !== undefined) { 41 | this.children = [v]; 42 | } else { 43 | this.children = []; //maybe display something generic? Like... "pointer to function" 44 | } 45 | } else { 46 | //TODO: log error? 47 | this.children = []; 48 | } 49 | } 50 | 51 | async displayValue(): Promise { 52 | if (!this.loadedValue) { 53 | this.loadedValue = true; 54 | this._displayValue = await this.loadValue(); 55 | } 56 | return this._displayValue; 57 | } 58 | 59 | async loadValue(): Promise { 60 | const variableRawValue = await this.valueProvider.value(); 61 | if (!variableRawValue) { 62 | return undefined; 63 | } 64 | 65 | assert(this.type.TypeClass === TCFTypeClass.pointer); 66 | const value = '0x' + variableRawValue.toString('hex'); 67 | //TODO: actually read memory and load that type? 68 | //const expr = "*(${" + typeDetails[0].ID + "})" + (variableRawValue.toString('hex')); 69 | //const v = new EvaluateExpressionCommand(expr); 70 | return value; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/variables/primitive.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { TCFSymbolContextData, TCFTypeClass } from "../tcf-all"; 6 | import { Logger } from "./helper"; 7 | import { AbstractVariable, ClientVariable, NameProvider, RawValueProvider } from "./types"; 8 | 9 | export class PrimitiveVariable extends AbstractVariable { 10 | logger: Logger; 11 | 12 | constructor(type: TCFSymbolContextData, symbolDetails: TCFSymbolContextData | undefined, nameProvider: NameProvider, valueProvider: RawValueProvider, log: Logger) { 13 | super(type, symbolDetails, nameProvider, valueProvider); 14 | this.logger = log; 15 | } 16 | 17 | async getChildren(): Promise { 18 | return []; 19 | } 20 | 21 | async displayValue(): Promise { 22 | const variableRawValue = await this.valueProvider.value(); 23 | if (!variableRawValue) { 24 | return undefined; 25 | } 26 | let bigEndian = this.valueProvider.isBigEndian(); 27 | 28 | switch (this.type.TypeClass) { 29 | case TCFTypeClass.integer: // SIGNED integer 30 | switch (variableRawValue.length) { 31 | case 8: //64bit 32 | const variable64Value = bigEndian ? variableRawValue.readBigInt64BE() : variableRawValue.readBigInt64LE(); 33 | 34 | return String(variable64Value); 35 | case 4: //32bit 36 | const variable32Value = bigEndian ? variableRawValue.readInt32BE() : variableRawValue.readInt32LE(); 37 | 38 | return String(variable32Value); 39 | case 2: //16 bit 40 | const variable16Value = bigEndian ? variableRawValue.readInt16BE() : variableRawValue.readInt16LE(); 41 | 42 | return String(variable16Value); 43 | default: 44 | this.logger.log(`Could not parse integer variable value for variable ${this.name()}. Expected 2, 4 or 8 bytes, found ${variableRawValue.length} bytes`); 45 | return undefined; 46 | } 47 | case TCFTypeClass.cardinal: // UNSIGNED integer 48 | switch (variableRawValue.length) { 49 | case 8: //64bit 50 | const variable64Value = bigEndian ? variableRawValue.readBigUInt64BE() : variableRawValue.readBigUInt64LE(); 51 | 52 | return String(variable64Value); 53 | case 4: //32bit 54 | const variable32Value = bigEndian ? variableRawValue.readUInt32BE() : variableRawValue.readUInt32LE(); 55 | 56 | return String(variable32Value); 57 | case 2: //16 bit 58 | const variable16Value = bigEndian ? variableRawValue.readUInt16BE() : variableRawValue.readUInt16LE(); 59 | 60 | return String(variable16Value); 61 | default: 62 | this.logger.log(`Could not parse unsigned integer variable value for variable ${this.name()}. Expected 2, 4 or 8 bytes, found ${variableRawValue.length} bytes`); 63 | return undefined; 64 | } 65 | case TCFTypeClass.real: 66 | switch (variableRawValue.length) { 67 | case 8: //64 bit 68 | const doubleValue = bigEndian ? variableRawValue.readDoubleBE() : variableRawValue.readDoubleLE(); 69 | 70 | return String(doubleValue); 71 | case 4: //32bit 72 | const floatValue = bigEndian ? variableRawValue.readFloatBE() : variableRawValue.readFloatLE(); 73 | 74 | return String(floatValue); 75 | default: 76 | this.logger.log(`Could not parse float/double variable value for variable ${this.name()}. Expected 4 or 8 bytes, found ${variableRawValue.length} bytes`); 77 | return undefined; 78 | } 79 | default: 80 | this.logger.log(`Could not parse unknown primitive variable value for variable ${this.name()}, type class ${this.type.TypeClass}`); 81 | return undefined; 82 | } 83 | 84 | } 85 | } 86 | 87 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/variables/raw.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { TCFSymbolContextData } from "../tcf-all"; 6 | import { AbstractVariable, ClientVariable, NameProvider, RawValueProvider } from "./types"; 7 | 8 | export class RawVariable extends AbstractVariable { 9 | children?: ClientVariable[]; 10 | 11 | constructor(type: TCFSymbolContextData, symbolDetails: TCFSymbolContextData | undefined, children: ClientVariable[], nameProvider: NameProvider, valueProvider: RawValueProvider) { 12 | super(type, symbolDetails, nameProvider, valueProvider); 13 | this.children = children; 14 | } 15 | 16 | async displayValue(): Promise { 17 | return undefined; 18 | } 19 | 20 | async getChildren(): Promise { 21 | return this.children ?? []; 22 | } 23 | 24 | } 25 | 26 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/variables/symbol.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { GetChildrenMemoryCommand, GetMemoryCommand, MemoryResult, TCFSymbolContextData } from "../tcf-all"; 6 | import { Logger } from "./helper"; 7 | import { RawValueProvider, VariableHelper } from "./types"; 8 | 9 | export const SYM_FLAG_BIG_ENDIAN = 0x00001000; 10 | export const SYM_FLAG_ARTIFICIAL = 0x00020000; 11 | export const SYM_FLAG_TYPEDEF = 0x00000002; 12 | export const SYM_FLAG_TYPE_PARAMETER = 0x00040000; 13 | 14 | export class SymbolRawValueProvider implements RawValueProvider { 15 | rawValue: Buffer | undefined = undefined; 16 | loaded = false; 17 | bigEndian: boolean = false; //any default as good? 18 | symbol: TCFSymbolContextData; 19 | helper: VariableHelper; 20 | context: string; 21 | logger: Logger; 22 | 23 | constructor(symbol: TCFSymbolContextData, context: string, helper: VariableHelper, log: Logger) { 24 | this.symbol = symbol; 25 | this.helper = helper; 26 | this.context = context; //TODO: let's hope this context does something. delete if nhot 27 | if (symbol.Flags !== undefined) { 28 | this.bigEndian = (symbol.Flags & SYM_FLAG_BIG_ENDIAN) !== 0; 29 | } 30 | this.logger = log; 31 | } 32 | 33 | //A horrible hack to read the memory by looking into *ALL* the context IDs. 34 | //TODO: find out which is the corresponding memory context ID for a given symbol? there must be some direct way. 35 | private async findMemory(memoryContextID: string | null): Promise { 36 | if (memoryContextID !== null && this.symbol.Address && this.symbol.Size) { 37 | try { 38 | const r: MemoryResult = await this.helper.sendCommand(new GetMemoryCommand(memoryContextID, this.symbol.Address, 1, this.symbol.Size)); 39 | return r; 40 | } catch (e) { 41 | //ignore 42 | } 43 | } 44 | 45 | const children: string[] = await this.helper.sendCommand(new GetChildrenMemoryCommand(memoryContextID)) ?? []; 46 | for (const child of children) { 47 | const r = await this.findMemory(child); 48 | if (r !== undefined) { 49 | return r; 50 | } 51 | } 52 | 53 | return undefined; 54 | } 55 | 56 | private async loadValue() { 57 | if (this.symbol.Value) { 58 | this.rawValue = Buffer.from(Buffer.from(this.symbol.Value).toString(), "base64"); 59 | return; 60 | } 61 | 62 | if (this.symbol.Address && this.symbol.Size) { 63 | try { 64 | const r: MemoryResult = await this.helper.sendCommand(new GetMemoryCommand(this.context, this.symbol.Address, 1, this.symbol.Size)); //TODO: what is the wordsize here? assuming 1 (probably wrongly) 65 | this.rawValue = Buffer.from(Buffer.from(r.base64).toString(), "base64"); 66 | } catch (e) { 67 | this.logger.log(String(e)); 68 | } 69 | } 70 | } 71 | 72 | async value(): Promise { 73 | if (!this.loaded) { 74 | this.loaded = true; 75 | await this.loadValue(); 76 | } 77 | return this.rawValue; 78 | } 79 | 80 | isBigEndian(): boolean { 81 | return this.bigEndian; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /vscode-tcf-debug/src/variables/types.ts: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (C) 2023 Intel Corporation 3 | SPDX-License-Identifier: MIT 4 | */ 5 | import { SimpleCommand, TCFSymbolContextData } from "../tcf-all"; 6 | 7 | export interface NameProvider { 8 | name(): string | undefined; 9 | } 10 | export interface RawValueProvider { 11 | value(): Promise; 12 | isBigEndian(): boolean; 13 | } 14 | 15 | export interface ClientVariable extends RawValueProvider, NameProvider { 16 | type: TCFSymbolContextData, 17 | 18 | getChildren(): Promise; //for array/struct 19 | 20 | displayValue(): Promise; 21 | 22 | isRegister(): boolean; 23 | } 24 | 25 | export interface VariableHelper { 26 | sendCommand(c: SimpleCommand): Promise; 27 | createVariable(type: TCFSymbolContextData, symbolDetails: TCFSymbolContextData | undefined, nameProvider: NameProvider, valueProvider: RawValueProvider): ClientVariable | undefined; 28 | } 29 | 30 | export class SymbolNameProvider implements NameProvider { 31 | _name: string; 32 | constructor(symbolDetails: TCFSymbolContextData) { 33 | this._name = symbolDetails.Name || (symbolDetails.Register || ""); 34 | } 35 | 36 | name() { 37 | return this._name; 38 | } 39 | } 40 | 41 | export class FixedNameProvider implements NameProvider { 42 | _name: string; 43 | 44 | constructor(name: string) { 45 | this._name = name; 46 | } 47 | 48 | name(): string | undefined { 49 | return this._name; 50 | } 51 | } 52 | 53 | export abstract class AbstractVariable implements ClientVariable { 54 | type: TCFSymbolContextData; 55 | valueProvider: RawValueProvider; 56 | nameProvider: NameProvider; 57 | register: boolean = false; 58 | 59 | constructor(type: TCFSymbolContextData, symbolDetails: TCFSymbolContextData | undefined, nameProvider: NameProvider, valueProvider: RawValueProvider) { 60 | this.type = type; 61 | this.valueProvider = valueProvider; 62 | this.nameProvider = nameProvider; 63 | this.register = symbolDetails?.Register !== undefined; 64 | } 65 | 66 | value(): Promise { 67 | return this.valueProvider.value(); 68 | } 69 | 70 | isBigEndian(): boolean { 71 | return this.valueProvider.isBigEndian(); 72 | } 73 | 74 | abstract getChildren(): Promise; 75 | abstract displayValue(): Promise; 76 | isRegister(): boolean { 77 | return this.register; 78 | } 79 | 80 | name() { 81 | return this.nameProvider.name(); 82 | } 83 | } 84 | 85 | export class UndefinedRawValueProvider implements RawValueProvider { 86 | async value(): Promise { 87 | return undefined; 88 | } 89 | isBigEndian(): boolean { 90 | return false; //doesn't matter. 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /vscode-tcf-debug/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "module": "commonjs", 4 | "target": "ES2022", 5 | "outDir": "out", 6 | "lib": [ 7 | "ES2022" 8 | ], 9 | "allowJs": true, // strictly for JSON validators 10 | "sourceMap": true, 11 | "declaration": true, 12 | "rootDir": "src", 13 | "strict": true /* enable all strict type-checking options */ 14 | /* Additional Checks */ 15 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 16 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 17 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 18 | } 19 | } 20 | --------------------------------------------------------------------------------