diff --git a/debug_attributes.md b/debug_attributes.md index 31a14794..5f5d63d9 100644 --- a/debug_attributes.md +++ b/debug_attributes.md @@ -32,6 +32,7 @@ If the type is marked as `{...}` it means that it is a complex item can have mul | debuggerArgs | array | Both | Additional arguments to pass to GDB command line | | device | string | Both | Target Device Identifier | | executable | string | Both | Path of executable for symbols and program information. See also `loadFiles`, `symbolFiles` | +| gdbInterruptMode | string | Both | Whether GDB shall be interrupted using "exec-interrupt" (default) or by signaling "SIGINT" | | gdbPath | string | Both | This setting can be used to override the GDB path user/workspace setting for a particular launch configuration. This should be the full pathname to the executable (or name of the executable if it is in your PATH). Note that other toolchain executables with the configured prefix must still be available. | | gdbTarget | string | Both | For externally (servertype = "external") controlled GDB Servers you must specify the GDB target to connect to. This can either be a "hostname:port" combination or path to a serial port | | graphConfig | {object} | Both | Description of how graphing can be done. See our Wiki for details | diff --git a/package-lock.json b/package-lock.json index 5cbca827..bf2439b0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "cortex-debug", - "version": "1.13.0-pre4", + "version": "1.13.0-pre6", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "cortex-debug", - "version": "1.13.0-pre4", + "version": "1.13.0-pre6", "license": "MIT", "dependencies": { "@vscode/extension-telemetry": "^0.9.8", diff --git a/package.json b/package.json index 25231a1d..98baf5a1 100644 --- a/package.json +++ b/package.json @@ -754,6 +754,15 @@ }, "default": null }, + "gdbInterruptMode": { + "default": "exec-interrupt", + "description": "Whether GDB shall be interrupted using \"exec-interrupt\" (default) or by signaling \"SIGINT\"", + "type": "string", + "enum": [ + "exec-interrupt", + "SIGINT" + ] + }, "gdbTarget": { "default": null, "description": "For externally (servertype = \"external\") controlled GDB Servers you must specify the GDB target to connect to. This can either be a \"hostname:port\" combination or path to a serial port", @@ -1883,6 +1892,15 @@ }, "default": null }, + "gdbInterruptMode": { + "default": "exec-interrupt", + "description": "Whether GDB shall be interrupted using \"exec-interrupt\" (default) or by signaling \"SIGINT\"", + "type": "string", + "enum": [ + "exec-interrupt", + "SIGINT" + ] + }, "gdbTarget": { "default": null, "description": "For externally (servertype = \"external\") controlled GDB Servers you must specify the GDB target to connect to. This can either be a \"hostname:port\" combination or path to a serial port", diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 5033cf6a..0349e92a 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -7,7 +7,7 @@ import { posix } from 'path'; import * as os from 'os'; import { ServerConsoleLog } from '../server'; import { hexFormat } from '../../frontend/utils'; -import { ADAPTER_DEBUG_MODE } from '../../common'; +import { ADAPTER_DEBUG_MODE, GDBInterruptMode } from '../../common'; const path = posix; export interface ReadMemResults { @@ -47,6 +47,7 @@ const trace = false; export class MI2 extends EventEmitter implements IBackend { public debugOutput: ADAPTER_DEBUG_MODE; + public interruptMode: GDBInterruptMode = GDBInterruptMode.EXEC_INTERRUPT; public procEnv: any; protected currentToken: number = 1; protected nextTokenComing = 1; // This will be the next token output from gdb @@ -495,11 +496,21 @@ export class MI2 extends EventEmitter implements IBackend { if (trace) { this.log('stderr', 'interrupt ' + arg); } - return new Promise((resolve, reject) => { - this.sendCommand(`exec-interrupt ${arg}`).then((info) => { - resolve(info.resultRecords.resultClass === 'done'); - }, reject); - }); + if (this.interruptMode == GDBInterruptMode.EXEC_INTERRUPT) { + return new Promise((resolve, reject) => { + this.sendCommand(`exec-interrupt ${arg}`).then((info) => { + resolve(info.resultRecords.resultClass === 'done'); + }, reject); + }); + } else if (this.interruptMode == GDBInterruptMode.SIGINT) { + if (this.process.kill('SIGINT')) { + return Promise.resolve(true); + } else { + return Promise.reject(new Error('Could not send SIGINT to gdb')); + } + } else { + this.log('stderr', `WARNING: Invalid GDB interrupt mode '${this.interruptMode as string}'`); + } } public continue(threadId: number): Thenable { diff --git a/src/common.ts b/src/common.ts index 22fdcf1e..7f7c9f10 100644 --- a/src/common.ts +++ b/src/common.ts @@ -262,6 +262,7 @@ export interface ConfigurationArguments extends DebugProtocol.LaunchRequestArgum serverpath: string; gdbPath: string; gdbServerConsolePort: number; + gdbInterruptMode: GDBInterruptMode; objdumpPath: string; serverArgs: string[]; serverCwd: string; @@ -365,6 +366,11 @@ export enum CTIAction { 'resume' } +export enum GDBInterruptMode { + EXEC_INTERRUPT = 'exec-interrupt', + SIGINT = 'SIGINT' +} + export interface GDBServerController extends EventEmitter { portsNeeded: string[]; name: string; diff --git a/src/gdb.ts b/src/gdb.ts index 6b61b84e..2719d06e 100755 --- a/src/gdb.ts +++ b/src/gdb.ts @@ -938,6 +938,9 @@ export class GDBDebugSession extends LoggingDebugSession { this.miDebugger = new MI2(gdbExePath, gdbargs); this.miDebugger.debugOutput = this.args.showDevDebugOutput; + if (this.args.gdbInterruptMode) { + this.miDebugger.interruptMode = this.args.gdbInterruptMode; + } this.miDebugger.on('launcherror', (err) => { const msg = 'Could not start GDB process, does the program exist in filesystem?\n' + err.toString() + '\n'; this.launchErrorResponse(response, 103, msg); @@ -1001,6 +1004,9 @@ export class GDBDebugSession extends LoggingDebugSession { liveGdb.setupEvents(mi2); const commands = [...this.gdbInitCommands]; mi2.debugOutput = this.args.showDevDebugOutput; + if (this.args.gdbInterruptMode) { + mi2.interruptMode = this.args.gdbInterruptMode; + } commands.push('interpreter-exec console "set stack-cache off"'); commands.push('interpreter-exec console "set remote interrupt-on-connect off"'); if (this.serverController) { @@ -1591,7 +1597,7 @@ export class GDBDebugSession extends LoggingDebugSession { } }); try { - await this.miDebugger.sendCommand('exec-interrupt'); + await this.miDebugger.interrupt(); } catch (e) { // The timeout will take care of it... this.handleMsg('log', `Could not interrupt program. Trying to end session anyways ${e}\n`); @@ -1675,7 +1681,7 @@ export class GDBDebugSession extends LoggingDebugSession { restartProcessing(); } else { this.miDebugger.once('generic-stopped', restartProcessing); - this.miDebugger.sendCommand('exec-interrupt'); + this.miDebugger.interrupt(); } }); } @@ -2158,7 +2164,7 @@ export class GDBDebugSession extends LoggingDebugSession { this.miDebugger.once('generic-stopped', () => { createBreakpoints(); }); - this.miDebugger.sendCommand('exec-interrupt'); + this.miDebugger.interrupt(); } }