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