in internal/gocore/type.go [526:644]
func (p *Process) typeObject(a core.Address, t *Type, r reader, add func(core.Address, *Type, int64)) {
ptrSize := p.proc.PtrSize()
switch t.Kind {
case KindBool, KindInt, KindUint, KindFloat, KindComplex:
// Nothing to do
case KindEface, KindIface:
// interface. Use the type word to determine the type
// of the pointed-to object.
typPtr := r.ReadPtr(a)
if typPtr == 0 { // nil interface
return
}
data := a.Add(ptrSize)
if t.Kind == KindIface {
typPtr = p.proc.ReadPtr(typPtr.Add(p.findType("runtime.itab").field("_type").Off))
}
// TODO: for KindEface, type typPtr. It might point to the heap
// if the type was allocated with reflect.
typ := p.runtimeType2Type(typPtr)
typr := region{p: p, a: typPtr, typ: p.findType("runtime._type")}
if typr.Field("kind").Uint8()&uint8(p.rtConstants["kindDirectIface"]) == 0 {
// Indirect interface: the interface introduced a new
// level of indirection, not reflected in the type.
// Read through it.
add(r.ReadPtr(data), typ, 1)
return
}
// Direct interface: the contained type is a single pointer.
// Figure out what it is and type it. See isdirectiface() for the rules.
directTyp := typ
findDirect:
for {
if directTyp.Kind == KindArray {
directTyp = typ.Elem
continue findDirect
}
if directTyp.Kind == KindStruct {
for _, f := range directTyp.Fields {
if f.Type.Size != 0 {
directTyp = f.Type
continue findDirect
}
}
}
if directTyp.Kind != KindFunc && directTyp.Kind != KindPtr {
panic(fmt.Sprintf("type of direct interface, originally %s (kind %s), isn't a pointer: %s (kind %s)", typ, typ.Kind, directTyp, directTyp.Kind))
}
break
}
add(data, directTyp, 1)
case KindString:
ptr := r.ReadPtr(a)
len := r.ReadInt(a.Add(ptrSize))
add(ptr, t.Elem, len)
case KindSlice:
ptr := r.ReadPtr(a)
cap := r.ReadInt(a.Add(2 * ptrSize))
add(ptr, t.Elem, cap)
case KindPtr:
if t.Elem != nil { // unsafe.Pointer has a nil Elem field.
add(r.ReadPtr(a), t.Elem, 1)
}
case KindFunc:
// The referent is a closure. We don't know much about the
// type of the referent. Its first entry is a code pointer.
// The runtime._type we want exists in the binary (for all
// heap-allocated closures, anyway) but it would be hard to find
// just given the pc.
closure := r.ReadPtr(a)
if closure == 0 {
break
}
pc := p.proc.ReadPtr(closure)
f := p.funcTab.find(pc)
if f == nil {
panic(fmt.Sprintf("can't find func for closure pc %x", pc))
}
ft := f.closure
if ft == nil {
ft = &Type{Name: "closure for " + f.name, Size: ptrSize, Kind: KindPtr}
// For now, treat a closure like an unsafe.Pointer.
// TODO: better value for size?
f.closure = ft
}
p.typeObject(closure, ft, r, add)
case KindArray:
n := t.Elem.Size
for i := int64(0); i < t.Count; i++ {
p.typeObject(a.Add(i*n), t.Elem, r, add)
}
case KindStruct:
if strings.HasPrefix(t.Name, "hash<") {
// Special case - maps have a pointer to the first bucket
// but it really types all the buckets (like a slice would).
var bPtr core.Address
var bTyp *Type
var n int64
for _, f := range t.Fields {
if f.Name == "buckets" {
bPtr = p.proc.ReadPtr(a.Add(f.Off))
bTyp = f.Type.Elem
}
if f.Name == "B" {
n = int64(1) << p.proc.ReadUint8(a.Add(f.Off))
}
}
add(bPtr, bTyp, n)
// TODO: also oldbuckets
}
// TODO: also special case for channels?
for _, f := range t.Fields {
p.typeObject(a.Add(f.Off), f.Type, r, add)
}
default:
panic(fmt.Sprintf("unknown type kind %s\n", t.Kind))
}
}