Utilize GDB/MI Variable Objects for local variables

Replace own value parser with GDB's variable objects interface.
See https://sourceware.org/gdb/onlinedocs/gdb/GDB_002fMI-Variable-Objects.html
This commit is contained in:
gentoo90 2017-05-20 19:19:15 +03:00
commit f171d9f4ac
2 changed files with 61 additions and 42 deletions

View file

@ -196,6 +196,9 @@ export class MI2 extends EventEmitter implements IBackend {
]; ];
if (!attach) if (!attach)
cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\"")); cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\""));
// TODO: add extension parameter for enabling/disabling pretty printers
cmds.push(this.sendCommand("enable-pretty-printing"));
return cmds; return cmds;
} }
@ -658,6 +661,19 @@ export class MI2 extends EventEmitter implements IBackend {
}); });
} }
async varCreate(expression: string): Promise<MINode> {
if (trace)
this.log("stderr", "varCreate");
return this.sendCommand(`var-create - * "${expression}"`);
}
async varListChildren(name: string): Promise<MINode> {
if (trace)
this.log("stderr", "varListChildren");
//TODO: add `from` and `to` arguments
return this.sendCommand(`var-list-children --simple-values ${name}`);
}
logNoNewLine(type: string, msg: string) { logNoNewLine(type: string, msg: string) {
this.emit("msg", type, msg); this.emit("msg", type, msg);
} }

View file

@ -272,32 +272,49 @@ export class MI2DebugSession extends DebugSession {
return this.variableHandles.create(arg); return this.variableHandles.create(arg);
}; };
let miVarObjToVariable = (varObj: any): DebugProtocol.Variable => {
const evaluateName = MINode.valueOf(varObj, "name");
const value = MINode.valueOf(varObj, "value");
const numChild = parseInt(MINode.valueOf(varObj, "numchild"));
const dynamic = MINode.valueOf(varObj, "dynamic") || 0;
let displayHint, hasMore;
if (dynamic) {
displayHint = MINode.valueOf(varObj, "displayhint");
hasMore = parseInt(MINode.valueOf(varObj, "has_more"));
}
const isCompound = numChild > 0 ||
value === "{...}" ||
(dynamic > 0 && (displayHint === "array" || displayHint === "map"));
let res = {
name: MINode.valueOf(varObj, "exp"),
evaluateName,
type: MINode.valueOf(varObj, "type"),
value: value || "<value>",
variablesReference: isCompound ? createVariable(evaluateName) : 0
} as DebugProtocol.Variable;
return res;
};
if (typeof id == "string") { if (typeof id == "string") {
if (id.startsWith("@frame:")) { if (id.startsWith("@frame:")) {
let stack: Variable[]; let stack: Variable[];
try { try {
stack = await this.miDebugger.getStackVariables(this.threadID, parseInt(id.substr("@frame:".length))); stack = await this.miDebugger.getStackVariables(this.threadID, parseInt(id.substr("@frame:".length)));
for (const variable of stack) { for (const variable of stack) {
if (variable.valueStr !== undefined) { try {
let expanded = expandValue(createVariable, `{${variable.name}=${variable.valueStr})`, "", variable.raw); const varObj = await this.miDebugger.varCreate(variable.name);
if (expanded) { let v = miVarObjToVariable(varObj.resultRecords.results);
if (typeof expanded[0] == "string") v.name = variable.name;
expanded = [ variables.push(v);
{ }
name: "<value>", catch (err) {
value: prettyStringArray(expanded),
variablesReference: 0
}
];
variables.push(expanded[0]);
}
} else
variables.push({ variables.push({
name: variable.name, name: variable.name,
type: variable.type, value: err,
value: "<unknown>", variablesReference: 0
variablesReference: createVariable(variable.name)
}); });
}
} }
response.body = { response.body = {
variables: variables variables: variables
@ -310,32 +327,18 @@ export class MI2DebugSession extends DebugSession {
} }
else { else {
// Variable members // Variable members
let variable; let listChildren;
try { try {
variable = await this.miDebugger.evalExpression(JSON.stringify(id)); listChildren = await this.miDebugger.varListChildren(id);
try { const children: any[] = listChildren.result("children");
let expanded = expandValue(createVariable, variable.result("value"), id, variable); // TODO: use hasMore when it's > 0
if (!expanded) { // const hasMore = parseInt(listChildren.result("has_more"));
this.sendErrorResponse(response, 2, `Could not expand variable`); const vars = children.map(child => miVarObjToVariable(child[1]));
}
else { response.body = {
if (typeof expanded[0] == "string") variables: vars
expanded = [
{
name: "<value>",
value: prettyStringArray(expanded),
variablesReference: 0
}
];
response.body = {
variables: expanded
};
this.sendResponse(response);
}
}
catch (e) {
this.sendErrorResponse(response, 2, `Could not expand variable: ${e}`);
} }
this.sendResponse(response);
} }
catch (err) { catch (err) {
this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`); this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`);
@ -514,4 +517,4 @@ function prettyStringArray(strings) {
return JSON.stringify(strings); return JSON.stringify(strings);
} }
else return strings; else return strings;
} }