Skip to content
157 changes: 157 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,163 @@
}
}
]
},
{
"type": "aliceserver-mi",
"program": "./out/src/aliceserver.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"
},
"aliceserver_path": {
"type": "string",
"description": "Path to the aliceserver executable or the command if in PATH",
"default": "aliceserver"
},
"env": {
"type": "object",
"description": "Environment overriding the aliceserver environment variables",
"default": null
},
"debugger_args": {
"type": "array",
"description": "Additional arguments to pass to specifically 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
}
}
},
"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 aliceserver calls to the console",
"default": false
},
"showDevDebugOutput": {
"type": "boolean",
"description": "Prints all aliceserver responses to the console",
"default": false
},
"executable": {
"type": "string",
"description": "Path of executable for debugging symbols"
},
"aliceserverpath": {
"type": "string",
"description": "Path to the aliceserver executable or the command if in PATH",
"default": "aliceservere"
},
"env": {
"type": "object",
"description": "Environment overriding the aliceserver environment variables",
"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": "aliceserver 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": "aliceserver-mi",
"request": "launch",
"target": "./bin/executable",
"cwd": "${workspaceRoot}"
}
],
"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"
}
}
]
}
]
},
Expand Down
140 changes: 140 additions & 0 deletions src/aliceserver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// 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;
target_arguments: string;
aliceserver_path: string;
env: any;
debugger_args: string[];
autorun: string[];
stopAtEntry: boolean | string;
ssh: SSHArguments;
valuesFormatting: ValuesFormattingMode;
printCalls: boolean;
showDevDebugOutput: boolean;
}

export interface AttachRequestArguments extends DebugProtocol.AttachRequestArguments {
cwd: string;
target: string;
aliceserver_path: string;
env: any;
debugger_args: string[];
executable: string;
autorun: string[];
stopAtConnect: boolean;
stopAtEntry: boolean | string;
printCalls: boolean;
showDevDebugOutput: boolean;
}

class AliceserverDebugSession extends MI2DebugSession {
protected override initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
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.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.initDebugger();

// Defaults
this.quit = false;
this.attached = false;
this.initialRunCommand = RunCommand.RUN;
this.isSSH = false;
this.started = false;
this.crashed = false;
this.miDebugger.printCalls = !!args.printCalls;
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
this.stopAtEntry = args.stopAtEntry;

// 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.target_arguments, undefined, false, args.autorun || []).then(() => {
this.sendResponse(response);
}, err => {
this.sendErrorResponse(response, 106, `Failed to SSH: ${err.toString()}`);
});
} 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()}`);
});
}
}

protected override attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void {
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.initDebugger();

// Defaults
this.quit = false;
this.attached = true;
this.initialRunCommand = args.stopAtConnect ? RunCommand.NONE : RunCommand.CONTINUE;
this.isSSH = false;
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()}`);
});
}
}

DebugSession.run(AliceserverDebugSession);
Loading