mirror of
https://github.com/golang/go
synced 2024-11-25 00:07:56 -07:00
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
This commit is contained in:
parent
1f5511560e
commit
e7601e2980
@ -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) $<
|
||||
|
216
src/pkg/gob/debug.go
Normal file
216
src/pkg/gob/debug.go
Normal file
@ -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")
|
||||
}
|
||||
}
|
22
src/pkg/gob/dump.go
Normal file
22
src/pkg/gob/dump.go
Normal file
@ -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)
|
||||
}
|
Loading…
Reference in New Issue
Block a user