proc: fix stacktrace frame after runtime.sigpanic (#3638)

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
This commit is contained in:
Alessandro Arzilli 2024-01-18 01:31:04 +01:00 committed by GitHub
parent 88380654fe
commit 4ed69d0280
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 36 additions and 1 deletions

8
_fixtures/panicline.go Normal file

@ -0,0 +1,8 @@
package main
import "os"
func main() {
fi, _ := os.Lstat("/this/path/does/not/exist")
fi.Size()
}

@ -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")
}
})
}

@ -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,