internal/gocore: find new names of runtime._type and runtime.itab

This change makes (e.g.) `viewcore histogram` run without crashing cores
produced by current toolchains again. The output is still partially
wrong, in the sense that it outputs a mixture of named and unnamed
types:

    runtime.g size=448
    []*runtime.moduledata size=24
    [1+1?]*runtime.moduledata size=16
    [10+6?]uint8 size=16
    [1+3?]uint32 size=16

Still it's an improvement over the status quo.

In Go 1.21, runtime._type was converted from its own type into an alias
of internal/abi.Type. In the process, its fields became public too. For
an overview of the history:

 - https://go.dev/cl/462995 (internal/abi: refactor (basic) type struct into one definition)
 - https://go.dev/cl/484856 (internal/reflectlite, runtime: move more constants and types into internal/abi)
 - https://go.dev/cl/488435 (runtime: redefine _type to abi.Type; add rtype for methods)

In https://go.dev/cl/608475 (internal/gocore: support Go 1.22 allocation
headers), this was partially reflected in viewcore, but only just enough
to get basic tests for the current toolchain working.

There were still references to the old `runtime._type` and
`runtime.itab` (renamed `abi.ITab`), causing crashes for certain
operations, like `viewcore histogram` as well as the nascent dominator
tree code:

    panic: can't find type runtime._type [recovered]
            panic: can't find type runtime._type

    golang.org/x/debug/internal/gocore.(*Process).findType(...)
            /home/aktau/go/debug/internal/gocore/process.go:112
    golang.org/x/debug/internal/gocore.(*Process).runtimeType2Type(0xc00026a000, 0x46d8a0, 0x4ee3a8)
            /home/aktau/go/debug/internal/gocore/type.go:153 +0x14d9
    golang.org/x/debug/internal/gocore.(*Process).typeObject(0xc00026a000, 0x4ee3a0, 0xc000392460, {0x7b9e40, 0xc0001f4000}, 0xc00052d960)
            /home/aktau/go/debug/internal/gocore/type.go:636 +0xd45
    golang.org/x/debug/internal/gocore.(*Process).typeHeap.func1.2(0xc000582a08?)
            /home/aktau/go/debug/internal/gocore/type.go:514 +0x79
    golang.org/x/debug/internal/gocore.(*Process).ForEachRoot(0xc00026a000, 0xc00052db20)
            /home/aktau/go/debug/internal/gocore/object.go:220 +0x6a
    golang.org/x/debug/internal/gocore.(*Process).typeHeap.func1()
            /home/aktau/go/debug/internal/gocore/type.go:509 +0x179
    sync.(*Once).doSlow(0x6fe760?, 0xc00026a000?)
            /usr/lib/google-golang/src/sync/once.go:76 +0xb4
    sync.(*Once).Do(...)
            /usr/lib/google-golang/src/sync/once.go:67
    golang.org/x/debug/internal/gocore.(*Process).typeHeap(0x3?)
            /home/aktau/go/debug/internal/gocore/type.go:383 +0x3b
    golang.org/x/debug/internal/gocore.runLT(0xc00026a000)
            /home/aktau/go/debug/internal/gocore/dominator.go:89 +0x58
    golang.org/x/debug/internal/gocore.TestVersions.func2.1(0xc00012c680)
            /home/aktau/go/debug/internal/gocore/gocore_test.go:513 +0x5e

Change-Id: I8559c86f03d52b114f92756caf4487df75237983
Reviewed-on: https://go-review.googlesource.com/c/debug/+/634755
Auto-Submit: Nicolas Hillegeer <aktau@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Commit-Queue: Nicolas Hillegeer <aktau@google.com>
diff --git a/internal/gocore/gocore_test.go b/internal/gocore/gocore_test.go
index c716e8e..ec60ad9 100644
--- a/internal/gocore/gocore_test.go
+++ b/internal/gocore/gocore_test.go
@@ -471,6 +471,11 @@
 	if heapStat == nil || heapStat.Size == 0 {
 		t.Errorf("stat[%q].Size == 0, want >0", heapName)
 	}
+
+	lt := runLT(p)
+	if !checkDominator(t, lt) {
+		t.Errorf("sanityCheckDominator(...) = false, want true")
+	}
 }
 
 func TestVersions(t *testing.T) {
@@ -490,11 +495,6 @@
 		t.Run(ver, func(t *testing.T) {
 			p := loadExampleVersion(t, ver)
 			checkProcess(t, p)
-
-			lt := runLT(p)
-			if !checkDominator(t, lt) {
-				t.Errorf("sanityCheckDominator(...) = false, want true")
-			}
 		})
 	}
 
@@ -506,14 +506,6 @@
 			t.Run(strings.Join(buildFlags, ","), func(t *testing.T) {
 				p := loadExampleGenerated(t, buildFlags...)
 				checkProcess(t, p)
-
-				// TODO(aktau): Move checkDominator into checkProcess once this passes
-				// for loadExampleGenerated.
-				t.Skip(`skipping dominator check due to "panic: can't find type runtime.itab"`)
-				lt := runLT(p)
-				if !checkDominator(t, lt) {
-					t.Errorf("checkDominator(...) = false, want true")
-				}
 			})
 		}
 	})
diff --git a/internal/gocore/type.go b/internal/gocore/type.go
index 9f0b0ea..b3a4b27 100644
--- a/internal/gocore/type.go
+++ b/internal/gocore/type.go
@@ -140,6 +140,102 @@
 	}
 }
 
+// runtimeType is a thin wrapper around a runtime._type (AKA abi.Type) region
+// that abstracts over the name changes seen in Go 1.21.
+type runtimeType struct {
+	reg        region
+	hasAbiType bool // True if Go 1.21+
+}
+
+// findRuntimeType finds either abi.Type (Go 1.21+) or runtime._type.
+func (p *Process) findRuntimeType(a core.Address) runtimeType {
+	typ := runtimeType{
+		reg:        region{p: p, a: a, typ: p.tryFindType("abi.Type")},
+		hasAbiType: true,
+	}
+	if typ.reg.typ == nil {
+		typ.reg.typ = p.findType("runtime._type")
+		typ.hasAbiType = false
+	}
+	return typ
+}
+
+// Size_ is either abi.Type.Size_ or runtime._type.Size_.
+func (r runtimeType) Size_() int64 {
+	if !r.hasAbiType {
+		return int64(r.reg.Field("size").Uintptr())
+	}
+	return int64(r.reg.Field("Size_").Uintptr())
+}
+
+// TFlag is either abi.Type.TFlag or runtime._type.TFlag.
+func (r runtimeType) TFlag() uint8 {
+	if !r.hasAbiType {
+		return r.reg.Field("tflag").Uint8()
+	}
+	return r.reg.Field("TFlag").Uint8()
+}
+
+// Str is either abi.Type.Str or runtime._type.Str.
+func (r runtimeType) Str() int64 {
+	if !r.hasAbiType {
+		return int64(r.reg.Field("str").Int32())
+	}
+	return int64(r.reg.Field("Str").Int32())
+}
+
+// PtrBytes is either abi.Type.PtrBytes or runtime._type.PtrBytes.
+func (r runtimeType) PtrBytes() int64 {
+	if !r.hasAbiType {
+		return int64(r.reg.Field("ptrdata").Uintptr())
+	}
+	return int64(r.reg.Field("PtrBytes").Uintptr())
+}
+
+// Kind_ is either abi.Type.Kind_ or runtime._type.Kind_.
+func (r runtimeType) Kind_() uint8 {
+	if !r.hasAbiType {
+		return r.reg.Field("kind").Uint8()
+	}
+	return r.reg.Field("Kind_").Uint8()
+}
+
+// GCData is either abi.Type.GCData or runtime._type.GCData.
+func (r runtimeType) GCData() core.Address {
+	if !r.hasAbiType {
+		return r.reg.Field("gcdata").Address()
+	}
+	return r.reg.Field("GCData").Address()
+}
+
+// runtimeItab is a thin wrapper around a abi.ITab (used to be runtime.itab). It
+// abstracts over name/package changes in Go 1.21.
+type runtimeItab struct {
+	typ        *Type
+	hasAbiITab bool // True if Go 1.21+
+}
+
+// findItab finds either abi.ITab (Go 1.21+) or runtime.itab.
+func (p *Process) findItab() runtimeItab {
+	typ := runtimeItab{
+		typ:        p.tryFindType("abi.ITab"),
+		hasAbiITab: true,
+	}
+	if typ.typ == nil {
+		typ.typ = p.findType("runtime.itab")
+		typ.hasAbiITab = false
+	}
+	return typ
+}
+
+// Type is the field representing either abi.ITab.Type or runtime.itab._type.
+func (r runtimeItab) Type() *Field {
+	if !r.hasAbiITab {
+		return r.typ.field("_type")
+	}
+	return r.typ.field("Type")
+}
+
 // Convert the address of a runtime._type to a *Type.
 // The "d" is the address of the second field of an interface, used to help disambiguate types.
 // If "d" is 0, just return *Type and not to do the interface disambiguation.
@@ -150,8 +246,8 @@
 	}
 
 	// Read runtime._type.size
-	r := region{p: p, a: a, typ: p.findType("runtime._type")}
-	size := int64(r.Field("size").Uintptr())
+	r := p.findRuntimeType(a)
+	size := r.Size_()
 
 	// Find module this type is in.
 	var m *module
@@ -165,12 +261,12 @@
 	// Read information out of the runtime._type.
 	var name string
 	if m != nil {
-		x := m.types.Add(int64(r.Field("str").Int32()))
+		x := m.types.Add(r.Str())
 		i, n := readNameLen(p, x)
 		b := make([]byte, n)
 		p.proc.ReadAt(b, x.Add(i+1))
 		name = string(b)
-		if r.Field("tflag").Uint8()&uint8(p.rtConstants["tflagExtraStar"]) != 0 {
+		if r.TFlag()&uint8(p.rtConstants["tflagExtraStar"]) != 0 {
 			name = name[1:]
 		}
 	} else {
@@ -182,10 +278,10 @@
 
 	// Read ptr/nonptr bits
 	ptrSize := p.proc.PtrSize()
-	nptrs := int64(r.Field("ptrdata").Uintptr()) / ptrSize
+	nptrs := int64(r.PtrBytes()) / ptrSize
 	var ptrs []int64
-	if r.Field("kind").Uint8()&uint8(p.rtConstants["kindGCProg"]) == 0 {
-		gcdata := r.Field("gcdata").Address()
+	if r.Kind_()&uint8(p.rtConstants["kindGCProg"]) == 0 {
+		gcdata := r.GCData()
 		for i := int64(0); i < nptrs; i++ {
 			if p.proc.ReadUint8(gcdata.Add(i/8))>>uint(i%8)&1 != 0 {
 				ptrs = append(ptrs, i*ptrSize)
@@ -604,11 +700,8 @@
 
 // ifaceIndir reports whether t is stored indirectly in an interface value.
 func ifaceIndir(t core.Address, p *Process) bool {
-	typr := region{p: p, a: t, typ: p.findType("runtime._type")}
-	if typr.Field("kind").Uint8()&uint8(p.rtConstants["kindDirectIface"]) == 0 {
-		return true
-	}
-	return false
+	typr := p.findRuntimeType(t)
+	return typr.Kind_()&uint8(p.rtConstants["kindDirectIface"]) == 0
 }
 
 // typeObject takes an address and a type for the data at that address.
@@ -629,7 +722,7 @@
 		}
 		data := a.Add(ptrSize)
 		if t.Kind == KindIface {
-			typPtr = p.proc.ReadPtr(typPtr.Add(p.findType("runtime.itab").field("_type").Off))
+			typPtr = p.proc.ReadPtr(typPtr.Add(p.findItab().Type().Off))
 		}
 		// TODO: for KindEface, type typPtr. It might point to the heap
 		// if the type was allocated with reflect.