func gocoreName(dt dwarf.Type) string {
	if dt == nil {
		return "<badtype>"
	}
	switch x := dt.(type) {
	case *dwarf.PtrType:
		if _, ok := x.Type.(*dwarf.VoidType); ok {
			return "unsafe.Pointer"
		}
		return "*" + gocoreName(x.Type)
	case *dwarf.ArrayType:
		return fmt.Sprintf("[%d]%s", x.Count, gocoreName(x.Type))
	case *dwarf.StructType:
		if !strings.HasPrefix(x.StructName, "struct {") {
			return x.StructName
		}
		s := "struct {"
		first := true
		for _, f := range x.Field {
			if !first {
				s += ";"
			}
			name := f.Name
			if i := strings.Index(name, "."); i >= 0 {
				name = name[i+1:]
			}
			s += fmt.Sprintf(" %s %s", name, gocoreName(f.Type))
			first = false
		}
		s += " }"
		return s
	default:
		return dt.String()
	}
}
gocoreName generates the name this package uses to refer to a dwarf type.
package gocore
import (
	"debug/dwarf"
	"fmt"
	"os"
	"regexp"
	"sort"
	"strings"
	"github.com/randall77/corelib/core"
)
func wrapType(d *dwarf.Data, off dwarf.Offset) (dt dwarf.Type, err error) {
	defer func() {
		if r := recover(); r != nil {
			if false {
				fmt.Fprintf(os.Stderr, "bad offset: %d\n", off)
			}
			dt = nil
			err = r.(error)
		}
	}()
	dt, err = d.Type(off)
	return
}
func wrapSize(dt dwarf.Type) (size int64) {
	defer func() {
		if r := recover(); r != nil {
			if false {
				fmt.Fprintf(os.Stderr, "bad size: %s\n", dt)
			}
			size = 0
		}
	}()
	size = dt.Size()
	return
}
func (p *Process) readDWARFTypes() {
	d, _ := p.proc.DWARF()
	r := d.Reader()
	var types []*Type
	for e, err := r.Next(); e != nil && err == nil; e, err = r.Next() {
		switch e.Tag {
		case dwarf.TagArrayType, dwarf.TagPointerType, dwarf.TagStructType, dwarf.TagBaseType, dwarf.TagSubroutineType, dwarf.TagTypedef:
			dt, err := wrapType(d, e.Offset)
			if err != nil {
				continue
			}
			size := wrapSize(dt)
			if size < 0 {  
				size = dwarfSize(dt, p.proc.PtrSize())
			}
			t := &Type{name: gocoreName(dt), Size: size}
			p.dwarfMap[dt] = t
			types = append(types, t)
		}
	}
	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
			if t.Elem == nil {
				delete(p.dwarfMap, dt)
			}
		case *dwarf.PtrType:
			t.Kind = KindPtr
			if _, ok := x.Type.(*dwarf.VoidType); !ok {
				t.Elem = p.dwarfMap[x.Type]
			}
		case *dwarf.StructType:
			t.Kind = KindStruct
			for _, f := range x.Field {
				if p.dwarfMap[f.Type] == nil {
					continue
				}
				t.Fields = append(t.Fields, Field{Name: f.Name, Type: p.dwarfMap[f.Type], 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:
		case *dwarf.CharType:
			t.Kind = KindInt
		case *dwarf.UcharType:
			t.Kind = KindUint
		default:
			panic(fmt.Sprintf("unknown type %s %T", dt, dt))
		}
	}
	for _, t := range types {
		if t.Kind != KindStruct {
			continue
		}
		if t.name == "string" || t.name == "struct runtime.stringStructDWARF" {
			t.Kind = KindString
			t.Elem = t.Fields[0].Type.Elem  
			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
		}
	}
	r = d.Reader()
	for e, err := r.Next(); e != nil && err == nil; e, err = r.Next() {
		if e.Tag != dwarf.TagTypedef {
			continue
		}
		dt, err := d.Type(e.Offset)
		if err != nil {
			continue
		}
		base := dt.(*dwarf.TypedefType).Type
		for {
			if x, ok := base.(*dwarf.TypedefType); ok {
				base = x.Type
				continue
			}
			break
		}
		t := p.dwarfMap[dt]
		bt := p.dwarfMap[base]
		if bt == nil {
			delete(p.dwarfMap, dt)
			continue
		}
		name := t.name
		*t = *bt
		t.name = name
		if bt.name == "runtime.eface" {
			t.Kind = KindEface
			t.Fields = nil
		}
		if bt.name == "runtime.iface" {
			t.Kind = KindIface
			t.Fields = nil
		}
	}
	p.runtimeNameMap = map[string][]*Type{}
	for dt, t := range p.dwarfMap {
		name := runtimeName(dt)
		p.runtimeNameMap[name] = append(p.runtimeNameMap[name], t)
	}
	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 dwarfSize(dt dwarf.Type, ptrSize int64) int64 {
	switch x := dt.(type) {
	case *dwarf.FuncType:
		return ptrSize  
	case *dwarf.ArrayType:
		return x.Count * dwarfSize(x.Type, ptrSize)
	case *dwarf.TypedefType:
		return dwarfSize(x.Type, ptrSize)
	case *dwarf.UnspecifiedType:
		return 0  
	case *dwarf.StructType:
		return 0  
	case *dwarf.QualType:
		return 0  
	default:
		panic(fmt.Sprintf("unhandled %T", dt))
	}
}