diff --git a/package.json b/package.json index b0e3e8a7..cb5e9345 100644 --- a/package.json +++ b/package.json @@ -108,9 +108,18 @@ }, "autorun": { "type": "array", - "description": "GDB commands to run when starting to debug", + "description": "GDB commands to be run after connection", "default": [] }, + "autorunBefore": { + "type": "array", + "description": "GDB commands to be run before connection", + "default": [ + "gdb-set target-async on", + "environment-directory \"$cwd\"", + "target-select $target" + ] + }, "ssh": { "required": [ "host", @@ -218,9 +227,18 @@ }, "autorun": { "type": "array", - "description": "GDB commands to run when starting to debug", + "description": "GDB commands to be run after connection", "default": [] }, + "autorunBefore": { + "type": "array", + "description": "GDB commands to be run before connection", + "default": [ + "gdb-set target-async on", + "environment-directory \"$cwd\"", + "target-select remote $target" + ] + }, "ssh": { "required": [ "host", @@ -463,9 +481,18 @@ }, "autorun": { "type": "array", - "description": "lldb commands to run when starting to debug", + "description": "lldb commands to be run after connection", "default": [] }, + "autorunBefore": { + "type": "array", + "description": "lldb commands to be run before connection", + "default": [ + "gdb-set target-async on", + "environment-directory \"$cwd\"", + "target-select $target" + ] + }, "ssh": { "required": [ "host", @@ -568,8 +595,17 @@ }, "autorun": { "type": "array", - "description": "lldb commands to run when starting to debug", + "description": "lldb commands to be run after connection", "default": [] + }, + "autorunBefore": { + "type": "array", + "description": "lldb commands to be run before connection", + "default": [ + "gdb-set target-async on", + "environment-directory \"$cwd\"", + "target-select $target" + ] } } } @@ -700,8 +736,17 @@ }, "autorun": { "type": "array", - "description": "mago commands to run when starting to debug", + "description": "mago commands to be run after connection", "default": [] + }, + "autorunBefore": { + "type": "array", + "description": "mago commands to be run before connection", + "default": [ + "gdb-set target-async on", + "environment-directory \"$cwd\"", + "target-select $target" + ] } } }, @@ -745,8 +790,17 @@ }, "autorun": { "type": "array", - "description": "mago commands to run when starting to debug", + "description": "mago commands to be run after connection", "default": [] + }, + "autorunBefore": { + "type": "array", + "description": "mago commands to be run before connection", + "default": [ + "gdb-set target-async on", + "environment-directory \"$cwd\"", + "target-select $target" + ] } } } diff --git a/src/backend/backend.ts b/src/backend/backend.ts index d2738a70..0d760895 100644 --- a/src/backend/backend.ts +++ b/src/backend/backend.ts @@ -37,10 +37,10 @@ export interface SSHArguments { } export interface IBackend { - load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable; - ssh(args: SSHArguments, cwd: string, target: string, procArgs: string, separateConsole: string, attach: boolean): Thenable; - attach(cwd: string, executable: string, target: string): Thenable; - connect(cwd: string, executable: string, target: string): Thenable; + load(cwd: string, target: string, autorunBeforeCmds: string[], procArgs: string, separateConsole: string): Thenable; + ssh(args: SSHArguments, cwd: string, target: string, autorunBeforeCmds: string[], procArgs: string, separateConsole: string, attach: boolean): Thenable; + attach(cwd: string, executable: string, target: string, autorunBeforeCmds: string[]): Thenable; + connect(cwd: string, executable: string, target: string, autorunBeforeCmds: string[]): Thenable; start(): Thenable; stop(); detach(); diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 5f340bb4..63c95503 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -1,4 +1,5 @@ import { Breakpoint, IBackend, Stack, SSHArguments, Variable } from "../backend" +import { escape } from "../mi_parse" import * as ChildProcess from "child_process" import { EventEmitter } from "events" import { parseMI, MINode } from '../mi_parse'; @@ -10,10 +11,6 @@ import * as nativePath from "path" let path = posix; var Client = require("ssh2").Client; -export function escape(str: string) { - return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\""); -} - const nonOutput = /^(?:\d*|undefined)[\*\+\=]|[\~\@\&\^]/; const gdbMatch = /(?:\d*|undefined)\(gdb\)/; const numRegex = /\d+/; @@ -31,7 +28,7 @@ export class MI2 extends EventEmitter implements IBackend { super(); } - load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable { + load(cwd: string, target: string, autorunBeforeCmds: string[], procArgs: string, separateConsole: string): Thenable { if (!nativePath.isAbsolute(target)) target = nativePath.join(cwd, target); return new Promise((resolve, reject) => { @@ -41,7 +38,7 @@ export class MI2 extends EventEmitter implements IBackend { 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"); }).bind(this)); - let promises = this.initCommands(target, cwd); + let promises = this.initCommands(target, cwd, autorunBeforeCmds); if (procArgs && procArgs.length) promises.push(this.sendCommand("exec-arguments " + procArgs)); if (process.platform == "win32") { @@ -72,7 +69,7 @@ export class MI2 extends EventEmitter implements IBackend { }); } - ssh(args: SSHArguments, cwd: string, target: string, procArgs: string, separateConsole: string, attach: boolean): Thenable { + ssh(args: SSHArguments, cwd: string, target: string, autorunBeforeCmds: string[], procArgs: string, separateConsole: string, attach: boolean): Thenable { return new Promise((resolve, reject) => { this.isSSH = true; this.sshReady = false; @@ -143,7 +140,7 @@ export class MI2 extends EventEmitter implements IBackend { this.emit("quit"); this.sshConn.end(); }).bind(this)); - let promises = this.initCommands(target, cwd, true, attach); + let promises = this.initCommands(target, cwd, autorunBeforeCmds, true, attach); promises.push(this.sendCommand("environment-cd \"" + escape(cwd) + "\"")); if (procArgs && procArgs.length && !attach) promises.push(this.sendCommand("exec-arguments " + procArgs)); @@ -161,7 +158,8 @@ export class MI2 extends EventEmitter implements IBackend { }); } - protected initCommands(target: string, cwd: string, ssh: boolean = false, attach: boolean = false) { + protected initCommands(target: string, cwd: string, autorunBeforeCmds: string[], ssh: boolean = false, attach: boolean = false) { + let cmds = []; if (ssh) { if (!path.isAbsolute(target)) target = path.join(cwd, target); @@ -170,17 +168,17 @@ export class MI2 extends EventEmitter implements IBackend { if (!nativePath.isAbsolute(target)) target = nativePath.join(cwd, target); } - var cmds = [ - this.sendCommand("gdb-set target-async on", true), - this.sendCommand("environment-directory \"" + escape(cwd) + "\"", true) - ]; + autorunBeforeCmds.forEach(command => { + cmds.push(this.sendCommand(command)); + }); if (!attach) cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\"")); return cmds; } - attach(cwd: string, executable: string, target: string): Thenable { + attach(cwd: string, executable: string, target: string, autorunBeforeCmds: string[]): Thenable { return new Promise((resolve, reject) => { + let cmds = []; let args = []; if (executable && !nativePath.isAbsolute(executable)) executable = nativePath.join(cwd, executable); @@ -196,39 +194,38 @@ export class MI2 extends EventEmitter implements IBackend { 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"); }).bind(this)); - var commands = [ - this.sendCommand("gdb-set target-async on"), - this.sendCommand("environment-directory \"" + escape(cwd) + "\"") - ]; + autorunBeforeCmds.forEach(command => { + cmds.push(this.sendCommand(command)); + }); + if (isExtendedRemote) { - commands.push(this.sendCommand("target-select " + target)); - commands.push(this.sendCommand("file-symbol-file \"" + escape(executable) + "\"")); + cmds.push(this.sendCommand("file-symbol-file \"" + escape(executable) + "\"")); } - Promise.all(commands).then(() => { + Promise.all(cmds).then(() => { this.emit("debug-ready") resolve(); }, reject); }); } - connect(cwd: string, executable: string, target: string): Thenable { + connect(cwd: string, executable: string, target: string, autorunBeforeCmds: string[]): Thenable { return new Promise((resolve, reject) => { + let commands = []; let args = []; if (executable && !nativePath.isAbsolute(executable)) executable = nativePath.join(cwd, executable); if (executable) args = args.concat([executable], this.preargs); else - args = this.preargs; + args = this.preargs; this.process = ChildProcess.spawn(this.application, args, { cwd: cwd }); 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"); }).bind(this)); - Promise.all([ - this.sendCommand("gdb-set target-async on"), - this.sendCommand("environment-directory \"" + escape(cwd) + "\""), - this.sendCommand("target-select remote " + target) - ]).then(() => { + autorunBeforeCmds.forEach(command => { + commands.push(this.sendCommand(command)); + }); + Promise.all(commands).then(() => { this.emit("debug-ready") resolve(); }, reject); diff --git a/src/backend/mi2/mi2lldb.ts b/src/backend/mi2/mi2lldb.ts index 6cb52634..2c73d72b 100644 --- a/src/backend/mi2/mi2lldb.ts +++ b/src/backend/mi2/mi2lldb.ts @@ -1,4 +1,5 @@ -import { MI2, escape } from "./mi2" +import { MI2 } from "./mi2" +import { escape } from "../mi_parse" import { Breakpoint } from "../backend" import * as ChildProcess from "child_process" import { posix } from "path" @@ -6,7 +7,8 @@ import * as nativePath from "path" let path = posix; export class MI2_LLDB extends MI2 { - protected initCommands(target: string, cwd: string, ssh: boolean = false, attach: boolean = false) { + protected initCommands(target: string, cwd: string, autorunBeforeCmds: string[], ssh: boolean = false, attach: boolean = false) { + let cmds = []; if (ssh) { if (!path.isAbsolute(target)) target = path.join(cwd, target); @@ -15,25 +17,26 @@ export class MI2_LLDB extends MI2 { if (!nativePath.isAbsolute(target)) target = nativePath.join(cwd, target); } - var cmds = [ - this.sendCommand("gdb-set target-async on") - ]; + autorunBeforeCmds.forEach(command => { + cmds.push(this.sendCommand(command)); + }); if (!attach) cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\"")); return cmds; } - attach(cwd: string, executable: string, target: string): Thenable { + attach(cwd: string, executable: string, target: string, autorunBeforeCmds: string[]): Thenable { return new Promise((resolve, reject) => { + let cmds = []; this.process = ChildProcess.spawn(this.application, this.preargs, { cwd: cwd }); 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"); }).bind(this)); - Promise.all([ - this.sendCommand("gdb-set target-async on"), - this.sendCommand("file-exec-and-symbols \"" + escape(executable) + "\""), - this.sendCommand("target-attach " + target) - ]).then(() => { + autorunBeforeCmds.forEach(command => { + cmds.push(this.sendCommand(command)); + }); + cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(executable) + "\"")); + Promise.all(cmds).then(() => { this.emit("debug-ready"); resolve(); }, reject); diff --git a/src/backend/mi_parse.ts b/src/backend/mi_parse.ts index 76503c2b..9f7929bf 100644 --- a/src/backend/mi_parse.ts +++ b/src/backend/mi_parse.ts @@ -4,6 +4,10 @@ export interface MIInfo { resultRecords: { resultClass: string, results: [string, any][] }; } +export function escape(str: string) { + return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\""); +} + var octalMatch = /^[0-7]{3}/; function parseString(str: string): string { var ret = new Buffer(str.length * 4); diff --git a/src/gdb.ts b/src/gdb.ts index 428d6f44..f6c3c815 100644 --- a/src/gdb.ts +++ b/src/gdb.ts @@ -1,35 +1,29 @@ import { MI2DebugSession } from './mibase'; import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; +import { escape } from "./backend/mi_parse" import { MI2 } from "./backend/mi2/mi2"; import { SSHArguments } from './backend/backend'; -export interface LaunchRequestArguments { +export interface CommonRequestArguments { cwd: string; target: string; gdbpath: string; debugger_args: string[]; - arguments: string; - terminal: string; + autorunBefore: string[]; autorun: string[]; ssh: SSHArguments; printCalls: boolean; showDevDebugOutput: boolean; -} - -export interface AttachRequestArguments { - cwd: string; - target: string; - gdbpath: string; - debugger_args: string[]; executable: string; remote: boolean; - autorun: string[]; - ssh: SSHArguments; - printCalls: boolean; - showDevDebugOutput: boolean; + arguments: string; + terminal: string; } +export interface LaunchRequestArguments extends CommonRequestArguments { } +export interface AttachRequestArguments extends CommonRequestArguments { } + class GDBDebugSession extends MI2DebugSession { protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { response.body.supportsHitConditionalBreakpoints = true; @@ -42,9 +36,8 @@ class GDBDebugSession extends MI2DebugSession { this.sendResponse(response); } - protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { - this.miDebugger = new MI2(args.gdbpath || "gdb", ["-q", "--interpreter=mi2"], args.debugger_args); - this.initDebugger(); + + private initiliaseDefaultValueArgs(args: CommonRequestArguments, attach: boolean) { this.quit = false; this.attached = false; this.needContinue = false; @@ -54,6 +47,9 @@ class GDBDebugSession extends MI2DebugSession { this.debugReady = false; this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; + var hasAutorunBeforeArgs = args.autorunBefore !== undefined; + + if (args.ssh !== undefined) { if (args.ssh.forwardX11 === undefined) args.ssh.forwardX11 = true; @@ -68,11 +64,47 @@ class GDBDebugSession extends MI2DebugSession { this.isSSH = true; this.trimCWD = args.cwd.replace(/\\/g, "/"); this.switchCWD = args.ssh.cwd; - this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments, args.terminal, false).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + } + if (args.autorun === undefined) + args.autorun = []; + + if (!hasAutorunBeforeArgs) + args.autorunBefore = ["gdb-set target-async on", + "environment-directory \"$cwd\""]; + + if (attach) { + this.attached = !args.remote; + if (!hasAutorunBeforeArgs) + args.autorunBefore.push("target-select remote $target"); + + } else { + this.attached = false; + this.needContinue = true; + if (!hasAutorunBeforeArgs) + args.autorunBefore.push("target-select $target"); + } + args.autorun = args.autorun.map( + s => {return escape(s); + }); + + args.autorunBefore = args.autorunBefore.map( + s => {return s.replace(/\$cwd/, escape(args.cwd)) + .replace(/\$target/, args.target); + }); + } + + + + protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { + this.miDebugger = new MI2(args.gdbpath || "gdb", ["-q", "--interpreter=mi2"], args.debugger_args); + this.initDebugger(); + this.initiliaseDefaultValueArgs(args, false); + + if (this.isSSH) { + this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.autorunBefore, args.arguments, args.terminal, false).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); setTimeout(() => { this.miDebugger.emit("ui-break-done"); }, 50); @@ -89,11 +121,10 @@ class GDBDebugSession extends MI2DebugSession { }); } else { - this.miDebugger.load(args.cwd, args.target, args.arguments, args.terminal).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + this.miDebugger.load(args.cwd, args.target, args.autorunBefore, args.arguments, args.terminal).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); setTimeout(() => { this.miDebugger.emit("ui-break-done"); }, 50); @@ -114,32 +145,15 @@ class GDBDebugSession extends MI2DebugSession { protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void { this.miDebugger = new MI2(args.gdbpath || "gdb", ["-q", "--interpreter=mi2"], args.debugger_args); this.initDebugger(); - this.quit = false; - this.attached = !args.remote; - this.needContinue = true; - this.isSSH = false; - this.debugReady = false; - this.miDebugger.printCalls = !!args.printCalls; - this.miDebugger.debugOutput = !!args.showDevDebugOutput; - 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.trimCWD = args.cwd.replace(/\\/g, "/"); - this.switchCWD = args.ssh.cwd; - this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, "", undefined, true).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + this.initiliaseDefaultValueArgs(args, true); + + + + if (this.isSSH) { + this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.autorunBefore, "", undefined, true).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); setTimeout(() => { this.miDebugger.emit("ui-break-done"); }, 50); @@ -150,22 +164,20 @@ class GDBDebugSession extends MI2DebugSession { } else { if (args.remote) { - this.miDebugger.connect(args.cwd, args.executable, args.target).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + this.miDebugger.connect(args.cwd, args.executable, args.target, args.autorunBefore).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); this.sendResponse(response); }, err => { this.sendErrorResponse(response, 102, `Failed to attach: ${err.toString()}`) }); } else { - this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + this.miDebugger.attach(args.cwd, args.executable, args.target, args.autorunBefore).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); this.sendResponse(response); }, err => { this.sendErrorResponse(response, 101, `Failed to attach: ${err.toString()}`) diff --git a/src/lldb.ts b/src/lldb.ts index bb9ccd61..05e562f6 100644 --- a/src/lldb.ts +++ b/src/lldb.ts @@ -1,31 +1,26 @@ import { MI2DebugSession } from './mibase'; import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; +import { escape } from "./backend/mi_parse" import { MI2_LLDB } from "./backend/mi2/mi2lldb"; import { SSHArguments } from './backend/backend'; -export interface LaunchRequestArguments { +export interface CommonRequestArguments { cwd: string; target: string; lldbmipath: string; debugger_args: string[]; + executable: string; arguments: string; autorun: string[]; + autorunBefore: string[]; ssh: SSHArguments; printCalls: boolean; showDevDebugOutput: boolean; } -export interface AttachRequestArguments { - cwd: string; - target: string; - lldbmipath: string; - debugger_args: string[]; - executable: string; - autorun: string[]; - printCalls: boolean; - showDevDebugOutput: boolean; -} +export interface LaunchRequestArguments extends CommonRequestArguments { } +export interface AttachRequestArguments extends CommonRequestArguments { } class LLDBDebugSession extends MI2DebugSession { protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { @@ -37,9 +32,7 @@ class LLDBDebugSession extends MI2DebugSession { this.sendResponse(response); } - protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { - this.miDebugger = new MI2_LLDB(args.lldbmipath || "lldb-mi", [], args.debugger_args); - this.initDebugger(); + private initiliaseDefaultValueArgs(args: CommonRequestArguments, attach: boolean) { this.quit = false; this.attached = false; this.needContinue = false; @@ -49,6 +42,9 @@ class LLDBDebugSession extends MI2DebugSession { this.debugReady = false; this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; + var hasAutorunBeforeArgs = args.autorunBefore !== undefined; + + if (args.ssh !== undefined) { if (args.ssh.forwardX11 === undefined) args.ssh.forwardX11 = true; @@ -63,11 +59,43 @@ class LLDBDebugSession extends MI2DebugSession { this.isSSH = true; this.trimCWD = args.cwd.replace(/\\/g, "/"); this.switchCWD = args.ssh.cwd; - this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.arguments, undefined, false).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + } + if (args.autorun === undefined) + args.autorun = []; + + if (!hasAutorunBeforeArgs) + args.autorunBefore = ["gdb-set target-async on", + "environment-directory \"$cwd\""]; + + if (attach) { + this.attached = true; + this.needContinue = true; + if (!hasAutorunBeforeArgs) + args.autorunBefore.push("target-select remote $target"); + + } + + args.autorun = args.autorun.map( + s => {return escape(s); + }); + + args.autorunBefore = args.autorunBefore.map( + s => { + return s.replace(/\$cwd/, escape(args.cwd)) + .replace(/\$target/, args.target); + }); + } + + protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { + this.miDebugger = new MI2_LLDB(args.lldbmipath || "lldb-mi", [], args.debugger_args); + this.initDebugger(); + this.initiliaseDefaultValueArgs(args, false); + + if (this.isSSH) { + this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.target, args.autorunBefore, args.arguments, undefined, false).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); setTimeout(() => { this.miDebugger.emit("ui-break-done"); }, 50); @@ -80,11 +108,10 @@ class LLDBDebugSession extends MI2DebugSession { }); } else { - this.miDebugger.load(args.cwd, args.target, args.arguments, undefined).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + this.miDebugger.load(args.cwd, args.target, args.autorunBefore, args.arguments, undefined).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); setTimeout(() => { this.miDebugger.emit("ui-break-done"); }, 50); @@ -101,18 +128,12 @@ class LLDBDebugSession extends MI2DebugSession { protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void { this.miDebugger = new MI2_LLDB(args.lldbmipath || "lldb-mi", [], args.debugger_args); this.initDebugger(); - this.quit = false; - this.attached = true; - this.needContinue = true; - this.isSSH = false; - this.debugReady = false; - this.miDebugger.printCalls = !!args.printCalls; - this.miDebugger.debugOutput = !!args.showDevDebugOutput; - this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { - if (args.autorun) - args.autorun.forEach(command => { - this.miDebugger.sendUserInput(command); - }); + this.initiliaseDefaultValueArgs(args, true); + + this.miDebugger.attach(args.cwd, args.executable, args.target, args.autorunBefore).then(() => { + args.autorun.forEach(command => { + this.miDebugger.sendUserInput(command); + }); this.sendResponse(response); }); } diff --git a/src/mago.ts b/src/mago.ts index dfe44cf8..0fb017e2 100644 --- a/src/mago.ts +++ b/src/mago.ts @@ -1,30 +1,25 @@ import { MI2DebugSession } from './mibase'; import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; +import { escape } from "./backend/mi_parse" import { MI2_Mago } from "./backend/mi2/mi2mago"; import { SSHArguments } from './backend/backend'; -export interface LaunchRequestArguments { - cwd: string; - target: string; - magomipath: string; - debugger_args: string[]; - arguments: string; - autorun: string[]; - printCalls: boolean; - showDevDebugOutput: boolean; -} +export interface CommonRequestArguments { -export interface AttachRequestArguments { cwd: string; target: string; magomipath: string; + executable: string; debugger_args: string[]; - executable: string; + arguments: string; autorun: string[]; + autorunBefore: string[]; printCalls: boolean; showDevDebugOutput: boolean; } +export interface LaunchRequestArguments extends CommonRequestArguments{} +export interface AttachRequestArguments extends CommonRequestArguments{} class MagoDebugSession extends MI2DebugSession { public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) { @@ -40,13 +35,7 @@ class MagoDebugSession extends MI2DebugSession { this.sendResponse(response); } - getThreadID() { - return 0; - } - - protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { - this.miDebugger = new MI2_Mago(args.magomipath || "mago-mi", ["-q"], args.debugger_args); - this.initDebugger(); +private initiliaseDefaultValueArgs(args: CommonRequestArguments, attach: boolean) { this.quit = false; this.attached = false; this.needContinue = false; @@ -56,7 +45,44 @@ class MagoDebugSession extends MI2DebugSession { this.debugReady = false; this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; - this.miDebugger.load(args.cwd, args.target, args.arguments, undefined).then(() => { + var hasAutorunBeforeArgs = args.autorunBefore !== undefined; + + if (args.autorun === undefined) + args.autorun = []; + + if (!hasAutorunBeforeArgs) + args.autorunBefore = ["gdb-set target-async on", + "environment-directory \"$cwd\""]; + + if (attach) { + this.attached = true; + this.needContinue = true; + if (!hasAutorunBeforeArgs) + args.autorunBefore.push("target-select remote $target"); + + } + + args.autorun = args.autorun.map( + s => {return escape(s); + }); + + args.autorunBefore = args.autorunBefore.map( + s => { + return s.replace(/\$cwd/, escape(args.cwd)) + .replace(/\$target/, args.target); + }); + } + + getThreadID() { + return 0; + } + + protected launchRequest(response: DebugProtocol.LaunchResponse, args: LaunchRequestArguments): void { + this.miDebugger = new MI2_Mago(args.magomipath || "mago-mi", ["-q"], args.debugger_args); + this.initDebugger(); + this.initiliaseDefaultValueArgs(args, false); + + this.miDebugger.load(args.cwd, args.target, args.autorunBefore, args.arguments, undefined).then(() => { if (args.autorun) args.autorun.forEach(command => { this.miDebugger.sendUserInput(command); @@ -76,14 +102,8 @@ class MagoDebugSession extends MI2DebugSession { protected attachRequest(response: DebugProtocol.AttachResponse, args: AttachRequestArguments): void { this.miDebugger = new MI2_Mago(args.magomipath || "mago-mi", [], args.debugger_args); this.initDebugger(); - this.quit = false; - this.attached = true; - this.needContinue = true; - this.isSSH = false; - this.debugReady = false; - this.miDebugger.printCalls = !!args.printCalls; - this.miDebugger.debugOutput = !!args.showDevDebugOutput; - this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { + this.initiliaseDefaultValueArgs(args, true); + this.miDebugger.attach(args.cwd, args.executable, args.target, args.autorunBefore).then(() => { if (args.autorun) args.autorun.forEach(command => { this.miDebugger.sendUserInput(command);