diff --git a/src/backend/backend.ts b/src/backend/backend.ts index f532f0ed..d47f89b3 100644 --- a/src/backend/backend.ts +++ b/src/backend/backend.ts @@ -33,6 +33,11 @@ export interface Variable { raw?: any; } +export interface RegisterValue { + index: number; + value: string; +} + export interface SSHArguments { forwardX11: boolean; host: string; diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 007fd209..e6411609 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -1,4 +1,4 @@ -import { Breakpoint, IBackend, Thread, Stack, SSHArguments, Variable, VariableObject, MIError } from "../backend"; +import { Breakpoint, IBackend, Thread, Stack, SSHArguments, Variable, RegisterValue, VariableObject, MIError } from "../backend"; import * as ChildProcess from "child_process"; import { EventEmitter } from "events"; import { parseMI, MINode } from '../mi_parse'; @@ -758,6 +758,57 @@ export class MI2 extends EventEmitter implements IBackend { return ret; } + async getRegisters(): Promise { + if (trace) + this.log("stderr", "getRegisters"); + + // Getting register names and values are separate GDB commands. + // We first retrieve the register names and then the values. + // The register names should never change, so we could cache and reuse them, + // but for now we just retrieve them every time to keep it simple. + const names = await this.getRegisterNames(); + const values = await this.getRegisterValues(); + const ret: Variable[] = []; + for (const val of values) { + const key = names[val.index]; + const value = val.value; + const type = "string"; + ret.push({ + name: key, + valueStr: value, + type: type + }); + } + return ret; + } + + async getRegisterNames(): Promise { + if (trace) + this.log("stderr", "getRegisterNames"); + const result = await this.sendCommand("data-list-register-names"); + const names = result.result('register-names'); + if (!Array.isArray(names)) { + throw new Error('Failed to retrieve register names.'); + } + return names.map(name => name.toString()); + } + + async getRegisterValues(): Promise { + if (trace) + this.log("stderr", "getRegisterValues"); + const result = await this.sendCommand("data-list-register-values N"); + const nodes = result.result('register-values'); + if (!Array.isArray(nodes)) { + throw new Error('Failed to retrieve register values.'); + } + const ret: RegisterValue[] = nodes.map(node => { + const index = parseInt(MINode.valueOf(node, "number")); + const value = MINode.valueOf(node, "value"); + return {index: index, value: value}; + }); + return ret; + } + examineMemory(from: number, length: number): Thenable { if (trace) this.log("stderr", "examineMemory"); diff --git a/src/mibase.ts b/src/mibase.ts index f0a19c6b..a8dabd49 100644 --- a/src/mibase.ts +++ b/src/mibase.ts @@ -405,7 +405,8 @@ export class MI2DebugSession extends DebugSession { return new Scope(scopeName, handle, expensive); }; - scopes.push(createScope("Local", false)); + scopes.push(createScope("Registers", false)); + scopes.push(createScope("Locals", false)); response.body = { scopes: scopes @@ -436,64 +437,74 @@ export class MI2DebugSession extends DebugSession { }; if (id instanceof VariableScope) { - let stack: Variable[]; try { - stack = await this.miDebugger.getStackVariables(id.threadId, id.level); - for (const variable of stack) { - if (this.useVarObjects) { - try { - const varObjName = VariableScope.variableName(args.variablesReference, variable.name); - let varObj: VariableObject; + if (id.name == "Registers") { + const registers = await this.miDebugger.getRegisters(); + for (const reg of registers) { + variables.push({ + name: reg.name, + value: reg.valueStr, + variablesReference: 0 + }); + } + } else { + const stack: Variable[] = await this.miDebugger.getStackVariables(id.threadId, id.level); + for (const variable of stack) { + if (this.useVarObjects) { try { - 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[name]; - const v = this.variableHandles.get(vId) as any; - v.applyChanges(change); - }); - 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, varObjName); - const varId = findOrCreateVariable(varObj); - varObj.exp = variable.name; - varObj.id = varId; - } else { - throw err; + const varObjName = VariableScope.variableName(args.variablesReference, variable.name); + let varObj: VariableObject; + try { + 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[name]; + const v = this.variableHandles.get(vId) as any; + v.applyChanges(change); + }); + 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, varObjName); + const varId = findOrCreateVariable(varObj); + varObj.exp = variable.name; + varObj.id = varId; + } else { + throw err; + } } + variables.push(varObj.toProtocolVariable()); + } catch (err) { + variables.push({ + name: variable.name, + value: `<${err}>`, + variablesReference: 0 + }); } - variables.push(varObj.toProtocolVariable()); - } catch (err) { - variables.push({ - name: variable.name, - value: `<${err}>`, - variablesReference: 0 - }); + } else { + if (variable.valueStr !== undefined) { + let expanded = expandValue(createVariable, `{${variable.name}=${variable.valueStr})`, "", variable.raw); + if (expanded) { + if (typeof expanded[0] == "string") + expanded = [ + { + name: "", + value: prettyStringArray(expanded), + variablesReference: 0 + } + ]; + variables.push(expanded[0]); + } + } else + variables.push({ + name: variable.name, + type: variable.type, + value: "", + variablesReference: createVariable(variable.name) + }); } - } else { - if (variable.valueStr !== undefined) { - let expanded = expandValue(createVariable, `{${variable.name}=${variable.valueStr})`, "", variable.raw); - if (expanded) { - if (typeof expanded[0] == "string") - expanded = [ - { - name: "", - value: prettyStringArray(expanded), - variablesReference: 0 - } - ]; - variables.push(expanded[0]); - } - } else - variables.push({ - name: variable.name, - type: variable.type, - value: "", - variablesReference: createVariable(variable.name) - }); } } response.body = {