From 281f3920ddc339e425a1b99d5d853d52021bc860 Mon Sep 17 00:00:00 2001 From: Alessandro Arzilli Date: Tue, 15 Aug 2023 00:32:15 +0200 Subject: [PATCH] proc: fix stacktraces on freebsd/amd64/go1.20 (#3458) TestStacktraceGoroutine failed intermittently on freebsd/amd64/go1.20. This happens because of two windows, in the scheduler (right after parking a goroutine and just before resuming a parked goroutine) where a thread is associated with a goroutine but running in the system stack and there is no systemstack_switch frame to connect the two stacks. --- pkg/proc/amd64_arch.go | 10 +++++++++- pkg/proc/arm64_arch.go | 11 ++++++++++- pkg/proc/i386_arch.go | 10 +++++++++- pkg/proc/ppc64le_arch.go | 9 ++++++++- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/pkg/proc/amd64_arch.go b/pkg/proc/amd64_arch.go index dc426ac3d8..26a16fa087 100644 --- a/pkg/proc/amd64_arch.go +++ b/pkg/proc/amd64_arch.go @@ -200,11 +200,19 @@ func amd64SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool { return true - case "runtime.goexit", "runtime.rt0_go", "runtime.mcall": + case "runtime.goexit", "runtime.rt0_go": // Look for "top of stack" functions. it.atend = true return true + case "runtime.mcall": + if it.systemstack && it.g != nil { + it.switchToGoroutineStack() + return true + } + it.atend = true + return true + case "runtime.mstart": // Calls to runtime.systemstack will switch to the systemstack then: // 1. alter the goroutine stack so that it looks like systemstack_switch diff --git a/pkg/proc/arm64_arch.go b/pkg/proc/arm64_arch.go index 426fbbce4d..2e646be4e5 100644 --- a/pkg/proc/arm64_arch.go +++ b/pkg/proc/arm64_arch.go @@ -217,10 +217,19 @@ func arm64SwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) bool return true } - case "runtime.goexit", "runtime.rt0_go", "runtime.mcall": + case "runtime.goexit", "runtime.rt0_go": // Look for "top of stack" functions. it.atend = true return true + + case "runtime.mcall": + if it.systemstack && it.g != nil { + it.switchToGoroutineStack() + return true + } + it.atend = true + return true + case "crosscall2": // The offsets get from runtime/cgo/asm_arm64.s:10 bpoff := uint64(14) diff --git a/pkg/proc/i386_arch.go b/pkg/proc/i386_arch.go index 2bb53cc381..f04aa0d3dd 100644 --- a/pkg/proc/i386_arch.go +++ b/pkg/proc/i386_arch.go @@ -127,11 +127,19 @@ func i386SwitchStack(it *stackIterator, _ *op.DwarfRegisters) bool { switch it.frame.Current.Fn.Name { case "runtime.asmcgocall", "runtime.cgocallback_gofunc": // TODO(chainhelen), need to support cgo stacktraces. return false - case "runtime.goexit", "runtime.rt0_go", "runtime.mcall": + case "runtime.goexit", "runtime.rt0_go": // Look for "top of stack" functions. it.atend = true return true + case "runtime.mcall": + if it.systemstack && it.g != nil { + it.switchToGoroutineStack() + return true + } + it.atend = true + return true + case "runtime.mstart": // Calls to runtime.systemstack will switch to the systemstack then: // 1. alter the goroutine stack so that it looks like systemstack_switch diff --git a/pkg/proc/ppc64le_arch.go b/pkg/proc/ppc64le_arch.go index 53c82125c2..ded9889637 100644 --- a/pkg/proc/ppc64le_arch.go +++ b/pkg/proc/ppc64le_arch.go @@ -106,10 +106,17 @@ func ppc64leSwitchStack(it *stackIterator, callFrameRegs *op.DwarfRegisters) boo switch it.frame.Current.Fn.Name { case "runtime.asmcgocall", "runtime.cgocallback_gofunc", "runtime.sigpanic", "runtime.cgocallback": //do nothing - case "runtime.goexit", "runtime.rt0_go", "runtime.mcall": + case "runtime.goexit", "runtime.rt0_go": // Look for "top of stack" functions. it.atend = true return true + case "runtime.mcall": + if it.systemstack && it.g != nil { + it.switchToGoroutineStack() + return true + } + it.atend = true + return true case "crosscall2": //The offsets get from runtime/cgo/asm_ppc64x.s:10 newsp, _ := readUintRaw(it.mem, it.regs.SP()+8*24, int64(it.bi.Arch.PtrSize()))