Skip to content

Commit

Permalink
Improve handling of breakpoints
Browse files Browse the repository at this point in the history
- Fixes cases where breakpoints could be clear incorrectly
- Adds support for breakpoints added through disassembly views
  • Loading branch information
Marus committed Jan 23, 2018
1 parent be40657 commit 4e6c1da
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 81 deletions.
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,8 @@
"c",
"cpp",
"asm",
"arm"
"arm",
"cortex-debug.disassembly"
]
},
"initialConfigurations": [
Expand Down
7 changes: 3 additions & 4 deletions src/backend/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Breakpoint {
raw?: string;
condition: string;
countCondition?: string;
number?: number;
}

export interface Stack {
Expand Down Expand Up @@ -35,10 +36,8 @@ export interface IBackend {
next(): Thenable<boolean>;
step(): Thenable<boolean>;
stepOut(): Thenable<boolean>;
loadBreakPoints(breakpoints: Breakpoint[]): Thenable<[boolean, Breakpoint][]>;
addBreakPoint(breakpoint: Breakpoint): Thenable<[boolean, Breakpoint]>;
removeBreakPoint(breakpoint: Breakpoint): Thenable<boolean>;
clearBreakPoints(): Thenable<any>;
addBreakPoint(breakpoint: Breakpoint): Promise<Breakpoint>;
removeBreakpoints(breakpoints: number[]): Promise<boolean>;
getStack(maxLevels: number): Thenable<Stack[]>;
getStackVariables(thread: number, frame: number): Thenable<Variable[]>;
evalExpression(name: string): Thenable<any>;
Expand Down
74 changes: 21 additions & 53 deletions src/backend/mi2/mi2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -272,28 +272,16 @@ export class MI2 extends EventEmitter implements IBackend {
return this.sendCommand("gdb-set var " + name + "=" + rawValue);
}

loadBreakPoints(breakpoints: Breakpoint[]): Thenable<[boolean, Breakpoint][]> {
if (trace)
this.log("stderr", "loadBreakPoints");
let promisses = [];
breakpoints.forEach(breakpoint => {
promisses.push(this.addBreakPoint(breakpoint));
});
return Promise.all(promisses);
}

setBreakPointCondition(bkptNum, condition): Thenable<any> {
if (trace)
this.log("stderr", "setBreakPointCondition");
return this.sendCommand("break-condition " + bkptNum + " " + condition);
}

addBreakPoint(breakpoint: Breakpoint): Thenable<[boolean, Breakpoint]> {
addBreakPoint(breakpoint: Breakpoint): Promise<Breakpoint> {
if (trace)
this.log("stderr", "addBreakPoint");
return new Promise((resolve, reject) => {
if (this.breakpoints.has(breakpoint))
return resolve([false, undefined]);
let location = "";
if (breakpoint.countCondition) {
if (breakpoint.countCondition[0] == ">")
Expand All @@ -308,69 +296,50 @@ export class MI2 extends EventEmitter implements IBackend {
location += "-t -i " + parseInt(match) + " ";
}
}

if (breakpoint.raw)
location += '"' + escape(breakpoint.raw) + '"';
location += '*' + escape(breakpoint.raw);
else
location += '"' + escape(breakpoint.file) + ":" + breakpoint.line + '"';
this.sendCommand("break-insert -f " + location).then((result) => {

this.sendCommand(`break-insert ${location}`).then((result) => {
if (result.resultRecords.resultClass == "done") {
let bkptNum = parseInt(result.result("bkpt.number"));
let newBrk = {
file: result.result("bkpt.file"),
line: parseInt(result.result("bkpt.line")),
condition: breakpoint.condition
};
breakpoint.number = bkptNum;

if (breakpoint.condition) {
this.setBreakPointCondition(bkptNum, breakpoint.condition).then((result) => {
if (result.resultRecords.resultClass == "done") {
this.breakpoints.set(newBrk, bkptNum);
resolve([true, newBrk]);
resolve(breakpoint);
} else {
resolve([false, null]);
resolve(null);
}
}, reject);
}
else {
this.breakpoints.set(newBrk, bkptNum);
resolve([true, newBrk]);
resolve(breakpoint);
}
}
else {
reject(result);
resolve(null);
}
}, reject);
});
}

removeBreakPoint(breakpoint: Breakpoint): Thenable<boolean> {
removeBreakpoints(breakpoints: number[]): Promise<boolean> {
if (trace)
this.log("stderr", "removeBreakPoint");
return new Promise((resolve, reject) => {
if (!this.breakpoints.has(breakpoint))
return resolve(false);
this.sendCommand("break-delete " + this.breakpoints.get(breakpoint)).then((result) => {
if (result.resultRecords.resultClass == "done") {
this.breakpoints.delete(breakpoint);
resolve(true);
}
else resolve(false);
});
});
}

clearBreakPoints(): Thenable<any> {
if (trace)
this.log("stderr", "clearBreakPoints");
return new Promise((resolve, reject) => {
this.sendCommand("break-delete").then((result) => {
if (result.resultRecords.resultClass == "done") {
this.breakpoints.clear();
resolve(true);
}
else resolve(false);
}, () => {
resolve(false);
});
if (breakpoints.length === 0) {
resolve(true);
}
else {
let cmd = 'break-delete ' + breakpoints.join(' ');
this.sendCommand(cmd).then((result) => {
resolve(result.resultRecords.resultClass == 'done');
}, reject);
}
});
}

Expand Down Expand Up @@ -563,7 +532,6 @@ export class MI2 extends EventEmitter implements IBackend {
public procEnv: any;
protected currentToken: number = 1;
protected handlers: { [index: number]: (info: MINode) => any } = {};
protected breakpoints: Map<Breakpoint, Number> = new Map();
protected buffer: string;
protected errbuf: string;
protected process: ChildProcess.ChildProcess;
Expand Down
82 changes: 59 additions & 23 deletions src/gdb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@ export class GDBDebugSession extends DebugSession {
protected commandServer: net.Server;
protected forceDisassembly: boolean = false;

protected breakpointMap: Map<string, Breakpoint[]> = new Map();

private currentFile: string;

public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false, threadID: number = 1) {
Expand Down Expand Up @@ -605,32 +607,66 @@ export class GDBDebugSession extends DebugSession {
this.miDebugger.once("debug-ready", cb);
}

protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
let cb = (() => {
protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments) {
let cb = (async () => {
this.debugReady = true;
this.miDebugger.clearBreakPoints().then(() => {
let path = args.source.path;
let all = [];
args.breakpoints.forEach(brk => {
all.push(this.miDebugger.addBreakPoint({ file: path, line: brk.line, condition: brk.condition, countCondition: brk.hitCondition }));
});
Promise.all(all).then(brkpoints => {
let finalBrks = [];
brkpoints.forEach(brkp => {
if (brkp[0])
finalBrks.push({ line: brkp[1].line, verified: true });
});
response.body = {
breakpoints: finalBrks
};
this.sendResponse(response);
let currentBreakpoints = (this.breakpointMap.get(args.source.path) || []).map(bp => bp.number);

try {
await this.miDebugger.removeBreakpoints(currentBreakpoints);
this.breakpointMap.set(args.source.path, []);

let all: Promise<Breakpoint>[] = [];
if (args.source.path.startsWith('disassembly:///')) {
let eidx = args.source.path.indexOf('?');
let path = args.source.path.substring(15, eidx - 6); // Account for protocol and extension
let parts = path.split('::');
let func: string;
let file: string;

if (parts.length == 2) {
func = parts[1];
file = parts[0];
}
else {
func = parts[0];
}

let symbol: SymbolInformation = await this.getDisassemblyForFunction(func, file);

}, msg => {
this.sendErrorResponse(response, 9, msg.toString());
});
}, msg => {
args.breakpoints.forEach(brk => {
if (brk.line <= symbol.instructions.length) {
let line = symbol.instructions[brk.line - 1];
all.push(this.miDebugger.addBreakPoint({ file: args.source.path, line: brk.line, condition: brk.condition, countCondition: brk.hitCondition, raw: line.address }));
}
});
}
else {
args.breakpoints.forEach(brk => {
all.push(this.miDebugger.addBreakPoint({ file: args.source.path, line: brk.line, condition: brk.condition, countCondition: brk.hitCondition }));
});
}

let brkpoints = await Promise.all(all);

let finalBrks: Breakpoint[] = brkpoints.filter(bp => bp !== null);

response.body = {
breakpoints: finalBrks.map(bp => {
return {
line: bp.line,
id: bp.number,
verified: true
};
})
};

this.breakpointMap.set(args.source.path, finalBrks);
this.sendResponse(response);
}
catch (msg) {
this.sendErrorResponse(response, 9, msg.toString());
});
};
}).bind(this);

if (this.debugReady)
Expand Down

0 comments on commit 4e6c1da

Please sign in to comment.