diff options
Diffstat (limited to 'src/pkg/gob/debug.go')
-rw-r--r-- | src/pkg/gob/debug.go | 689 |
1 files changed, 0 insertions, 689 deletions
diff --git a/src/pkg/gob/debug.go b/src/pkg/gob/debug.go deleted file mode 100644 index 79aee7788..000000000 --- a/src/pkg/gob/debug.go +++ /dev/null @@ -1,689 +0,0 @@ -package gob - -// This file is not normally included in the gob package. Used only for debugging the package itself. -// Add debug.go to the files listed in the Makefile to add Debug to the gob package. -// Except for reading uints, it is an implementation of a reader that is independent of -// the one implemented by Decoder. - -import ( - "bytes" - "fmt" - "io" - "os" - "strings" - "sync" -) - -var dumpBytes = 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, the tests in codec_test.go are no-ops. -func init() { - debugFunc = Debug -} - -var ( - blanks = bytes.Repeat([]byte{' '}, 3*10) - empty = []byte(": <empty>\n") - tabs = strings.Repeat("\t", 100) -) - -// tab indents itself when printed. -type tab int - -func (t tab) String() string { - n := int(t) - if n > len(tabs) { - n = len(tabs) - } - return tabs[0:n] -} - -func (t tab) print() { - fmt.Fprint(os.Stderr, t) -} - -// A peekReader wraps an io.Reader, allowing one to peek ahead to see -// what's coming without stealing the data from the client of the Reader. -type peekReader struct { - r io.Reader - data []byte // read-ahead data -} - -// newPeekReader returns a peekReader that wraps r. -func newPeekReader(r io.Reader) *peekReader { - return &peekReader{r: r} -} - -// Read is the usual method. It will first take data that has been read ahead. -func (p *peekReader) Read(b []byte) (n int, err os.Error) { - if len(p.data) == 0 { - return p.r.Read(b) - } - // Satisfy what's possible from the read-ahead data. - n = copy(b, p.data) - // Move data down to beginning of slice, to avoid endless growth - copy(p.data, p.data[n:]) - p.data = p.data[:len(p.data)-n] - return -} - -// peek returns as many bytes as possible from the unread -// portion of the stream, up to the length of b. -func (p *peekReader) peek(b []byte) (n int, err os.Error) { - if len(p.data) > 0 { - n = copy(b, p.data) - if n == len(b) { - return - } - b = b[n:] - } - if len(b) == 0 { - return - } - m, e := io.ReadFull(p.r, b) - if m > 0 { - p.data = append(p.data, b[:m]...) - } - n += m - if e == io.ErrUnexpectedEOF { - // That means m > 0 but we reached EOF. If we got data - // we won't complain about not being able to peek enough. - if n > 0 { - e = nil - } else { - e = os.EOF - } - } - return n, e -} - -type debugger struct { - mutex sync.Mutex - remain int // the number of bytes known to remain in the input - remainingKnown bool // the value of 'remain' is valid - r *peekReader - wireType map[typeId]*wireType - tmp []byte // scratch space for decoding uints. -} - -// dump prints the next nBytes of the input. -// It arranges to print the output aligned from call to -// call, to make it easy to see what has been consumed. -func (deb *debugger) dump(format string, args ...interface{}) { - if !dumpBytes { - return - } - fmt.Fprintf(os.Stderr, format+" ", args...) - if !deb.remainingKnown { - return - } - if deb.remain < 0 { - fmt.Fprintf(os.Stderr, "remaining byte count is negative! %d\n", deb.remain) - return - } - data := make([]byte, deb.remain) - n, _ := deb.r.peek(data) - if n == 0 { - os.Stderr.Write(empty) - return - } - b := new(bytes.Buffer) - fmt.Fprintf(b, "[%d]{\n", deb.remain) - // Blanks until first byte - lineLength := 0 - if n := len(data); n%10 != 0 { - lineLength = 10 - n%10 - fmt.Fprintf(b, "\t%s", blanks[:lineLength*3]) - } - // 10 bytes per line - for len(data) > 0 { - if lineLength == 0 { - fmt.Fprint(b, "\t") - } - m := 10 - lineLength - lineLength = 0 - if m > len(data) { - m = len(data) - } - fmt.Fprintf(b, "% x\n", data[:m]) - data = data[m:] - } - fmt.Fprint(b, "}\n") - os.Stderr.Write(b.Bytes()) -} - -// Debug prints a human-readable representation of the gob data read from r. -func Debug(r io.Reader) { - err := debug(r) - if err != nil { - fmt.Fprintf(os.Stderr, "gob debug: %s\n", err) - } -} - -// debug implements Debug, but catches panics and returns -// them as errors to be printed by Debug. -func debug(r io.Reader) (err os.Error) { - defer catchError(&err) - fmt.Fprintln(os.Stderr, "Start of debugging") - deb := &debugger{ - r: newPeekReader(r), - wireType: make(map[typeId]*wireType), - tmp: make([]byte, 16), - } - if b, ok := r.(*bytes.Buffer); ok { - deb.remain = b.Len() - deb.remainingKnown = true - } - deb.gobStream() - return -} - -// note that we've consumed some bytes -func (deb *debugger) consumed(n int) { - if deb.remainingKnown { - deb.remain -= n - } -} - -// int64 decodes and returns the next integer, which must be present. -// Don't call this if you could be at EOF. -func (deb *debugger) int64() int64 { - return toInt(deb.uint64()) -} - -// uint64 returns and decodes the next unsigned integer, which must be present. -// Don't call this if you could be at EOF. -// TODO: handle errors better. -func (deb *debugger) uint64() uint64 { - n, w, err := decodeUintReader(deb.r, deb.tmp) - if err != nil { - errorf("debug: read error: %s", err) - } - deb.consumed(w) - return n -} - -// GobStream: -// DelimitedMessage* (until EOF) -func (deb *debugger) gobStream() { - // Make sure we're single-threaded through here. - deb.mutex.Lock() - defer deb.mutex.Unlock() - - for deb.delimitedMessage(0) { - } -} - -// DelimitedMessage: -// uint(lengthOfMessage) Message -func (deb *debugger) delimitedMessage(indent tab) bool { - for { - n := deb.loadBlock(true) - if n < 0 { - return false - } - deb.dump("Delimited message of length %d", n) - deb.message(indent) - } - return true -} - -// loadBlock preps us to read a message -// of the length specified next in the input. It returns -// the length of the block. The argument tells whether -// an EOF is acceptable now. If it is and one is found, -// the return value is negative. -func (deb *debugger) loadBlock(eofOK bool) int { - n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF - if err != nil { - if eofOK && err == os.EOF { - return -1 - } - errorf("debug: unexpected error: %s", err) - } - deb.consumed(w) - n := int(n64) - if n < 0 { - errorf("huge value for message length: %d", n64) - } - return int(n) -} - -// Message: -// TypeSequence TypedValue -// TypeSequence -// (TypeDefinition DelimitedTypeDefinition*)? -// DelimitedTypeDefinition: -// uint(lengthOfTypeDefinition) TypeDefinition -// TypedValue: -// int(typeId) Value -func (deb *debugger) message(indent tab) bool { - for { - // Convert the uint64 to a signed integer typeId - uid := deb.int64() - id := typeId(uid) - deb.dump("type id=%d", id) - if id < 0 { - deb.typeDefinition(indent, -id) - n := deb.loadBlock(false) - deb.dump("Message of length %d", n) - continue - } else { - deb.value(indent, id) - break - } - } - return true -} - -// Helper methods to make it easy to scan a type descriptor. - -// common returns the CommonType at the input point. -func (deb *debugger) common() CommonType { - fieldNum := -1 - name := "" - id := typeId(0) - for { - delta := deb.delta(-1) - if delta == 0 { - break - } - fieldNum += delta - switch fieldNum { - case 0: - name = deb.string() - case 1: - // Id typeId - id = deb.typeId() - default: - errorf("corrupted CommonType") - } - } - return CommonType{name, id} -} - -// uint returns the unsigned int at the input point, as a uint (not uint64). -func (deb *debugger) uint() uint { - return uint(deb.uint64()) -} - -// int returns the signed int at the input point, as an int (not int64). -func (deb *debugger) int() int { - return int(deb.int64()) -} - -// typeId returns the type id at the input point. -func (deb *debugger) typeId() typeId { - return typeId(deb.int64()) -} - -// string returns the string at the input point. -func (deb *debugger) string() string { - x := int(deb.uint64()) - b := make([]byte, x) - nb, _ := deb.r.Read(b) - if nb != x { - errorf("corrupted type") - } - deb.consumed(nb) - return string(b) -} - -// delta returns the field delta at the input point. The expect argument, -// if non-negative, identifies what the value should be. -func (deb *debugger) delta(expect int) int { - delta := int(deb.uint64()) - if delta < 0 || (expect >= 0 && delta != expect) { - errorf("decode: corrupted type: delta %d expected %d", delta, expect) - } - return delta -} - -// TypeDefinition: -// [int(-typeId) (already read)] encodingOfWireType -func (deb *debugger) typeDefinition(indent tab, id typeId) { - deb.dump("type definition for id %d", id) - // Encoding is of a wireType. Decode the structure as usual - fieldNum := -1 - wire := new(wireType) - // A wireType defines a single field. - delta := deb.delta(-1) - fieldNum += delta - switch fieldNum { - case 0: // array type, one field of {{Common}, elem, length} - // Field number 0 is CommonType - deb.delta(1) - com := deb.common() - // Field number 1 is type Id of elem - deb.delta(1) - id := deb.typeId() - // Field number 3 is length - deb.delta(1) - length := deb.int() - wire.ArrayT = &arrayType{com, id, length} - - case 1: // slice type, one field of {{Common}, elem} - // Field number 0 is CommonType - deb.delta(1) - com := deb.common() - // Field number 1 is type Id of elem - deb.delta(1) - id := deb.typeId() - wire.SliceT = &sliceType{com, id} - - case 2: // struct type, one field of {{Common}, []fieldType} - // Field number 0 is CommonType - deb.delta(1) - com := deb.common() - // Field number 1 is slice of FieldType - deb.delta(1) - numField := int(deb.uint()) - field := make([]*fieldType, numField) - for i := 0; i < numField; i++ { - field[i] = new(fieldType) - deb.delta(1) // field 0 of fieldType: name - field[i].Name = deb.string() - deb.delta(1) // field 1 of fieldType: id - field[i].Id = deb.typeId() - deb.delta(0) // end of fieldType - } - wire.StructT = &structType{com, field} - - case 3: // map type, one field of {{Common}, key, elem} - // Field number 0 is CommonType - deb.delta(1) - com := deb.common() - // Field number 1 is type Id of key - deb.delta(1) - keyId := deb.typeId() - // Field number 2 is type Id of elem - deb.delta(1) - elemId := deb.typeId() - wire.MapT = &mapType{com, keyId, elemId} - case 4: // GobEncoder type, one field of {{Common}} - // Field number 0 is CommonType - deb.delta(1) - com := deb.common() - wire.GobEncoderT = &gobEncoderType{com} - default: - errorf("bad field in type %d", fieldNum) - } - deb.printWireType(indent, wire) - deb.delta(0) // end inner type (arrayType, etc.) - deb.delta(0) // end wireType - // Remember we've seen this type. - deb.wireType[id] = wire -} - - -// Value: -// SingletonValue | StructValue -func (deb *debugger) value(indent tab, id typeId) { - wire, ok := deb.wireType[id] - if ok && wire.StructT != nil { - deb.structValue(indent, id) - } else { - deb.singletonValue(indent, id) - } -} - -// SingletonValue: -// uint(0) FieldValue -func (deb *debugger) singletonValue(indent tab, id typeId) { - deb.dump("Singleton value") - // is it a builtin type? - wire := deb.wireType[id] - _, ok := builtinIdToType[id] - if !ok && wire == nil { - errorf("type id %d not defined", id) - } - m := deb.uint64() - if m != 0 { - errorf("expected zero; got %d", m) - } - deb.fieldValue(indent, id) -} - -// InterfaceValue: -// NilInterfaceValue | NonNilInterfaceValue -func (deb *debugger) interfaceValue(indent tab) { - deb.dump("Start of interface value") - if nameLen := deb.uint64(); nameLen == 0 { - deb.nilInterfaceValue(indent) - } else { - deb.nonNilInterfaceValue(indent, int(nameLen)) - } -} - -// NilInterfaceValue: -// uint(0) [already read] -func (deb *debugger) nilInterfaceValue(indent tab) int { - fmt.Fprintf(os.Stderr, "%snil interface\n", indent) - return 0 -} - - -// NonNilInterfaceValue: -// ConcreteTypeName TypeSequence InterfaceContents -// ConcreteTypeName: -// uint(lengthOfName) [already read=n] name -// InterfaceContents: -// int(concreteTypeId) DelimitedValue -// DelimitedValue: -// uint(length) Value -func (deb *debugger) nonNilInterfaceValue(indent tab, nameLen int) { - // ConcreteTypeName - b := make([]byte, nameLen) - deb.r.Read(b) // TODO: CHECK THESE READS!! - deb.consumed(nameLen) - name := string(b) - - for { - id := deb.typeId() - if id < 0 { - deb.typeDefinition(indent, -id) - n := deb.loadBlock(false) - deb.dump("Nested message of length %d", n) - } else { - // DelimitedValue - x := deb.uint64() // in case we want to ignore the value; we don't. - fmt.Fprintf(os.Stderr, "%sinterface value, type %q id=%d; valueLength %d\n", indent, name, id, x) - deb.value(indent, id) - break - } - } -} - -// printCommonType prints a common type; used by printWireType. -func (deb *debugger) printCommonType(indent tab, kind string, common *CommonType) { - indent.print() - fmt.Fprintf(os.Stderr, "%s %q id=%d\n", kind, common.Name, common.Id) -} - -// printWireType prints the contents of a wireType. -func (deb *debugger) printWireType(indent tab, wire *wireType) { - fmt.Fprintf(os.Stderr, "%stype definition {\n", indent) - indent++ - switch { - case wire.ArrayT != nil: - deb.printCommonType(indent, "array", &wire.ArrayT.CommonType) - fmt.Fprintf(os.Stderr, "%slen %d\n", indent+1, wire.ArrayT.Len) - fmt.Fprintf(os.Stderr, "%selemid %d\n", indent+1, wire.ArrayT.Elem) - case wire.MapT != nil: - deb.printCommonType(indent, "map", &wire.MapT.CommonType) - fmt.Fprintf(os.Stderr, "%skey id=%d\n", indent+1, wire.MapT.Key) - fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.MapT.Elem) - case wire.SliceT != nil: - deb.printCommonType(indent, "slice", &wire.SliceT.CommonType) - fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.SliceT.Elem) - case wire.StructT != nil: - deb.printCommonType(indent, "struct", &wire.StructT.CommonType) - for i, field := range wire.StructT.Field { - fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\tid=%d\n", indent+1, i, field.Name, field.Id) - } - case wire.GobEncoderT != nil: - deb.printCommonType(indent, "GobEncoder", &wire.GobEncoderT.CommonType) - } - indent-- - fmt.Fprintf(os.Stderr, "%s}\n", indent) -} - -// fieldValue prints a value of any type, such as a struct field. -// FieldValue: -// builtinValue | ArrayValue | MapValue | SliceValue | StructValue | InterfaceValue -func (deb *debugger) fieldValue(indent tab, id typeId) { - _, ok := builtinIdToType[id] - if ok { - if id == tInterface { - deb.interfaceValue(indent) - } else { - deb.printBuiltin(indent, id) - } - return - } - wire, ok := deb.wireType[id] - if !ok { - errorf("type id %d not defined", id) - } - switch { - case wire.ArrayT != nil: - deb.arrayValue(indent, wire) - case wire.MapT != nil: - deb.mapValue(indent, wire) - case wire.SliceT != nil: - deb.sliceValue(indent, wire) - case wire.StructT != nil: - deb.structValue(indent, id) - case wire.GobEncoderT != nil: - deb.gobEncoderValue(indent, id) - default: - panic("bad wire type for field") - } -} - -// printBuiltin prints a value not of a fundamental type, that is, -// one whose type is known to gobs at bootstrap time. -func (deb *debugger) printBuiltin(indent tab, id typeId) { - switch id { - case tBool: - x := deb.int64() - if x == 0 { - fmt.Fprintf(os.Stderr, "%sfalse\n", indent) - } else { - fmt.Fprintf(os.Stderr, "%strue\n", indent) - } - case tInt: - x := deb.int64() - fmt.Fprintf(os.Stderr, "%s%d\n", indent, x) - case tUint: - x := deb.int64() - fmt.Fprintf(os.Stderr, "%s%d\n", indent, x) - case tFloat: - x := deb.uint64() - fmt.Fprintf(os.Stderr, "%s%g\n", indent, floatFromBits(x)) - case tComplex: - r := deb.uint64() - i := deb.uint64() - fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, floatFromBits(r), floatFromBits(i)) - case tBytes: - x := int(deb.uint64()) - b := make([]byte, x) - deb.r.Read(b) - deb.consumed(x) - fmt.Fprintf(os.Stderr, "%s{% x}=%q\n", indent, b, b) - case tString: - x := int(deb.uint64()) - b := make([]byte, x) - deb.r.Read(b) - deb.consumed(x) - fmt.Fprintf(os.Stderr, "%s%q\n", indent, b) - default: - panic("unknown builtin") - } -} - - -// ArrayValue: -// uint(n) FieldValue*n -func (deb *debugger) arrayValue(indent tab, wire *wireType) { - elemId := wire.ArrayT.Elem - u := deb.uint64() - length := int(u) - for i := 0; i < length; i++ { - deb.fieldValue(indent, elemId) - } - if length != wire.ArrayT.Len { - fmt.Fprintf(os.Stderr, "%s(wrong length for array: %d should be %d)\n", indent, length, wire.ArrayT.Len) - } -} - -// MapValue: -// uint(n) (FieldValue FieldValue)*n [n (key, value) pairs] -func (deb *debugger) mapValue(indent tab, wire *wireType) { - keyId := wire.MapT.Key - elemId := wire.MapT.Elem - u := deb.uint64() - length := int(u) - for i := 0; i < length; i++ { - deb.fieldValue(indent+1, keyId) - deb.fieldValue(indent+1, elemId) - } -} - -// SliceValue: -// uint(n) (n FieldValue) -func (deb *debugger) sliceValue(indent tab, wire *wireType) { - elemId := wire.SliceT.Elem - u := deb.uint64() - length := int(u) - deb.dump("Start of slice of length %d", length) - - for i := 0; i < length; i++ { - deb.fieldValue(indent, elemId) - } -} - -// StructValue: -// (uint(fieldDelta) FieldValue)* -func (deb *debugger) structValue(indent tab, id typeId) { - deb.dump("Start of struct value of %q id=%d\n<<\n", id.name(), id) - fmt.Fprintf(os.Stderr, "%s%s struct {\n", indent, id.name()) - wire, ok := deb.wireType[id] - if !ok { - errorf("type id %d not defined", id) - } - strct := wire.StructT - fieldNum := -1 - indent++ - for { - delta := deb.uint64() - if delta == 0 { // struct terminator is zero delta fieldnum - break - } - fieldNum += int(delta) - if fieldNum < 0 || fieldNum >= len(strct.Field) { - deb.dump("field number out of range: prevField=%d delta=%d", fieldNum-int(delta), delta) - break - } - fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\n", indent, fieldNum, wire.StructT.Field[fieldNum].Name) - deb.fieldValue(indent+1, strct.Field[fieldNum].Id) - } - indent-- - fmt.Fprintf(os.Stderr, "%s} // end %s struct\n", indent, id.name()) - deb.dump(">> End of struct value of type %d %q", id, id.name()) -} - -// GobEncoderValue: -// uint(n) byte*n -func (deb *debugger) gobEncoderValue(indent tab, id typeId) { - len := deb.uint64() - deb.dump("GobEncoder value of %q id=%d, length %d\n", id.name(), id, len) - fmt.Fprintf(os.Stderr, "%s%s (implements GobEncoder)\n", indent, id.name()) - data := make([]byte, len) - _, err := deb.r.Read(data) - if err != nil { - errorf("gobEncoder data read: %s", err) - } - fmt.Fprintf(os.Stderr, "%s[% .2x]\n", indent+1, data) -} |