Skip to content
This repository has been archived by the owner on Jul 15, 2023. It is now read-only.

Commit

Permalink
debug: fix updating breakpoints while debuggee is running (#2128)
Browse files Browse the repository at this point in the history
  • Loading branch information
xiphon authored and ramya-rao-a committed Jan 24, 2019
1 parent fd66ca8 commit 4249d0c
Showing 1 changed file with 50 additions and 10 deletions.
60 changes: 50 additions & 10 deletions src/debugAdapter/goDebug.ts
Original file line number Diff line number Diff line change
Expand Up @@ -544,6 +544,7 @@ class GoDebugSession extends LoggingDebugSession {

private _variableHandles: Handles<DebugVariable>;
private breakpoints: Map<string, DebugBreakpoint[]>;
private skipStopEventOnce: boolean; // Editing breakpoints requires halting delve, skip sending Stop Event to VS Code in such cases
private threads: Set<number>;
private debugState: DebuggerState;
private delve: Delve;
Expand All @@ -558,6 +559,7 @@ class GoDebugSession extends LoggingDebugSession {
public constructor(debuggerLinesStartAt1: boolean, isServer: boolean = false) {
super('', debuggerLinesStartAt1, isServer);
this._variableHandles = new Handles<DebugVariable>();
this.skipStopEventOnce = false;
this.threads = new Set<number>();
this.debugState = null;
this.delve = null;
Expand Down Expand Up @@ -704,15 +706,14 @@ class GoDebugSession extends LoggingDebugSession {
return pathToConvert.replace(this.delve.remotePath, this.delve.program).split(this.remotePathSeparator).join(this.localPathSeparator);
}

protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
log('SetBreakPointsRequest');
private setBreakPoints(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): Thenable<void> {
let file = normalizePath(args.source.path);
if (!this.breakpoints.get(file)) {
this.breakpoints.set(file, []);
}
let remoteFile = this.toDebuggerPath(file);

Promise.all(this.breakpoints.get(file).map(existingBP => {
return Promise.all(this.breakpoints.get(file).map(existingBP => {
log('Clearing: ' + existingBP.id);
return this.delve.callPromise('ClearBreakpoint', [this.delve.isApiV1 ? existingBP.id : { Id: existingBP.id }]);
})).then(() => {
Expand Down Expand Up @@ -761,6 +762,26 @@ class GoDebugSession extends LoggingDebugSession {
});
}

protected setBreakPointsRequest(response: DebugProtocol.SetBreakpointsResponse, args: DebugProtocol.SetBreakpointsArguments): void {
log('SetBreakPointsRequest');
if (!this.continueRequestRunning) {
this.setBreakPoints(response, args);
} else {
this.skipStopEventOnce = true;
this.delve.callPromise('Command', [{ name: 'halt' }]).then(() => {
return this.setBreakPoints(response, args).then(() => {
return this.continue(true).then(null, err => {
logError(`Failed to continue delve after halting it to set breakpoints: "${err.toString()}"`);
});
});
}, err => {
this.skipStopEventOnce = false;
logError(err);
return this.sendErrorResponse(response, 2008, 'Failed to halt delve before attempting to set breakpoint: "{e}"', { e: err.toString() });
});
}
}

protected threadsRequest(response: DebugProtocol.ThreadsResponse): void {
if (this.continueRequestRunning) {
// Thread request to delve is syncronous and will block if a previous async continue request didn't return
Expand Down Expand Up @@ -1115,32 +1136,51 @@ class GoDebugSession extends LoggingDebugSession {
this.threads.delete(id);
});

if (this.skipStopEventOnce) {
this.skipStopEventOnce = false;
return;
}

let stoppedEvent = new StoppedEvent(reason, this.debugState.currentGoroutine.id);
(<any>stoppedEvent.body).allThreadsStopped = true;
this.sendEvent(stoppedEvent);
log('StoppedEvent("' + reason + '")');
});
}
}

private continueEpoch = 0;
private continueRequestRunning = false;
protected continueRequest(response: DebugProtocol.ContinueResponse): void {
log('ContinueRequest');
private continue(calledWhenSettingBreakpoint?: boolean): Thenable<void> {
this.continueEpoch++;
let closureEpoch = this.continueEpoch;
this.continueRequestRunning = true;
this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'continue' }], (err, out) => {

const callback = (out) => {
if (closureEpoch === this.continueEpoch) {
this.continueRequestRunning = false;
}
if (err) {
logError('Failed to continue - ' + err.toString());
}
const state = this.delve.isApiV1 ? <DebuggerState>out : (<CommandOut>out).State;
log('continue state', state);
this.debugState = state;
this.handleReenterDebug('breakpoint');
});
};

// If called when setting breakpoint internally, we want the error to bubble up.
const errorCallback = calledWhenSettingBreakpoint ? null : (err) => {
if (err) {
logError('Failed to continue - ' + err.toString());
}
this.handleReenterDebug('breakpoint');
throw err;
};

return this.delve.callPromise('Command', [{ name: 'continue' }]).then(callback, errorCallback);
}

protected continueRequest(response: DebugProtocol.ContinueResponse): void {
log('ContinueRequest');
this.continue();
this.sendResponse(response);
log('ContinueResponse');
}
Expand Down

0 comments on commit 4249d0c

Please sign in to comment.