Detect errors in spawned process

This commit is contained in:
Miro Spönemann 2020-02-25 14:08:08 +01:00
parent 2d9fa5615b
commit 3ed72de810
3 changed files with 72 additions and 10 deletions

View File

@ -65,15 +65,6 @@ export class ArduinoDebugSession extends GDBDebugSession {
} }
} }
protected async stackTraceRequest(response: DebugProtocol.StackTraceResponse, args: DebugProtocol.StackTraceArguments): Promise<void> {
try {
return super.stackTraceRequest(response, args);
} catch (err) {
this.sendErrorResponse(response, 1, err.message);
}
}
protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void { protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
try { try {
const frame: FrameVariableReference = { const frame: FrameVariableReference = {

View File

@ -4,9 +4,15 @@ import { spawn } from 'child_process';
import { GDBBackend } from 'cdt-gdb-adapter/dist/GDBBackend'; import { GDBBackend } from 'cdt-gdb-adapter/dist/GDBBackend';
import { MIFrameInfo } from 'cdt-gdb-adapter/dist/mi'; import { MIFrameInfo } from 'cdt-gdb-adapter/dist/mi';
import { ArduinoLaunchRequestArguments } from './arduino-debug-session'; import { ArduinoLaunchRequestArguments } from './arduino-debug-session';
import { ArduinoParser } from './arduino-parser';
export class ArduinoGDBBackend extends GDBBackend { export class ArduinoGDBBackend extends GDBBackend {
constructor() {
super();
this.parser = new ArduinoParser(this);
}
spawn(requestArgs: ArduinoLaunchRequestArguments): Promise<void> { spawn(requestArgs: ArduinoLaunchRequestArguments): Promise<void> {
if (!requestArgs.sketch) { if (!requestArgs.sketch) {
throw new Error('Missing argument: sketch'); throw new Error('Missing argument: sketch');
@ -26,7 +32,7 @@ export class ArduinoGDBBackend extends GDBBackend {
const proc = spawn(command, args); const proc = spawn(command, args);
this.proc = proc; this.proc = proc;
this.out = proc.stdin; this.out = proc.stdin;
return this.parser.parse(proc.stdout); return (this.parser as ArduinoParser).parseFull(proc);
} }
sendFileExecAndSymbols(): Promise<void> { sendFileExecAndSymbols(): Promise<void> {

View File

@ -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<void> {
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);
}
});
}
}