Improved error reporting on launch

This commit is contained in:
Miro Spönemann 2019-12-20 11:51:49 +01:00
parent 38ab95973e
commit 1441b685ee
4 changed files with 45 additions and 41 deletions

View File

@ -1,23 +1,12 @@
import { injectable, inject } from 'inversify'; import { injectable } from 'inversify';
import { DebugAdapterContribution, DebugAdapterExecutable, DebugAdapterSessionFactory } from '@theia/debug/lib/common/debug-model'; import { DebugAdapterContribution, DebugAdapterExecutable, DebugAdapterSessionFactory } from '@theia/debug/lib/common/debug-model';
import { DebugConfiguration } from "@theia/debug/lib/common/debug-configuration"; import { DebugConfiguration } from "@theia/debug/lib/common/debug-configuration";
import { MaybePromise } from "@theia/core/lib/common/types"; import { MaybePromise } from "@theia/core/lib/common/types";
import { IJSONSchema, IJSONSchemaSnippet } from "@theia/core/lib/common/json-schema"; import { IJSONSchema, IJSONSchemaSnippet } from "@theia/core/lib/common/json-schema";
import * as path from 'path'; import * as path from 'path';
import { BoardsService } from 'arduino-ide-extension/lib/common/protocol/boards-service';
import { CoreService } from 'arduino-ide-extension/lib/common/protocol/core-service';
import { FileSystem } from '@theia/filesystem/lib/common';
@injectable() @injectable()
export class ArduinoDebugAdapterContribution implements DebugAdapterContribution { export class ArduinoDebugAdapterContribution implements DebugAdapterContribution {
@inject(BoardsService)
protected readonly boardsService: BoardsService;
@inject(CoreService)
protected readonly coreService: CoreService;
@inject(FileSystem)
protected readonly fileSystem: FileSystem;
type = "arduino"; type = "arduino";
@ -39,26 +28,25 @@ export class ArduinoDebugAdapterContribution implements DebugAdapterContribution
"description": "path to the sketch root ino file", "description": "path to the sketch root ino file",
"default": "${file}", "default": "${file}",
}, },
"runToMain": {
"description": "If enabled the debugger will run until the start of the main function.",
"type": "boolean",
"default": false
},
"fqbn": { "fqbn": {
"type": "string", "type": "string",
"description": "Fully-qualified board name to debug on", "description": "Fully-qualified board name to debug on",
"default": "" "default": ""
}, },
"runToMain": {
"description": "If enabled the debugger will run until the start of the main function.",
"type": "boolean",
"default": false
},
"verbose": { "verbose": {
"type": "boolean", "type": "boolean",
"description": "Produce verbose log output", "description": "Produce verbose log output",
"default": "false" "default": false
}, },
"debugDebugAdapter": { "debugDebugAdapter": {
"type": "boolean", "type": "boolean",
"description": "Start the debug adapter in debug mode (with --inspect-brk)", "description": "Start the debug adapter in debug mode (with --inspect-brk)",
"default": "false" "default": false
}, },
} }
} }
@ -74,7 +62,7 @@ export class ArduinoDebugAdapterContribution implements DebugAdapterContribution
if (!!config.debugDebugAdapter) { if (!!config.debugDebugAdapter) {
args.push('--inspect-brk') args.push('--inspect-brk')
} }
args = args.concat([path.join(__dirname, 'debug-adapter', 'index.js')]); args = args.concat([path.join(__dirname, 'debug-adapter', 'main')]);
return { return {
command: "node", command: "node",
@ -88,11 +76,7 @@ export class ArduinoDebugAdapterContribution implements DebugAdapterContribution
name: this.label, name: this.label,
type: this.type, type: this.type,
request: "launch", request: "launch",
sketch: "${file}", sketch: "${file}",
verbose: true,
runToMain: true,
}, },
<DebugConfiguration>{ <DebugConfiguration>{
name: this.label + " (explicit)", name: this.label + " (explicit)",
@ -105,8 +89,8 @@ export class ArduinoDebugAdapterContribution implements DebugAdapterContribution
gdbServer: "${boardTools:openocd}", gdbServer: "${boardTools:openocd}",
gdbServerArguments: ["-s", "${boardTools:openocd-scripts}", "--file", "${board:openocd-debug-file}"], gdbServerArguments: ["-s", "${boardTools:openocd-scripts}", "--file", "${board:openocd-debug-file}"],
verbose: true, runToMain: false,
runToMain: true, verbose: false,
} }
]; ];
} }

View File

@ -25,7 +25,7 @@
import { normalize } from 'path'; import { normalize } from 'path';
import { DebugProtocol } from 'vscode-debugprotocol'; import { DebugProtocol } from 'vscode-debugprotocol';
import { Logger, logger, InitializedEvent, OutputEvent, Scope, TerminatedEvent } from 'vscode-debugadapter'; import { Logger, logger, InitializedEvent, OutputEvent, Scope, TerminatedEvent, ErrorDestination } from 'vscode-debugadapter';
import { GDBDebugSession, RequestArguments, FrameVariableReference, FrameReference } from 'cdt-gdb-adapter/dist/GDBDebugSession'; import { GDBDebugSession, RequestArguments, FrameVariableReference, FrameReference } from 'cdt-gdb-adapter/dist/GDBDebugSession';
import { GDBBackend } from 'cdt-gdb-adapter/dist/GDBBackend'; import { GDBBackend } from 'cdt-gdb-adapter/dist/GDBBackend';
import { CmsisBackend } from './cmsis-backend'; import { CmsisBackend } from './cmsis-backend';
@ -117,7 +117,6 @@ export class CmsisDebugSession extends GDBDebugSession {
protected async setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): Promise<void> { protected async setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): Promise<void> {
await super.setBreakPointsRequest(response, args); await super.setBreakPointsRequest(response, args);
return;
} }
protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void { protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
@ -224,13 +223,10 @@ export class CmsisDebugSession extends GDBDebugSession {
this.gdb.on('notifyAsync', (resultClass, resultData) => this.handleGDBNotify(resultClass, resultData)); this.gdb.on('notifyAsync', (resultClass, resultData) => this.handleGDBNotify(resultClass, resultData));
// gdb server has main info channel on stderr // gdb server has main info channel on stderr
this.gdbServer.on('stderr', data => { this.gdbServer.on('stderr', data => this.sendEvent(new OutputEvent(data, 'stdout')));
this.sendEvent(new OutputEvent(data, 'stdout')) const gdbServerErrors: any[] = []
}); const gdbServerErrorAccumulator = (message: any) => gdbServerErrors.push(message);
this.gdbServer.on('error', message => { this.gdbServer.on('error', gdbServerErrorAccumulator);
this.sendEvent(new TerminatedEvent());
throw message;
});
try { try {
this.symbolTable = new SymbolTable(args.program, args.objdump); this.symbolTable = new SymbolTable(args.program, args.objdump);
@ -264,12 +260,18 @@ export class CmsisDebugSession extends GDBDebugSession {
this.sendEvent(new OutputEvent(`Starting debugger: ${JSON.stringify(args)}`)); this.sendEvent(new OutputEvent(`Starting debugger: ${JSON.stringify(args)}`));
await this.gdbServer.spawn(args); await this.gdbServer.spawn(args);
await this.spawn(args); await this.spawn(args);
if (gdbServerErrors.length > 0) {
throw new Error(gdbServerErrors.join('\n'));
}
// Send commands // Send commands
await mi.sendTargetAsyncOn(this.gdb); await mi.sendTargetAsyncOn(this.gdb);
await mi.sendTargetSelectRemote(this.gdb, remote); await mi.sendTargetSelectRemote(this.gdb, remote);
await mi.sendMonitorResetHalt(this.gdb); await mi.sendMonitorResetHalt(this.gdb);
this.sendEvent(new OutputEvent(`Attached to debugger on port ${port}`)); this.sendEvent(new OutputEvent(`Attached to debugger on port ${port}`));
if (gdbServerErrors.length > 0) {
throw new Error(gdbServerErrors.join('\n'));
}
// Download image // Download image
const progressListener = (percent: number) => this.progressEvent(percent, 'Loading Image'); const progressListener = (percent: number) => this.progressEvent(percent, 'Loading Image');
@ -287,8 +289,17 @@ export class CmsisDebugSession extends GDBDebugSession {
await mi.sendBreakOnFunction(this.gdb); await mi.sendBreakOnFunction(this.gdb);
} }
if (gdbServerErrors.length > 0) {
throw new Error(gdbServerErrors.join('\n'));
}
this.sendEvent(new OutputEvent(`Image loaded: ${args.program}`)); this.sendEvent(new OutputEvent(`Image loaded: ${args.program}`));
this.sendEvent(new InitializedEvent()); this.sendEvent(new InitializedEvent());
this.gdbServer.removeListener('error', gdbServerErrorAccumulator);
this.gdbServer.on('error', message => {
logger.error(JSON.stringify(message));
this.sendEvent(new TerminatedEvent());
});
} }
private async getGlobalVariables(frameHandle: number): Promise<DebugProtocol.Variable[]> { private async getGlobalVariables(frameHandle: number): Promise<DebugProtocol.Variable[]> {
@ -378,6 +389,15 @@ export class CmsisDebugSession extends GDBDebugSession {
})); }));
} }
protected sendErrorResponse(response: DebugProtocol.Response,
codeOrMessage: number | DebugProtocol.Message, format?: string,
variables?: any, dest?: ErrorDestination): void {
if (!!format && (dest === undefined || dest === ErrorDestination.User)) {
format = format.replace('\n', '<br>');
}
super.sendErrorResponse(response, codeOrMessage, format, variables, dest);
}
protected async stopSession() { protected async stopSession() {
// Pause debugging // Pause debugging
if (this.isRunning) { if (this.isRunning) {

View File

@ -6,7 +6,7 @@ import * as path from 'path';
import * as os from 'os'; import * as os from 'os';
const LAUNCH_REGEX = /GDB server started/; const LAUNCH_REGEX = /GDB server started/;
const ERROR_REGEX = /:ERROR:gdbserver:/; const ERROR_REGEX = /^error:/mi;
const PERCENT_MULTIPLIER = 100 / 40; // pyOCD outputs 40 markers for progress const PERCENT_MULTIPLIER = 100 / 40; // pyOCD outputs 40 markers for progress
export class OpenocdServer extends AbstractServer { export class OpenocdServer extends AbstractServer {