LEFT | RIGHT |
1 // Copyright 2014 The Go Authors. All rights reserved. | 1 // Copyright 2014 The Go Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style | 2 // Use of this source code is governed by a BSD-style |
3 // license that can be found in the LICENSE file. | 3 // license that can be found in the LICENSE file. |
4 | 4 |
5 // Generation of runtime function information (pclntab). | 5 // Generation of runtime function information (pclntab). |
6 // See runtime.go. | |
7 | 6 |
8 package main | 7 package main |
9 | 8 |
10 import ( | 9 import ( |
11 "debug/goobj" | 10 "debug/goobj" |
12 "encoding/binary" | 11 "encoding/binary" |
13 "os" | 12 "os" |
14 "sort" | 13 "sort" |
15 ) | 14 ) |
16 | 15 |
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
93 } | 92 } |
94 | 93 |
95 // off is the offset of the table entry where we're going to wri
te | 94 // off is the offset of the table entry where we're going to wri
te |
96 // the encoded form of Func. | 95 // the encoded form of Func. |
97 // indexOff is the current position in the table index; | 96 // indexOff is the current position in the table index; |
98 // we add an entry in the index pointing at off. | 97 // we add an entry in the index pointing at off. |
99 off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1) | 98 off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1) |
100 indexOff = buf.Addr(indexOff, sym.SymID, 0) | 99 indexOff = buf.Addr(indexOff, sym.SymID, 0) |
101 indexOff = buf.Uint(indexOff, uint64(off), p.ptrsize) | 100 indexOff = buf.Uint(indexOff, uint64(off), p.ptrsize) |
102 | 101 |
103 » » // The Func encoding starts with a fixed size header and then | 102 » » // The Func encoding starts with a header giving offsets |
104 » » // variable-sized data. end gives the current write position for | 103 » » // to data blobs, and then the data blobs themselves. |
105 » » // the variable-sized data. | 104 » » // end gives the current write position for the data blobs. |
106 end := off + p.ptrsize + 3*4 + 5*4 + len(f.PCData)*4 + len(f.Fun
cData)*p.ptrsize | 105 end := off + p.ptrsize + 3*4 + 5*4 + len(f.PCData)*4 + len(f.Fun
cData)*p.ptrsize |
107 if len(f.FuncData) > 0 { | 106 if len(f.FuncData) > 0 { |
108 end += -end & (p.ptrsize - 1) | 107 end += -end & (p.ptrsize - 1) |
109 } | 108 } |
110 buf.SetSize(end) | 109 buf.SetSize(end) |
111 | 110 |
112 // entry uintptr | 111 // entry uintptr |
113 // name int32 | 112 // name int32 |
114 // args int32 | 113 // args int32 |
115 // frame int32 | 114 // frame int32 |
| 115 // |
| 116 // The frame recorded in the object file is |
| 117 // the frame size used in an assembly listing, which does |
| 118 // not include the caller PC on the stack. |
| 119 // The frame size we want to list here is the delta from |
| 120 // this function's SP to its caller's SP, which does include |
| 121 // the caller PC. Add p.ptrsize to f.Frame to adjust. |
| 122 // TODO(rsc): Record the same frame size in the object file. |
116 off = buf.Addr(off, sym.SymID, 0) | 123 off = buf.Addr(off, sym.SymID, 0) |
117 off = buf.Uint32(off, uint32(addString(buf, sym.Name))) | 124 off = buf.Uint32(off, uint32(addString(buf, sym.Name))) |
118 off = buf.Uint32(off, uint32(f.Args)) | 125 off = buf.Uint32(off, uint32(f.Args)) |
119 off = buf.Uint32(off, uint32(f.Frame+p.ptrsize)) | 126 off = buf.Uint32(off, uint32(f.Frame+p.ptrsize)) |
120 | 127 |
121 // pcdata | 128 // pcdata |
122 off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCSP))) | 129 off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCSP))) |
123 off = buf.Uint32(off, uint32(addPCFileTable(p, buf, file, f.PCFi
le, sym, files))) | 130 off = buf.Uint32(off, uint32(addPCFileTable(p, buf, file, f.PCFi
le, sym, files))) |
124 off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCLine))
) | 131 off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCLine))
) |
125 off = buf.Uint32(off, uint32(len(f.PCData))) | 132 off = buf.Uint32(off, uint32(len(f.PCData))) |
126 off = buf.Uint32(off, uint32(len(f.FuncData))) | 133 off = buf.Uint32(off, uint32(len(f.FuncData))) |
127 for _, pcdata := range f.PCData { | 134 for _, pcdata := range f.PCData { |
128 off = buf.Uint32(off, uint32(addPCTable(p, buf, file, pc
data))) | 135 off = buf.Uint32(off, uint32(addPCTable(p, buf, file, pc
data))) |
129 } | 136 } |
130 | 137 |
131 // funcdata | 138 // funcdata |
132 if len(f.FuncData) > 0 { | 139 if len(f.FuncData) > 0 { |
133 » » » off += off & 4 // must be pointer-aligned and we're only
int32-aligned. | 140 » » » off += -off & (p.ptrsize - 1) // must be pointer-aligned |
134 for _, funcdata := range f.FuncData { | 141 for _, funcdata := range f.FuncData { |
135 if funcdata.Sym.Name == "" { | 142 if funcdata.Sym.Name == "" { |
136 off = buf.Uint(off, uint64(funcdata.Offs
et), p.ptrsize) | 143 off = buf.Uint(off, uint64(funcdata.Offs
et), p.ptrsize) |
137 } else { | 144 } else { |
138 off = buf.Addr(off, funcdata.Sym, funcda
ta.Offset) | 145 off = buf.Addr(off, funcdata.Sym, funcda
ta.Offset) |
139 } | 146 } |
140 } | 147 } |
141 } | 148 } |
142 | 149 |
143 if off != end { | 150 if off != end { |
144 p.errorf("internal error: invalid math in pclntab: off=%
#x end=%#x", off, end) | 151 p.errorf("internal error: invalid math in pclntab: off=%
#x end=%#x", off, end) |
145 break | 152 break |
146 } | 153 } |
147 } | 154 } |
148 if file != nil { | 155 if file != nil { |
149 file.Close() | 156 file.Close() |
150 } | 157 } |
151 | 158 |
152 // Final entry of index is end PC of last function. | 159 // Final entry of index is end PC of last function. |
153 indexOff = buf.Addr(indexOff, lastSym.SymID, int64(lastSym.Size)) | 160 indexOff = buf.Addr(indexOff, lastSym.SymID, int64(lastSym.Size)) |
154 | 161 |
155 // Start file table. | 162 // Start file table. |
156 // Function index is immediately followed by offset to file table. | 163 // Function index is immediately followed by offset to file table. |
157 off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1) | 164 off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1) |
158 buf.Uint32(indexOff, uint32(off)) | 165 buf.Uint32(indexOff, uint32(off)) |
159 | 166 |
160 // File table is an array of uint32s. | 167 // File table is an array of uint32s. |
161 » // The first entry gives n, the size of the array. | 168 » // The first entry gives 1+n, the size of the array. |
162 » // The following n-1 entries hold offsets to string data. | 169 » // The following n entries hold offsets to string data. |
163 // File number n uses the string pointed at by entry n. | 170 // File number n uses the string pointed at by entry n. |
164 // File number 0 is invalid. | 171 // File number 0 is invalid. |
165 » buf.SetSize(off + (len(files)+1)*4) | 172 » buf.SetSize(off + (1+len(files))*4) |
166 » buf.Uint32(off, uint32(len(files)+1)) | 173 » buf.Uint32(off, uint32(1+len(files))) |
167 var filestr []string | 174 var filestr []string |
168 for file := range files { | 175 for file := range files { |
169 filestr = append(filestr, file) | 176 filestr = append(filestr, file) |
170 } | 177 } |
171 sort.Strings(filestr) | 178 sort.Strings(filestr) |
172 for _, file := range filestr { | 179 for _, file := range filestr { |
173 id := files[file] | 180 id := files[file] |
174 buf.Uint32(off+4*id, uint32(addString(buf, file))) | 181 buf.Uint32(off+4*id, uint32(addString(buf, file))) |
175 } | 182 } |
176 | 183 |
(...skipping 75 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
252 val = int32(filenum[oldval]) | 259 val = int32(filenum[oldval]) |
253 } | 260 } |
254 dv := val - newval | 261 dv := val - newval |
255 newval = val | 262 newval = val |
256 uv := uint32(dv<<1) ^ uint32(dv>>31) | 263 uv := uint32(dv<<1) ^ uint32(dv>>31) |
257 dst = appendVarint(dst, uv) | 264 dst = appendVarint(dst, uv) |
258 | 265 |
259 // pc delta | 266 // pc delta |
260 dst = appendVarint(dst, it.NextPC-it.PC) | 267 dst = appendVarint(dst, it.NextPC-it.PC) |
261 } | 268 } |
262 » if it.Error { | 269 » if it.Corrupt { |
263 p.errorf("%s: corrupt pc-file table", sym) | 270 p.errorf("%s: corrupt pc-file table", sym) |
264 } | 271 } |
265 | 272 |
266 // terminating value delta | 273 // terminating value delta |
267 dst = appendVarint(dst, 0) | 274 dst = appendVarint(dst, 0) |
268 | 275 |
269 b.SetSize(off + len(dst)) | 276 b.SetSize(off + len(dst)) |
270 copy(b.data[off:], dst) | 277 copy(b.data[off:], dst) |
271 return off | 278 return off |
272 } | 279 } |
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 return off + b.ptrsize | 376 return off + b.ptrsize |
370 } | 377 } |
371 | 378 |
372 // A PCIter implements iteration over PC-data tables. | 379 // A PCIter implements iteration over PC-data tables. |
373 // | 380 // |
374 // var it PCIter | 381 // var it PCIter |
375 // it.Init(p, data) | 382 // it.Init(p, data) |
376 // for it.Init(p, data); !it.Done; it.Next() { | 383 // for it.Init(p, data); !it.Done; it.Next() { |
377 // it.Value holds from it.PC up to (but not including) it.NextPC | 384 // it.Value holds from it.PC up to (but not including) it.NextPC |
378 // } | 385 // } |
379 //» if it.Error { | 386 //» if it.Corrupt { |
380 // data was malformed | 387 // data was malformed |
381 // } | 388 // } |
382 // | 389 // |
383 type PCIter struct { | 390 type PCIter struct { |
384 PC uint32 | 391 PC uint32 |
385 NextPC uint32 | 392 NextPC uint32 |
386 Value int32 | 393 Value int32 |
387 Done bool | 394 Done bool |
388 » Error bool | 395 » Corrupt bool |
389 p []byte | 396 p []byte |
390 start bool | 397 start bool |
391 pcquantum uint32 | 398 pcquantum uint32 |
392 } | 399 } |
393 | 400 |
394 // Init initializes the iteration. | 401 // Init initializes the iteration. |
395 // On return, if it.Done is true, the iteration is over. | 402 // On return, if it.Done is true, the iteration is over. |
396 // Otherwise it.Value applies in the pc range [it.PC, it.NextPC). | 403 // Otherwise it.Value applies in the pc range [it.PC, it.NextPC). |
397 func (it *PCIter) Init(p *Prog, buf []byte) { | 404 func (it *PCIter) Init(p *Prog, buf []byte) { |
398 it.p = buf | 405 it.p = buf |
(...skipping 16 matching lines...) Expand all Loading... |
415 } | 422 } |
416 if len(it.p) == 0 { | 423 if len(it.p) == 0 { |
417 it.Done = true | 424 it.Done = true |
418 return | 425 return |
419 } | 426 } |
420 | 427 |
421 // value delta | 428 // value delta |
422 uv, p, ok := decodeVarint(it.p) | 429 uv, p, ok := decodeVarint(it.p) |
423 if !ok { | 430 if !ok { |
424 it.Done = true | 431 it.Done = true |
425 » » it.Error = true | 432 » » it.Corrupt = true |
426 return | 433 return |
427 } | 434 } |
428 it.p = p | 435 it.p = p |
429 if uv == 0 && !it.start { | 436 if uv == 0 && !it.start { |
430 it.Done = true | 437 it.Done = true |
431 return | 438 return |
432 } | 439 } |
433 it.start = false | 440 it.start = false |
434 sv := int32(uv)>>1 ^ int32(uv)<<31>>31 | 441 sv := int32(uv)>>1 ^ int32(uv)<<31>>31 |
435 it.Value += sv | 442 it.Value += sv |
436 | 443 |
437 // pc delta | 444 // pc delta |
438 uv, it.p, ok = decodeVarint(it.p) | 445 uv, it.p, ok = decodeVarint(it.p) |
439 if !ok { | 446 if !ok { |
440 it.Done = true | 447 it.Done = true |
441 » » it.Error = true | 448 » » it.Corrupt = true |
442 return | 449 return |
443 } | 450 } |
444 it.NextPC = it.PC + uv*it.pcquantum | 451 it.NextPC = it.PC + uv*it.pcquantum |
445 } | 452 } |
446 | 453 |
447 // decodeVarint decodes an unsigned varint from p, | 454 // decodeVarint decodes an unsigned varint from p, |
448 // reporting the value, the remainder of the data, and | 455 // reporting the value, the remainder of the data, and |
449 // whether the decoding was successful. | 456 // whether the decoding was successful. |
450 func decodeVarint(p []byte) (v uint32, rest []byte, ok bool) { | 457 func decodeVarint(p []byte) (v uint32, rest []byte, ok bool) { |
451 for shift := uint(0); ; shift += 7 { | 458 for shift := uint(0); ; shift += 7 { |
(...skipping 12 matching lines...) Expand all Loading... |
464 | 471 |
465 // appendVarint appends an unsigned varint encoding of v to p | 472 // appendVarint appends an unsigned varint encoding of v to p |
466 // and returns the resulting slice. | 473 // and returns the resulting slice. |
467 func appendVarint(p []byte, v uint32) []byte { | 474 func appendVarint(p []byte, v uint32) []byte { |
468 for ; v >= 0x80; v >>= 7 { | 475 for ; v >= 0x80; v >>= 7 { |
469 p = append(p, byte(v)|0x80) | 476 p = append(p, byte(v)|0x80) |
470 } | 477 } |
471 p = append(p, byte(v)) | 478 p = append(p, byte(v)) |
472 return p | 479 return p |
473 } | 480 } |
LEFT | RIGHT |