Home | History | Annotate | Download | only in gob
      1 // Copyright 2009 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 // Delete the next line to include in the gob package.
      6 // +build ignore
      7 
      8 package gob
      9 
     10 // This file is not normally included in the gob package. Used only for debugging the package itself.
     11 // Except for reading uints, it is an implementation of a reader that is independent of
     12 // the one implemented by Decoder.
     13 // To enable the Debug function, delete the +build ignore line above and do
     14 //	go install
     15 
     16 import (
     17 	"bytes"
     18 	"fmt"
     19 	"io"
     20 	"os"
     21 	"strings"
     22 	"sync"
     23 )
     24 
     25 var dumpBytes = false // If true, print the remaining bytes in the input buffer at each item.
     26 
     27 // Init installs the debugging facility. If this file is not compiled in the
     28 // package, the tests in codec_test.go are no-ops.
     29 func init() {
     30 	debugFunc = Debug
     31 }
     32 
     33 var (
     34 	blanks = bytes.Repeat([]byte{' '}, 3*10)
     35 	empty  = []byte(": <empty>\n")
     36 	tabs   = strings.Repeat("\t", 100)
     37 )
     38 
     39 // tab indents itself when printed.
     40 type tab int
     41 
     42 func (t tab) String() string {
     43 	n := int(t)
     44 	if n > len(tabs) {
     45 		n = len(tabs)
     46 	}
     47 	return tabs[0:n]
     48 }
     49 
     50 func (t tab) print() {
     51 	fmt.Fprint(os.Stderr, t)
     52 }
     53 
     54 // A peekReader wraps an io.Reader, allowing one to peek ahead to see
     55 // what's coming without stealing the data from the client of the Reader.
     56 type peekReader struct {
     57 	r    io.Reader
     58 	data []byte // read-ahead data
     59 }
     60 
     61 // newPeekReader returns a peekReader that wraps r.
     62 func newPeekReader(r io.Reader) *peekReader {
     63 	return &peekReader{r: r}
     64 }
     65 
     66 // Read is the usual method. It will first take data that has been read ahead.
     67 func (p *peekReader) Read(b []byte) (n int, err error) {
     68 	if len(p.data) == 0 {
     69 		return p.r.Read(b)
     70 	}
     71 	// Satisfy what's possible from the read-ahead data.
     72 	n = copy(b, p.data)
     73 	// Move data down to beginning of slice, to avoid endless growth
     74 	copy(p.data, p.data[n:])
     75 	p.data = p.data[:len(p.data)-n]
     76 	return
     77 }
     78 
     79 // peek returns as many bytes as possible from the unread
     80 // portion of the stream, up to the length of b.
     81 func (p *peekReader) peek(b []byte) (n int, err error) {
     82 	if len(p.data) > 0 {
     83 		n = copy(b, p.data)
     84 		if n == len(b) {
     85 			return
     86 		}
     87 		b = b[n:]
     88 	}
     89 	if len(b) == 0 {
     90 		return
     91 	}
     92 	m, e := io.ReadFull(p.r, b)
     93 	if m > 0 {
     94 		p.data = append(p.data, b[:m]...)
     95 	}
     96 	n += m
     97 	if e == io.ErrUnexpectedEOF {
     98 		// That means m > 0 but we reached EOF. If we got data
     99 		// we won't complain about not being able to peek enough.
    100 		if n > 0 {
    101 			e = nil
    102 		} else {
    103 			e = io.EOF
    104 		}
    105 	}
    106 	return n, e
    107 }
    108 
    109 type debugger struct {
    110 	mutex          sync.Mutex
    111 	remain         int  // the number of bytes known to remain in the input
    112 	remainingKnown bool // the value of 'remain' is valid
    113 	r              *peekReader
    114 	wireType       map[typeId]*wireType
    115 	tmp            []byte // scratch space for decoding uints.
    116 }
    117 
    118 // dump prints the next nBytes of the input.
    119 // It arranges to print the output aligned from call to
    120 // call, to make it easy to see what has been consumed.
    121 func (deb *debugger) dump(format string, args ...interface{}) {
    122 	if !dumpBytes {
    123 		return
    124 	}
    125 	fmt.Fprintf(os.Stderr, format+" ", args...)
    126 	if !deb.remainingKnown {
    127 		return
    128 	}
    129 	if deb.remain < 0 {
    130 		fmt.Fprintf(os.Stderr, "remaining byte count is negative! %d\n", deb.remain)
    131 		return
    132 	}
    133 	data := make([]byte, deb.remain)
    134 	n, _ := deb.r.peek(data)
    135 	if n == 0 {
    136 		os.Stderr.Write(empty)
    137 		return
    138 	}
    139 	b := new(bytes.Buffer)
    140 	fmt.Fprintf(b, "[%d]{\n", deb.remain)
    141 	// Blanks until first byte
    142 	lineLength := 0
    143 	if n := len(data); n%10 != 0 {
    144 		lineLength = 10 - n%10
    145 		fmt.Fprintf(b, "\t%s", blanks[:lineLength*3])
    146 	}
    147 	// 10 bytes per line
    148 	for len(data) > 0 {
    149 		if lineLength == 0 {
    150 			fmt.Fprint(b, "\t")
    151 		}
    152 		m := 10 - lineLength
    153 		lineLength = 0
    154 		if m > len(data) {
    155 			m = len(data)
    156 		}
    157 		fmt.Fprintf(b, "% x\n", data[:m])
    158 		data = data[m:]
    159 	}
    160 	fmt.Fprint(b, "}\n")
    161 	os.Stderr.Write(b.Bytes())
    162 }
    163 
    164 // Debug prints a human-readable representation of the gob data read from r.
    165 // It is a no-op unless debugging was enabled when the package was built.
    166 func Debug(r io.Reader) {
    167 	err := debug(r)
    168 	if err != nil {
    169 		fmt.Fprintf(os.Stderr, "gob debug: %s\n", err)
    170 	}
    171 }
    172 
    173 // debug implements Debug, but catches panics and returns
    174 // them as errors to be printed by Debug.
    175 func debug(r io.Reader) (err error) {
    176 	defer catchError(&err)
    177 	fmt.Fprintln(os.Stderr, "Start of debugging")
    178 	deb := &debugger{
    179 		r:        newPeekReader(r),
    180 		wireType: make(map[typeId]*wireType),
    181 		tmp:      make([]byte, 16),
    182 	}
    183 	if b, ok := r.(*bytes.Buffer); ok {
    184 		deb.remain = b.Len()
    185 		deb.remainingKnown = true
    186 	}
    187 	deb.gobStream()
    188 	return
    189 }
    190 
    191 // note that we've consumed some bytes
    192 func (deb *debugger) consumed(n int) {
    193 	if deb.remainingKnown {
    194 		deb.remain -= n
    195 	}
    196 }
    197 
    198 // int64 decodes and returns the next integer, which must be present.
    199 // Don't call this if you could be at EOF.
    200 func (deb *debugger) int64() int64 {
    201 	return toInt(deb.uint64())
    202 }
    203 
    204 // uint64 returns and decodes the next unsigned integer, which must be present.
    205 // Don't call this if you could be at EOF.
    206 // TODO: handle errors better.
    207 func (deb *debugger) uint64() uint64 {
    208 	n, w, err := decodeUintReader(deb.r, deb.tmp)
    209 	if err != nil {
    210 		errorf("debug: read error: %s", err)
    211 	}
    212 	deb.consumed(w)
    213 	return n
    214 }
    215 
    216 // GobStream:
    217 //	DelimitedMessage* (until EOF)
    218 func (deb *debugger) gobStream() {
    219 	// Make sure we're single-threaded through here.
    220 	deb.mutex.Lock()
    221 	defer deb.mutex.Unlock()
    222 
    223 	for deb.delimitedMessage(0) {
    224 	}
    225 }
    226 
    227 // DelimitedMessage:
    228 //	uint(lengthOfMessage) Message
    229 func (deb *debugger) delimitedMessage(indent tab) bool {
    230 	for {
    231 		n := deb.loadBlock(true)
    232 		if n < 0 {
    233 			return false
    234 		}
    235 		deb.dump("Delimited message of length %d", n)
    236 		deb.message(indent)
    237 	}
    238 	return true
    239 }
    240 
    241 // loadBlock preps us to read a message
    242 // of the length specified next in the input. It returns
    243 // the length of the block. The argument tells whether
    244 // an EOF is acceptable now. If it is and one is found,
    245 // the return value is negative.
    246 func (deb *debugger) loadBlock(eofOK bool) int {
    247 	n64, w, err := decodeUintReader(deb.r, deb.tmp) // deb.uint64 will error at EOF
    248 	if err != nil {
    249 		if eofOK && err == io.EOF {
    250 			return -1
    251 		}
    252 		errorf("debug: unexpected error: %s", err)
    253 	}
    254 	deb.consumed(w)
    255 	n := int(n64)
    256 	if n < 0 {
    257 		errorf("huge value for message length: %d", n64)
    258 	}
    259 	return int(n)
    260 }
    261 
    262 // Message:
    263 //	TypeSequence TypedValue
    264 // TypeSequence
    265 //	(TypeDefinition DelimitedTypeDefinition*)?
    266 // DelimitedTypeDefinition:
    267 //	uint(lengthOfTypeDefinition) TypeDefinition
    268 // TypedValue:
    269 //	int(typeId) Value
    270 func (deb *debugger) message(indent tab) bool {
    271 	for {
    272 		// Convert the uint64 to a signed integer typeId
    273 		uid := deb.int64()
    274 		id := typeId(uid)
    275 		deb.dump("type id=%d", id)
    276 		if id < 0 {
    277 			deb.typeDefinition(indent, -id)
    278 			n := deb.loadBlock(false)
    279 			deb.dump("Message of length %d", n)
    280 			continue
    281 		} else {
    282 			deb.value(indent, id)
    283 			break
    284 		}
    285 	}
    286 	return true
    287 }
    288 
    289 // Helper methods to make it easy to scan a type descriptor.
    290 
    291 // common returns the CommonType at the input point.
    292 func (deb *debugger) common() CommonType {
    293 	fieldNum := -1
    294 	name := ""
    295 	id := typeId(0)
    296 	for {
    297 		delta := deb.delta(-1)
    298 		if delta == 0 {
    299 			break
    300 		}
    301 		fieldNum += delta
    302 		switch fieldNum {
    303 		case 0:
    304 			name = deb.string()
    305 		case 1:
    306 			// Id typeId
    307 			id = deb.typeId()
    308 		default:
    309 			errorf("corrupted CommonType, delta is %d fieldNum is %d", delta, fieldNum)
    310 		}
    311 	}
    312 	return CommonType{name, id}
    313 }
    314 
    315 // uint returns the unsigned int at the input point, as a uint (not uint64).
    316 func (deb *debugger) uint() uint {
    317 	return uint(deb.uint64())
    318 }
    319 
    320 // int returns the signed int at the input point, as an int (not int64).
    321 func (deb *debugger) int() int {
    322 	return int(deb.int64())
    323 }
    324 
    325 // typeId returns the type id at the input point.
    326 func (deb *debugger) typeId() typeId {
    327 	return typeId(deb.int64())
    328 }
    329 
    330 // string returns the string at the input point.
    331 func (deb *debugger) string() string {
    332 	x := int(deb.uint64())
    333 	b := make([]byte, x)
    334 	nb, _ := deb.r.Read(b)
    335 	if nb != x {
    336 		errorf("corrupted type")
    337 	}
    338 	deb.consumed(nb)
    339 	return string(b)
    340 }
    341 
    342 // delta returns the field delta at the input point. The expect argument,
    343 // if non-negative, identifies what the value should be.
    344 func (deb *debugger) delta(expect int) int {
    345 	delta := int(deb.uint64())
    346 	if delta < 0 || (expect >= 0 && delta != expect) {
    347 		errorf("decode: corrupted type: delta %d expected %d", delta, expect)
    348 	}
    349 	return delta
    350 }
    351 
    352 // TypeDefinition:
    353 //	[int(-typeId) (already read)] encodingOfWireType
    354 func (deb *debugger) typeDefinition(indent tab, id typeId) {
    355 	deb.dump("type definition for id %d", id)
    356 	// Encoding is of a wireType. Decode the structure as usual
    357 	fieldNum := -1
    358 	wire := new(wireType)
    359 	// A wireType defines a single field.
    360 	delta := deb.delta(-1)
    361 	fieldNum += delta
    362 	switch fieldNum {
    363 	case 0: // array type, one field of {{Common}, elem, length}
    364 		// Field number 0 is CommonType
    365 		deb.delta(1)
    366 		com := deb.common()
    367 		// Field number 1 is type Id of elem
    368 		deb.delta(1)
    369 		id := deb.typeId()
    370 		// Field number 3 is length
    371 		deb.delta(1)
    372 		length := deb.int()
    373 		wire.ArrayT = &arrayType{com, id, length}
    374 
    375 	case 1: // slice type, one field of {{Common}, elem}
    376 		// Field number 0 is CommonType
    377 		deb.delta(1)
    378 		com := deb.common()
    379 		// Field number 1 is type Id of elem
    380 		deb.delta(1)
    381 		id := deb.typeId()
    382 		wire.SliceT = &sliceType{com, id}
    383 
    384 	case 2: // struct type, one field of {{Common}, []fieldType}
    385 		// Field number 0 is CommonType
    386 		deb.delta(1)
    387 		com := deb.common()
    388 		// Field number 1 is slice of FieldType
    389 		deb.delta(1)
    390 		numField := int(deb.uint())
    391 		field := make([]*fieldType, numField)
    392 		for i := 0; i < numField; i++ {
    393 			field[i] = new(fieldType)
    394 			deb.delta(1) // field 0 of fieldType: name
    395 			field[i].Name = deb.string()
    396 			deb.delta(1) // field 1 of fieldType: id
    397 			field[i].Id = deb.typeId()
    398 			deb.delta(0) // end of fieldType
    399 		}
    400 		wire.StructT = &structType{com, field}
    401 
    402 	case 3: // map type, one field of {{Common}, key, elem}
    403 		// Field number 0 is CommonType
    404 		deb.delta(1)
    405 		com := deb.common()
    406 		// Field number 1 is type Id of key
    407 		deb.delta(1)
    408 		keyId := deb.typeId()
    409 		// Field number 2 is type Id of elem
    410 		deb.delta(1)
    411 		elemId := deb.typeId()
    412 		wire.MapT = &mapType{com, keyId, elemId}
    413 	case 4: // GobEncoder type, one field of {{Common}}
    414 		// Field number 0 is CommonType
    415 		deb.delta(1)
    416 		com := deb.common()
    417 		wire.GobEncoderT = &gobEncoderType{com}
    418 	case 5: // BinaryMarshaler type, one field of {{Common}}
    419 		// Field number 0 is CommonType
    420 		deb.delta(1)
    421 		com := deb.common()
    422 		wire.BinaryMarshalerT = &gobEncoderType{com}
    423 	case 6: // TextMarshaler type, one field of {{Common}}
    424 		// Field number 0 is CommonType
    425 		deb.delta(1)
    426 		com := deb.common()
    427 		wire.TextMarshalerT = &gobEncoderType{com}
    428 	default:
    429 		errorf("bad field in type %d", fieldNum)
    430 	}
    431 	deb.printWireType(indent, wire)
    432 	deb.delta(0) // end inner type (arrayType, etc.)
    433 	deb.delta(0) // end wireType
    434 	// Remember we've seen this type.
    435 	deb.wireType[id] = wire
    436 }
    437 
    438 // Value:
    439 //	SingletonValue | StructValue
    440 func (deb *debugger) value(indent tab, id typeId) {
    441 	wire, ok := deb.wireType[id]
    442 	if ok && wire.StructT != nil {
    443 		deb.structValue(indent, id)
    444 	} else {
    445 		deb.singletonValue(indent, id)
    446 	}
    447 }
    448 
    449 // SingletonValue:
    450 //	uint(0) FieldValue
    451 func (deb *debugger) singletonValue(indent tab, id typeId) {
    452 	deb.dump("Singleton value")
    453 	// is it a builtin type?
    454 	wire := deb.wireType[id]
    455 	_, ok := builtinIdToType[id]
    456 	if !ok && wire == nil {
    457 		errorf("type id %d not defined", id)
    458 	}
    459 	m := deb.uint64()
    460 	if m != 0 {
    461 		errorf("expected zero; got %d", m)
    462 	}
    463 	deb.fieldValue(indent, id)
    464 }
    465 
    466 // InterfaceValue:
    467 //	NilInterfaceValue | NonNilInterfaceValue
    468 func (deb *debugger) interfaceValue(indent tab) {
    469 	deb.dump("Start of interface value")
    470 	if nameLen := deb.uint64(); nameLen == 0 {
    471 		deb.nilInterfaceValue(indent)
    472 	} else {
    473 		deb.nonNilInterfaceValue(indent, int(nameLen))
    474 	}
    475 }
    476 
    477 // NilInterfaceValue:
    478 //	uint(0) [already read]
    479 func (deb *debugger) nilInterfaceValue(indent tab) int {
    480 	fmt.Fprintf(os.Stderr, "%snil interface\n", indent)
    481 	return 0
    482 }
    483 
    484 // NonNilInterfaceValue:
    485 //	ConcreteTypeName TypeSequence InterfaceContents
    486 // ConcreteTypeName:
    487 //	uint(lengthOfName) [already read=n] name
    488 // InterfaceContents:
    489 //	int(concreteTypeId) DelimitedValue
    490 // DelimitedValue:
    491 //	uint(length) Value
    492 func (deb *debugger) nonNilInterfaceValue(indent tab, nameLen int) {
    493 	// ConcreteTypeName
    494 	b := make([]byte, nameLen)
    495 	deb.r.Read(b) // TODO: CHECK THESE READS!!
    496 	deb.consumed(nameLen)
    497 	name := string(b)
    498 
    499 	for {
    500 		id := deb.typeId()
    501 		if id < 0 {
    502 			deb.typeDefinition(indent, -id)
    503 			n := deb.loadBlock(false)
    504 			deb.dump("Nested message of length %d", n)
    505 		} else {
    506 			// DelimitedValue
    507 			x := deb.uint64() // in case we want to ignore the value; we don't.
    508 			fmt.Fprintf(os.Stderr, "%sinterface value, type %q id=%d; valueLength %d\n", indent, name, id, x)
    509 			deb.value(indent, id)
    510 			break
    511 		}
    512 	}
    513 }
    514 
    515 // printCommonType prints a common type; used by printWireType.
    516 func (deb *debugger) printCommonType(indent tab, kind string, common *CommonType) {
    517 	indent.print()
    518 	fmt.Fprintf(os.Stderr, "%s %q id=%d\n", kind, common.Name, common.Id)
    519 }
    520 
    521 // printWireType prints the contents of a wireType.
    522 func (deb *debugger) printWireType(indent tab, wire *wireType) {
    523 	fmt.Fprintf(os.Stderr, "%stype definition {\n", indent)
    524 	indent++
    525 	switch {
    526 	case wire.ArrayT != nil:
    527 		deb.printCommonType(indent, "array", &wire.ArrayT.CommonType)
    528 		fmt.Fprintf(os.Stderr, "%slen %d\n", indent+1, wire.ArrayT.Len)
    529 		fmt.Fprintf(os.Stderr, "%selemid %d\n", indent+1, wire.ArrayT.Elem)
    530 	case wire.MapT != nil:
    531 		deb.printCommonType(indent, "map", &wire.MapT.CommonType)
    532 		fmt.Fprintf(os.Stderr, "%skey id=%d\n", indent+1, wire.MapT.Key)
    533 		fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.MapT.Elem)
    534 	case wire.SliceT != nil:
    535 		deb.printCommonType(indent, "slice", &wire.SliceT.CommonType)
    536 		fmt.Fprintf(os.Stderr, "%selem id=%d\n", indent+1, wire.SliceT.Elem)
    537 	case wire.StructT != nil:
    538 		deb.printCommonType(indent, "struct", &wire.StructT.CommonType)
    539 		for i, field := range wire.StructT.Field {
    540 			fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\tid=%d\n", indent+1, i, field.Name, field.Id)
    541 		}
    542 	case wire.GobEncoderT != nil:
    543 		deb.printCommonType(indent, "GobEncoder", &wire.GobEncoderT.CommonType)
    544 	}
    545 	indent--
    546 	fmt.Fprintf(os.Stderr, "%s}\n", indent)
    547 }
    548 
    549 // fieldValue prints a value of any type, such as a struct field.
    550 // FieldValue:
    551 //	builtinValue | ArrayValue | MapValue | SliceValue | StructValue | InterfaceValue
    552 func (deb *debugger) fieldValue(indent tab, id typeId) {
    553 	_, ok := builtinIdToType[id]
    554 	if ok {
    555 		if id == tInterface {
    556 			deb.interfaceValue(indent)
    557 		} else {
    558 			deb.printBuiltin(indent, id)
    559 		}
    560 		return
    561 	}
    562 	wire, ok := deb.wireType[id]
    563 	if !ok {
    564 		errorf("type id %d not defined", id)
    565 	}
    566 	switch {
    567 	case wire.ArrayT != nil:
    568 		deb.arrayValue(indent, wire)
    569 	case wire.MapT != nil:
    570 		deb.mapValue(indent, wire)
    571 	case wire.SliceT != nil:
    572 		deb.sliceValue(indent, wire)
    573 	case wire.StructT != nil:
    574 		deb.structValue(indent, id)
    575 	case wire.GobEncoderT != nil:
    576 		deb.gobEncoderValue(indent, id)
    577 	default:
    578 		panic("bad wire type for field")
    579 	}
    580 }
    581 
    582 // printBuiltin prints a value not of a fundamental type, that is,
    583 // one whose type is known to gobs at bootstrap time.
    584 func (deb *debugger) printBuiltin(indent tab, id typeId) {
    585 	switch id {
    586 	case tBool:
    587 		x := deb.int64()
    588 		if x == 0 {
    589 			fmt.Fprintf(os.Stderr, "%sfalse\n", indent)
    590 		} else {
    591 			fmt.Fprintf(os.Stderr, "%strue\n", indent)
    592 		}
    593 	case tInt:
    594 		x := deb.int64()
    595 		fmt.Fprintf(os.Stderr, "%s%d\n", indent, x)
    596 	case tUint:
    597 		x := deb.uint64()
    598 		fmt.Fprintf(os.Stderr, "%s%d\n", indent, x)
    599 	case tFloat:
    600 		x := deb.uint64()
    601 		fmt.Fprintf(os.Stderr, "%s%g\n", indent, float64FromBits(x))
    602 	case tComplex:
    603 		r := deb.uint64()
    604 		i := deb.uint64()
    605 		fmt.Fprintf(os.Stderr, "%s%g+%gi\n", indent, float64FromBits(r), float64FromBits(i))
    606 	case tBytes:
    607 		x := int(deb.uint64())
    608 		b := make([]byte, x)
    609 		deb.r.Read(b)
    610 		deb.consumed(x)
    611 		fmt.Fprintf(os.Stderr, "%s{% x}=%q\n", indent, b, b)
    612 	case tString:
    613 		x := int(deb.uint64())
    614 		b := make([]byte, x)
    615 		deb.r.Read(b)
    616 		deb.consumed(x)
    617 		fmt.Fprintf(os.Stderr, "%s%q\n", indent, b)
    618 	default:
    619 		panic("unknown builtin")
    620 	}
    621 }
    622 
    623 // ArrayValue:
    624 //	uint(n) FieldValue*n
    625 func (deb *debugger) arrayValue(indent tab, wire *wireType) {
    626 	elemId := wire.ArrayT.Elem
    627 	u := deb.uint64()
    628 	length := int(u)
    629 	for i := 0; i < length; i++ {
    630 		deb.fieldValue(indent, elemId)
    631 	}
    632 	if length != wire.ArrayT.Len {
    633 		fmt.Fprintf(os.Stderr, "%s(wrong length for array: %d should be %d)\n", indent, length, wire.ArrayT.Len)
    634 	}
    635 }
    636 
    637 // MapValue:
    638 //	uint(n) (FieldValue FieldValue)*n  [n (key, value) pairs]
    639 func (deb *debugger) mapValue(indent tab, wire *wireType) {
    640 	keyId := wire.MapT.Key
    641 	elemId := wire.MapT.Elem
    642 	u := deb.uint64()
    643 	length := int(u)
    644 	for i := 0; i < length; i++ {
    645 		deb.fieldValue(indent+1, keyId)
    646 		deb.fieldValue(indent+1, elemId)
    647 	}
    648 }
    649 
    650 // SliceValue:
    651 //	uint(n) (n FieldValue)
    652 func (deb *debugger) sliceValue(indent tab, wire *wireType) {
    653 	elemId := wire.SliceT.Elem
    654 	u := deb.uint64()
    655 	length := int(u)
    656 	deb.dump("Start of slice of length %d", length)
    657 
    658 	for i := 0; i < length; i++ {
    659 		deb.fieldValue(indent, elemId)
    660 	}
    661 }
    662 
    663 // StructValue:
    664 //	(uint(fieldDelta) FieldValue)*
    665 func (deb *debugger) structValue(indent tab, id typeId) {
    666 	deb.dump("Start of struct value of %q id=%d\n<<\n", id.name(), id)
    667 	fmt.Fprintf(os.Stderr, "%s%s struct {\n", indent, id.name())
    668 	wire, ok := deb.wireType[id]
    669 	if !ok {
    670 		errorf("type id %d not defined", id)
    671 	}
    672 	strct := wire.StructT
    673 	fieldNum := -1
    674 	indent++
    675 	for {
    676 		delta := deb.uint64()
    677 		if delta == 0 { // struct terminator is zero delta fieldnum
    678 			break
    679 		}
    680 		fieldNum += int(delta)
    681 		if fieldNum < 0 || fieldNum >= len(strct.Field) {
    682 			deb.dump("field number out of range: prevField=%d delta=%d", fieldNum-int(delta), delta)
    683 			break
    684 		}
    685 		fmt.Fprintf(os.Stderr, "%sfield %d:\t%s\n", indent, fieldNum, wire.StructT.Field[fieldNum].Name)
    686 		deb.fieldValue(indent+1, strct.Field[fieldNum].Id)
    687 	}
    688 	indent--
    689 	fmt.Fprintf(os.Stderr, "%s} // end %s struct\n", indent, id.name())
    690 	deb.dump(">> End of struct value of type %d %q", id, id.name())
    691 }
    692 
    693 // GobEncoderValue:
    694 //	uint(n) byte*n
    695 func (deb *debugger) gobEncoderValue(indent tab, id typeId) {
    696 	len := deb.uint64()
    697 	deb.dump("GobEncoder value of %q id=%d, length %d\n", id.name(), id, len)
    698 	fmt.Fprintf(os.Stderr, "%s%s (implements GobEncoder)\n", indent, id.name())
    699 	data := make([]byte, len)
    700 	_, err := deb.r.Read(data)
    701 	if err != nil {
    702 		errorf("gobEncoder data read: %s", err)
    703 	}
    704 	fmt.Fprintf(os.Stderr, "%s[% .2x]\n", indent+1, data)
    705 }
    706