f8d9fa9e80
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. From-SVN: r219627
706 lines
18 KiB
Go
706 lines
18 KiB
Go
// Copyright 2009 The Go Authors. All rights reserved.
|
|
// Use of this source code is governed by a BSD-style
|
|
// license that can be found in the LICENSE file.
|
|
|
|
// Delete the next line to include in the gob package.
|
|
// +build ignore
|
|
|
|
package gob
|
|
|
|
// This file is not normally included in the gob package. Used only for debugging the package itself.
|
|
// Except for reading uints, it is an implementation of a reader that is independent of
|
|
// the one implemented by Decoder.
|
|
// To enable the Debug function, delete the +build ignore line above and do
|
|
// go install
|
|
|
|
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 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 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 = io.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.
|
|
// It is a no-op unless debugging was enabled when the package was built.
|
|
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 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 == io.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, delta is %d fieldNum is %d", delta, fieldNum)
|
|
}
|
|
}
|
|
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}
|
|
case 5: // BinaryMarshaler type, one field of {{Common}}
|
|
// Field number 0 is CommonType
|
|
deb.delta(1)
|
|
com := deb.common()
|
|
wire.BinaryMarshalerT = &gobEncoderType{com}
|
|
case 6: // TextMarshaler type, one field of {{Common}}
|
|
// Field number 0 is CommonType
|
|
deb.delta(1)
|
|
com := deb.common()
|
|
wire.TextMarshalerT = &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, float64FromBits(x))
|
|
case tComplex:
|
|
r := deb.uint64()
|
|
i := deb.uint64()
|
|
fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, float64FromBits(r), float64FromBits(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)
|
|
}
|