]> Cypherpunks repositories - gostls13.git/commitdiff
add a debugging printer to the gob package.
authorRob Pike <r@golang.org>
Tue, 29 Dec 2009 03:03:33 +0000 (14:03 +1100)
committerRob Pike <r@golang.org>
Tue, 29 Dec 2009 03:03:33 +0000 (14:03 +1100)
used only for debugging, debug.go is not normally part of the package source.

also add a dump program to call it.

R=rsc
CC=golang-dev
https://golang.org/cl/183075

src/pkg/gob/Makefile
src/pkg/gob/debug.go [new file with mode: 0644]
src/pkg/gob/dump.go [new file with mode: 0644]

index 5b175b3476fdb6d8aac66d9aa1da44587b505796..1091adb01f07a4847736a4c0c3eb70a78d649432 100644 (file)
@@ -13,3 +13,11 @@ GOFILES=\
        type.go\
 
 include ../../Make.pkg
+
+# Help for debugging. Requires adding debug.go to the gob package as well.
+
+dump:  dump.$O
+       $(LD) -o dump $<
+
+dump.$O:       dump.go
+       $(GC) $<
diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go
new file mode 100644 (file)
index 0000000..02f2602
--- /dev/null
@@ -0,0 +1,216 @@
+package gob
+
+// This file is not normally included in the gob package.  Used only for debugging the package itself.
+
+import (
+       "bytes"
+       "fmt"
+       "io"
+       "log"
+       "os"
+)
+
+// Debug prints a human-readable representation of the gob data read from r.
+func Debug(r io.Reader) { NewDecoder(r).debug() }
+
+// debug is like Decode but just prints what it finds.  It should be safe even for corrupted data.
+func (dec *Decoder) debug() {
+       dec.state.err = nil
+       for {
+               // Read a count.
+               var nbytes uint64
+               nbytes, dec.state.err = decodeUintReader(dec.r, dec.countBuf[0:])
+               if dec.state.err != nil {
+                       break
+               }
+
+               // Allocate the buffer.
+               if nbytes > uint64(len(dec.buf)) {
+                       dec.buf = make([]byte, nbytes+1000)
+               }
+               dec.state.b = bytes.NewBuffer(dec.buf[0:nbytes])
+
+               // Read the data
+               _, dec.state.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
+               if dec.state.err != nil {
+                       if dec.state.err == os.EOF {
+                               dec.state.err = io.ErrUnexpectedEOF
+                       }
+                       break
+               }
+
+               // Receive a type id.
+               id := typeId(decodeInt(dec.state))
+               if dec.state.err != nil {
+                       break
+               }
+
+               // Is it a new type?
+               if id < 0 { // 0 is the error state, handled above
+                       // If the id is negative, we have a type.
+                       fmt.Printf("new type id %d\n", -id)
+                       dec.printType(-id)
+                       if dec.state.err != nil {
+                               break
+                       }
+                       continue
+               }
+
+               fmt.Printf("type id %d\n", id)
+               // No, it's a value.
+               // Make sure the type has been defined already.
+               _, ok := dec.wireType[id]
+               if !ok {
+                       dec.state.err = errBadType
+                       break
+               }
+               fmt.Printf("\t%d bytes:\t% x\n", nbytes, dec.state.b.Bytes())
+               dec.printData(0, id)
+               break
+       }
+       if dec.state.err != nil {
+               log.Stderr("debug:", dec.state.err)
+       }
+}
+
+func (dec *Decoder) printType(id typeId) {
+       // Have we already seen this type?  That's an error
+       if _, alreadySeen := dec.wireType[id]; alreadySeen {
+               dec.state.err = os.ErrorString("gob: duplicate type received")
+               return
+       }
+
+       // Type:
+       wire := new(wireType)
+       dec.state.err = dec.decode(tWireType, wire)
+       if dec.state.err == nil {
+               printWireType(wire)
+       }
+       // Remember we've seen this type.
+       dec.wireType[id] = wire
+}
+
+func printWireType(wire *wireType) {
+       switch {
+       case wire.array != nil:
+               printCommonType("array", &wire.array.commonType)
+               fmt.Printf("\tlen %d\n\telemid %d\n", wire.array.Len, wire.array.Elem)
+       case wire.slice != nil:
+               printCommonType("slice", &wire.slice.commonType)
+               fmt.Printf("\telemid %d\n", wire.slice.Elem)
+       case wire.strct != nil:
+               printCommonType("struct", &wire.strct.commonType)
+               for i, field := range wire.strct.field {
+                       fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.name, field.id)
+               }
+       }
+}
+
+func printCommonType(kind string, common *commonType) {
+       fmt.Printf("\t%s %s\n\tid: %d\n", kind, common.name, common._id)
+}
+
+func (dec *Decoder) printData(indent int, id typeId) {
+       if dec.state.err != nil {
+               return
+       }
+       // is it a builtin type?
+       _, ok := builtinIdToType[id]
+       if ok {
+               dec.printBuiltin(indent, id)
+               return
+       }
+       wire, ok := dec.wireType[id]
+       if !ok {
+               fmt.Printf("type id %d not defined\n", id)
+               return
+       }
+       switch {
+       case wire.array != nil:
+               dec.printArray(indent+1, wire)
+       case wire.slice != nil:
+               dec.printSlice(indent+1, wire)
+       case wire.strct != nil:
+               dec.printStruct(indent+1, wire)
+       }
+}
+
+func (dec *Decoder) printArray(indent int, wire *wireType) {
+       elemId := wire.array.Elem
+       n := int(decodeUint(dec.state))
+       for i := 0; i < n && dec.state.err == nil; i++ {
+               dec.printData(indent, elemId)
+       }
+       if n != wire.array.Len {
+               tab(indent)
+               fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.array.Len)
+       }
+}
+
+func (dec *Decoder) printSlice(indent int, wire *wireType) {
+       elemId := wire.slice.Elem
+       n := int(decodeUint(dec.state))
+       for i := 0; i < n && dec.state.err == nil; i++ {
+               dec.printData(indent, elemId)
+       }
+}
+
+func (dec *Decoder) printBuiltin(indent int, id typeId) {
+       tab(indent)
+       switch id {
+       case tBool:
+               if decodeInt(dec.state) == 0 {
+                       fmt.Printf("false")
+               } else {
+                       fmt.Printf("true")
+               }
+       case tInt:
+               fmt.Printf("%d", decodeInt(dec.state))
+       case tUint:
+               fmt.Printf("%d", decodeUint(dec.state))
+       case tFloat:
+               fmt.Printf("%g", floatFromBits(decodeUint(dec.state)))
+       case tBytes:
+               b := make([]byte, decodeUint(dec.state))
+               dec.state.b.Read(b)
+               fmt.Printf("% x", b)
+       case tString:
+               b := make([]byte, decodeUint(dec.state))
+               dec.state.b.Read(b)
+               fmt.Printf("%q", b)
+       default:
+               fmt.Print("unknown")
+       }
+       fmt.Print("\n")
+}
+
+func (dec *Decoder) printStruct(indent int, wire *wireType) {
+       strct := wire.strct
+       state := newDecodeState(dec.state.b)
+       state.fieldnum = -1
+       for state.err == nil {
+               delta := int(decodeUint(state))
+               if delta < 0 {
+                       dec.state.err = os.ErrorString("gob decode: corrupted data: negative delta")
+                       return
+               }
+               if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum
+                       return
+               }
+               fieldnum := state.fieldnum + delta
+               if fieldnum < 0 || fieldnum >= len(strct.field) {
+                       dec.state.err = os.ErrorString("field number out of range")
+                       return
+               }
+               tab(indent)
+               fmt.Printf("field %d:\n", fieldnum)
+               dec.printData(indent+1, strct.field[fieldnum].id)
+               state.fieldnum = fieldnum
+       }
+}
+
+func tab(indent int) {
+       for i := 0; i < indent; i++ {
+               fmt.Print("\t")
+       }
+}
diff --git a/src/pkg/gob/dump.go b/src/pkg/gob/dump.go
new file mode 100644 (file)
index 0000000..a055105
--- /dev/null
@@ -0,0 +1,22 @@
+package main
+
+// Need to compile package gob with debug.go to build this program.
+
+import (
+       "fmt"
+       "gob"
+       "os"
+)
+
+func main() {
+       var err os.Error
+       file := os.Stdin
+       if len(os.Args) > 1 {
+               file, err = os.Open(os.Args[1], os.O_RDONLY, 0)
+               if err != nil {
+                       fmt.Fprintf(os.Stderr, "dump: %s\n", err)
+                       os.Exit(1)
+               }
+       }
+       gob.Debug(file)
+}