debug: Print information about channels.  Add ChanType to DWARF parser.

Channels were previously printed as raw pointers.

Change-Id: I4b2b4e4e91f2aabd08ddda0f29ccdee5a91ce288
Reviewed-on: https://go-review.googlesource.com/2717
Reviewed-by: Nigel Tao <nigeltao@golang.org>
diff --git a/dwarf/type.go b/dwarf/type.go
index 5669c10..4f58b74 100644
--- a/dwarf/type.go
+++ b/dwarf/type.go
@@ -287,7 +287,7 @@
 
 func (t *TypedefType) Size() int64 { return t.Type.Size() }
 
-// A MapType represents a Go slice type. It looks like a TypedefType, describing
+// A MapType represents a Go map type. It looks like a TypedefType, describing
 // the runtime-internal structure, with extra fields.
 type MapType struct {
 	TypedefType
@@ -302,6 +302,19 @@
 	return "map[" + t.KeyType.String() + "]" + t.ElemType.String()
 }
 
+// A ChanType represents a Go channel type.
+type ChanType struct {
+	TypedefType
+	ElemType Type
+}
+
+func (t *ChanType) String() string {
+	if t.Name != "" {
+		return t.Name
+	}
+	return "chan " + t.ElemType.String()
+}
+
 // typeReader is used to read from either the info section or the
 // types section.
 type typeReader interface {
@@ -710,12 +723,12 @@
 
 	case TagTypedef:
 		// Typedef (DWARF v2 §5.3)
-		// Also maps (Go-specific).
+		// Also maps and channels (Go-specific).
 		// Attributes:
 		//	AttrName: name [required]
 		//	AttrType: type definition [required]
-		//	AttrGoKey: present for maps only.
-		//	AttrElemKey: present for maps only.
+		//	AttrGoKey: present for maps.
+		//	AttrGoElem: present for maps and channels.
 		t := new(TypedefType)
 		t.ReflectKind = getKind(e)
 		switch t.ReflectKind {
@@ -725,6 +738,11 @@
 			m.ElemType = typeOf(e, AttrGoElem)
 			t = &m.TypedefType
 			typ = m
+		case reflect.Chan:
+			c := new(ChanType)
+			c.ElemType = typeOf(e, AttrGoElem)
+			t = &c.TypedefType
+			typ = c
 		default:
 			typ = t
 		}
diff --git a/ogle/demo/ogler/ogler_test.go b/ogle/demo/ogler/ogler_test.go
index dcf0904..9b02f96 100644
--- a/ogle/demo/ogler/ogler_test.go
+++ b/ogle/demo/ogler/ogler_test.go
@@ -22,9 +22,9 @@
 	`main.Z_array_empty`:         `[0]int8{}`,
 	`main.Z_bool_false`:          `false`,
 	`main.Z_bool_true`:           `true`,
-	`main.Z_channel`:             `0xX`,
-	`main.Z_channel_buffered`:    `0xX`,
-	`main.Z_channel_nil`:         `0x0`,
+	`main.Z_channel`:             `(chan int 0xX)`,
+	`main.Z_channel_buffered`:    `(chan int 0xX [0/10])`,
+	`main.Z_channel_nil`:         `(chan int <nil>)`,
 	`main.Z_array_of_empties`:    `[2]struct struct {}{struct struct {} {}, (struct struct {} 0xX)}`,
 	`main.Z_complex128`:          `(1.987654321-2.987654321i)`,
 	`main.Z_complex64`:           `(1.54321+2.54321i)`,
diff --git a/ogle/program/server/print.go b/ogle/program/server/print.go
index 46af8c6..8d93b3a 100644
--- a/ogle/program/server/print.go
+++ b/ogle/program/server/print.go
@@ -329,6 +329,8 @@
 		p.printArrayAt(typ, a)
 	case *dwarf.MapType:
 		p.printMapAt(typ, a)
+	case *dwarf.ChanType:
+		p.printChannelAt(typ, a)
 	case *dwarf.SliceType:
 		p.printSliceAt(typ, a)
 	case *dwarf.StringType:
@@ -340,7 +342,7 @@
 	case *dwarf.VoidType:
 		p.printf("void")
 	default:
-		// TODO: chan interface
+		// TODO: interface
 		p.errorf("unimplemented type %v", typ)
 	}
 }
@@ -376,12 +378,12 @@
 
 func (p *Printer) printMapAt(typ *dwarf.MapType, a address) {
 	// Maps are pointers to structs.
-	pst, ok := typ.Type.(*dwarf.PtrType)
+	pt, ok := typ.Type.(*dwarf.PtrType)
 	if !ok {
 		p.errorf("bad map type: not a pointer")
 		return
 	}
-	st, ok := pst.Type.(*dwarf.StructType)
+	st, ok := pt.Type.(*dwarf.StructType)
 	if !ok {
 		p.errorf("bad map type: not a pointer to a struct")
 		return
@@ -540,6 +542,50 @@
 	}
 }
 
+func (p *Printer) printChannelAt(ct *dwarf.ChanType, a address) {
+	p.printf("(chan %s ", ct.ElemType)
+	defer p.printf(")")
+
+	a, ok := p.peekPtr(a)
+	if !ok {
+		p.errorf("couldn't read channel")
+		return
+	}
+	if a == 0 {
+		p.printf("<nil>")
+		return
+	}
+	p.printf("%#x", a)
+
+	// ct is a typedef for a pointer to a struct.
+	pt, ok := ct.TypedefType.Type.(*dwarf.PtrType)
+	if !ok {
+		p.errorf("bad channel type: not a pointer")
+		return
+	}
+	st, ok := pt.Type.(*dwarf.StructType)
+	if !ok {
+		p.errorf("bad channel type: not a pointer to a struct")
+		return
+	}
+
+	// Print the channel buffer's length (qcount) and capacity (dataqsiz),
+	// if not 0/0.
+	qcount, ok := p.peekUintStructField(st, a, "qcount")
+	if !ok {
+		p.errorf(`couldn't read channel field "qcount"`)
+		return
+	}
+	dataqsiz, ok := p.peekUintStructField(st, a, "dataqsiz")
+	if !ok {
+		p.errorf(`couldn't read channel field "dataqsiz"`)
+		return
+	}
+	if qcount != 0 || dataqsiz != 0 {
+		p.printf(" [%d/%d]", qcount, dataqsiz)
+	}
+}
+
 func (p *Printer) printSliceAt(typ *dwarf.SliceType, a address) {
 	// Slices look like a struct with fields array *elemtype, len uint32/64, cap uint32/64.
 	// BUG: Slice header appears to have fields with ByteSize == 0