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