pkg/proc: improve support unwinding from sigpanic (#3559)
See: https://github.com/golang/go/issues/63862 Fixes #3545
This commit is contained in:
parent
438d036fed
commit
d186e14fd9
6
_fixtures/nilptr.go
Normal file
6
_fixtures/nilptr.go
Normal file
@ -0,0 +1,6 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
var p_value *int = nil
|
||||
*p_value = 1
|
||||
}
|
@ -112,7 +112,7 @@ func amd64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *Binary
|
||||
fctxt.CFA = rule
|
||||
}
|
||||
|
||||
// We assume that RBP is the frame pointer and we want to keep it updated,
|
||||
// We assume that RBP is the frame pointer, and we want to keep it updated,
|
||||
// so that we can use it to unwind the stack even when we encounter frames
|
||||
// without descriptor entries.
|
||||
// If there isn't a rule already we emit one.
|
||||
|
@ -117,7 +117,7 @@ func arm64FixFrameUnwindContext(fctxt *frame.FrameContext, pc uint64, bi *Binary
|
||||
fctxt.CFA = rule
|
||||
}
|
||||
|
||||
// We assume that RBP is the frame pointer and we want to keep it updated,
|
||||
// We assume that RBP is the frame pointer, and we want to keep it updated,
|
||||
// so that we can use it to unwind the stack even when we encounter frames
|
||||
// without descriptor entries.
|
||||
// If there isn't a rule already we emit one.
|
||||
|
@ -6358,3 +6358,27 @@ func TestNextGenericMethodThroughInterface(t *testing.T) {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestIssue3545(t *testing.T) {
|
||||
protest.AllowRecording(t)
|
||||
withTestProcessArgs("nilptr", t, "", []string{}, protest.EnableOptimization, func(p *proc.Target, grp *proc.TargetGroup, fixture protest.Fixture) {
|
||||
err := grp.Continue()
|
||||
if err != nil && err.Error() == "bad access" {
|
||||
grp.Continue()
|
||||
}
|
||||
locations, err := proc.ThreadStacktrace(p, p.CurrentThread(), 40)
|
||||
assertNoError(err, t, "Stacktrace()")
|
||||
var foundMain bool
|
||||
for _, loc := range locations {
|
||||
if loc.Call.Fn != nil && loc.Call.Fn.Name == "main.main" {
|
||||
if foundMain {
|
||||
t.Fatal("main.main found more than once in the stacktrace")
|
||||
}
|
||||
foundMain = true
|
||||
}
|
||||
}
|
||||
if !foundMain {
|
||||
t.Fatal("did not find main.main in stack trace")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
package proc
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"debug/dwarf"
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/constant"
|
||||
@ -481,7 +483,6 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
|
||||
for i, regRule := range framectx.Regs {
|
||||
if logflags.Stack() {
|
||||
logger.Debugf("\t%s rule %s ", it.bi.Arch.RegnumToString(i), ruleString(®Rule, it.bi.Arch.RegnumToString))
|
||||
|
||||
}
|
||||
reg, err := it.executeFrameRegRule(i, regRule, it.regs.CFA)
|
||||
if reg != nil {
|
||||
@ -499,6 +500,22 @@ func (it *stackIterator) advanceRegs() (callFrameRegs op.DwarfRegisters, ret uin
|
||||
it.err = err
|
||||
} else {
|
||||
ret = reg.Uint64Val
|
||||
// On systems which use a link register to store the return address of a function,
|
||||
// certain leaf functions may not have correct DWARF information present in the
|
||||
// .debug_frame FDE when unwinding after a fatal signal. This is due to the fact
|
||||
// that runtime.sigpanic inserts a frame to make it look like the function which
|
||||
// triggered the signal called runtime.sigpanic directly, making the value of the
|
||||
// link register unreliable. Instead, treat it as a non-leaf function and read the
|
||||
// return address from the stack. For more details, see:
|
||||
// https://github.com/golang/go/issues/63862#issuecomment-1802672629.
|
||||
if it.frame.Call.Fn != nil && it.frame.Call.Fn.Name == "runtime.sigpanic" && it.bi.Arch.usesLR {
|
||||
buf := make([]byte, 8)
|
||||
_, err := it.mem.ReadMemory(buf, uint64(it.regs.CFA))
|
||||
if err != nil {
|
||||
it.err = err
|
||||
}
|
||||
binary.Read(bytes.NewReader(buf), binary.LittleEndian, &ret)
|
||||
}
|
||||
}
|
||||
retaddr = uint64(it.regs.CFA + regRule.Offset)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user