Merge branch 'master' of github.com:WebFreak001/code-debug
This commit is contained in:
commit
7aec463e19
7 changed files with 402 additions and 118 deletions
62
package.json
62
package.json
|
|
@ -101,6 +101,16 @@
|
|||
"description": "Additional arguments to pass to GDB",
|
||||
"default": []
|
||||
},
|
||||
"valuesFormatting": {
|
||||
"type": "string",
|
||||
"description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any",
|
||||
"default": "parseText",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"parseText",
|
||||
"prettyPrinters"
|
||||
]
|
||||
},
|
||||
"printCalls": {
|
||||
"type": "boolean",
|
||||
"description": "Prints all GDB calls to the console",
|
||||
|
|
@ -192,6 +202,16 @@
|
|||
"description": "If true this will connect to a gdbserver instead of attaching to a PID",
|
||||
"default": false
|
||||
},
|
||||
"valuesFormatting": {
|
||||
"type": "string",
|
||||
"description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any",
|
||||
"default": "parseText",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"parseText",
|
||||
"prettyPrinters"
|
||||
]
|
||||
},
|
||||
"printCalls": {
|
||||
"type": "boolean",
|
||||
"description": "Prints all GDB calls to the console",
|
||||
|
|
@ -466,6 +486,16 @@
|
|||
"description": "Additional arguments to pass to LLDB",
|
||||
"default": []
|
||||
},
|
||||
"valuesFormatting": {
|
||||
"type": "string",
|
||||
"description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any",
|
||||
"default": "parseText",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"parseText",
|
||||
"prettyPrinters"
|
||||
]
|
||||
},
|
||||
"printCalls": {
|
||||
"type": "boolean",
|
||||
"description": "Prints all lldb calls to the console",
|
||||
|
|
@ -552,6 +582,16 @@
|
|||
"type": "string",
|
||||
"description": "PID of running program or program name"
|
||||
},
|
||||
"valuesFormatting": {
|
||||
"type": "string",
|
||||
"description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any",
|
||||
"default": "parseText",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"parseText",
|
||||
"prettyPrinters"
|
||||
]
|
||||
},
|
||||
"printCalls": {
|
||||
"type": "boolean",
|
||||
"description": "Prints all LLDB calls to the console",
|
||||
|
|
@ -713,6 +753,16 @@
|
|||
"description": "Additional arguments to pass to mago",
|
||||
"default": []
|
||||
},
|
||||
"valuesFormatting": {
|
||||
"type": "string",
|
||||
"description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any",
|
||||
"default": "parseText",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"parseText",
|
||||
"prettyPrinters"
|
||||
]
|
||||
},
|
||||
"printCalls": {
|
||||
"type": "boolean",
|
||||
"description": "Prints all mago calls to the console",
|
||||
|
|
@ -739,6 +789,16 @@
|
|||
"type": "string",
|
||||
"description": "PID of running program or program name"
|
||||
},
|
||||
"valuesFormatting": {
|
||||
"type": "string",
|
||||
"description": "Set the way of showing variable values. 'disabled' - show value as is, 'parseText' - parse debuggers output text into structure, 'prettyPrinters' - enable debuggers custom pretty-printers if there are any",
|
||||
"default": "parseText",
|
||||
"enum": [
|
||||
"disabled",
|
||||
"parseText",
|
||||
"prettyPrinters"
|
||||
]
|
||||
},
|
||||
"printCalls": {
|
||||
"type": "boolean",
|
||||
"description": "Prints all mago calls to the console",
|
||||
|
|
@ -834,4 +894,4 @@
|
|||
"@types/node": "^7.0.5",
|
||||
"@types/mocha": "^2.2.39"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
import { MINode } from "./mi_parse";
|
||||
import { DebugProtocol } from "vscode-debugprotocol/lib/debugProtocol";
|
||||
|
||||
export type ValuesFormattingMode = "disabled" | "parseText" | "prettyPrinters";
|
||||
|
||||
export interface Breakpoint {
|
||||
file?: string;
|
||||
line?: number;
|
||||
|
|
@ -59,4 +64,62 @@ export interface IBackend {
|
|||
isReady(): boolean;
|
||||
changeVariable(name: string, rawValue: string): Thenable<any>;
|
||||
examineMemory(from: number, to: number): Thenable<any>;
|
||||
}
|
||||
}
|
||||
|
||||
export class VariableObject {
|
||||
name: string;
|
||||
exp: string;
|
||||
numchild: number;
|
||||
type: string;
|
||||
value: string;
|
||||
threadId: string;
|
||||
frozen: boolean;
|
||||
dynamic: boolean;
|
||||
displayhint: string;
|
||||
has_more: boolean;
|
||||
id: number;
|
||||
constructor(node: any) {
|
||||
this.name = MINode.valueOf(node, "name");
|
||||
this.exp = MINode.valueOf(node, "exp");
|
||||
this.numchild = parseInt(MINode.valueOf(node, "numchild"));
|
||||
this.type = MINode.valueOf(node, "type");
|
||||
this.value = MINode.valueOf(node, "value");
|
||||
this.threadId = MINode.valueOf(node, "thread-id");
|
||||
this.frozen = !!MINode.valueOf(node, "frozen");
|
||||
this.dynamic = !!MINode.valueOf(node, "dynamic");
|
||||
this.displayhint = MINode.valueOf(node, "displayhint");
|
||||
// TODO: use has_more when it's > 0
|
||||
this.has_more = !!MINode.valueOf(node, "has_more");
|
||||
}
|
||||
|
||||
public applyChanges(node: MINode) {
|
||||
this.value = MINode.valueOf(node, "value");
|
||||
if (!!MINode.valueOf(node, "type_changed")) {
|
||||
this.type = MINode.valueOf(node, "new_type");
|
||||
}
|
||||
this.dynamic = !!MINode.valueOf(node, "dynamic");
|
||||
this.displayhint = MINode.valueOf(node, "displayhint");
|
||||
this.has_more = !!MINode.valueOf(node, "has_more");
|
||||
}
|
||||
|
||||
public isCompound(): boolean {
|
||||
return this.numchild > 0 ||
|
||||
this.value === "{...}" ||
|
||||
(this.dynamic && (this.displayhint === "array" || this.displayhint === "map"));
|
||||
}
|
||||
|
||||
public toProtocolVariable(): DebugProtocol.Variable {
|
||||
let res: DebugProtocol.Variable = {
|
||||
name: this.exp,
|
||||
evaluateName: this.name,
|
||||
value: (this.value === void 0) ? "<unknown>" : this.value,
|
||||
type: this.type,
|
||||
// kind: this.displayhint,
|
||||
variablesReference: this.id
|
||||
};
|
||||
if (this.displayhint) {
|
||||
res.kind = this.displayhint;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Breakpoint, IBackend, Stack, SSHArguments, Variable } from "../backend"
|
||||
import { Breakpoint, IBackend, Stack, SSHArguments, Variable, VariableObject } from "../backend"
|
||||
import * as ChildProcess from "child_process"
|
||||
import { EventEmitter } from "events"
|
||||
import { parseMI, MINode } from '../mi_parse';
|
||||
|
|
@ -196,6 +196,9 @@ export class MI2 extends EventEmitter implements IBackend {
|
|||
];
|
||||
if (!attach)
|
||||
cmds.push(this.sendCommand("file-exec-and-symbols \"" + escape(target) + "\""));
|
||||
if (this.prettyPrint)
|
||||
cmds.push(this.sendCommand("enable-pretty-printing"));
|
||||
|
||||
return cmds;
|
||||
}
|
||||
|
||||
|
|
@ -617,27 +620,25 @@ export class MI2 extends EventEmitter implements IBackend {
|
|||
});
|
||||
}
|
||||
|
||||
getStackVariables(thread: number, frame: number): Thenable<Variable[]> {
|
||||
async getStackVariables(thread: number, frame: number): Promise<Variable[]> {
|
||||
if (trace)
|
||||
this.log("stderr", "getStackVariables");
|
||||
return new Promise((resolve, reject) => {
|
||||
this.sendCommand("stack-list-variables --thread " + thread + " --frame " + frame + " --simple-values").then((result) => {
|
||||
let variables = result.result("variables");
|
||||
let ret: Variable[] = [];
|
||||
variables.forEach(element => {
|
||||
const key = MINode.valueOf(element, "name");
|
||||
const value = MINode.valueOf(element, "value");
|
||||
const type = MINode.valueOf(element, "type");
|
||||
ret.push({
|
||||
name: key,
|
||||
valueStr: value,
|
||||
type: type,
|
||||
raw: element
|
||||
});
|
||||
});
|
||||
resolve(ret);
|
||||
}, reject);
|
||||
});
|
||||
|
||||
const result = await this.sendCommand(`stack-list-variables --thread ${thread} --frame ${frame} --simple-values`);
|
||||
const variables = result.result("variables");
|
||||
let ret: Variable[] = [];
|
||||
for (const element of variables) {
|
||||
const key = MINode.valueOf(element, "name");
|
||||
const value = MINode.valueOf(element, "value");
|
||||
const type = MINode.valueOf(element, "type");
|
||||
ret.push({
|
||||
name: key,
|
||||
valueStr: value,
|
||||
type: type,
|
||||
raw: element
|
||||
});
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
examineMemory(from: number, length: number): Thenable<any> {
|
||||
|
|
@ -660,6 +661,41 @@ export class MI2 extends EventEmitter implements IBackend {
|
|||
});
|
||||
}
|
||||
|
||||
async varCreate(expression: string, name: string = "-"): Promise<VariableObject> {
|
||||
if (trace)
|
||||
this.log("stderr", "varCreate");
|
||||
const res = await this.sendCommand(`var-create ${name} @ "${expression}"`);
|
||||
return new VariableObject(res.result(""));
|
||||
}
|
||||
|
||||
async varEvalExpression(name: string): Promise<MINode> {
|
||||
if (trace)
|
||||
this.log("stderr", "varEvalExpression");
|
||||
return this.sendCommand(`var-evaluate-expression ${name}`);
|
||||
}
|
||||
|
||||
async varListChildren(name: string): Promise<VariableObject[]> {
|
||||
if (trace)
|
||||
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");
|
||||
let omg: VariableObject[] = children.map(child => new VariableObject(child[1]));
|
||||
return omg;
|
||||
}
|
||||
|
||||
async varUpdate(name: string = "*"): Promise<MINode> {
|
||||
if (trace)
|
||||
this.log("stderr", "varUpdate");
|
||||
return this.sendCommand(`var-update --all-values ${name}`)
|
||||
}
|
||||
|
||||
async varAssign(name: string, rawValue: string): Promise<MINode> {
|
||||
if (trace)
|
||||
this.log("stderr", "varAssign");
|
||||
return this.sendCommand(`var-assign ${name} ${rawValue}`);
|
||||
}
|
||||
|
||||
logNoNewLine(type: string, msg: string) {
|
||||
this.emit("msg", type, msg);
|
||||
}
|
||||
|
|
@ -710,6 +746,7 @@ export class MI2 extends EventEmitter implements IBackend {
|
|||
return this.isSSH ? this.sshReady : !!this.process;
|
||||
}
|
||||
|
||||
prettyPrint: boolean = true;
|
||||
printCalls: boolean;
|
||||
debugOutput: boolean;
|
||||
public procEnv: any;
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { MI2DebugSession } from './mibase';
|
|||
import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter';
|
||||
import { DebugProtocol } from 'vscode-debugprotocol';
|
||||
import { MI2 } from "./backend/mi2/mi2";
|
||||
import { SSHArguments } from './backend/backend';
|
||||
import { SSHArguments, ValuesFormattingMode } from './backend/backend';
|
||||
|
||||
export interface LaunchRequestArguments {
|
||||
cwd: string;
|
||||
|
|
@ -14,6 +14,7 @@ export interface LaunchRequestArguments {
|
|||
terminal: string;
|
||||
autorun: string[];
|
||||
ssh: SSHArguments;
|
||||
valuesFormatting: ValuesFormattingMode;
|
||||
printCalls: boolean;
|
||||
showDevDebugOutput: boolean;
|
||||
}
|
||||
|
|
@ -28,6 +29,7 @@ export interface AttachRequestArguments {
|
|||
remote: boolean;
|
||||
autorun: string[];
|
||||
ssh: SSHArguments;
|
||||
valuesFormatting: ValuesFormattingMode;
|
||||
printCalls: boolean;
|
||||
showDevDebugOutput: boolean;
|
||||
}
|
||||
|
|
@ -54,6 +56,7 @@ class GDBDebugSession extends MI2DebugSession {
|
|||
this.started = false;
|
||||
this.crashed = false;
|
||||
this.debugReady = false;
|
||||
this.setValuesFormattingMode(args.valuesFormatting);
|
||||
this.miDebugger.printCalls = !!args.printCalls;
|
||||
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
|
||||
if (args.ssh !== undefined) {
|
||||
|
|
@ -121,6 +124,7 @@ class GDBDebugSession extends MI2DebugSession {
|
|||
this.needContinue = true;
|
||||
this.isSSH = false;
|
||||
this.debugReady = false;
|
||||
this.setValuesFormattingMode(args.valuesFormatting);
|
||||
this.miDebugger.printCalls = !!args.printCalls;
|
||||
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
|
||||
if (args.ssh !== undefined) {
|
||||
|
|
@ -177,4 +181,4 @@ class GDBDebugSession extends MI2DebugSession {
|
|||
}
|
||||
}
|
||||
|
||||
DebugSession.run(GDBDebugSession);
|
||||
DebugSession.run(GDBDebugSession);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { MI2DebugSession } from './mibase';
|
|||
import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter';
|
||||
import { DebugProtocol } from 'vscode-debugprotocol';
|
||||
import { MI2_LLDB } from "./backend/mi2/mi2lldb";
|
||||
import { SSHArguments } from './backend/backend';
|
||||
import { SSHArguments, ValuesFormattingMode } from './backend/backend';
|
||||
|
||||
export interface LaunchRequestArguments {
|
||||
cwd: string;
|
||||
|
|
@ -13,6 +13,7 @@ export interface LaunchRequestArguments {
|
|||
arguments: string;
|
||||
autorun: string[];
|
||||
ssh: SSHArguments;
|
||||
valuesFormatting: ValuesFormattingMode;
|
||||
printCalls: boolean;
|
||||
showDevDebugOutput: boolean;
|
||||
}
|
||||
|
|
@ -25,6 +26,7 @@ export interface AttachRequestArguments {
|
|||
debugger_args: string[];
|
||||
executable: string;
|
||||
autorun: string[];
|
||||
valuesFormatting: ValuesFormattingMode;
|
||||
printCalls: boolean;
|
||||
showDevDebugOutput: boolean;
|
||||
}
|
||||
|
|
@ -49,6 +51,7 @@ class LLDBDebugSession extends MI2DebugSession {
|
|||
this.started = false;
|
||||
this.crashed = false;
|
||||
this.debugReady = false;
|
||||
this.setValuesFormattingMode(args.valuesFormatting);
|
||||
this.miDebugger.printCalls = !!args.printCalls;
|
||||
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
|
||||
if (args.ssh !== undefined) {
|
||||
|
|
@ -108,6 +111,7 @@ class LLDBDebugSession extends MI2DebugSession {
|
|||
this.needContinue = true;
|
||||
this.isSSH = false;
|
||||
this.debugReady = false;
|
||||
this.setValuesFormattingMode(args.valuesFormatting);
|
||||
this.miDebugger.printCalls = !!args.printCalls;
|
||||
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
|
||||
this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => {
|
||||
|
|
@ -120,4 +124,4 @@ class LLDBDebugSession extends MI2DebugSession {
|
|||
}
|
||||
}
|
||||
|
||||
DebugSession.run(LLDBDebugSession);
|
||||
DebugSession.run(LLDBDebugSession);
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import { MI2DebugSession } from './mibase';
|
|||
import { DebugSession, InitializedEvent, TerminatedEvent, StoppedEvent, OutputEvent, Thread, StackFrame, Scope, Source, Handles } from 'vscode-debugadapter';
|
||||
import { DebugProtocol } from 'vscode-debugprotocol';
|
||||
import { MI2_Mago } from "./backend/mi2/mi2mago";
|
||||
import { SSHArguments } from './backend/backend';
|
||||
import { SSHArguments, ValuesFormattingMode } from './backend/backend';
|
||||
|
||||
export interface LaunchRequestArguments {
|
||||
cwd: string;
|
||||
|
|
@ -12,6 +12,7 @@ export interface LaunchRequestArguments {
|
|||
debugger_args: string[];
|
||||
arguments: string;
|
||||
autorun: string[];
|
||||
valuesFormatting: ValuesFormattingMode;
|
||||
printCalls: boolean;
|
||||
showDevDebugOutput: boolean;
|
||||
}
|
||||
|
|
@ -24,6 +25,7 @@ export interface AttachRequestArguments {
|
|||
debugger_args: string[];
|
||||
executable: string;
|
||||
autorun: string[];
|
||||
valuesFormatting: ValuesFormattingMode;
|
||||
printCalls: boolean;
|
||||
showDevDebugOutput: boolean;
|
||||
}
|
||||
|
|
@ -56,6 +58,7 @@ class MagoDebugSession extends MI2DebugSession {
|
|||
this.started = false;
|
||||
this.crashed = false;
|
||||
this.debugReady = false;
|
||||
this.setValuesFormattingMode(args.valuesFormatting);
|
||||
this.miDebugger.printCalls = !!args.printCalls;
|
||||
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
|
||||
this.miDebugger.load(args.cwd, args.target, args.arguments, undefined).then(() => {
|
||||
|
|
@ -83,6 +86,7 @@ class MagoDebugSession extends MI2DebugSession {
|
|||
this.needContinue = true;
|
||||
this.isSSH = false;
|
||||
this.debugReady = false;
|
||||
this.setValuesFormattingMode(args.valuesFormatting);
|
||||
this.miDebugger.printCalls = !!args.printCalls;
|
||||
this.miDebugger.debugOutput = !!args.showDevDebugOutput;
|
||||
this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => {
|
||||
|
|
@ -95,4 +99,4 @@ class MagoDebugSession extends MI2DebugSession {
|
|||
}
|
||||
}
|
||||
|
||||
DebugSession.run(MagoDebugSession);
|
||||
DebugSession.run(MagoDebugSession);
|
||||
|
|
|
|||
292
src/mibase.ts
292
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 } from './backend/backend';
|
||||
import { Breakpoint, IBackend, Variable, VariableObject, ValuesFormattingMode } from './backend/backend';
|
||||
import { MINode } from './backend/mi_parse';
|
||||
import { expandValue, isExpandable } from './backend/gdb_expansion';
|
||||
import { MI2 } from './backend/mi2/mi2';
|
||||
|
|
@ -18,8 +18,13 @@ class ExtendedVariable {
|
|||
}
|
||||
}
|
||||
|
||||
const STACK_HANDLES_START = 1000;
|
||||
const VAR_HANDLES_START = 2000;
|
||||
|
||||
export class MI2DebugSession extends DebugSession {
|
||||
protected variableHandles = new Handles<any>();
|
||||
protected variableHandles = new Handles<string | VariableObject | ExtendedVariable>(VAR_HANDLES_START);
|
||||
protected variableHandlesReverse: { [id: string]: number } = {};
|
||||
protected useVarObjects: boolean;
|
||||
protected quit: boolean;
|
||||
protected attached: boolean;
|
||||
protected needContinue: boolean;
|
||||
|
|
@ -78,6 +83,23 @@ export class MI2DebugSession extends DebugSession {
|
|||
}
|
||||
}
|
||||
|
||||
protected setValuesFormattingMode(mode: ValuesFormattingMode) {
|
||||
switch (mode) {
|
||||
case "disabled":
|
||||
this.useVarObjects = true;
|
||||
this.miDebugger.prettyPrint = false;
|
||||
break;
|
||||
case "prettyPrinters":
|
||||
this.useVarObjects = true;
|
||||
this.miDebugger.prettyPrint = true;
|
||||
break;
|
||||
case "parseText":
|
||||
default:
|
||||
this.useVarObjects = false;
|
||||
this.miDebugger.prettyPrint = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected handleMsg(type: string, msg: string) {
|
||||
if (type == "target")
|
||||
type = "stdout";
|
||||
|
|
@ -126,15 +148,31 @@ export class MI2DebugSession extends DebugSession {
|
|||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
protected setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): void {
|
||||
this.miDebugger.changeVariable(args.name, args.value).then(() => {
|
||||
response.body = {
|
||||
value: args.value
|
||||
};
|
||||
protected async setVariableRequest(response: DebugProtocol.SetVariableResponse, args: DebugProtocol.SetVariableArguments): Promise<void> {
|
||||
try {
|
||||
if (this.useVarObjects) {
|
||||
let name = args.name;
|
||||
if (args.variablesReference >= VAR_HANDLES_START) {
|
||||
const parent = this.variableHandles.get(args.variablesReference) as VariableObject;
|
||||
name = `${parent.name}.${name}`;
|
||||
}
|
||||
|
||||
let res = await this.miDebugger.varAssign(name, args.value);
|
||||
response.body = {
|
||||
value: res.result("value")
|
||||
};
|
||||
}
|
||||
else {
|
||||
await this.miDebugger.changeVariable(args.name, args.value);
|
||||
response.body = {
|
||||
value: args.value
|
||||
};
|
||||
}
|
||||
this.sendResponse(response);
|
||||
}, err => {
|
||||
}
|
||||
catch (err) {
|
||||
this.sendErrorResponse(response, 11, `Could not continue: ${err}`);
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
protected setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void {
|
||||
|
|
@ -253,7 +291,7 @@ export class MI2DebugSession extends DebugSession {
|
|||
|
||||
protected scopesRequest(response: DebugProtocol.ScopesResponse, args: DebugProtocol.ScopesArguments): void {
|
||||
const scopes = new Array<Scope>();
|
||||
scopes.push(new Scope("Local", this.variableHandles.create("@frame:" + (args.frameId || 0)), false));
|
||||
scopes.push(new Scope("Local", STACK_HANDLES_START + (parseInt(args.frameId as any) || 0), false));
|
||||
|
||||
response.body = {
|
||||
scopes: scopes
|
||||
|
|
@ -261,9 +299,15 @@ export class MI2DebugSession extends DebugSession {
|
|||
this.sendResponse(response);
|
||||
}
|
||||
|
||||
protected variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): void {
|
||||
protected async variablesRequest(response: DebugProtocol.VariablesResponse, args: DebugProtocol.VariablesArguments): Promise<void> {
|
||||
const variables: DebugProtocol.Variable[] = [];
|
||||
const id = this.variableHandles.get(args.variablesReference);
|
||||
let id: number | string | VariableObject | ExtendedVariable;
|
||||
if (args.variablesReference < VAR_HANDLES_START) {
|
||||
id = args.variablesReference - STACK_HANDLES_START;
|
||||
}
|
||||
else {
|
||||
id = this.variableHandles.get(args.variablesReference);
|
||||
}
|
||||
|
||||
let createVariable = (arg, options?) => {
|
||||
if (options)
|
||||
|
|
@ -272,12 +316,57 @@ export class MI2DebugSession extends DebugSession {
|
|||
return this.variableHandles.create(arg);
|
||||
};
|
||||
|
||||
if (typeof id == "string") {
|
||||
if (id.startsWith("@frame:")) {
|
||||
this.miDebugger.getStackVariables(this.threadID, parseInt(id.substr("@frame:".length))).then(stack => {
|
||||
stack.forEach(variable => {
|
||||
let findOrCreateVariable = (varObj: VariableObject): number => {
|
||||
let id: number;
|
||||
if (this.variableHandlesReverse.hasOwnProperty(varObj.name)) {
|
||||
id = this.variableHandlesReverse[varObj.name];
|
||||
}
|
||||
else {
|
||||
id = createVariable(varObj);
|
||||
this.variableHandlesReverse[varObj.name] = id;
|
||||
}
|
||||
return varObj.isCompound() ? id : 0;
|
||||
};
|
||||
|
||||
if (typeof id == "number") {
|
||||
let stack: Variable[];
|
||||
try {
|
||||
stack = await this.miDebugger.getStackVariables(this.threadID, id);
|
||||
for (const variable of stack) {
|
||||
if (this.useVarObjects) {
|
||||
try {
|
||||
let varObj: VariableObject;
|
||||
try {
|
||||
const changes = await this.miDebugger.varUpdate(variable.name);
|
||||
const changelist = changes.result("changelist");
|
||||
changelist.forEach((change) => {
|
||||
const name = MINode.valueOf(change, "name");
|
||||
const vId = this.variableHandlesReverse[variable.name];
|
||||
const v = this.variableHandles.get(vId) as any;
|
||||
v.applyChanges(change);
|
||||
});
|
||||
const varId = this.variableHandlesReverse[variable.name];
|
||||
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;
|
||||
}
|
||||
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);
|
||||
let expanded = expandValue(createVariable, `{${variable.name}=${variable.valueStr})`, "", variable.raw);
|
||||
if (expanded) {
|
||||
if (typeof expanded[0] == "string")
|
||||
expanded = [
|
||||
|
|
@ -296,49 +385,73 @@ export class MI2DebugSession extends DebugSession {
|
|||
value: "<unknown>",
|
||||
variablesReference: createVariable(variable.name)
|
||||
});
|
||||
});
|
||||
response.body = {
|
||||
variables: variables
|
||||
};
|
||||
this.sendResponse(response);
|
||||
}, err => {
|
||||
this.sendErrorResponse(response, 1, "Could not expand variable: " + err);
|
||||
});
|
||||
}
|
||||
}
|
||||
response.body = {
|
||||
variables: variables
|
||||
};
|
||||
this.sendResponse(response);
|
||||
}
|
||||
else {
|
||||
// Variable members
|
||||
this.miDebugger.evalExpression(JSON.stringify(id)).then(variable => {
|
||||
try {
|
||||
let expanded = expandValue(createVariable, variable.result("value"), id, variable);
|
||||
if (!expanded) {
|
||||
this.sendErrorResponse(response, 2, `Could not expand variable`);
|
||||
}
|
||||
else {
|
||||
if (typeof expanded[0] == "string")
|
||||
expanded = [
|
||||
{
|
||||
name: "<value>",
|
||||
value: prettyStringArray(expanded),
|
||||
variablesReference: 0
|
||||
}
|
||||
];
|
||||
response.body = {
|
||||
variables: expanded
|
||||
};
|
||||
this.sendResponse(response);
|
||||
}
|
||||
catch (err) {
|
||||
this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`);
|
||||
}
|
||||
}
|
||||
else if (typeof id == "string") {
|
||||
// Variable members
|
||||
let variable;
|
||||
try {
|
||||
variable = await this.miDebugger.evalExpression(JSON.stringify(id));
|
||||
try {
|
||||
let expanded = expandValue(createVariable, variable.result("value"), id, variable);
|
||||
if (!expanded) {
|
||||
this.sendErrorResponse(response, 2, `Could not expand variable`);
|
||||
}
|
||||
catch (e) {
|
||||
this.sendErrorResponse(response, 2, `Could not expand variable: ` + e);
|
||||
else {
|
||||
if (typeof expanded[0] == "string")
|
||||
expanded = [
|
||||
{
|
||||
name: "<value>",
|
||||
value: prettyStringArray(expanded),
|
||||
variablesReference: 0
|
||||
}
|
||||
];
|
||||
response.body = {
|
||||
variables: expanded
|
||||
};
|
||||
this.sendResponse(response);
|
||||
}
|
||||
}, err => {
|
||||
this.sendErrorResponse(response, 1, `Could not expand variable`);
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
this.sendErrorResponse(response, 2, `Could not expand variable: ${e}`);
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`);
|
||||
}
|
||||
}
|
||||
else if (typeof id == "object") {
|
||||
if (id instanceof ExtendedVariable) {
|
||||
let varReq = <ExtendedVariable>id;
|
||||
if (id instanceof VariableObject) {
|
||||
// Variable members
|
||||
let children: VariableObject[];
|
||||
try {
|
||||
children = await this.miDebugger.varListChildren(id.name);
|
||||
const vars = children.map(child => {
|
||||
const varId = findOrCreateVariable(child);
|
||||
child.id = varId;
|
||||
return child.toProtocolVariable();
|
||||
});
|
||||
|
||||
response.body = {
|
||||
variables: vars
|
||||
}
|
||||
this.sendResponse(response);
|
||||
}
|
||||
catch (err) {
|
||||
this.sendErrorResponse(response, 1, `Could not expand variable: ${err}`);
|
||||
}
|
||||
}
|
||||
else if (id instanceof ExtendedVariable) {
|
||||
let varReq = id;
|
||||
if (varReq.options.arg) {
|
||||
let strArr = [];
|
||||
let argsPart = true;
|
||||
|
|
@ -349,55 +462,54 @@ export class MI2DebugSession extends DebugSession {
|
|||
};
|
||||
this.sendResponse(response);
|
||||
};
|
||||
let addOne = () => {
|
||||
this.miDebugger.evalExpression(JSON.stringify(varReq.name + "+" + arrIndex + ")")).then(variable => {
|
||||
try {
|
||||
let expanded = expandValue(createVariable, variable.result("value"), varReq.name, variable);
|
||||
if (!expanded) {
|
||||
this.sendErrorResponse(response, 15, `Could not expand variable`);
|
||||
}
|
||||
else {
|
||||
if (typeof expanded == "string") {
|
||||
if (expanded == "<nullptr>") {
|
||||
if (argsPart)
|
||||
argsPart = false;
|
||||
else
|
||||
return submit();
|
||||
}
|
||||
else if (expanded[0] != '"') {
|
||||
strArr.push({
|
||||
name: "[err]",
|
||||
value: expanded,
|
||||
variablesReference: 0
|
||||
});
|
||||
let addOne = async () => {
|
||||
const variable = await this.miDebugger.evalExpression(JSON.stringify(`${varReq.name}+${arrIndex})`));
|
||||
try {
|
||||
let expanded = expandValue(createVariable, variable.result("value"), varReq.name, variable);
|
||||
if (!expanded) {
|
||||
this.sendErrorResponse(response, 15, `Could not expand variable`);
|
||||
}
|
||||
else {
|
||||
if (typeof expanded == "string") {
|
||||
if (expanded == "<nullptr>") {
|
||||
if (argsPart)
|
||||
argsPart = false;
|
||||
else
|
||||
return submit();
|
||||
}
|
||||
strArr.push({
|
||||
name: "[" + (arrIndex++) + "]",
|
||||
value: expanded,
|
||||
variablesReference: 0
|
||||
});
|
||||
addOne();
|
||||
}
|
||||
else {
|
||||
else if (expanded[0] != '"') {
|
||||
strArr.push({
|
||||
name: "[err]",
|
||||
value: expanded,
|
||||
variablesReference: 0
|
||||
});
|
||||
submit();
|
||||
return submit();
|
||||
}
|
||||
strArr.push({
|
||||
name: `[${(arrIndex++)}]`,
|
||||
value: expanded,
|
||||
variablesReference: 0
|
||||
});
|
||||
addOne();
|
||||
}
|
||||
else {
|
||||
strArr.push({
|
||||
name: "[err]",
|
||||
value: expanded,
|
||||
variablesReference: 0
|
||||
});
|
||||
submit();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
this.sendErrorResponse(response, 14, `Could not expand variable: ` + e);
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
this.sendErrorResponse(response, 14, `Could not expand variable: ${e}`);
|
||||
}
|
||||
};
|
||||
addOne();
|
||||
}
|
||||
else
|
||||
this.sendErrorResponse(response, 13, `Unimplemented variable request options: ` + JSON.stringify(varReq.options));
|
||||
this.sendErrorResponse(response, 13, `Unimplemented variable request options: ${JSON.stringify(varReq.options)}`);
|
||||
}
|
||||
else {
|
||||
response.body = {
|
||||
|
|
@ -509,4 +621,4 @@ function prettyStringArray(strings) {
|
|||
return JSON.stringify(strings);
|
||||
}
|
||||
else return strings;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue