...

Source file src/encoding/gob/debug.go

     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	

View as plain text