From 6319bb1597ac302b8fb796b5879fc74c12ce23c4 Mon Sep 17 00:00:00 2001 From: aarzilli Date: Wed, 17 Jan 2024 14:53:38 +0100 Subject: [PATCH] proc: fix stacktrace frame after runtime.sigpanic The first frame after sigpanic didn't execute a call so we shouldn't decrement the PC address to look up its location. Fixes #3634 --- _fixtures/panicline.go | 8 ++++++++ pkg/proc/proc_test.go | 25 +++++++++++++++++++++++++ pkg/proc/stack.go | 4 +++- 3 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 _fixtures/panicline.go diff --git a/_fixtures/panicline.go b/_fixtures/panicline.go new file mode 100644 index 0000000000..5103bfa704 --- /dev/null +++ b/_fixtures/panicline.go @@ -0,0 +1,8 @@ +package main + +import "os" + +func main() { + fi, _ := os.Lstat("/this/path/does/not/exist") + fi.Size() +} diff --git a/pkg/proc/proc_test.go b/pkg/proc/proc_test.go index f1485cddf7..bb1eb4a499 100644 --- a/pkg/proc/proc_test.go +++ b/pkg/proc/proc_test.go @@ -6121,3 +6121,28 @@ func TestIssue3545(t *testing.T) { } }) } + +func TestPanicLine(t *testing.T) { + withTestProcess("panicline", t, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) { + err := grp.Continue() + if runtime.GOOS == "darwin" && err != nil && err.Error() == "bad access" { + // not supported + return + } + assertNoError(err, t, "Continue()") + frames, err := proc.ThreadStacktrace(p, p.CurrentThread(), 20) + assertNoError(err, t, "ThreadStacktrace") + logStacktrace(t, p, frames) + + found := false + for _, frame := range frames { + if strings.HasSuffix(frame.Call.File, "panicline.go") && frame.Call.Line == 7 { + found = true + break + } + } + if !found { + t.Fatalf("could not find panicline.go:6") + } + }) +} diff --git a/pkg/proc/stack.go b/pkg/proc/stack.go index e0ed2024aa..55034ebf6f 100644 --- a/pkg/proc/stack.go +++ b/pkg/proc/stack.go @@ -180,6 +180,7 @@ type stackIterator struct { pc uint64 top bool atend bool + sigret bool frame Stackframe target *Target bi *BinaryInfo @@ -270,6 +271,7 @@ func (it *stackIterator) Next() bool { return true } + it.sigret = it.frame.Current.Fn != nil && it.frame.Current.Fn.Name == "runtime.sigpanic" it.top = false it.pc = it.frame.Ret it.regs = callFrameRegs @@ -329,7 +331,7 @@ func (it *stackIterator) newStackframe(ret, retaddr uint64) Stackframe { r.Regs.AddReg(it.regs.PCRegNum, op.DwarfRegisterFromUint64(it.pc)) } r.Call = r.Current - if !it.top && r.Current.Fn != nil && it.pc != r.Current.Fn.Entry { + if !it.top && r.Current.Fn != nil && it.pc != r.Current.Fn.Entry && !it.sigret { // if the return address is the entry point of the function that // contains it then this is some kind of fake return frame (for example // runtime.sigreturn) that didn't actually call the current frame,