ogle/debug/dwarf: add SliceType, StringType, MapType
These new types make it cleaner to disambiguate DWARF items
representing Go types. They were previously just structs with
funny names.
Depends on 116720043

LGTM=rsc
R=rsc
https://golang.org/cl/116730043
diff --git a/debug/dwarf/const.go b/debug/dwarf/const.go
index 93c6888..454f789 100644
--- a/debug/dwarf/const.go
+++ b/debug/dwarf/const.go
@@ -84,6 +84,11 @@
 	AttrCallFile       Attr = 0x58
 	AttrCallLine       Attr = 0x59
 	AttrDescription    Attr = 0x5A
+
+	// Go-specific attributes.
+	AttrGoKind Attr = 0x2900
+	AttrGoKey  Attr = 0x2901
+	AttrGoElem Attr = 0x2902
 )
 
 var attrNames = [...]string{
@@ -168,6 +173,14 @@
 			return s
 		}
 	}
+	switch a {
+	case AttrGoKind:
+		return "GoKind"
+	case AttrGoKey:
+		return "GoKey"
+	case AttrGoElem:
+		return "GoElem"
+	}
 	return strconv.Itoa(int(a))
 }
 
diff --git a/debug/dwarf/type.go b/debug/dwarf/type.go
index 33e68e7..9a1ea2e 100644
--- a/debug/dwarf/type.go
+++ b/debug/dwarf/type.go
@@ -8,7 +8,10 @@
 
 package dwarf
 
-import "strconv"
+import (
+	"reflect"
+	"strconv"
+)
 
 // A Type conventionally represents a pointer to any of the
 // specific Type structures (CharType, StructType, etc.).
@@ -22,8 +25,9 @@
 // If a field is not known or not applicable for a given type,
 // the zero value is used.
 type CommonType struct {
-	ByteSize int64  // size of value of this type, in bytes
-	Name     string // name that can be used to refer to type
+	ByteSize    int64        // size of value of this type, in bytes
+	Name        string       // name that can be used to refer to type
+	ReflectKind reflect.Kind // the reflect kind of the type.
 }
 
 func (c *CommonType) Common() *CommonType { return c }
@@ -181,6 +185,33 @@
 	return s
 }
 
+// A SliceType represents a Go slice type. It looks like a StructType, describing
+// the runtime-internal structure, with extra fields.
+type SliceType struct {
+	StructType
+	ElemType Type
+}
+
+func (t *SliceType) String() string {
+	if t.Name != "" {
+		return t.Name
+	}
+	return "[]" + t.ElemType.String()
+}
+
+// A StringType represents a Go string type. It looks like a StructType, describing
+// the runtime-internal structure, but we wrap it for neatness.
+type StringType struct {
+	StructType
+}
+
+func (t *StringType) String() string {
+	if t.Name != "" {
+		return t.Name
+	}
+	return "string"
+}
+
 // An EnumType represents an enumerated type.
 // The only indication of its native integer type is its ByteSize
 // (inside CommonType).
@@ -251,6 +282,21 @@
 
 func (t *TypedefType) Size() int64 { return t.Type.Size() }
 
+// A MapType represents a Go slice type. It looks like a TypedefType, describing
+// the runtime-internal structure, with extra fields.
+type MapType struct {
+	TypedefType
+	KeyType  Type
+	ElemType Type
+}
+
+func (t *MapType) String() string {
+	if t.Name != "" {
+		return t.Name
+	}
+	return "map[" + t.KeyType.String() + "]" + t.ElemType.String()
+}
+
 // typeReader is used to read from either the info section or the
 // types section.
 type typeReader interface {
@@ -265,6 +311,11 @@
 	return d.readType("info", d.Reader(), off, d.typeCache)
 }
 
+func getKind(e *Entry) reflect.Kind {
+	integer, _ := e.Val(AttrGoKind).(int64)
+	return reflect.Kind(integer)
+}
+
 // readType reads a type from r at off of name using and updating a
 // type cache.
 func (d *Data) readType(name string, r typeReader, off Offset, typeCache map[Offset]Type) (Type, error) {
@@ -324,10 +375,10 @@
 		}
 	}
 
-	// Get Type referred to by Entry's AttrType field.
+	// Get Type referred to by Entry's attr.
 	// Set err if error happens.  Not having a type is an error.
-	typeOf := func(e *Entry) Type {
-		tval := e.Val(AttrType)
+	typeOf := func(e *Entry, attr Attr) Type {
+		tval := e.Val(attr)
 		var t Type
 		switch toff := tval.(type) {
 		case Offset:
@@ -356,9 +407,10 @@
 		//	TagSubrangeType or TagEnumerationType giving one dimension.
 		//	dimensions are in left to right order.
 		t := new(ArrayType)
+		t.ReflectKind = getKind(e)
 		typ = t
 		typeCache[off] = t
-		if t.Type = typeOf(e); err != nil {
+		if t.Type = typeOf(e, AttrType); err != nil {
 			goto Error
 		}
 		t.StrideBitSize, _ = e.Val(AttrStrideSize).(int64)
@@ -435,13 +487,16 @@
 		t.Name = name
 		t.BitSize, _ = e.Val(AttrBitSize).(int64)
 		t.BitOffset, _ = e.Val(AttrBitOffset).(int64)
+		t.ReflectKind = getKind(e)
 
 	case TagClassType, TagStructType, TagUnionType:
 		// Structure, union, or class type.  (DWARF v2 §5.5)
+		// Also Slices and Strings (Go-specific).
 		// Attributes:
 		//	AttrName: name of struct, union, or class
 		//	AttrByteSize: byte size [required]
 		//	AttrDeclaration: if true, struct/union/class is incomplete
+		// 	AttrGoElem: present for slices only.
 		// Children:
 		//	TagMember to describe one member.
 		//		AttrName: name of member [required]
@@ -452,8 +507,21 @@
 		//		AttrDataMemberLoc: location within struct [required for struct, class]
 		// There is much more to handle C++, all ignored for now.
 		t := new(StructType)
-		typ = t
-		typeCache[off] = t
+		t.ReflectKind = getKind(e)
+		switch t.ReflectKind {
+		case reflect.Slice:
+			slice := new(SliceType)
+			slice.ElemType = typeOf(e, AttrGoElem)
+			t = &slice.StructType
+			typ = slice
+		case reflect.String:
+			str := new(StringType)
+			t = &str.StructType
+			typ = str
+		default:
+			typ = t
+		}
+		typeCache[off] = typ
 		switch e.Tag {
 		case TagClassType:
 			t.Kind = "class"
@@ -470,7 +538,7 @@
 		for kid := next(); kid != nil; kid = next() {
 			if kid.Tag == TagMember {
 				f := new(StructField)
-				if f.Type = typeOf(kid); err != nil {
+				if f.Type = typeOf(kid, AttrType); err != nil {
 					goto Error
 				}
 				switch loc := kid.Val(AttrDataMemberLoc).(type) {
@@ -524,9 +592,10 @@
 		// Attributes:
 		//	AttrType: subtype
 		t := new(QualType)
+		t.ReflectKind = getKind(e)
 		typ = t
 		typeCache[off] = t
-		if t.Type = typeOf(e); err != nil {
+		if t.Type = typeOf(e, AttrType); err != nil {
 			goto Error
 		}
 		switch e.Tag {
@@ -548,6 +617,7 @@
 		//		AttrName: name of constant
 		//		AttrConstValue: value of constant
 		t := new(EnumType)
+		t.ReflectKind = getKind(e)
 		typ = t
 		typeCache[off] = t
 		t.EnumName, _ = e.Val(AttrName).(string)
@@ -574,13 +644,14 @@
 		//	AttrType: subtype [not required!  void* has no AttrType]
 		//	AttrAddrClass: address class [ignored]
 		t := new(PtrType)
+		t.ReflectKind = getKind(e)
 		typ = t
 		typeCache[off] = t
 		if e.Val(AttrType) == nil {
 			t.Type = &VoidType{}
 			break
 		}
-		t.Type = typeOf(e)
+		t.Type = typeOf(e, AttrType)
 
 	case TagSubroutineType:
 		// Subroutine type.  (DWARF v2 §5.7)
@@ -593,9 +664,10 @@
 		//		AttrType: type of parameter
 		//	TagUnspecifiedParameter: final ...
 		t := new(FuncType)
+		t.ReflectKind = getKind(e)
 		typ = t
 		typeCache[off] = t
-		if t.ReturnType = typeOf(e); err != nil {
+		if t.ReturnType = typeOf(e, AttrType); err != nil {
 			goto Error
 		}
 		t.ParamType = make([]Type, 0, 8)
@@ -605,7 +677,7 @@
 			default:
 				continue
 			case TagFormalParameter:
-				if tkid = typeOf(kid); err != nil {
+				if tkid = typeOf(kid, AttrType); err != nil {
 					goto Error
 				}
 			case TagUnspecifiedParameters:
@@ -616,14 +688,27 @@
 
 	case TagTypedef:
 		// Typedef (DWARF v2 §5.3)
+		// Also maps (Go-specific).
 		// Attributes:
 		//	AttrName: name [required]
 		//	AttrType: type definition [required]
+		//	AttrGoKey: present for maps only.
+		//	AttrElemKey: present for maps only.
 		t := new(TypedefType)
-		typ = t
-		typeCache[off] = t
+		t.ReflectKind = getKind(e)
+		switch t.ReflectKind {
+		case reflect.Map:
+			m := new(MapType)
+			m.KeyType = typeOf(e, AttrGoKey)
+			m.ElemType = typeOf(e, AttrGoElem)
+			t = &m.TypedefType
+			typ = m
+		default:
+			typ = t
+		}
+		typeCache[off] = typ
 		t.Name, _ = e.Val(AttrName).(string)
-		t.Type = typeOf(e)
+		t.Type = typeOf(e, AttrType)
 	}
 
 	if err != nil {