in internal/gocore/dwarf.go [18:201]
func (p *Process) readDWARFTypes() {
d, _ := p.proc.DWARF()
// Make one of our own Types for each dwarf type.
r := d.Reader()
var types []*Type
for e, err := r.Next(); e != nil && err == nil; e, err = r.Next() {
if isNonGoCU(e) {
r.SkipChildren()
continue
}
switch e.Tag {
case dwarf.TagArrayType, dwarf.TagPointerType, dwarf.TagStructType, dwarf.TagBaseType, dwarf.TagSubroutineType, dwarf.TagTypedef:
dt, err := d.Type(e.Offset)
if err != nil {
continue
}
t := &Type{Name: gocoreName(dt), Size: dwarfSize(dt, p.proc.PtrSize())}
p.dwarfMap[dt] = t
types = append(types, t)
}
}
p.runtimeNameMap = map[string][]*Type{}
// Fill in fields of types. Postponed until now so we're sure
// we have all the Types allocated and available.
for dt, t := range p.dwarfMap {
switch x := dt.(type) {
case *dwarf.ArrayType:
t.Kind = KindArray
t.Elem = p.dwarfMap[x.Type]
t.Count = x.Count
case *dwarf.PtrType:
t.Kind = KindPtr
// unsafe.Pointer has a void base type.
if _, ok := x.Type.(*dwarf.VoidType); !ok {
t.Elem = p.dwarfMap[x.Type]
}
case *dwarf.StructType:
t.Kind = KindStruct
for _, f := range x.Field {
fType := p.dwarfMap[f.Type]
// Work around issue 21094. There's no guarantee that the
// pointer type is in the DWARF, so just invent a Type.
if strings.HasPrefix(t.Name, "sudog<") && f.Name == "elem" &&
strings.Count(t.Name, "*")+1 != strings.Count(gocoreName(f.Type), "*") {
ptrName := "*" + gocoreName(f.Type)
fType = &Type{Name: ptrName, Kind: KindPtr, Size: p.proc.PtrSize(), Elem: fType}
p.runtimeNameMap[ptrName] = []*Type{fType}
}
t.Fields = append(t.Fields, Field{Name: f.Name, Type: fType, Off: f.ByteOffset})
}
case *dwarf.BoolType:
t.Kind = KindBool
case *dwarf.IntType:
t.Kind = KindInt
case *dwarf.UintType:
t.Kind = KindUint
case *dwarf.FloatType:
t.Kind = KindFloat
case *dwarf.ComplexType:
t.Kind = KindComplex
case *dwarf.FuncType:
t.Kind = KindFunc
case *dwarf.TypedefType:
// handle these types in the loop below
default:
panic(fmt.Sprintf("unknown type %s %T", dt, dt))
}
}
// Detect strings & slices
for _, t := range types {
if t.Kind != KindStruct {
continue
}
if t.Name == "string" { // TODO: also "struct runtime.stringStructDWARF" ?
t.Kind = KindString
t.Elem = t.Fields[0].Type.Elem // TODO: check that it is always uint8.
t.Fields = nil
}
if len(t.Name) >= 9 && t.Name[:9] == "struct []" ||
len(t.Name) >= 2 && t.Name[:2] == "[]" {
t.Kind = KindSlice
t.Elem = t.Fields[0].Type.Elem
t.Fields = nil
}
}
// Copy info from base types into typedefs.
for dt, t := range p.dwarfMap {
tt, ok := dt.(*dwarf.TypedefType)
if !ok {
continue
}
base := tt.Type
// Walk typedef chain until we reach a non-typedef type.
for {
if x, ok := base.(*dwarf.TypedefType); ok {
base = x.Type
continue
}
break
}
bt := p.dwarfMap[base]
// Copy type info from base. Everything except the name.
name := t.Name
*t = *bt
t.Name = name
// Detect some special types. If the base is some particular type,
// then the alias gets marked as special.
// We have aliases like:
// interface {} -> struct runtime.eface
// error -> struct runtime.iface
// Note: the base itself does not get marked as special.
// (Unlike strings and slices, where they do.)
if bt.Name == "runtime.eface" {
t.Kind = KindEface
t.Fields = nil
}
if bt.Name == "runtime.iface" {
t.Kind = KindIface
t.Fields = nil
}
}
// Make a runtime name -> Type map for existing DWARF types.
for dt, t := range p.dwarfMap {
name := runtimeName(dt)
p.runtimeNameMap[name] = append(p.runtimeNameMap[name], t)
}
// Construct the runtime.specialfinalizer type. It won't be found
// in DWARF before 1.10 because it does not appear in the type of any variable.
// type specialfinalizer struct {
// special special
// fn *funcval
// nret uintptr
// fint *_type
// ot *ptrtype
// }
if p.runtimeNameMap["runtime.specialfinalizer"] == nil {
special := p.findType("runtime.special")
p.runtimeNameMap["runtime.specialfinalizer"] = []*Type{
&Type{
Name: "runtime.specialfinalizer",
Size: special.Size + 4*p.proc.PtrSize(),
Kind: KindStruct,
Fields: []Field{
Field{
Name: "special",
Off: 0,
Type: special,
},
Field{
Name: "fn",
Off: special.Size,
Type: p.findType("*runtime.funcval"),
},
Field{
Name: "nret",
Off: special.Size + p.proc.PtrSize(),
Type: p.findType("uintptr"),
},
Field{
Name: "fint",
Off: special.Size + 2*p.proc.PtrSize(),
Type: p.findType("*runtime._type"),
},
Field{
Name: "fn",
Off: special.Size + 3*p.proc.PtrSize(),
Type: p.findType("*runtime.ptrtype"),
},
},
},
}
}
}