internal/gocore: update for Go 1.18

All of the changes required are related to josharian@'s series removing
relocations from FUNCDATA, etc (CL 352110, CL 353138, CL 352191).

I am least confident about the changes in Process.readFrame. Some
functions are missing the LocalsPointerMap, which is possible for small
frames (we don't check this), but I don't see why behavior should have
changed here from prior versions, and thus I worry that I've missed
something.

Change-Id: I4b9c4b5ea7adcfb0b82036f8c7068d49fd8b8cb9
Reviewed-on: https://go-review.googlesource.com/c/debug/+/425700
Run-TryBot: Michael Pratt <mpratt@google.com>
Reviewed-by: Keith Randall <khr@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
diff --git a/internal/gocore/gocore_test.go b/internal/gocore/gocore_test.go
index 5f8bfd3..ce50b5d 100644
--- a/internal/gocore/gocore_test.go
+++ b/internal/gocore/gocore_test.go
@@ -276,6 +276,7 @@
 	loadExampleVersion(t, "1.14.zip")
 	loadExampleVersion(t, "1.16.zip")
 	loadExampleVersion(t, "1.17.zip")
+	loadExampleVersion(t, "1.18.zip")
 }
 
 func loadZipCore(t *testing.T, name string) *Process {
diff --git a/internal/gocore/module.go b/internal/gocore/module.go
index aacbd0c..f17c181 100644
--- a/internal/gocore/module.go
+++ b/internal/gocore/module.go
@@ -46,9 +46,21 @@
 	n := ftab.SliceLen() - 1 // last slot is a dummy, just holds entry
 	for i := int64(0); i < n; i++ {
 		ft := ftab.SliceIndex(i)
-		min := core.Address(ft.Field("entry").Uintptr())
-		max := core.Address(ftab.SliceIndex(i + 1).Field("entry").Uintptr())
-		fr := pcln.SliceIndex(int64(ft.Field("funcoff").Uintptr())).Cast("runtime._func")
+		var min, max core.Address
+		var funcoff int64
+		if p.minorVersion >= 18 {
+			min = m.textAddr(ft.Field("entryoff").Uint32())
+			max = m.textAddr(ftab.SliceIndex(i + 1).Field("entryoff").Uint32())
+			funcoff = int64(ft.Field("funcoff").Uint32())
+		} else {
+			// Prior to 1.18, functab.entry directly referenced the
+			// entries.
+			min = core.Address(ft.Field("entry").Uintptr())
+			max = core.Address(ftab.SliceIndex(i + 1).Field("entry").Uintptr())
+			// funcoff changed type, but had the same meaning.
+			funcoff = int64(ft.Field("funcoff").Uintptr())
+		}
+		fr := pcln.SliceIndex(funcoff).Cast("runtime._func")
 		var f *Func
 		if p.minorVersion >= 16 {
 			f = m.readFunc(fr, pctab, funcnametab)
@@ -69,7 +81,12 @@
 // pcln must have type []byte and represent the module's pcln table region.
 func (m *module) readFunc(r region, pctab region, funcnametab region) *Func {
 	f := &Func{module: m, r: r}
-	f.entry = core.Address(r.Field("entry").Uintptr())
+	if m.p.minorVersion >= 18 {
+		f.entry = m.textAddr(r.Field("entryoff").Uint32())
+	} else {
+		// Prior to 1.18, _func.entry directly referenced the entries.
+		f.entry = core.Address(r.Field("entry").Uintptr())
+	}
 	f.name = r.p.proc.ReadCString(funcnametab.SliceIndex(int64(r.Field("nameoff").Int32())).a)
 	pcsp := r.Field("pcsp")
 	var pcspIdx int64
@@ -106,8 +123,22 @@
 		n = uint32(nfd.Int32())
 	}
 	for i := uint32(0); i < n; i++ {
-		f.funcdata = append(f.funcdata, r.p.proc.ReadPtr(a))
-		a = a.Add(r.p.proc.PtrSize())
+		if m.p.minorVersion >= 18 {
+			// Since 1.18, funcdata contains offsets from go.func.*.
+			off := r.p.proc.ReadUint32(a)
+			if off == ^uint32(0) {
+				// No entry.
+				f.funcdata = append(f.funcdata, 0)
+			} else {
+				f.funcdata = append(f.funcdata, core.Address(m.r.Field("gofunc").Uintptr() + uint64(off)))
+			}
+			a = a.Add(4)
+		} else {
+			// Prior to 1.18, funcdata contains pointers directly
+			// to the data.
+			f.funcdata = append(f.funcdata, r.p.proc.ReadPtr(a))
+			a = a.Add(r.p.proc.PtrSize())
+		}
 	}
 
 	// Read pcln tables we need.
@@ -120,6 +151,32 @@
 	return f
 }
 
+// textAddr returns the address of a text offset.
+//
+// Equivalent to runtime.moduledata.textAddr.
+func (m *module) textAddr(off32 uint32) core.Address {
+	off := uint64(off32)
+	res := m.r.Field("text").Uintptr() + off
+
+	textsectmap := m.r.Field("textsectmap")
+	length := textsectmap.SliceLen()
+	if length > 1 {
+		for i := int64(0); i < length; i++ {
+			sect := textsectmap.SliceIndex(i)
+
+			vaddr := sect.Field("vaddr").Uintptr()
+			end := sect.Field("end").Uintptr()
+			baseaddr := sect.Field("baseaddr").Uintptr()
+
+			if off >= vaddr && off < end || (i == length-1 && off == end) {
+				res = baseaddr + off - vaddr
+			}
+		}
+	}
+
+	return core.Address(res)
+}
+
 type funcTabEntry struct {
 	min, max core.Address
 	f        *Func
diff --git a/internal/gocore/process.go b/internal/gocore/process.go
index c46a731..6bc6960 100644
--- a/internal/gocore/process.go
+++ b/internal/gocore/process.go
@@ -678,46 +678,55 @@
 	// Find live ptrs in locals
 	live := map[core.Address]bool{}
 	if x := int(p.rtConstants["_FUNCDATA_LocalsPointerMaps"]); x < len(f.funcdata) {
-		locals := region{p: p, a: f.funcdata[x], typ: p.findType("runtime.stackmap")}
-		n := locals.Field("n").Int32()       // # of bitmaps
-		nbit := locals.Field("nbit").Int32() // # of bits per bitmap
-		idx, err := f.stackMap.find(off)
-		if err != nil {
-			return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
-		}
-		if idx < 0 {
-			idx = 0
-		}
-		if idx < int64(n) {
-			bits := locals.Field("bytedata").a.Add(int64(nbit+7) / 8 * idx)
-			base := frame.max.Add(-16).Add(-int64(nbit) * p.proc.PtrSize())
-			// TODO: -16 for amd64. Return address and parent's frame pointer
-			for i := int64(0); i < int64(nbit); i++ {
-				if p.proc.ReadUint8(bits.Add(i/8))>>uint(i&7)&1 != 0 {
-					live[base.Add(i*p.proc.PtrSize())] = true
+		addr := f.funcdata[x]
+		// TODO: Ideally we should have the same frame size check as
+		// runtime.getStackSize to detect errors when we are missing
+		// the stackmap.
+		if addr != 0 {
+			locals := region{p: p, a: addr, typ: p.findType("runtime.stackmap")}
+			n := locals.Field("n").Int32()       // # of bitmaps
+			nbit := locals.Field("nbit").Int32() // # of bits per bitmap
+			idx, err := f.stackMap.find(off)
+			if err != nil {
+				return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
+			}
+			if idx < 0 {
+				idx = 0
+			}
+			if idx < int64(n) {
+				bits := locals.Field("bytedata").a.Add(int64(nbit+7) / 8 * idx)
+				base := frame.max.Add(-16).Add(-int64(nbit) * p.proc.PtrSize())
+				// TODO: -16 for amd64. Return address and parent's frame pointer
+				for i := int64(0); i < int64(nbit); i++ {
+					if p.proc.ReadUint8(bits.Add(i/8))>>uint(i&7)&1 != 0 {
+						live[base.Add(i*p.proc.PtrSize())] = true
+					}
 				}
 			}
 		}
 	}
 	// Same for args
 	if x := int(p.rtConstants["_FUNCDATA_ArgsPointerMaps"]); x < len(f.funcdata) {
-		args := region{p: p, a: f.funcdata[x], typ: p.findType("runtime.stackmap")}
-		n := args.Field("n").Int32()       // # of bitmaps
-		nbit := args.Field("nbit").Int32() // # of bits per bitmap
-		idx, err := f.stackMap.find(off)
-		if err != nil {
-			return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
-		}
-		if idx < 0 {
-			idx = 0
-		}
-		if idx < int64(n) {
-			bits := args.Field("bytedata").a.Add(int64(nbit+7) / 8 * idx)
-			base := frame.max
-			// TODO: add to base for LR archs.
-			for i := int64(0); i < int64(nbit); i++ {
-				if p.proc.ReadUint8(bits.Add(i/8))>>uint(i&7)&1 != 0 {
-					live[base.Add(i*p.proc.PtrSize())] = true
+		addr := f.funcdata[x]
+		if addr != 0 {
+			args := region{p: p, a: addr, typ: p.findType("runtime.stackmap")}
+			n := args.Field("n").Int32()       // # of bitmaps
+			nbit := args.Field("nbit").Int32() // # of bits per bitmap
+			idx, err := f.stackMap.find(off)
+			if err != nil {
+				return nil, fmt.Errorf("cannot read stack map at pc=%#x: %v", pc, err)
+			}
+			if idx < 0 {
+				idx = 0
+			}
+			if idx < int64(n) {
+				bits := args.Field("bytedata").a.Add(int64(nbit+7) / 8 * idx)
+				base := frame.max
+				// TODO: add to base for LR archs.
+				for i := int64(0); i < int64(nbit); i++ {
+					if p.proc.ReadUint8(bits.Add(i/8))>>uint(i&7)&1 != 0 {
+						live[base.Add(i*p.proc.PtrSize())] = true
+					}
 				}
 			}
 		}
diff --git a/internal/gocore/testdata/1.18.zip b/internal/gocore/testdata/1.18.zip
new file mode 100644
index 0000000..105a586
--- /dev/null
+++ b/internal/gocore/testdata/1.18.zip
Binary files differ