diff --git a/.gitignore b/.gitignore index 12624048..080f7ba8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,10 @@ out node_modules *.vsix -.vscode-test \ No newline at end of file +.vscode-test + +# Editor littering +*.swp +*.orig +*.rej +*~ diff --git a/package.json b/package.json index ea44d57d..34611a20 100644 --- a/package.json +++ b/package.json @@ -73,13 +73,17 @@ "configurationAttributes": { "launch": { "required": [ - "target" + "executable" ], "properties": { - "target": { + "executable": { "type": "string", "description": "Path of executable" }, + "target": { + "type": "string", + "description": "Path of executable (DEPRECATED use executable argument instead)" + }, "arguments": { "type": "string", "description": "Arguments to append after the executable. You can also use pipes." @@ -107,6 +111,10 @@ "description": "Additional arguments to pass to GDB", "default": [] }, + "extendedRemote": { + "type": "string", + "description": "gdbserver (extended-remote) to connect to (eg :2345)" + }, "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", @@ -436,6 +444,19 @@ ] }, "valuesFormatting": "parseText" + }, + { + "label": "GDB: Debug on remote device", + "description": "Transfer program to and debug it on a remote device", + "body": { + "type": "gdb", + "request": "launch", + "name": "${3:Debug remote device}", + "extendedRemote": "${2:192.168.0.1:2345}", + "executable": "${1:./bin/executable.elf}", + "cwd": "^\"\\${workspaceRoot}\"" + }, + "valuesFormatting": "parseText" } ] }, diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 5cbd8284..c7486aea 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -50,18 +50,30 @@ export class MI2 extends EventEmitter implements IBackend { } } - load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable { - if (!nativePath.isAbsolute(target)) - target = nativePath.join(cwd, target); + load(cwd: string, executable: string, procArgs: string, separateConsole: string, extendedRemote?: string): Thenable { + if (!nativePath.isAbsolute(executable)) + executable = nativePath.join(cwd, executable); return new Promise((resolve, reject) => { this.isSSH = false; - const args = this.preargs.concat(this.extraargs || []); + const args = this.preargs.concat(this.extraargs || [], [executable]); 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"); }).bind(this)); this.process.on("error", ((err) => { this.emit("launcherror", err); }).bind(this)); - const promises = this.initCommands(target, cwd); + let promises; + if (extendedRemote !== undefined) { + let remoteExecutable = nativePath.basename(executable); + promises = [ + this.sendCommand(`set target-async on`, true), + this.sendCommand(`environment-directory "${escape(cwd)}"`, true), + this.sendCommand(`target-select extended-remote ${extendedRemote}`), + this.sendCommand(`target-file-put "${escape(executable)}" ${remoteExecutable}`), + this.sendCommand(`gdb-set remote exec-file ./${remoteExecutable}`) + ]; + } else + promises = this.initCommands(executable, cwd); + if (procArgs && procArgs.length) promises.push(this.sendCommand("exec-arguments " + procArgs)); if (process.platform == "win32") { @@ -181,20 +193,20 @@ export class MI2 extends EventEmitter implements IBackend { }); } - protected initCommands(target: string, cwd: string, ssh: boolean = false, attach: boolean = false) { + protected initCommands(executable: string, cwd: string, ssh: boolean = false, attach: boolean = false) { if (ssh) { - if (!path.isAbsolute(target)) - target = path.join(cwd, target); + if (!path.isAbsolute(executable)) + executable = path.join(cwd, executable); } else { - if (!nativePath.isAbsolute(target)) - target = nativePath.join(cwd, target); + if (!nativePath.isAbsolute(executable)) + executable = nativePath.join(cwd, executable); } const cmds = [ this.sendCommand("gdb-set target-async on", true), this.sendCommand("environment-directory \"" + escape(cwd) + "\"", true) ]; if (!attach) - cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\"")); + cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(executable) + "\"")); if (this.prettyPrint) cmds.push(this.sendCommand("enable-pretty-printing")); diff --git a/src/gdb.ts b/src/gdb.ts index a8b547c7..4119dfb7 100644 --- a/src/gdb.ts +++ b/src/gdb.ts @@ -6,12 +6,14 @@ import { SSHArguments, ValuesFormattingMode } from './backend/backend'; export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments { cwd: string; + executable: string; target: string; gdbpath: string; env: any; debugger_args: string[]; arguments: string; terminal: string; + extendedRemote: string; autorun: string[]; ssh: SSHArguments; valuesFormatting: ValuesFormattingMode; @@ -60,6 +62,8 @@ class GDBDebugSession extends MI2DebugSession { this.setValuesFormattingMode(args.valuesFormatting); this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.debugOutput = !!args.showDevDebugOutput; + if (args.executable == undefined) + args.executable = args.target; // legacy compatibility if (args.ssh !== undefined) { if (args.ssh.forwardX11 === undefined) args.ssh.forwardX11 = true; @@ -74,7 +78,7 @@ 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(() => { + this.miDebugger.ssh(args.ssh, args.ssh.cwd, args.executable, args.arguments, args.terminal, false).then(() => { if (args.autorun) args.autorun.forEach(command => { this.miDebugger.sendUserInput(command); @@ -94,7 +98,7 @@ class GDBDebugSession extends MI2DebugSession { this.sendErrorResponse(response, 102, `Failed to SSH: ${err.toString()}`); }); } else { - this.miDebugger.load(args.cwd, args.target, args.arguments, args.terminal).then(() => { + this.miDebugger.load(args.cwd, args.executable, args.arguments, args.terminal, args.extendedRemote).then(() => { if (args.autorun) args.autorun.forEach(command => { this.miDebugger.sendUserInput(command);