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