in internal/gocore/type.go [115:217]
func (p *Process) runtimeType2Type(a core.Address) *Type {
if t := p.runtimeMap[a]; t != nil {
return t
}
// Read runtime._type.size
r := region{p: p, a: a, typ: p.findType("runtime._type")}
size := int64(r.Field("size").Uintptr())
// Find module this type is in.
var m *module
for _, x := range p.modules {
if x.types <= a && a < x.etypes {
m = x
break
}
}
// Read information out of the runtime._type.
var name string
if m != nil {
x := m.types.Add(int64(r.Field("str").Int32()))
n := uint16(p.proc.ReadUint8(x.Add(1)))<<8 + uint16(p.proc.ReadUint8(x.Add(2)))
b := make([]byte, n)
p.proc.ReadAt(b, x.Add(3))
name = string(b)
if r.Field("tflag").Uint8()&uint8(p.rtConstants["tflagExtraStar"]) != 0 {
name = name[1:]
}
} else {
// A reflect-generated type.
// TODO: The actual name is in the runtime.reflectOffs map.
// Too hard to look things up in maps here, just allocate a placeholder for now.
name = fmt.Sprintf("reflect.generatedType%x", a)
}
// Read ptr/nonptr bits
ptrSize := p.proc.PtrSize()
nptrs := int64(r.Field("ptrdata").Uintptr()) / ptrSize
var ptrs []int64
if r.Field("kind").Uint8()&uint8(p.rtConstants["kindGCProg"]) == 0 {
gcdata := r.Field("gcdata").Address()
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)
}
}
} else {
// TODO: run GC program to get ptr indexes
}
// Find a Type that matches this type.
// (The matched type will be one constructed from DWARF info.)
// It must match name, size, and pointer bits.
var candidates []*Type
for _, t := range p.runtimeNameMap[name] {
if size == t.Size && equal(ptrs, t.ptrs()) {
candidates = append(candidates, t)
}
}
var t *Type
if len(candidates) > 0 {
// If a runtime type matches more than one DWARF type,
// pick one arbitrarily.
// This looks mostly harmless. DWARF has some redundant entries.
// For example, [32]uint8 appears twice.
// TODO: investigate the reason for this duplication.
t = candidates[0]
} else {
// There's no corresponding DWARF type. Make our own.
t = &Type{Name: name, Size: size, Kind: KindStruct}
n := t.Size / ptrSize
// Types to use for ptr/nonptr fields of runtime types which
// have no corresponding DWARF type.
ptr := p.findType("unsafe.Pointer")
nonptr := p.findType("uintptr")
if ptr == nil || nonptr == nil {
panic("ptr / nonptr standins missing")
}
for i := int64(0); i < n; i++ {
typ := nonptr
if len(ptrs) > 0 && ptrs[0] == i*ptrSize {
typ = ptr
ptrs = ptrs[1:]
}
t.Fields = append(t.Fields, Field{
Name: fmt.Sprintf("f%d", i),
Off: i * ptrSize,
Type: typ,
})
}
if t.Size%ptrSize != 0 {
// TODO: tail of <ptrSize data.
}
}
// Memoize.
p.runtimeMap[a] = t
return t
}