From bd2a5cc8b5046de654b42a857e8f409c1da68f85 Mon Sep 17 00:00:00 2001
From: dd86k
Date: Mon, 5 Aug 2024 17:40:14 -0400
Subject: [PATCH 1/9] mi2: Follow tsc type recommendations for some parameters
---
src/backend/mi2/mi2.ts | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts
index 706ae03..b2ca3aa 100644
--- a/src/backend/mi2/mi2.ts
+++ b/src/backend/mi2/mi2.ts
@@ -33,7 +33,7 @@ class LogMessage {
protected logReplaceTest = /{([^}]*)}/g;
public logMsgBrkList: Breakpoint[] = [];
- logMsgOutput(record){
+ logMsgOutput(record: { isStream?: boolean; type: any; asyncClass?: string; output?: [string, any][]; content: any; }){
if ((record.type === 'console')) {
if(record.content.startsWith("$")){
const content = record.content;
@@ -54,7 +54,7 @@ class LogMessage {
}
}
- logMsgProcess(parsed){
+ logMsgProcess(parsed: MINode){
this.logMsgBrkList.forEach((brk)=>{
if(parsed.outOfBandRecord[0].output[0][1] == "breakpoint-hit" && parsed.outOfBandRecord[0].output[2][1] == brk.id){
this.logMsgVar = brk?.logMessage;
@@ -626,7 +626,7 @@ export class MI2 extends EventEmitter implements IBackend {
return this.sendCommand("break-condition " + bkptNum + " " + condition);
}
- setLogPoint(bkptNum, command): Thenable {
+ setLogPoint(bkptNum: number, command: string): Thenable {
const regex = /{([a-z0-9A-Z-_\.\>\&\*\[\]]*)}/gm;
let m:RegExpExecArray;
let commands:string = "";
From 91c2249100abbad89b950aca6d7319b2404d8a7b Mon Sep 17 00:00:00 2001
From: dd86k
Date: Mon, 5 Aug 2024 18:08:37 -0400
Subject: [PATCH 2/9] Add Aliceserver as a test
---
package.json | 148 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 148 insertions(+)
diff --git a/package.json b/package.json
index fb20330..04bc5ed 100644
--- a/package.json
+++ b/package.json
@@ -1087,6 +1087,154 @@
}
}
]
+ },
+ {
+ "type": "aliceserver-mi",
+ "program": "./out/src/aliceserver-mi.js",
+ "runtime": "node",
+ "label": "Aliceserver",
+ "languages": [
+ "c",
+ "cpp",
+ "d"
+ ],
+ "configurationAttributes": {
+ "launch": {
+ "required": [
+ "target"
+ ],
+ "properties": {
+ "target": {
+ "type": "string",
+ "description": "Path of executable"
+ },
+ "arguments": {
+ "type": "string",
+ "description": "Arguments to append after the executable"
+ },
+ "cwd": {
+ "type": "string",
+ "description": "project path"
+ },
+ "aliceserverpath": {
+ "type": "string",
+ "description": "Path to the aliceserver executable or the command if in PATH",
+ "default": "aliceserver"
+ },
+ "env": {
+ "type": "object",
+ "description": "Environment overriding the aliceserver (and in turn also the process) environment",
+ "default": null
+ },
+ "debugger_args": {
+ "type": "array",
+ "description": "Additional arguments to pass to aliceserver",
+ "default": [ "-a", "mi" ]
+ }
+ }
+ },
+ "attach": {
+ "required": [
+ "target"
+ ],
+ "properties": {
+ "target": {
+ "type": "string",
+ "description": "PID of running program or program name"
+ },
+ "valuesFormatting": {
+ "type": "string",
+ "description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any",
+ "default": "parseText",
+ "enum": [
+ "disabled",
+ "parseText",
+ "prettyPrinters"
+ ]
+ },
+ "printCalls": {
+ "type": "boolean",
+ "description": "Prints all mago calls to the console",
+ "default": false
+ },
+ "showDevDebugOutput": {
+ "type": "boolean",
+ "description": "Prints all mago responses to the console",
+ "default": false
+ },
+ "executable": {
+ "type": "string",
+ "description": "Path of executable for debugging symbols"
+ },
+ "magomipath": {
+ "type": "string",
+ "description": "Path to the mago-mi executable or the command if in PATH",
+ "default": "mago-mi"
+ },
+ "env": {
+ "type": "object",
+ "description": "Environment overriding the mago-mi (and in turn also the process) environment",
+ "default": null
+ },
+ "debugger_args": {
+ "type": "array",
+ "description": "Additional arguments to pass to mago",
+ "default": []
+ },
+ "cwd": {
+ "type": "string",
+ "description": "project path",
+ "default": "${workspaceRoot}"
+ },
+ "autorun": {
+ "type": "array",
+ "description": "mago commands to run when starting to debug",
+ "default": []
+ },
+ "stopAtConnect": {
+ "type": "boolean",
+ "description": "Whether debugger should stop after connecting to target",
+ "default": false
+ }
+ }
+ }
+ },
+ "initialConfigurations": [
+ {
+ "name": "Debug",
+ "type": "mago-mi",
+ "request": "launch",
+ "target": "./bin/executable",
+ "cwd": "${workspaceRoot}",
+ "valuesFormatting": "parseText"
+ }
+ ],
+ "configurationSnippets": [
+ {
+ "label": "Aliceserver: Launch Program",
+ "description": "Starts the program using aliceserver",
+ "body": {
+ "type": "aliceserver",
+ "request": "launch",
+ "name": "${2:Launch Program}",
+ "target": "${1:./executable}",
+ "cwd": "^\"\\${workspaceRoot}\"",
+ "valuesFormatting": "parseText"
+ }
+ },
+ {
+ "label": "Aliceserver: Attach to PID",
+ "description": "Attaches to a running program pid using aliceserver",
+ "body": {
+ "type": "aliceserver",
+ "request": "attach",
+ "name": "${2:Attach to PID}",
+ "target": "${1:[PID]}",
+ "cwd": "^\"\\${workspaceRoot}\"",
+ "valuesFormatting": "parseText"
+ }
+ }
+ ]
}
]
},
From bc62abe201c130e7b024b94bb2d736dd10d4c2e4 Mon Sep 17 00:00:00 2001
From: dd86k
Date: Tue, 6 Aug 2024 23:53:35 -0400
Subject: [PATCH 3/9] Update Initial configuration
---
package.json | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/package.json b/package.json
index 04bc5ed..7b791c4 100644
--- a/package.json
+++ b/package.json
@@ -1202,11 +1202,10 @@
"initialConfigurations": [
{
"name": "Debug",
- "type": "mago-mi",
+ "type": "aliceserver-mi",
"request": "launch",
"target": "./bin/executable",
- "cwd": "${workspaceRoot}",
- "valuesFormatting": "parseText"
+ "cwd": "${workspaceRoot}"
}
],
"configurationSnippets": [
From 6fa64205906409a5e3b64e673a00320848cbb86b Mon Sep 17 00:00:00 2001
From: dd86k
Date: Thu, 8 Aug 2024 12:21:08 -0400
Subject: [PATCH 4/9] Add code to support Aliceserver
---
package.json | 4 +-
src/aliceserver.ts | 130 ++++++++++++++++++++++++++++++
src/backend/mi2/mi2aliceserver.ts | 75 +++++++++++++++++
3 files changed, 207 insertions(+), 2 deletions(-)
create mode 100644 src/aliceserver.ts
create mode 100644 src/backend/mi2/mi2aliceserver.ts
diff --git a/package.json b/package.json
index 7b791c4..fd59a6a 100644
--- a/package.json
+++ b/package.json
@@ -1090,7 +1090,7 @@
},
{
"type": "aliceserver-mi",
- "program": "./out/src/aliceserver-mi.js",
+ "program": "./out/src/aliceserver.js",
"runtime": "node",
"label": "Aliceserver",
"languages": [
@@ -1129,7 +1129,7 @@
"debugger_args": {
"type": "array",
"description": "Additional arguments to pass to aliceserver",
- "default": [ "-a", "mi" ]
+ "default": []
}
}
},
diff --git a/src/aliceserver.ts b/src/aliceserver.ts
new file mode 100644
index 0000000..9fa325c
--- /dev/null
+++ b/src/aliceserver.ts
@@ -0,0 +1,130 @@
+import { MI2DebugSession, RunCommand } from './mibase';
+import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter';
+import { DebugProtocol } from 'vscode-debugprotocol';
+import { MI2_ALICE } from "./backend/mi2/mi2aliceserver";
+import { SSHArguments, ValuesFormattingMode } from './backend/backend';
+
+export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
+ cwd: string;
+ target: string;
+ aliceserverpath: string;
+ env: any;
+ debugger_args: string[];
+ pathSubstitutions: { [index: string]: string };
+ arguments: string;
+ autorun: string[];
+ stopAtEntry: boolean | string;
+ ssh: SSHArguments;
+ valuesFormatting: ValuesFormattingMode;
+ printCalls: boolean;
+ showDevDebugOutput: boolean;
+}
+
+export interface AttachRequestArguments extends DebugProtocol.AttachRequestArguments {
+ cwd: string;
+ target: string;
+ aliceserverpath: string;
+ env: any;
+ debugger_args: string[];
+ pathSubstitutions: { [index: string]: string };
+ executable: string;
+ autorun: string[];
+ stopAtConnect: boolean;
+ stopAtEntry: boolean | string;
+ valuesFormatting: ValuesFormattingMode;
+ printCalls: boolean;
+ showDevDebugOutput: boolean;
+}
+
+class AliceserverDebugSession extends MI2DebugSession {
+ protected override initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
+ response.body.supportsGotoTargetsRequest = true;
+ response.body.supportsHitConditionalBreakpoints = true;
+ response.body.supportsConfigurationDoneRequest = true;
+ response.body.supportsConditionalBreakpoints = true;
+ response.body.supportsFunctionBreakpoints = true;
+ response.body.supportsEvaluateForHovers = true;
+ this.sendResponse(response);
+ }
+
+ protected override launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
+ const dbgCommand = args.aliceserverpath || "lldb-mi";
+ if (this.checkCommand(dbgCommand)) {
+ this.sendErrorResponse(response, 104, `Configured debugger ${dbgCommand} not found.`);
+ return;
+ }
+ this.miDebugger = new MI2_ALICE(dbgCommand, [], args.debugger_args, args.env);
+ this.setPathSubstitutions(args.pathSubstitutions);
+ this.initDebugger();
+ this.quit = false;
+ this.attached = false;
+ this.initialRunCommand = RunCommand.RUN;
+ this.isSSH = false;
+ this.started = false;
+ this.crashed = false;
+ this.setValuesFormattingMode(args.valuesFormatting);
+ this.miDebugger.printCalls = !!args.printCalls;
+ this.miDebugger.debugOutput = !!args.showDevDebugOutput;
+ this.stopAtEntry = args.stopAtEntry;
+ if (args.ssh !== undefined) {
+ if (args.ssh.forwardX11 === undefined)
+ args.ssh.forwardX11 = true;
+ if (args.ssh.port === undefined)
+ args.ssh.port = 22;
+ if (args.ssh.x11port === undefined)
+ args.ssh.x11port = 6000;
+ if (args.ssh.x11host === undefined)
+ args.ssh.x11host = "localhost";
+ if (args.ssh.remotex11screen === undefined)
+ args.ssh.remotex11screen = 0;
+ this.isSSH = true;
+ this.setSourceFileMap(args.ssh.sourceFileMap, args.ssh.cwd, args.cwd);
+ this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments, undefined, false, args.autorun || []).then(() => {
+ this.sendResponse(response);
+ }, err => {
+ this.sendErrorResponse(response, 106, `Failed to SSH: ${err.toString()}`);
+ });
+ } else {
+ this.miDebugger.load(args.cwd, args.target, args.arguments, undefined, args.autorun || []).then(() => {
+ this.sendResponse(response);
+ }, err => {
+ this.sendErrorResponse(response, 107, `Failed to load MI Debugger: ${err.toString()}`);
+ });
+ }
+ }
+
+ protected override attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void {
+ const dbgCommand = args.aliceserverpath || "lldb-mi";
+ if (this.checkCommand(dbgCommand)) {
+ this.sendErrorResponse(response, 104, `Configured debugger ${dbgCommand} not found.`);
+ return;
+ }
+ this.miDebugger = new MI2_ALICE(dbgCommand, [], args.debugger_args, args.env);
+ this.setPathSubstitutions(args.pathSubstitutions);
+ this.initDebugger();
+ this.quit = false;
+ this.attached = true;
+ this.initialRunCommand = args.stopAtConnect ? RunCommand.NONE : RunCommand.CONTINUE;
+ this.isSSH = false;
+ this.setValuesFormattingMode(args.valuesFormatting);
+ this.miDebugger.printCalls = !!args.printCalls;
+ this.miDebugger.debugOutput = !!args.showDevDebugOutput;
+ this.stopAtEntry = args.stopAtEntry;
+ this.miDebugger.attach(args.cwd, args.executable, args.target, args.autorun || []).then(() => {
+ this.sendResponse(response);
+ }, err => {
+ this.sendErrorResponse(response, 108, `Failed to attach: ${err.toString()}`);
+ });
+ }
+
+ // Add extra commands for source file path substitution in LLDB-specific syntax
+ protected setPathSubstitutions(substitutions: { [index: string]: string }): void {
+ if (substitutions) {
+ Object.keys(substitutions).forEach(source => {
+ this.miDebugger.extraCommands.push("settings append target.source-map " + source + " " + substitutions[source]);
+ });
+ }
+ }
+}
+
+DebugSession.run(AliceserverDebugSession);
diff --git a/src/backend/mi2/mi2aliceserver.ts b/src/backend/mi2/mi2aliceserver.ts
new file mode 100644
index 0000000..edebac9
--- /dev/null
+++ b/src/backend/mi2/mi2aliceserver.ts
@@ -0,0 +1,75 @@
+import { MI2, escape } from "./mi2";
+import { Breakpoint } from "../backend";
+import * as ChildProcess from "child_process";
+import * as path from "path";
+import { MINode } from "../mi_parse";
+
+export class MI2_ALICE extends MI2 {
+ protected override initCommands(target: string, cwd: string, attach: boolean = false) {
+ // We need to account for the possibility of the path type used by the debugger being different
+ // than the path type where the extension is running (e.g., SSH from Linux to Windows machine).
+ // Since the CWD is expected to be an absolute path in the debugger's environment, we can test
+ // that to determine the path type used by the debugger and use the result of that test to
+ // select the correct API to check whether the target path is an absolute path.
+ const debuggerPath = path.posix.isAbsolute(cwd) ? path.posix : path.win32;
+
+ if (!debuggerPath.isAbsolute(target))
+ target = debuggerPath.join(cwd, target);
+
+ const cmds = [
+ // Aliceserver is already async by default
+ //this.sendCommand("gdb-set target-async on"),
+ new Promise(resolve => {
+ this.sendCommand("list-features").then(done => {
+ this.features = done.result("features");
+ resolve(undefined);
+ }, err => {
+ this.features = [];
+ resolve(undefined);
+ });
+ }) as Thenable
+ ];
+ if (!attach)
+ cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\""));
+ for (const cmd of this.extraCommands) {
+ cmds.push(this.sendCliCommand(cmd));
+ }
+ return cmds;
+ }
+
+ override attach(cwd: string, executable: string, target: string, autorun: string[]): Thenable {
+ return new Promise((resolve, reject) => {
+ const args = this.preargs.concat(this.extraargs || []);
+ this.process = ChildProcess.spawn(this.application, args, { cwd: cwd, env: this.procEnv });
+ this.process.stdout.on("data", this.stdout.bind(this));
+ this.process.stderr.on("data", this.stderr.bind(this));
+ this.process.on("exit", () => this.emit("quit"));
+ this.process.on("error", err => this.emit("launcherror", err));
+ const promises = this.initCommands(target, cwd, true);
+ promises.push(this.sendCommand("file-exec-and-symbols \"" + escape(executable) + "\""));
+ promises.push(this.sendCommand("attach " + target));
+ promises.push(...autorun.map(value => { return this.sendUserInput(value); }));
+ Promise.all(promises).then(() => {
+ this.emit("debug-ready");
+ resolve(undefined);
+ }, reject);
+ });
+ }
+
+ override setBreakPointCondition(bkptNum: number, condition: string): Thenable {
+ return this.sendCommand("break-condition " + bkptNum + " \"" + escape(condition) + "\" 1");
+ }
+
+ override goto(filename: string, line: number): Thenable {
+ return new Promise((resolve, reject) => {
+ // LLDB parses the file differently than GDB...
+ // GDB doesn't allow quoting only the file but only the whole argument
+ // LLDB doesn't allow quoting the whole argument but rather only the file
+ const target: string = (filename ? '"' + escape(filename) + '":' : "") + line;
+ this.sendCliCommand("jump " + target).then(() => {
+ this.emit("step-other", undefined);
+ resolve(true);
+ }, reject);
+ });
+ }
+}
From 92e983a656ce05d6411fea0960bb74abaefc8dc6 Mon Sep 17 00:00:00 2001
From: dd86k
Date: Mon, 26 Aug 2024 09:44:43 -0400
Subject: [PATCH 5/9] package: Add printCalls and showDevDebugOutput for
aliceserver
---
package.json | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/package.json b/package.json
index fd59a6a..7408e81 100644
--- a/package.json
+++ b/package.json
@@ -1130,6 +1130,16 @@
"type": "array",
"description": "Additional arguments to pass to aliceserver",
"default": []
+ },
+ "printCalls": {
+ "type": "boolean",
+ "description": "Prints all aliceserver calls to the console",
+ "default": false
+ },
+ "showDevDebugOutput": {
+ "type": "boolean",
+ "description": "Prints all aliceserver responses to the console",
+ "default": false
}
}
},
From baa76e836555b8cab796809e6a3419848b262897 Mon Sep 17 00:00:00 2001
From: dd86k
Date: Mon, 26 Aug 2024 09:44:53 -0400
Subject: [PATCH 6/9] Misc. progress
---
src/aliceserver.ts | 22 ++++++++++++++--------
src/backend/mi2/mi2aliceserver.ts | 3 ++-
2 files changed, 16 insertions(+), 9 deletions(-)
diff --git a/src/aliceserver.ts b/src/aliceserver.ts
index 9fa325c..1c4232a 100644
--- a/src/aliceserver.ts
+++ b/src/aliceserver.ts
@@ -48,13 +48,18 @@ class AliceserverDebugSession extends MI2DebugSession {
}
protected override launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
- const dbgCommand = args.aliceserverpath || "lldb-mi";
- if (this.checkCommand(dbgCommand)) {
+ const dbgCommand = args.aliceserverpath || "aliceserver";
+ // NOTE: checkCommand
+ // On non-Win32 platforms, this uses `command -v`, which only confirms if
+ // commands, including full paths, are within PATH.
+ // This fix bypasses this check.
+ // Temporary fix.
+ if (args.aliceserverpath === undefined && this.checkCommand(dbgCommand)) {
this.sendErrorResponse(response, 104, `Configured debugger ${dbgCommand} not found.`);
return;
}
- this.miDebugger = new MI2_ALICE(dbgCommand, [], args.debugger_args, args.env);
- this.setPathSubstitutions(args.pathSubstitutions);
+ this.miDebugger = new MI2_ALICE(dbgCommand, ["-a", "mi"], args.debugger_args, args.env);
+ //this.setPathSubstitutions(args.pathSubstitutions);
this.initDebugger();
this.quit = false;
this.attached = false;
@@ -62,7 +67,7 @@ class AliceserverDebugSession extends MI2DebugSession {
this.isSSH = false;
this.started = false;
this.crashed = false;
- this.setValuesFormattingMode(args.valuesFormatting);
+ //this.setValuesFormattingMode(args.valuesFormatting);
this.miDebugger.printCalls = !!args.printCalls;
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
this.stopAtEntry = args.stopAtEntry;
@@ -94,12 +99,13 @@ class AliceserverDebugSession extends MI2DebugSession {
}
protected override attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void {
- const dbgCommand = args.aliceserverpath || "lldb-mi";
- if (this.checkCommand(dbgCommand)) {
+ const dbgCommand = args.aliceserverpath || "aliceserver";
+ // See NOTE in launchRequest
+ if (args.aliceserverpath === undefined && this.checkCommand(dbgCommand)) {
this.sendErrorResponse(response, 104, `Configured debugger ${dbgCommand} not found.`);
return;
}
- this.miDebugger = new MI2_ALICE(dbgCommand, [], args.debugger_args, args.env);
+ this.miDebugger = new MI2_ALICE(dbgCommand, ["-a", "mi"], args.debugger_args, args.env);
this.setPathSubstitutions(args.pathSubstitutions);
this.initDebugger();
this.quit = false;
diff --git a/src/backend/mi2/mi2aliceserver.ts b/src/backend/mi2/mi2aliceserver.ts
index edebac9..2857f93 100644
--- a/src/backend/mi2/mi2aliceserver.ts
+++ b/src/backend/mi2/mi2aliceserver.ts
@@ -27,7 +27,8 @@ export class MI2_ALICE extends MI2 {
this.features = [];
resolve(undefined);
});
- }) as Thenable
+ }) as Thenable,
+ //this.sendCommand("environment-directory \"" + escape(cwd) + "\"", true)
];
if (!attach)
cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\""));
From f9e183f319a3051af8355a52ef53f118599d4c56 Mon Sep 17 00:00:00 2001
From: dd86k
Date: Wed, 28 Aug 2024 12:06:11 -0400
Subject: [PATCH 7/9] package: forgot to set proper descriptions
---
package.json | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/package.json b/package.json
index cd8694a..a77a8cd 100644
--- a/package.json
+++ b/package.json
@@ -1133,12 +1133,12 @@
},
"env": {
"type": "object",
- "description": "Environment overriding the aliceserver (and in turn also the process) environment",
+ "description": "Environment overriding the aliceserver environment variables",
"default": null
},
"debugger_args": {
"type": "array",
- "description": "Additional arguments to pass to aliceserver",
+ "description": "Additional arguments to pass to aliceserver specifically",
"default": []
},
"printCalls": {
@@ -1174,26 +1174,26 @@
},
"printCalls": {
"type": "boolean",
- "description": "Prints all mago calls to the console",
+ "description": "Prints all aliceserver calls to the console",
"default": false
},
"showDevDebugOutput": {
"type": "boolean",
- "description": "Prints all mago responses to the console",
+ "description": "Prints all aliceserver responses to the console",
"default": false
},
"executable": {
"type": "string",
"description": "Path of executable for debugging symbols"
},
- "magomipath": {
+ "aliceserverpath": {
"type": "string",
- "description": "Path to the mago-mi executable or the command if in PATH",
- "default": "mago-mi"
+ "description": "Path to the aliceserver executable or the command if in PATH",
+ "default": "aliceservere"
},
"env": {
"type": "object",
- "description": "Environment overriding the mago-mi (and in turn also the process) environment",
+ "description": "Environment overriding the aliceserver environment variables",
"default": null
},
"debugger_args": {
@@ -1208,7 +1208,7 @@
},
"autorun": {
"type": "array",
- "description": "mago commands to run when starting to debug",
+ "description": "aliceserver commands to run when starting to debug",
"default": []
},
"stopAtConnect": {
From e2e2a00cf51df2f5658f27cb88db7b8c78d99507 Mon Sep 17 00:00:00 2001
From: dd86k
Date: Wed, 28 Aug 2024 16:01:06 -0400
Subject: [PATCH 8/9] Progress on launching requests
---
package.json | 4 +-
src/aliceserver.ts | 106 ++++++++++++++++--------------
src/backend/mi2/mi2aliceserver.ts | 32 +++++++--
3 files changed, 85 insertions(+), 57 deletions(-)
diff --git a/package.json b/package.json
index a77a8cd..8da0ba4 100644
--- a/package.json
+++ b/package.json
@@ -1126,7 +1126,7 @@
"type": "string",
"description": "project path"
},
- "aliceserverpath": {
+ "aliceserver_path": {
"type": "string",
"description": "Path to the aliceserver executable or the command if in PATH",
"default": "aliceserver"
@@ -1138,7 +1138,7 @@
},
"debugger_args": {
"type": "array",
- "description": "Additional arguments to pass to aliceserver specifically",
+ "description": "Additional arguments to pass to specifically to aliceserver",
"default": []
},
"printCalls": {
diff --git a/src/aliceserver.ts b/src/aliceserver.ts
index 1c4232a..4def9c6 100644
--- a/src/aliceserver.ts
+++ b/src/aliceserver.ts
@@ -1,17 +1,22 @@
+// Manages a debugging session using Aliceserver.
+//
+// This imports and uses the MI2_ALICE class to manage its session using
+// supported commands.
+
import { MI2DebugSession, RunCommand } from './mibase';
import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter';
import { DebugProtocol } from 'vscode-debugprotocol';
import { MI2_ALICE } from "./backend/mi2/mi2aliceserver";
import { SSHArguments, ValuesFormattingMode } from './backend/backend';
+import { execSync } from 'child_process'; // Temporary import
export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
cwd: string;
target: string;
- aliceserverpath: string;
+ target_arguments: string;
+ aliceserver_path: string;
env: any;
debugger_args: string[];
- pathSubstitutions: { [index: string]: string };
- arguments: string;
autorun: string[];
stopAtEntry: boolean | string;
ssh: SSHArguments;
@@ -23,74 +28,80 @@ export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArgum
export interface AttachRequestArguments extends DebugProtocol.AttachRequestArguments {
cwd: string;
target: string;
- aliceserverpath: string;
+ aliceserver_path: string;
env: any;
debugger_args: string[];
- pathSubstitutions: { [index: string]: string };
executable: string;
autorun: string[];
stopAtConnect: boolean;
stopAtEntry: boolean | string;
- valuesFormatting: ValuesFormattingMode;
printCalls: boolean;
showDevDebugOutput: boolean;
}
class AliceserverDebugSession extends MI2DebugSession {
protected override initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
- response.body.supportsGotoTargetsRequest = true;
- response.body.supportsHitConditionalBreakpoints = true;
- response.body.supportsConfigurationDoneRequest = true;
- response.body.supportsConditionalBreakpoints = true;
- response.body.supportsFunctionBreakpoints = true;
- response.body.supportsEvaluateForHovers = true;
+ response.body.supportsGotoTargetsRequest = false;
+ response.body.supportsHitConditionalBreakpoints = false;
+ response.body.supportsConfigurationDoneRequest = false;
+ response.body.supportsConditionalBreakpoints = false;
+ response.body.supportsFunctionBreakpoints = false;
+ response.body.supportsEvaluateForHovers = false;
this.sendResponse(response);
}
+ // NOTE: Temporary fix that allows absolute executable paths outside of PATH
+ // Until Aliceserver is fully implemented.
+ // This fix bypasses the PATH check (performed by Windows' WHERE and
+ // POSIX's command(1)) by directly invoking the compiler.
+ protected checkCommand(debuggerName: string): boolean {
+ try {
+ execSync(`${debuggerName} --version`, { stdio: 'ignore' });
+ return true;
+ } catch (error) {
+ return false;
+ }
+ }
+
protected override launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
- const dbgCommand = args.aliceserverpath || "aliceserver";
- // NOTE: checkCommand
- // On non-Win32 platforms, this uses `command -v`, which only confirms if
- // commands, including full paths, are within PATH.
- // This fix bypasses this check.
- // Temporary fix.
- if (args.aliceserverpath === undefined && this.checkCommand(dbgCommand)) {
+ const dbgCommand = args.aliceserver_path || "aliceserver";
+ if (args.aliceserver_path === undefined && this.checkCommand(dbgCommand)) {
this.sendErrorResponse(response, 104, `Configured debugger ${dbgCommand} not found.`);
return;
}
- this.miDebugger = new MI2_ALICE(dbgCommand, ["-a", "mi"], args.debugger_args, args.env);
- //this.setPathSubstitutions(args.pathSubstitutions);
+
+ this.miDebugger = new MI2_ALICE(dbgCommand, [ "-a", "mi" ], args.debugger_args, args.env);
this.initDebugger();
+
+ // Defaults
this.quit = false;
this.attached = false;
this.initialRunCommand = RunCommand.RUN;
this.isSSH = false;
this.started = false;
this.crashed = false;
- //this.setValuesFormattingMode(args.valuesFormatting);
this.miDebugger.printCalls = !!args.printCalls;
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
this.stopAtEntry = args.stopAtEntry;
- if (args.ssh !== undefined) {
- if (args.ssh.forwardX11 === undefined)
- args.ssh.forwardX11 = true;
- if (args.ssh.port === undefined)
- args.ssh.port = 22;
- if (args.ssh.x11port === undefined)
- args.ssh.x11port = 6000;
- if (args.ssh.x11host === undefined)
- args.ssh.x11host = "localhost";
- if (args.ssh.remotex11screen === undefined)
- args.ssh.remotex11screen = 0;
- this.isSSH = true;
+
+ // Initiate session
+ this.isSSH = args.ssh !== undefined;
+ if (this.isSSH) {
+ // Set defaults if these are unset
+ args.ssh.forwardX11 ??= true;
+ args.ssh.port ??= 22;
+ args.ssh.x11port ??= 6000;
+ args.ssh.x11host ??= "localhost";
+ args.ssh.remotex11screen ??= 0;
+
this.setSourceFileMap(args.ssh.sourceFileMap, args.ssh.cwd, args.cwd);
- this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments, undefined, false, args.autorun || []).then(() => {
+ this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.target_arguments, undefined, false, args.autorun || []).then(() => {
this.sendResponse(response);
}, err => {
this.sendErrorResponse(response, 106, `Failed to SSH: ${err.toString()}`);
});
- } else {
- this.miDebugger.load(args.cwd, args.target, args.arguments, undefined, args.autorun || []).then(() => {
+ } else { // Local session
+ this.miDebugger.load(args.cwd, args.target, args.target_arguments, undefined, args.autorun || []).then(() => {
this.sendResponse(response);
}, err => {
this.sendErrorResponse(response, 107, `Failed to load MI Debugger: ${err.toString()}`);
@@ -99,38 +110,31 @@ class AliceserverDebugSession extends MI2DebugSession {
}
protected override attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void {
- const dbgCommand = args.aliceserverpath || "aliceserver";
- // See NOTE in launchRequest
- if (args.aliceserverpath === undefined && this.checkCommand(dbgCommand)) {
+ const dbgCommand = args.aliceserver_path || "aliceserver";
+ if (args.aliceserver_path === undefined && this.checkCommand(dbgCommand)) {
this.sendErrorResponse(response, 104, `Configured debugger ${dbgCommand} not found.`);
return;
}
+
this.miDebugger = new MI2_ALICE(dbgCommand, ["-a", "mi"], args.debugger_args, args.env);
- this.setPathSubstitutions(args.pathSubstitutions);
this.initDebugger();
+
+ // Defaults
this.quit = false;
this.attached = true;
this.initialRunCommand = args.stopAtConnect ? RunCommand.NONE : RunCommand.CONTINUE;
this.isSSH = false;
- this.setValuesFormattingMode(args.valuesFormatting);
this.miDebugger.printCalls = !!args.printCalls;
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
this.stopAtEntry = args.stopAtEntry;
+
+ // Start session
this.miDebugger.attach(args.cwd, args.executable, args.target, args.autorun || []).then(() => {
this.sendResponse(response);
}, err => {
this.sendErrorResponse(response, 108, `Failed to attach: ${err.toString()}`);
});
}
-
- // Add extra commands for source file path substitution in LLDB-specific syntax
- protected setPathSubstitutions(substitutions: { [index: string]: string }): void {
- if (substitutions) {
- Object.keys(substitutions).forEach(source => {
- this.miDebugger.extraCommands.push("settings append target.source-map " + source + " " + substitutions[source]);
- });
- }
- }
}
DebugSession.run(AliceserverDebugSession);
diff --git a/src/backend/mi2/mi2aliceserver.ts b/src/backend/mi2/mi2aliceserver.ts
index 2857f93..3add7b3 100644
--- a/src/backend/mi2/mi2aliceserver.ts
+++ b/src/backend/mi2/mi2aliceserver.ts
@@ -1,3 +1,5 @@
+// Directly manages an Aliceserver instance by managing MI requests.
+
import { MI2, escape } from "./mi2";
import { Breakpoint } from "../backend";
import * as ChildProcess from "child_process";
@@ -19,6 +21,8 @@ export class MI2_ALICE extends MI2 {
const cmds = [
// Aliceserver is already async by default
//this.sendCommand("gdb-set target-async on"),
+
+ /* Format unknown since I'm too lazy to compile lldb-mi
new Promise(resolve => {
this.sendCommand("list-features").then(done => {
this.features = done.result("features");
@@ -28,16 +32,36 @@ export class MI2_ALICE extends MI2 {
resolve(undefined);
});
}) as Thenable,
+ */
+
+ // TODO: environment-directory
+ // Command not currently supported
//this.sendCommand("environment-directory \"" + escape(cwd) + "\"", true)
- ];
- if (!attach)
+ ] as Thenable[];
+ if (!attach) // When launching
cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\""));
- for (const cmd of this.extraCommands) {
+ for (const cmd of this.extraCommands) // For the target process
cmds.push(this.sendCliCommand(cmd));
- }
return cmds;
}
+ // Start debugging target
+ override start(runToStart: boolean): Thenable {
+ const options: string[] = [];
+ if (runToStart)
+ options.push("--start");
+ const startCommand: string = ["exec-run"].concat(options).join(" ");
+ return new Promise((resolve, reject) => {
+ this.log("console", "Running executable");
+ this.sendCommand(startCommand).then((info) => {
+ if (info.resultRecords.resultClass == "running")
+ resolve(undefined);
+ else
+ reject();
+ }, reject);
+ });
+ }
+
override attach(cwd: string, executable: string, target: string, autorun: string[]): Thenable {
return new Promise((resolve, reject) => {
const args = this.preargs.concat(this.extraargs || []);
From f79eb5946cf5db70ceee5aa3fb183af540afd8d6 Mon Sep 17 00:00:00 2001
From: dd86k
Date: Thu, 29 Aug 2024 20:33:57 -0400
Subject: [PATCH 9/9] mi2aliceserver: Redo MI2.stop() with a try-catch when
killing debugger process
---
src/backend/mi2/mi2aliceserver.ts | 33 +++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/src/backend/mi2/mi2aliceserver.ts b/src/backend/mi2/mi2aliceserver.ts
index 3add7b3..3979135 100644
--- a/src/backend/mi2/mi2aliceserver.ts
+++ b/src/backend/mi2/mi2aliceserver.ts
@@ -81,6 +81,39 @@ export class MI2_ALICE extends MI2 {
});
}
+ override stop(): void {
+ this.sendRaw("-gdb-exit");
+ if (this.isSSH) {
+ const proc = this.stream;
+ const to = setTimeout(() => {
+ proc.signal("KILL");
+ }, 1000);
+ this.stream.on("exit", function (code) {
+ clearTimeout(to);
+ });
+ } else {
+ const proc = this.process;
+ const to = setTimeout(() => {
+ // When tinkering with Aliceserver:
+ // - the proc.pid field might be undefined (when exited too early)
+ // - the process could no longer be found after sending requests (crashed or exited)
+ try
+ {
+ process.kill(-proc.pid);
+ }
+ catch (error)
+ {
+ // Warning, since it does not prevent the intent of
+ // continuing to shut down the server.
+ console.warn("Failed to terminate process: " + error);
+ }
+ }, 1000);
+ this.process.on("exit", function (code) {
+ clearTimeout(to);
+ });
+ }
+ }
+
override setBreakPointCondition(bkptNum: number, condition: string): Thenable {
return this.sendCommand("break-condition " + bkptNum + " \"" + escape(condition) + "\" 1");
}