src/debugAdapter: add 'panic' and 'fatal error' as stopped reasons
Delve sets breakpoints in order to catch uncaught panics and fatal
throws when they happen. The extension was sending a stopped event
with reason breakpoint because it was stopped on a breakpoint, even
though it was not a user set breakpoint.
The extension will now check for these special breakpoints, and set
the reason for stopping as 'panic' and 'fatal error'.
Fixes golang/vscode-go#648
Change-Id: Ie72d35b2d02669cd011197c484cd0f99fbc57cc2
Reviewed-on: https://go-review.googlesource.com/c/vscode-go/+/256939
Trust: Suzy Mueller <suzmue@golang.org>
Run-TryBot: Suzy Mueller <suzmue@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Polina Sokolova <polina@google.com>
diff --git a/src/debugAdapter/goDebug.ts b/src/debugAdapter/goDebug.ts
index 8a51ec9..6dbe0c0 100644
--- a/src/debugAdapter/goDebug.ts
+++ b/src/debugAdapter/goDebug.ts
@@ -247,6 +247,14 @@
reason: string;
}
+// Unrecovered panic and fatal throw breakpoint IDs taken from delve:
+// https://github.com/go-delve/delve/blob/f90134eb4db1c423e24fddfbc6eff41b288e6297/pkg/proc/breakpoints.go#L11-L21
+// UnrecoveredPanic is the name given to the unrecovered panic breakpoint.
+const unrecoveredPanicID = -1;
+// FatalThrow is the name given to the breakpoint triggered when the target
+// process dies because of a fatal runtime error.
+const fatalThrowID = -2;
+
// This interface should always match the schema found in `package.json`.
interface LaunchRequestArguments extends DebugProtocol.LaunchRequestArguments {
request: 'launch';
@@ -2203,7 +2211,18 @@
// Other stopping events (eg pause) create their own StoppedEvents,
// if necessary.
if (!!state.currentThread.breakPoint) {
- this.handleReenterDebug('breakpoint');
+ const bp = state.currentThread.breakPoint;
+ if (bp.id === unrecoveredPanicID) {
+ // If the breakpoint is actually caused by a panic,
+ // we want to return on "panic".
+ this.handleReenterDebug('panic');
+ } else if (bp.id === fatalThrowID) {
+ // If the breakpoint is actually caused by a fatal throw,
+ // we want to return on "fatal error".
+ this.handleReenterDebug('fatal error');
+ } else {
+ this.handleReenterDebug('breakpoint');
+ }
}
};