internal/gocore/dwarf.go
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"),
					},
				},
			},
		}
	}
}
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"),
					},
				},
			},
		}
	}
}
// read DWARF types from core dump.