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

Commit 0884de1

Browse files
committed
Add stacktrace dump and better error messages on EXC_BAD_ACCESS panics
Fixes #1903
1 parent 9359e1c commit 0884de1

2 files changed

Lines changed: 58 additions & 7 deletions

File tree

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/debugAdapter/goDebug.ts

Lines changed: 57 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1445,9 +1445,7 @@ class GoDebugSession extends LoggingDebugSession {
14451445

14461446
// If called when setting breakpoint internally, we want the error to bubble up.
14471447
const errorCallback = calledWhenSettingBreakpoint ? null : (err: any) => {
1448-
if (err) {
1449-
logError('Failed to continue - ' + err.toString());
1450-
}
1448+
this.logDelveError(err, 'Failed to continue');
14511449
this.handleReenterDebug('breakpoint');
14521450
throw err;
14531451
};
@@ -1466,7 +1464,7 @@ class GoDebugSession extends LoggingDebugSession {
14661464
log('NextRequest');
14671465
this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'next' }], (err, out) => {
14681466
if (err) {
1469-
logError('Failed to next - ' + err.toString());
1467+
this.logDelveError(err, 'Failed to next');
14701468
}
14711469
const state = this.delve.isApiV1 ? <DebuggerState>out : (<CommandOut>out).State;
14721470
log('next state', state);
@@ -1481,7 +1479,7 @@ class GoDebugSession extends LoggingDebugSession {
14811479
log('StepInRequest');
14821480
this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'step' }], (err, out) => {
14831481
if (err) {
1484-
logError('Failed to step - ' + err.toString());
1482+
this.logDelveError(err, 'Failed to step - ');
14851483
}
14861484
const state = this.delve.isApiV1 ? <DebuggerState>out : (<CommandOut>out).State;
14871485
log('stop state', state);
@@ -1496,7 +1494,7 @@ class GoDebugSession extends LoggingDebugSession {
14961494
log('StepOutRequest');
14971495
this.delve.call<DebuggerState | CommandOut>('Command', [{ name: 'stepOut' }], (err, out) => {
14981496
if (err) {
1499-
logError('Failed to stepout - ' + err.toString());
1497+
this.logDelveError(err, 'Failed to stepout - ');
15001498
}
15011499
const state = this.delve.isApiV1 ? <DebuggerState>out : (<CommandOut>out).State;
15021500
log('stepout state', state);
@@ -1587,6 +1585,59 @@ class GoDebugSession extends LoggingDebugSession {
15871585
});
15881586
}
15891587

1588+
private logDelveError(err: any, message: string) {
1589+
if (err) {
1590+
let errorMessage = err.toString();
1591+
// Handle unpropagated fatalpanic errors with a more user friendly message:
1592+
// https://github.com/microsoft/vscode-go/issues/1903#issuecomment-460126884
1593+
// https://github.com/go-delve/delve/issues/852
1594+
// This affects macOS only although we're agnostic of the OS at this stage, only handle the error
1595+
if (errorMessage === 'bad access') {
1596+
errorMessage = 'unpropagated fatalpanic: signal SIGSEGV (EXC_BAD_ACCESS). This fatalpanic is not traceable on macOS, see https://github.com/go-delve/delve/issues/852';
1597+
}
1598+
logError(message + ' - ' + errorMessage);
1599+
}
1600+
this.dumpStacktrace();
1601+
}
1602+
1603+
private dumpStacktrace() {
1604+
const goroutineId = 0;
1605+
const stackTraceIn = { id: goroutineId, depth: this.delve.stackTraceDepth };
1606+
if (!this.delve.isApiV1) {
1607+
Object.assign(stackTraceIn, { full: false, cfg: this.delve.loadConfig });
1608+
}
1609+
this.delve.call<DebugLocation[] | StacktraceOut>(this.delve.isApiV1 ? 'StacktraceGoroutine' : 'Stacktrace', [stackTraceIn], (err, out) => {
1610+
if (err) {
1611+
logError('Failed to produce stack trace!');
1612+
return;
1613+
}
1614+
const locations = this.delve.isApiV1 ? <DebugLocation[]>out : (<StacktraceOut>out).Locations;
1615+
log('locations', locations);
1616+
const stackFrames = locations.map((location, frameId) => {
1617+
const uniqueStackFrameId = this.stackFrameHandles.create([goroutineId, frameId]);
1618+
return new StackFrame(
1619+
uniqueStackFrameId,
1620+
location.function ? location.function.name : '<unknown>',
1621+
location.file === '<autogenerated>' ? null : new Source(
1622+
basename(location.file),
1623+
this.toLocalPath(location.file)
1624+
),
1625+
location.line,
1626+
0
1627+
);
1628+
});
1629+
logError('Immediate stacktrace:');
1630+
let output = '';
1631+
stackFrames.forEach(stackFrame => {
1632+
output = output.concat(`\t${stackFrame.source.path}:${stackFrame.line}\n`);
1633+
if (stackFrame.name) {
1634+
output = output.concat(`\t\t${stackFrame.name}\n`);
1635+
}
1636+
});
1637+
logError(output);
1638+
});
1639+
}
1640+
15901641
private addFullyQualifiedName(variables: DebugVariable[]) {
15911642
variables.forEach(local => {
15921643
local.fullyQualifiedName = local.name;

0 commit comments

Comments
 (0)