Added mago-mi support (fix #67)
This commit is contained in:
parent
1a399b3292
commit
1e298815c4
4 changed files with 239 additions and 10 deletions
96
package.json
96
package.json
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "debug",
|
"name": "debug",
|
||||||
"displayName": "Debug",
|
"displayName": "Native Debug",
|
||||||
"description": "GDB & LLDB support for VSCode",
|
"description": "GDB, LLDB & Mago-MI Debugger support for VSCode",
|
||||||
"version": "0.8.1",
|
"version": "0.8.1",
|
||||||
"publisher": "webfreak",
|
"publisher": "webfreak",
|
||||||
"icon": "images/icon-plain.svg",
|
"icon": "images/icon-plain.svg",
|
||||||
|
|
@ -362,6 +362,98 @@
|
||||||
"cwd": "${workspaceRoot}"
|
"cwd": "${workspaceRoot}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "mago-mi",
|
||||||
|
"extensions": [],
|
||||||
|
"program": "./out/src/mago.js",
|
||||||
|
"runtime": "node",
|
||||||
|
"label": "Mago-MI",
|
||||||
|
"enableBreakpointsFor": {
|
||||||
|
"languageIds": [
|
||||||
|
"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": "Path of project"
|
||||||
|
},
|
||||||
|
"magomipath": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path to the mago-mi executable or the command if in PATH",
|
||||||
|
"default": "mago-mi"
|
||||||
|
},
|
||||||
|
"printCalls": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Prints all mago calls to console",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"autorun": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "mago commands to run when starting to debug",
|
||||||
|
"default": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"attach": {
|
||||||
|
"required": [
|
||||||
|
"target"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"target": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "PID of running program or program name"
|
||||||
|
},
|
||||||
|
"printCalls": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Prints all mago calls to 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"
|
||||||
|
},
|
||||||
|
"cwd": {
|
||||||
|
"type": "string",
|
||||||
|
"description": "Path of project",
|
||||||
|
"default": "${workspaceRoot}"
|
||||||
|
},
|
||||||
|
"autorun": {
|
||||||
|
"type": "array",
|
||||||
|
"description": "Mago commands to run when starting to debug",
|
||||||
|
"default": []
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"initialConfigurations": [
|
||||||
|
{
|
||||||
|
"name": "Debug",
|
||||||
|
"type": "mago-mi",
|
||||||
|
"request": "launch",
|
||||||
|
"target": "./bin/executable",
|
||||||
|
"cwd": "${workspaceRoot}"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
|
||||||
47
src/backend/mi2/mi2mago.ts
Normal file
47
src/backend/mi2/mi2mago.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import { MI2_LLDB } from "./mi2lldb"
|
||||||
|
import { Stack } from "../backend"
|
||||||
|
import { MINode } from "../mi_parse"
|
||||||
|
|
||||||
|
export class MI2_Mago extends MI2_LLDB {
|
||||||
|
getStack(maxLevels: number): Thenable<Stack[]> {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
let command = "stack-list-frames";
|
||||||
|
this.sendCommand(command).then((result) => {
|
||||||
|
let stack = result.resultRecords.results;
|
||||||
|
this.log("stdout", JSON.stringify(result.resultRecords.results.length));
|
||||||
|
let ret: Stack[] = [];
|
||||||
|
let remaining = [];
|
||||||
|
let addToStack = (element) => {
|
||||||
|
this.log("stdout", JSON.stringify(element));
|
||||||
|
let level = MINode.valueOf(element, "frame.level");
|
||||||
|
let addr = MINode.valueOf(element, "frame.addr");
|
||||||
|
let func = MINode.valueOf(element, "frame.func");
|
||||||
|
let filename = MINode.valueOf(element, "file");
|
||||||
|
let file = MINode.valueOf(element, "fullname");
|
||||||
|
let line = 0;
|
||||||
|
let lnstr = MINode.valueOf(element, "line");
|
||||||
|
if (lnstr)
|
||||||
|
line = parseInt(lnstr);
|
||||||
|
let from = parseInt(MINode.valueOf(element, "from"));
|
||||||
|
ret.push({
|
||||||
|
address: addr,
|
||||||
|
fileName: filename || "",
|
||||||
|
file: file || "<unknown>",
|
||||||
|
function: func || from || "<unknown>",
|
||||||
|
level: level,
|
||||||
|
line: line
|
||||||
|
});
|
||||||
|
}
|
||||||
|
stack.forEach(element => {
|
||||||
|
if (element)
|
||||||
|
if (element[0] == "stack") {
|
||||||
|
addToStack(element[1]);
|
||||||
|
} else remaining.push(element);
|
||||||
|
});
|
||||||
|
if (remaining.length)
|
||||||
|
addToStack(remaining);
|
||||||
|
resolve(ret);
|
||||||
|
}, reject);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
89
src/mago.ts
Normal file
89
src/mago.ts
Normal file
|
|
@ -0,0 +1,89 @@
|
||||||
|
import { MI2DebugSession } from './mibase';
|
||||||
|
import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter';
|
||||||
|
import { DebugProtocol } from 'vscode-debugprotocol';
|
||||||
|
import { MI2_Mago } from "./backend/mi2/mi2mago";
|
||||||
|
import { SSHArguments } from './backend/backend';
|
||||||
|
|
||||||
|
export interface LaunchRequestArguments {
|
||||||
|
cwd: string;
|
||||||
|
target: string;
|
||||||
|
magomipath: string;
|
||||||
|
arguments: string;
|
||||||
|
autorun: string[];
|
||||||
|
printCalls: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AttachRequestArguments {
|
||||||
|
cwd: string;
|
||||||
|
target: string;
|
||||||
|
magomipath: string;
|
||||||
|
executable: string;
|
||||||
|
autorun: string[];
|
||||||
|
printCalls: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
class MagoDebugSession extends MI2DebugSession {
|
||||||
|
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
|
||||||
|
super(debuggerLinesStartAt1, isServer, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void {
|
||||||
|
response.body.supportsConfigurationDoneRequest = true;
|
||||||
|
response.body.supportsConditionalBreakpoints = true;
|
||||||
|
response.body.supportsFunctionBreakpoints = true;
|
||||||
|
response.body.supportsEvaluateForHovers = true;
|
||||||
|
this.sendResponse(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
getThreadID() {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void {
|
||||||
|
this.miDebugger = new MI2_Mago(args.magomipath || "mago-mi", []);
|
||||||
|
this.initDebugger();
|
||||||
|
this.quit = false;
|
||||||
|
this.attached = false;
|
||||||
|
this.needContinue = false;
|
||||||
|
this.isSSH = false;
|
||||||
|
this.started = false;
|
||||||
|
this.crashed = false;
|
||||||
|
this.debugReady = false;
|
||||||
|
this.miDebugger.printCalls = !!args.printCalls;
|
||||||
|
this.miDebugger.load(args.cwd, args.target, args.arguments, undefined).then(() => {
|
||||||
|
if (args.autorun)
|
||||||
|
args.autorun.forEach(command => {
|
||||||
|
this.miDebugger.sendUserInput(command);
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
this.miDebugger.emit("ui-break-done");
|
||||||
|
}, 50);
|
||||||
|
this.sendResponse(response);
|
||||||
|
this.miDebugger.start().then(() => {
|
||||||
|
this.started = true;
|
||||||
|
if (this.crashed)
|
||||||
|
this.handlePause(undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void {
|
||||||
|
this.miDebugger = new MI2_Mago(args.magomipath || "mago-mi", []);
|
||||||
|
this.initDebugger();
|
||||||
|
this.quit = false;
|
||||||
|
this.attached = true;
|
||||||
|
this.needContinue = true;
|
||||||
|
this.isSSH = false;
|
||||||
|
this.debugReady = false;
|
||||||
|
this.miDebugger.printCalls = !!args.printCalls;
|
||||||
|
this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => {
|
||||||
|
if (args.autorun)
|
||||||
|
args.autorun.forEach(command => {
|
||||||
|
this.miDebugger.sendUserInput(command);
|
||||||
|
});
|
||||||
|
this.sendResponse(response);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DebugSession.run(MagoDebugSession);
|
||||||
|
|
@ -11,7 +11,6 @@ let resolve = posix.resolve;
|
||||||
let relative = posix.relative;
|
let relative = posix.relative;
|
||||||
|
|
||||||
export class MI2DebugSession extends DebugSession {
|
export class MI2DebugSession extends DebugSession {
|
||||||
protected static THREAD_ID = 1;
|
|
||||||
protected variableHandles = new Handles<any>();
|
protected variableHandles = new Handles<any>();
|
||||||
protected quit: boolean;
|
protected quit: boolean;
|
||||||
protected attached: boolean;
|
protected attached: boolean;
|
||||||
|
|
@ -23,9 +22,11 @@ export class MI2DebugSession extends DebugSession {
|
||||||
protected crashed: boolean;
|
protected crashed: boolean;
|
||||||
protected debugReady: boolean;
|
protected debugReady: boolean;
|
||||||
protected miDebugger: MI2;
|
protected miDebugger: MI2;
|
||||||
|
protected threadID: number = 1;
|
||||||
|
|
||||||
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
|
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false, threadID: number = 1) {
|
||||||
super(debuggerLinesStartAt1, isServer);
|
super(debuggerLinesStartAt1, isServer);
|
||||||
|
this.threadID = threadID;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected initDebugger() {
|
protected initDebugger() {
|
||||||
|
|
@ -49,22 +50,22 @@ export class MI2DebugSession extends DebugSession {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected handleBreakpoint(info: MINode) {
|
protected handleBreakpoint(info: MINode) {
|
||||||
this.sendEvent(new StoppedEvent("breakpoint", MI2DebugSession.THREAD_ID));
|
this.sendEvent(new StoppedEvent("breakpoint", this.threadID));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected handleBreak(info: MINode) {
|
protected handleBreak(info: MINode) {
|
||||||
this.sendEvent(new StoppedEvent("step", MI2DebugSession.THREAD_ID));
|
this.sendEvent(new StoppedEvent("step", this.threadID));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected handlePause(info: MINode) {
|
protected handlePause(info: MINode) {
|
||||||
this.sendEvent(new StoppedEvent("user request", MI2DebugSession.THREAD_ID));
|
this.sendEvent(new StoppedEvent("user request", this.threadID));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected stopEvent(info: MINode) {
|
protected stopEvent(info: MINode) {
|
||||||
if (!this.started)
|
if (!this.started)
|
||||||
this.crashed = true;
|
this.crashed = true;
|
||||||
if (!this.quit)
|
if (!this.quit)
|
||||||
this.sendEvent(new StoppedEvent("exception", MI2DebugSession.THREAD_ID));
|
this.sendEvent(new StoppedEvent("exception", this.threadID));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected quitEvent() {
|
protected quitEvent() {
|
||||||
|
|
@ -146,7 +147,7 @@ export class MI2DebugSession extends DebugSession {
|
||||||
protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
|
protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
|
||||||
response.body = {
|
response.body = {
|
||||||
threads: [
|
threads: [
|
||||||
new Thread(MI2DebugSession.THREAD_ID, "Thread 1")
|
new Thread(this.threadID, "Thread 1")
|
||||||
]
|
]
|
||||||
};
|
};
|
||||||
this.sendResponse(response);
|
this.sendResponse(response);
|
||||||
|
|
@ -203,7 +204,7 @@ export class MI2DebugSession extends DebugSession {
|
||||||
|
|
||||||
if (typeof id == "string") {
|
if (typeof id == "string") {
|
||||||
if (id.startsWith("@frame:")) {
|
if (id.startsWith("@frame:")) {
|
||||||
this.miDebugger.getStackVariables(1, parseInt(id.substr("@frame:".length))).then(stack => {
|
this.miDebugger.getStackVariables(this.threadID, parseInt(id.substr("@frame:".length))).then(stack => {
|
||||||
stack.forEach(variable => {
|
stack.forEach(variable => {
|
||||||
if (variable[1] !== undefined) {
|
if (variable[1] !== undefined) {
|
||||||
let expanded = expandValue(createVariable, "{" + variable[0] + "=" + variable[1] + ")");
|
let expanded = expandValue(createVariable, "{" + variable[0] + "=" + variable[1] + ")");
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue