diff --git a/package.json b/package.json index 6da05f61..8f5ae7e4 100644 --- a/package.json +++ b/package.json @@ -436,6 +436,20 @@ ] }, "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}", + "target": "${2:192.168.0.1:2345}", + "remote": true, + "executable": "${1:./bin/executable}", + "cwd": "^\"\\${workspaceRoot}\"" + }, + "valuesFormatting": "parseText" } ] }, diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index ecf2ee20..068bcde7 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -50,18 +50,33 @@ export class MI2 extends EventEmitter implements IBackend { } } - load(cwd: string, target: string, procArgs: string, separateConsole: string): Thenable { - if (!nativePath.isAbsolute(target)) + load(cwd: string, target: string, procArgs: string, separateConsole: string, executable?: string, remote?: boolean): Thenable { + if (!remote && !nativePath.isAbsolute(target)) target = nativePath.join(cwd, target); + if (remote && !nativePath.isAbsolute(executable)) + executable = nativePath.join(cwd, executable); return new Promise((resolve, reject) => { this.isSSH = false; const args = this.preargs.concat(this.extraargs || []); + if (executable !== undefined) + args.push(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 (remote) { + 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 ${target}`), + this.sendCommand(`target-file-put "${escape(executable)}" ${remoteExecutable}`), + this.sendCommand(`gdb-set remote exec-file ./${remoteExecutable}`), + ]; + } else + promises = this.initCommands(target, cwd); if (procArgs && procArgs.length) promises.push(this.sendCommand("exec-arguments " + procArgs)); if (process.platform == "win32") { diff --git a/src/gdb.ts b/src/gdb.ts index 507f240a..9a651717 100644 --- a/src/gdb.ts +++ b/src/gdb.ts @@ -12,6 +12,8 @@ export interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArgum debugger_args: string[]; arguments: string; terminal: string; + executable: string; + remote: boolean; autorun: string[]; ssh: SSHArguments; valuesFormatting: ValuesFormattingMode; @@ -93,7 +95,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.target, args.arguments, args.terminal, args.executable, args.remote).then(() => { if (args.autorun) args.autorun.forEach(command => { this.miDebugger.sendUserInput(command);