1
0
mirror of https://github.com/golang/go synced 2024-11-19 04:34:39 -07:00

gob: make the debugging (dumping) code work again. Mostly rewrite it, in fact.

It's still not compiled in by default.

R=rsc, r2
CC=golang-dev
https://golang.org/cl/2754043
This commit is contained in:
Rob Pike 2010-10-29 15:07:56 -07:00
parent 907e998cba
commit 96b9efe8a9
3 changed files with 239 additions and 101 deletions

View File

@ -1269,3 +1269,50 @@ func TestIgnoreInterface(t *testing.T) {
t.Error("normal float did not decode correctly") t.Error("normal float did not decode correctly")
} }
} }
// A type that won't be defined in the gob until we send it in an interface value.
type OnTheFly struct {
a int
}
type DT struct {
// X OnTheFly
a int
b string
c float
i interface{}
j interface{}
i_nil interface{}
m map[string]int
r [3]int
s []string
}
func TestDebug(t *testing.T) {
if debugFunc == nil {
return
}
Register(OnTheFly{})
var dt DT
dt.a = 17
dt.b = "hello"
dt.c = 3.14159
dt.i = 271828
dt.j = OnTheFly{3}
dt.i_nil = nil
dt.m = map[string]int{"one": 1, "two": 2}
dt.r = [3]int{11, 22, 33}
dt.s = []string{"hi", "joe"}
b := new(bytes.Buffer)
err := NewEncoder(b).Encode(dt)
if err != nil {
t.Fatal("encode:", err)
}
debugBuffer := bytes.NewBuffer(b.Bytes())
dt2 := &DT{}
err = NewDecoder(b).Decode(&dt2)
if err != nil {
t.Error("decode:", err)
}
debugFunc(debugBuffer)
}

View File

@ -6,152 +6,227 @@ import (
"bytes" "bytes"
"fmt" "fmt"
"io" "io"
"log"
"os" "os"
"reflect"
"runtime"
) )
var dump = false // If true, print the remaining bytes in the input buffer at each item.
// Init installs the debugging facility. If this file is not compiled in the
// package, Debug will be a no-op.
func init() {
debugFunc = Debug
}
// Debug prints a human-readable representation of the gob data read from r. // Debug prints a human-readable representation of the gob data read from r.
func Debug(r io.Reader) { NewDecoder(r).debug() } func Debug(r io.Reader) {
defer func() {
if e := recover(); e != nil {
if _, ok := e.(runtime.Error); ok {
panic(e)
}
fmt.Printf("error during debugging: %v\n", e)
}
}()
NewDecoder(r).debug()
}
// debugRecv is like recv but prints what it sees.
func (dec *Decoder) debugRecv() {
if dec.byteBuffer != nil && dec.byteBuffer.Len() != 0 {
fmt.Printf("error in recv: %d bytes left in input buffer\n", dec.byteBuffer.Len())
return
}
// Read a count.
var nbytes uint64
nbytes, dec.err = decodeUintReader(dec.r, dec.countBuf[0:])
if dec.err != nil {
fmt.Printf("receiver error on count: %s\n", dec.err)
return
}
// Allocate the buffer.
if nbytes > uint64(len(dec.buf)) {
dec.buf = make([]byte, nbytes+1000)
}
dec.byteBuffer = bytes.NewBuffer(dec.buf[0:nbytes])
// Read the data
_, dec.err = io.ReadFull(dec.r, dec.buf[0:nbytes])
if dec.err != nil {
fmt.Printf("receiver error on data: %s\n", dec.err)
if dec.err == os.EOF {
dec.err = io.ErrUnexpectedEOF
}
return
}
if dump {
fmt.Printf("received %d bytes:\n\t% x\n", nbytes, dec.byteBuffer.Bytes())
}
}
// debug is like Decode but just prints what it finds. It should be safe even for corrupted data. // debug is like Decode but just prints what it finds. It should be safe even for corrupted data.
func (dec *Decoder) debug() { func (dec *Decoder) debug() {
dec.state.err = nil // Make sure we're single-threaded through here.
for { dec.mutex.Lock()
// Read a count. defer dec.mutex.Unlock()
var nbytes uint64
nbytes, dec.state.err = decodeUintReader(dec.r, dec.countBuf[0:])
if dec.state.err != nil {
break
}
// Allocate the buffer. dec.err = nil
if nbytes > uint64(len(dec.buf)) { dec.debugRecv()
dec.buf = make([]byte, nbytes+1000) if dec.err != nil {
} return
dec.state.b = bytes.NewBuffer(dec.buf[0:nbytes]) }
dec.debugFromBuffer(0)
// 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
}
// printFromBuffer prints the next value. The buffer contains data, but it may
// be a type descriptor and we may need to load more data to see the value;
// printType takes care of that.
func (dec *Decoder) debugFromBuffer(indent int) {
for dec.state.b.Len() > 0 {
// Receive a type id. // Receive a type id.
id := typeId(decodeInt(dec.state)) id := typeId(decodeInt(dec.state))
if dec.state.err != nil {
break
}
// Is it a new type? // Is it a new type?
if id < 0 { // 0 is the error state, handled above if id < 0 { // 0 is the error state, handled above
// If the id is negative, we have a type. // If the id is negative, we have a type.
fmt.Printf("new type id %d\n", -id) dec.debugRecvType(-id)
dec.printType(-id) if dec.err != nil {
if dec.state.err != nil {
break break
} }
continue continue
} }
fmt.Printf("type id %d\n", id)
// No, it's a value. // No, it's a value.
// Make sure the type has been defined already. // Make sure the type has been defined already or is a builtin type (for
_, ok := dec.wireType[id] // top-level singleton values).
if !ok { if dec.wireType[id] == nil && builtinIdToType[id] == nil {
dec.state.err = errBadType dec.err = errBadType
break break
} }
fmt.Printf("\t%d bytes:\t% x\n", nbytes, dec.state.b.Bytes()) dec.debugPrint(indent, id)
dec.printData(0, id)
break break
} }
if dec.state.err != nil {
log.Print("debug:", dec.state.err)
}
} }
func (dec *Decoder) printType(id typeId) { func (dec *Decoder) debugRecvType(id typeId) {
// Have we already seen this type? That's an error // Have we already seen this type? That's an error
if _, alreadySeen := dec.wireType[id]; alreadySeen { if _, alreadySeen := dec.wireType[id]; alreadySeen {
dec.state.err = os.ErrorString("gob: duplicate type received") dec.err = os.ErrorString("gob: duplicate type received")
return return
} }
// Type: // Type:
wire := new(wireType) wire := new(wireType)
dec.state.err = dec.decode(tWireType, wire) dec.err = dec.decode(tWireType, reflect.NewValue(wire))
if dec.state.err == nil { if dec.err == nil {
printWireType(wire) printWireType(wire)
} }
// Remember we've seen this type. // Remember we've seen this type.
dec.wireType[id] = wire dec.wireType[id] = wire
// Load the next parcel.
dec.debugRecv()
} }
func printWireType(wire *wireType) { func printWireType(wire *wireType) {
fmt.Printf("type definition {\n")
switch { switch {
case wire.array != nil: case wire.arrayT != nil:
printCommonType("array", &wire.array.commonType) printCommonType("array", &wire.arrayT.commonType)
fmt.Printf("\tlen %d\n\telemid %d\n", wire.array.Len, wire.array.Elem) fmt.Printf("\tlen %d\n\telemid %d\n", wire.arrayT.Len, wire.arrayT.Elem)
case wire.slice != nil: case wire.mapT != nil:
printCommonType("slice", &wire.slice.commonType) printCommonType("map", &wire.mapT.commonType)
fmt.Printf("\telemid %d\n", wire.slice.Elem) fmt.Printf("\tkeyid %d\n", wire.mapT.Key)
case wire.strct != nil: fmt.Printf("\telemid %d\n", wire.mapT.Elem)
printCommonType("struct", &wire.strct.commonType) case wire.sliceT != nil:
for i, field := range wire.strct.field { printCommonType("slice", &wire.sliceT.commonType)
fmt.Printf("\telemid %d\n", wire.sliceT.Elem)
case wire.structT != nil:
printCommonType("struct", &wire.structT.commonType)
for i, field := range wire.structT.field {
fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.name, field.id) fmt.Printf("\tfield %d:\t%s\tid=%d\n", i, field.name, field.id)
} }
} }
fmt.Printf("}\n")
} }
func printCommonType(kind string, common *commonType) { func printCommonType(kind string, common *commonType) {
fmt.Printf("\t%s %s\n\tid: %d\n", kind, common.name, common._id) fmt.Printf("\t%s %q\n\tid: %d\n", kind, common.name, common._id)
} }
func (dec *Decoder) printData(indent int, id typeId) { func (dec *Decoder) debugPrint(indent int, id typeId) {
if dec.state.err != nil { wire, ok := dec.wireType[id]
return if ok && wire.structT != nil {
dec.debugStruct(indent+1, id, wire)
} else {
dec.debugSingle(indent+1, id, wire)
} }
}
func (dec *Decoder) debugSingle(indent int, id typeId, wire *wireType) {
// is it a builtin type? // is it a builtin type?
_, ok := builtinIdToType[id] _, ok := builtinIdToType[id]
if !ok && wire == nil {
errorf("type id %d not defined\n", id)
}
decodeUint(dec.state)
dec.printItem(indent, id)
}
func (dec *Decoder) printItem(indent int, id typeId) {
if dump {
fmt.Printf("print item %d bytes: % x\n", dec.state.b.Len(), dec.state.b.Bytes())
}
_, ok := builtinIdToType[id]
if ok { if ok {
dec.printBuiltin(indent, id) dec.printBuiltin(indent, id)
return return
} }
wire, ok := dec.wireType[id] wire, ok := dec.wireType[id]
if !ok { if !ok {
fmt.Printf("type id %d not defined\n", id) errorf("type id %d not defined\n", id)
return
} }
switch { switch {
case wire.array != nil: case wire.arrayT != nil:
dec.printArray(indent+1, wire) dec.printArray(indent, wire)
case wire.slice != nil: case wire.mapT != nil:
dec.printSlice(indent+1, wire) dec.printMap(indent, wire)
case wire.strct != nil: case wire.sliceT != nil:
dec.printStruct(indent+1, wire) dec.printSlice(indent, wire)
case wire.structT != nil:
dec.debugStruct(indent, id, wire)
} }
} }
func (dec *Decoder) printArray(indent int, wire *wireType) { func (dec *Decoder) printArray(indent int, wire *wireType) {
elemId := wire.array.Elem elemId := wire.arrayT.Elem
n := int(decodeUint(dec.state)) n := int(decodeUint(dec.state))
for i := 0; i < n && dec.state.err == nil; i++ { for i := 0; i < n && dec.err == nil; i++ {
dec.printData(indent, elemId) dec.printItem(indent, elemId)
} }
if n != wire.array.Len { if n != wire.arrayT.Len {
tab(indent) tab(indent)
fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.array.Len) fmt.Printf("(wrong length for array: %d should be %d)\n", n, wire.arrayT.Len)
}
}
func (dec *Decoder) printMap(indent int, wire *wireType) {
keyId := wire.mapT.Key
elemId := wire.mapT.Elem
n := int(decodeUint(dec.state))
for i := 0; i < n && dec.err == nil; i++ {
dec.printItem(indent, keyId)
dec.printItem(indent+1, elemId)
} }
} }
func (dec *Decoder) printSlice(indent int, wire *wireType) { func (dec *Decoder) printSlice(indent int, wire *wireType) {
elemId := wire.slice.Elem elemId := wire.sliceT.Elem
n := int(decodeUint(dec.state)) n := int(decodeUint(dec.state))
for i := 0; i < n && dec.state.err == nil; i++ { for i := 0; i < n && dec.err == nil; i++ {
dec.printData(indent, elemId) dec.printItem(indent, elemId)
} }
} }
@ -160,57 +235,72 @@ func (dec *Decoder) printBuiltin(indent int, id typeId) {
switch id { switch id {
case tBool: case tBool:
if decodeInt(dec.state) == 0 { if decodeInt(dec.state) == 0 {
fmt.Printf("false") fmt.Printf("false\n")
} else { } else {
fmt.Printf("true") fmt.Printf("true\n")
} }
case tInt: case tInt:
fmt.Printf("%d", decodeInt(dec.state)) fmt.Printf("%d\n", decodeInt(dec.state))
case tUint: case tUint:
fmt.Printf("%d", decodeUint(dec.state)) fmt.Printf("%d\n", decodeUint(dec.state))
case tFloat: case tFloat:
fmt.Printf("%g", floatFromBits(decodeUint(dec.state))) fmt.Printf("%g\n", floatFromBits(decodeUint(dec.state)))
case tBytes: case tBytes:
b := make([]byte, decodeUint(dec.state)) b := make([]byte, decodeUint(dec.state))
dec.state.b.Read(b) dec.state.b.Read(b)
fmt.Printf("% x", b) fmt.Printf("% x\n", b)
case tString: case tString:
b := make([]byte, decodeUint(dec.state)) b := make([]byte, decodeUint(dec.state))
dec.state.b.Read(b) dec.state.b.Read(b)
fmt.Printf("%q", b) fmt.Printf("%q\n", b)
case tInterface:
b := make([]byte, decodeUint(dec.state))
dec.state.b.Read(b)
if len(b) == 0 {
fmt.Printf("nil interface")
} else {
fmt.Printf("interface value; type %q\n", b)
dec.debugFromBuffer(indent)
}
default: default:
fmt.Print("unknown") fmt.Print("unknown\n")
} }
fmt.Print("\n")
} }
func (dec *Decoder) printStruct(indent int, wire *wireType) { func (dec *Decoder) debugStruct(indent int, id typeId, wire *wireType) {
strct := wire.strct tab(indent)
fmt.Printf("%s struct {\n", id.Name())
strct := wire.structT
state := newDecodeState(dec.state.b) state := newDecodeState(dec.state.b)
state.fieldnum = -1 state.fieldnum = -1
for state.err == nil { for dec.err == nil {
delta := int(decodeUint(state)) delta := int(decodeUint(state))
if delta < 0 { if delta < 0 {
dec.state.err = os.ErrorString("gob decode: corrupted data: negative delta") errorf("gob decode: corrupted data: negative delta")
return
} }
if state.err != nil || delta == 0 { // struct terminator is zero delta fieldnum if delta == 0 { // struct terminator is zero delta fieldnum
return break
} }
fieldnum := state.fieldnum + delta fieldNum := state.fieldnum + delta
if fieldnum < 0 || fieldnum >= len(strct.field) { if fieldNum < 0 || fieldNum >= len(strct.field) {
dec.state.err = os.ErrorString("field number out of range") errorf("field number out of range")
return break
} }
tab(indent) tab(indent)
fmt.Printf("field %d:\n", fieldnum) fmt.Printf("%s(%d):\n", wire.structT.field[fieldNum].name, fieldNum)
dec.printData(indent+1, strct.field[fieldnum].id) dec.printItem(indent+1, strct.field[fieldNum].id)
state.fieldnum = fieldnum state.fieldnum = fieldNum
} }
tab(indent)
fmt.Printf(" } // end %s struct\n", id.Name())
} }
func tab(indent int) { func tab(indent int) {
for i := 0; i < indent; i++ { for i, w := 0, 0; i < indent; i += w {
fmt.Print("\t") w = 10
if i+w > indent {
w = indent - i
}
fmt.Print("\t\t\t\t\t\t\t\t\t\t"[:w])
} }
} }

View File

@ -108,9 +108,6 @@ func (dec *Decoder) decodeValueFromBuffer(value reflect.Value, ignore bool) {
for dec.state.b.Len() > 0 { for dec.state.b.Len() > 0 {
// Receive a type id. // Receive a type id.
id := typeId(decodeInt(dec.state)) id := typeId(decodeInt(dec.state))
if dec.err != nil {
break
}
// Is it a new type? // Is it a new type?
if id < 0 { // 0 is the error state, handled above if id < 0 { // 0 is the error state, handled above
@ -155,3 +152,7 @@ func (dec *Decoder) DecodeValue(value reflect.Value) os.Error {
dec.decodeValueFromBuffer(value, false) dec.decodeValueFromBuffer(value, false)
return dec.err return dec.err
} }
// If enabled, Debug prints a human-readable representation of the gob data read from r.
// If debug.go is compiled into the program it will override this link.
var debugFunc func(io.Reader)