add a debugging printer to the gob package.
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
diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go
new file mode 100644
index 0000000..02f2602
--- /dev/null
+++ b/src/pkg/gob/debug.go
@@ -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")
+	}
+}