From 3ed72de810b71095931160096324fbebea969ee2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Sp=C3=B6nemann?= Date: Tue, 25 Feb 2020 14:08:08 +0100 Subject: [PATCH] Detect errors in spawned process --- .../debug-adapter/arduino-debug-session.ts | 9 --- .../node/debug-adapter/arduino-gdb-backend.ts | 8 ++- .../src/node/debug-adapter/arduino-parser.ts | 65 +++++++++++++++++++ 3 files changed, 72 insertions(+), 10 deletions(-) create mode 100644 arduino-debugger-extension/src/node/debug-adapter/arduino-parser.ts diff --git a/arduino-debugger-extension/src/node/debug-adapter/arduino-debug-session.ts b/arduino-debugger-extension/src/node/debug-adapter/arduino-debug-session.ts index 1b2f6683..d6c67746 100644 --- a/arduino-debugger-extension/src/node/debug-adapter/arduino-debug-session.ts +++ b/arduino-debugger-extension/src/node/debug-adapter/arduino-debug-session.ts @@ -65,15 +65,6 @@ export class ArduinoDebugSession extends GDBDebugSession { } } - protected async stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): Promise { - try { - - return super.stackTraceRequest(response, args); - } catch (err) { - this.sendErrorResponse(response, 1, err.message); - } - } - protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void { try { const frame: FrameVariableReference = { diff --git a/arduino-debugger-extension/src/node/debug-adapter/arduino-gdb-backend.ts b/arduino-debugger-extension/src/node/debug-adapter/arduino-gdb-backend.ts index a805522f..c791f1a0 100644 --- a/arduino-debugger-extension/src/node/debug-adapter/arduino-gdb-backend.ts +++ b/arduino-debugger-extension/src/node/debug-adapter/arduino-gdb-backend.ts @@ -4,9 +4,15 @@ import { spawn } from 'child_process'; import { GDBBackend } from 'cdt-gdb-adapter/dist/GDBBackend'; import { MIFrameInfo } from 'cdt-gdb-adapter/dist/mi'; import { ArduinoLaunchRequestArguments } from './arduino-debug-session'; +import { ArduinoParser } from './arduino-parser'; export class ArduinoGDBBackend extends GDBBackend { + constructor() { + super(); + this.parser = new ArduinoParser(this); + } + spawn(requestArgs: ArduinoLaunchRequestArguments): Promise { if (!requestArgs.sketch) { throw new Error('Missing argument: sketch'); @@ -26,7 +32,7 @@ export class ArduinoGDBBackend extends GDBBackend { const proc = spawn(command, args); this.proc = proc; this.out = proc.stdin; - return this.parser.parse(proc.stdout); + return (this.parser as ArduinoParser).parseFull(proc); } sendFileExecAndSymbols(): Promise { diff --git a/arduino-debugger-extension/src/node/debug-adapter/arduino-parser.ts b/arduino-debugger-extension/src/node/debug-adapter/arduino-parser.ts new file mode 100644 index 00000000..51507da5 --- /dev/null +++ b/arduino-debugger-extension/src/node/debug-adapter/arduino-parser.ts @@ -0,0 +1,65 @@ +import { ChildProcessWithoutNullStreams } from 'child_process'; +import { Readable } from 'stream'; +import { MIParser } from "cdt-gdb-adapter/dist/MIParser"; + +const READY_TIMEOUT = 7000; +const LINE_REGEX = /(.*)(\r?\n)/; + +export class ArduinoParser extends MIParser { + + parseFull(proc: ChildProcessWithoutNullStreams): Promise { + return new Promise((resolve, reject) => { + proc.on('error', reject); + let ready = false; + proc.on('exit', () => { + if (!ready) { + reject(new Error('The gdb debugger terminated unexpectedly.')); + } + }); + + const timeout = setTimeout(() => { + reject(new Error(`No response from gdb after ${READY_TIMEOUT} ms.`)); + }, READY_TIMEOUT); + this.waitReady = () => { + ready = true; + clearTimeout(timeout); + resolve(); + } + this.readInputStream(proc.stdout); + this.readErrorStream(proc.stderr, reject); + }); + } + + private readInputStream(stream: Readable) { + let buff = ''; + stream.on('data', chunk => { + buff += chunk.toString(); + let regexArray = LINE_REGEX.exec(buff); + while (regexArray) { + this.line = regexArray[1]; + this.pos = 0; + this.handleLine(); + buff = buff.substring(regexArray[1].length + regexArray[2].length); + regexArray = LINE_REGEX.exec(buff); + } + }); + } + + private readErrorStream(stream: Readable, reject: (reason?: any) => void) { + let buff = ''; + stream.on('data', chunk => { + buff += chunk.toString(); + let regexArray = LINE_REGEX.exec(buff); + while (regexArray) { + const line = regexArray[1]; + this.gdb.emit('consoleStreamOutput', line + '\n', 'stderr'); + if (line.toLowerCase().startsWith('error')) { + reject(new Error(line)); + } + buff = buff.substring(regexArray[1].length + regexArray[2].length); + regexArray = LINE_REGEX.exec(buff); + } + }); + } + +}