From 50fb4798b7e860947dcc4d5b9585d2f52499ec1e Mon Sep 17 00:00:00 2001 From: WebFreak001 Date: Thu, 10 Mar 2016 13:02:04 +0100 Subject: [PATCH] Added function breakpoints (fix #45) --- package.json | 4 ++-- src/backend/backend.ts | 5 +++-- src/backend/mi2/mi2.ts | 19 ++++++++++++------ src/backend/mi_parse.ts | 8 ++++---- src/gdb.ts | 7 +++++-- src/lldb.ts | 7 +++++-- src/mibase.ts | 44 ++++++++++++++++++++++++++++++++++++----- 7 files changed, 71 insertions(+), 23 deletions(-) diff --git a/package.json b/package.json index f00f136..c95955a 100644 --- a/package.json +++ b/package.json @@ -349,8 +349,8 @@ "test": "node ./node_modules/vscode/bin/test" }, "dependencies": { - "vscode-debugadapter": "^1.5.0", - "vscode-debugprotocol": "^1.5.0", + "vscode-debugadapter": "^1.7.0-pre.1", + "vscode-debugprotocol": "^1.7.0-pre.1", "ssh2": "^0.4.13" }, "devDependencies": { diff --git a/src/backend/backend.ts b/src/backend/backend.ts index 4112a43..7df1175 100644 --- a/src/backend/backend.ts +++ b/src/backend/backend.ts @@ -1,6 +1,7 @@ export interface Breakpoint { - file: string; - line: number; + file?: string; + line?: number; + raw?: string; condition: string; } diff --git a/src/backend/mi2/mi2.ts b/src/backend/mi2/mi2.ts index 0de4202..0cb0742 100644 --- a/src/backend/mi2/mi2.ts +++ b/src/backend/mi2/mi2.ts @@ -14,8 +14,8 @@ export function escape(str: string) { return str.replace(/\\/g, "\\\\").replace(/"/g, "\\\""); } -const nonOutput = /^[0-9]*[\*\+\=]|[\~\@\&\^]/; -const gdbMatch = /(undefined|\d*)\(gdb\)/; +const nonOutput = /^(?:\d*|undefined)[\*\+\=]|[\~\@\&\^]/; +const gdbMatch = /(?:\d*|undefined)\(gdb\)/; function couldBeOutput(line: string) { if (nonOutput.exec(line)) @@ -409,7 +409,12 @@ export class MI2 extends EventEmitter implements IBackend { return new Promise((resolve, reject) => { if (this.breakpoints.has(breakpoint)) return resolve(false); - this.sendCommand("break-insert -f " + breakpoint.file + ":" + breakpoint.line).then((result) => { + let location = ""; + if (breakpoint.raw) + location = '"' + escape(breakpoint.raw) + '"'; + else + location = breakpoint.file + ":" + breakpoint.line; + this.sendCommand("break-insert -f " + location).then((result) => { if (result.resultRecords.resultClass == "done") { let bkptNum = parseInt(result.result("bkpt.number")); let newBrk = { @@ -425,7 +430,7 @@ export class MI2 extends EventEmitter implements IBackend { } else { resolve([false, null]); } - }); + }, reject); } else { this.breakpoints.set(newBrk, bkptNum); @@ -433,9 +438,9 @@ export class MI2 extends EventEmitter implements IBackend { } } else { - resolve([false, null]); + reject(result); } - }); + }, reject); }); } @@ -461,6 +466,8 @@ export class MI2 extends EventEmitter implements IBackend { resolve(true); } else resolve(false); + }, () => { + resolve(false); }); }); } diff --git a/src/backend/mi_parse.ts b/src/backend/mi_parse.ts index 7d41d6c..cee3b0a 100644 --- a/src/backend/mi_parse.ts +++ b/src/backend/mi_parse.ts @@ -77,9 +77,9 @@ export class MINode implements MIInfo { } } -const tokenRegex = /^[0-9]+/; -const outOfBandRecordRegex = /^(?:([0-9]*)([\*\+\=])|([\~\@\&]))/; -const resultRecordRegex = /^([0-9]*)\^(done|running|connected|error|exit)/; +const tokenRegex = /^\d+/; +const outOfBandRecordRegex = /^(?:(\d*|undefined)([\*\+\=])|([\~\@\&]))/; +const resultRecordRegex = /^(\d*)\^(done|running|connected|error|exit)/; const newlineRegex = /^\r\n?/; const endRegex = /^\(gdb\)\r\n?/; const variableRegex = /^([a-zA-Z_\-][a-zA-Z0-9_\-]*)/; @@ -212,7 +212,7 @@ export function parseMI(output: string): MINode { while (match = outOfBandRecordRegex.exec(output)) { output = output.substr(match[0].length); - if (match[1] && token === undefined) { + if (match[1] && token === undefined && match[1] !== "undefined") { token = parseInt(match[1]); } diff --git a/src/gdb.ts b/src/gdb.ts index 11c1b73..ecfa97d 100644 --- a/src/gdb.ts +++ b/src/gdb.ts @@ -26,8 +26,9 @@ export interface AttachRequestArguments { class GDBDebugSession extends MI2DebugSession { protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { response.body.supportsConfigurationDoneRequest = true; - response.body.supportsEvaluateForHovers = true; // Assume working in future releases - response.body.supportsFunctionBreakpoints = true; // TODO: Implement in future release + response.body.supportsConditionalBreakpoints = true; + response.body.supportsFunctionBreakpoints = true; + response.body.supportsEvaluateForHovers = true; this.sendResponse(response); this.miDebugger = new MI2("gdb", ["-q", "--interpreter=mi2"]); this.initDebugger(); @@ -40,6 +41,7 @@ class GDBDebugSession extends MI2DebugSession { this.isSSH = false; this.started = false; this.crashed = false; + this.debugReady = false; this.miDebugger.printCalls = !!args.printCalls; if (args.ssh !== undefined) { if (args.ssh.forwardX11 === undefined) @@ -95,6 +97,7 @@ class GDBDebugSession extends MI2DebugSession { this.attached = !args.remote; this.needContinue = true; this.isSSH = false; + this.debugReady = false; this.miDebugger.printCalls = !!args.printCalls; if (args.remote) { this.miDebugger.connect(args.cwd, args.executable, args.target).then(() => { diff --git a/src/lldb.ts b/src/lldb.ts index 1e229d3..8190dfc 100644 --- a/src/lldb.ts +++ b/src/lldb.ts @@ -24,8 +24,9 @@ export interface AttachRequestArguments { class LLDBDebugSession extends MI2DebugSession { protected initializeRequest(response: DebugProtocol.InitializeResponse, args: DebugProtocol.InitializeRequestArguments): void { response.body.supportsConfigurationDoneRequest = true; - response.body.supportsEvaluateForHovers = true; // Assume working in future releases - response.body.supportsFunctionBreakpoints = true; // TODO: Implement in future release + response.body.supportsConditionalBreakpoints = true; + response.body.supportsFunctionBreakpoints = true; + response.body.supportsEvaluateForHovers = true; this.sendResponse(response); this.miDebugger = new MI2_LLDB("lldb-mi", []); this.initDebugger(); @@ -38,6 +39,7 @@ class LLDBDebugSession extends MI2DebugSession { this.isSSH = false; this.started = false; this.crashed = false; + this.debugReady = false; this.miDebugger.printCalls = !!args.printCalls; if (args.ssh !== undefined) { if (args.ssh.forwardX11 === undefined) @@ -93,6 +95,7 @@ class LLDBDebugSession extends MI2DebugSession { this.attached = true; this.needContinue = true; this.isSSH = false; + this.debugReady = false; this.miDebugger.printCalls = !!args.printCalls; this.miDebugger.attach(args.cwd, args.executable, args.target).then(() => { if (args.autorun) diff --git a/src/mibase.ts b/src/mibase.ts index ee6ab94..968f655 100644 --- a/src/mibase.ts +++ b/src/mibase.ts @@ -21,6 +21,7 @@ export class MI2DebugSession extends DebugSession { protected switchCWD: string; protected started: boolean; protected crashed: boolean; + protected debugReady: boolean; protected miDebugger: MI2; public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) { @@ -79,8 +80,36 @@ export class MI2DebugSession extends DebugSession { this.sendResponse(response); } + protected setFunctionBreakPointsRequest(response: DebugProtocol.SetFunctionBreakpointsResponse, args: DebugProtocol.SetFunctionBreakpointsArguments): void { + let cb = (() => { + this.debugReady = true; + let all = []; + args.breakpoints.forEach(brk => { + all.push(this.miDebugger.addBreakPoint({ raw: brk.name, condition: brk.condition })); + }); + Promise.all(all).then(brkpoints => { + let finalBrks = []; + brkpoints.forEach(brkp => { + if (brkp[0]) + finalBrks.push({ line: brkp[1].line }); + }); + response.body = { + breakpoints: finalBrks + }; + this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 10, msg.toString()); + }); + }).bind(this); + if (this.debugReady) + cb(); + else + this.miDebugger.once("debug-ready", cb); + } + protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void { - this.miDebugger.once("debug-ready", (() => { + let cb = (() => { + this.debugReady = true; this.miDebugger.clearBreakPoints().then(() => { let path = args.source.path; if (this.isSSH) { @@ -100,13 +129,18 @@ export class MI2DebugSession extends DebugSession { response.body = { breakpoints: finalBrks }; - setTimeout(() => { - this.miDebugger.emit("ui-break-done"); - }, 50); this.sendResponse(response); + }, msg => { + this.sendErrorResponse(response, 9, msg.toString()); }); + }, msg => { + this.sendErrorResponse(response, 9, msg.toString()); }); - }).bind(this)); + }).bind(this); + if (this.debugReady) + cb(); + else + this.miDebugger.once("debug-ready", cb); } protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {