Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Aliceserver as a debugger target. #440

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
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