base.Fatalf("invalid heap allocated var without Heapaddr")
}
debug := fn.DebugInfo.(*ssa.FuncDebug)
- list := createHeapDerefLocationList(n, fnsym, debug.EntryID, ssa.FuncEnd.ID)
+ list := createHeapDerefLocationList(n, debug.EntryID)
dvar.PutLocationList = func(listSym, startPC dwarf.Sym) {
debug.PutLocationList(list, base.Ctxt, listSym.(*obj.LSym), startPC.(*obj.LSym))
}
// createHeapDerefLocationList creates a location list for a heap-escaped variable
// that describes "dereference pointer at stack offset"
-func createHeapDerefLocationList(n *ir.Name, fnsym *obj.LSym, entryID, prologEndID ssa.ID) []byte {
+func createHeapDerefLocationList(n *ir.Name, entryID ssa.ID) []byte {
// Get the stack offset where the heap pointer is stored
heapPtrOffset := n.Heapaddr.FrameOffset()
if base.Ctxt.Arch.FixedFrameSize == 0 {
})
}
+// This test ensures that variables promoted to the heap, specifically
+// function return parameters, have correct location lists generated.
+//
+// TODO(deparker): This test is intentionally limited to GOOS=="linux"
+// and scoped to net.sendFile, which was the function reported originally in
+// issue #65405. There is relevant discussion in https://go-review.googlesource.com/c/go/+/684377
+// pertaining to these limitations. There are other missing location lists which must be fixed
+// particularly in functions where `linkname` is involved.
func TestDWARFLocationList(t *testing.T) {
+ if runtime.GOOS != "linux" {
+ t.Skip("skipping test on non-linux OS")
+ }
testenv.MustHaveCGO(t)
testenv.MustHaveGoBuild(t)
// Look for the net.sendFile subprogram
if entry.Tag == dwarf.TagSubprogram {
fnName, ok := entry.Val(dwarf.AttrName).(string)
- if !ok {
+ if !ok || fnName != "net.sendFile" {
+ reader.SkipChildren()
continue
}
- if strings.Contains(fnName, ".eq") || // Ignore autogenerated equality funcs
- strings.HasPrefix(fnName, "internal/") || // Ignore internal/runtime package TODO(deparker): Fix these too (likely same issue as other ignored packages below).
- strings.HasPrefix(fnName, "runtime.") || // Ignore runtime package which contain funcs implemented in assembly or exposed through linkname which seems to not generate location lists correctly (most likely linkname causing this). TODO(deparker) Fix these too.
- strings.HasPrefix(fnName, "reflect.") || // Ignore reflect package. TODO(deparker) Fix these too.
- strings.HasPrefix(fnName, "time.") { // Ignore funcs in time package which are exposed through linkname and seem to not generate location lists correctly TODO(deparker) Fix these too.
- continue
- }
- if fnName == "syscall.compileCallback" || fnName == "maps.clone" {
- continue // Ignore for now, possibly caused by linkname usage. TODO(deparker) Fix this too.
- }
- if runtime.GOOS == "windows" && strings.HasPrefix(fnName, "syscall.") {
- continue // Ignore, caused by linkname usage. TODO(deparker) Fix these too.
- }
for {
paramEntry, err := reader.Next()
}
if paramEntry.Tag == dwarf.TagFormalParameter {
- paramName, hasName := paramEntry.Val(dwarf.AttrName).(string)
- if !hasName {
- continue
- }
- if paramName[0] == '~' {
- continue
- }
+ paramName, _ := paramEntry.Val(dwarf.AttrName).(string)
+
// Check if this parameter has a location attribute
if loc := paramEntry.Val(dwarf.AttrLocation); loc != nil {
switch locData := loc.(type) {