From ca0f86a37c26dedd5425e7ed997b632f9b5e7b5c Mon Sep 17 00:00:00 2001 From: gentoo90 Date: Sat, 10 Jun 2017 14:55:41 +0300 Subject: [PATCH 1/3] Don't swallow errors on varUpdate() Add MIError class for exceptions. Check error type on varUpdate() failure and rethrow if it's not "Variable object not found". --- src/backend/backend.ts | 35 +++++++++++++++++++++++++++++++++++ src/backend/mi2/mi2.ts | 6 +++--- src/mibase.ts | 15 ++++++++++----- 3 files changed, 48 insertions(+), 8 deletions(-) diff --git a/src/backend/backend.ts b/src/backend/backend.ts index d85cd26..1a04c7b 100644 --- a/src/backend/backend.ts +++ b/src/backend/backend.ts @@ -123,3 +123,38 @@ export class VariableObject { return res; } } + +// from https://gist.github.com/justmoon/15511f92e5216fa2624b#gistcomment-1928632 +export interface MIError extends Error { + readonly name: string; + readonly message: string; + readonly source: string; +}; +export interface MIErrorConstructor { + new (message: string, source: string): MIError; + readonly prototype: MIError; +} + +export const MIError: MIErrorConstructor = class MIError { + readonly name: string; + readonly message: string; + readonly source: string; + public constructor(message: string, source: string) { + Object.defineProperty(this, 'name', { + get: () => (this.constructor as any).name, + }); + Object.defineProperty(this, 'message', { + get: () => message, + }); + Object.defineProperty(this, 'source', { + get: () => source, + }); + Error.captureStackTrace(this, this.constructor); + } + + public toString() { + return `${this.message} (from ${this.source})`; + } +}; +Object.setPrototypeOf(MIError as any, Object.create(Error.prototype)); +MIError.prototype.constructor = MIError; diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 9a89594..18f45fb 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -1,4 +1,4 @@ -import { Breakpoint, IBackend, Stack, SSHArguments, Variable, VariableObject } from "../backend" +import { Breakpoint, IBackend, Stack, SSHArguments, Variable, VariableObject, MIError } from "../backend" import * as ChildProcess from "child_process" import { EventEmitter } from "events" import { parseMI, MINode } from '../mi_parse'; @@ -729,11 +729,11 @@ export class MI2 extends EventEmitter implements IBackend { this.handlers[sel] = (node: MINode) => { if (node && node.resultRecords && node.resultRecords.resultClass === "error") { if (suppressFailure) { - this.log("stderr", "WARNING: Error executing command '" + command + "'"); + this.log("stderr", `WARNING: Error executing command '${command}'`); resolve(node); } else - reject((node.result("msg") || "Internal error") + " (from " + command + ")"); + reject(new MIError(node.result("msg") || "Internal error", command)); } else resolve(node); diff --git a/src/mibase.ts b/src/mibase.ts index aaeef58..d054823 100644 --- a/src/mibase.ts +++ b/src/mibase.ts @@ -1,6 +1,6 @@ import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter'; import { DebugProtocol } from 'vscode-debugprotocol'; -import { Breakpoint, IBackend, Variable, VariableObject, ValuesFormattingMode } from './backend/backend'; +import { Breakpoint, IBackend, Variable, VariableObject, ValuesFormattingMode, MIError } from './backend/backend'; import { MINode } from './backend/mi_parse'; import { expandValue, isExpandable } from './backend/gdb_expansion'; import { MI2 } from './backend/mi2/mi2'; @@ -349,10 +349,15 @@ export class MI2DebugSession extends DebugSession { varObj = this.variableHandles.get(varId) as any; } catch (err) { - varObj = await this.miDebugger.varCreate(variable.name, variable.name); - const varId = findOrCreateVariable(varObj); - varObj.exp = variable.name; - varObj.id = varId; + if (err instanceof MIError && err.message == "Variable object not found") { + varObj = await this.miDebugger.varCreate(variable.name, variable.name); + const varId = findOrCreateVariable(varObj); + varObj.exp = variable.name; + varObj.id = varId; + } + else { + throw err; + } } variables.push(varObj.toProtocolVariable()); } From c313af85b28a58e018fb550caaaa27daefde6a8d Mon Sep 17 00:00:00 2001 From: gentoo90 Date: Sat, 10 Jun 2017 15:01:21 +0300 Subject: [PATCH 2/3] Fix varListChildren() when there are no children Return [] instead of throwing exception. --- src/backend/mi2/mi2.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 18f45fb..18bd5ca 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -679,7 +679,7 @@ export class MI2 extends EventEmitter implements IBackend { this.log("stderr", "varListChildren"); //TODO: add `from` and `to` arguments const res = await this.sendCommand(`var-list-children --all-values ${name}`); - const children = res.result("children"); + const children = res.result("children") || []; let omg: VariableObject[] = children.map(child => new VariableObject(child[1])); return omg; } From 90c7b76f784dbedea017697272a36ef37a059720 Mon Sep 17 00:00:00 2001 From: gentoo90 Date: Sat, 10 Jun 2017 15:05:32 +0300 Subject: [PATCH 3/3] Add "var_" prefix to var object names The name of var object should begin with a letter, so names like "_id" caused errors. --- src/mibase.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/mibase.ts b/src/mibase.ts index d054823..0b623fd 100644 --- a/src/mibase.ts +++ b/src/mibase.ts @@ -335,22 +335,23 @@ export class MI2DebugSession extends DebugSession { for (const variable of stack) { if (this.useVarObjects) { try { + let varObjName = `var_${variable.name}`; let varObj: VariableObject; try { - const changes = await this.miDebugger.varUpdate(variable.name); + const changes = await this.miDebugger.varUpdate(varObjName); const changelist = changes.result("changelist"); changelist.forEach((change) => { const name = MINode.valueOf(change, "name"); - const vId = this.variableHandlesReverse[variable.name]; + const vId = this.variableHandlesReverse[varObjName]; const v = this.variableHandles.get(vId) as any; v.applyChanges(change); }); - const varId = this.variableHandlesReverse[variable.name]; + const varId = this.variableHandlesReverse[varObjName]; varObj = this.variableHandles.get(varId) as any; } catch (err) { if (err instanceof MIError && err.message == "Variable object not found") { - varObj = await this.miDebugger.varCreate(variable.name, variable.name); + varObj = await this.miDebugger.varCreate(variable.name, varObjName); const varId = findOrCreateVariable(varObj); varObj.exp = variable.name; varObj.id = varId;