diff options
Diffstat (limited to 'src/cmd/newlink/pclntab.go')
-rw-r--r-- | src/cmd/newlink/pclntab.go | 480 |
1 files changed, 0 insertions, 480 deletions
diff --git a/src/cmd/newlink/pclntab.go b/src/cmd/newlink/pclntab.go deleted file mode 100644 index 0a4cfc9c46..0000000000 --- a/src/cmd/newlink/pclntab.go +++ /dev/null @@ -1,480 +0,0 @@ -// Copyright 2014 The Go Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// Generation of runtime function information (pclntab). - -package main - -import ( - "cmd/internal/goobj" - "cmd/internal/obj" - "encoding/binary" - "os" - "sort" -) - -var zerofunc goobj.Func - -// pclntab collects the runtime function data for each function that will -// be listed in the binary and builds a single table describing all functions. -// This table is used at run time for stack traces and to look up PC-specific -// information during garbage collection. The symbol created is named -// "pclntab" for historical reasons; the scope of the table has grown to -// include more than just PC/line number correspondences. -// The table format is documented at https://golang.org/s/go12symtab. -func (p *Prog) pclntab() { - // Count number of functions going into the binary, - // so that we can size the initial index correctly. - nfunc := 0 - for _, sym := range p.SymOrder { - if sym.Kind != goobj.STEXT { - continue - } - nfunc++ - } - - // Table header. - buf := new(SymBuffer) - buf.Init(p) - buf.SetSize(8 + p.ptrsize) - off := 0 - off = buf.Uint32(off, 0xfffffffb) - off = buf.Uint8(off, 0) - off = buf.Uint8(off, 0) - off = buf.Uint8(off, uint8(p.pcquantum)) - off = buf.Uint8(off, uint8(p.ptrsize)) - off = buf.Uint(off, uint64(nfunc), p.ptrsize) - indexOff := off - off += (nfunc*2 + 1) * p.ptrsize // function index, to be filled in - off += 4 // file table start offset, to be filled in - buf.SetSize(off) - - // One-file cache for reading PCData tables from package files. - // TODO(rsc): Better I/O strategy. - var ( - file *os.File - fname string - ) - - // Files gives the file numbering for source file names recorded - // in the binary. - files := make(map[string]int) - - // Build the table, build the index, and build the file name numbering. - // The loop here must visit functions in the same order that they will - // be stored in the binary, or else binary search over the index will fail. - // The runtime checks that the index is sorted properly at program start time. - var lastSym *Sym - for _, sym := range p.SymOrder { - if sym.Kind != goobj.STEXT { - continue - } - lastSym = sym - - // Treat no recorded function information same as all zeros. - f := sym.Func - if f == nil { - f = &zerofunc - } - - // Open package file if needed, for reading PC data. - if fname != sym.Package.File { - if file != nil { - file.Close() - } - var err error - file, err = os.Open(sym.Package.File) - if err != nil { - p.errorf("%v: %v", sym, err) - return - } - fname = sym.Package.File - } - - // off is the offset of the table entry where we're going to write - // the encoded form of Func. - // indexOff is the current position in the table index; - // we add an entry in the index pointing at off. - off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1) - indexOff = buf.Addr(indexOff, sym.SymID, 0) - indexOff = buf.Uint(indexOff, uint64(off), p.ptrsize) - - // The Func encoding starts with a header giving offsets - // to data blobs, and then the data blobs themselves. - // end gives the current write position for the data blobs. - end := off + p.ptrsize + 3*4 + 5*4 + len(f.PCData)*4 + len(f.FuncData)*p.ptrsize - if len(f.FuncData) > 0 { - end += -end & (p.ptrsize - 1) - } - buf.SetSize(end) - - // entry uintptr - // name int32 - // args int32 - // frame int32 - // - // The frame recorded in the object file is - // the frame size used in an assembly listing, which does - // not include the caller PC on the stack. - // The frame size we want to list here is the delta from - // this function's SP to its caller's SP, which does include - // the caller PC. Add p.ptrsize to f.Frame to adjust. - // TODO(rsc): Record the same frame size in the object file. - off = buf.Addr(off, sym.SymID, 0) - off = buf.Uint32(off, uint32(addString(buf, sym.Name))) - off = buf.Uint32(off, uint32(f.Args)) - off = buf.Uint32(off, uint32(f.Frame+p.ptrsize)) - - // pcdata - off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCSP))) - off = buf.Uint32(off, uint32(addPCFileTable(p, buf, file, f.PCFile, sym, files))) - off = buf.Uint32(off, uint32(addPCTable(p, buf, file, f.PCLine))) - off = buf.Uint32(off, uint32(len(f.PCData))) - off = buf.Uint32(off, uint32(len(f.FuncData))) - for _, pcdata := range f.PCData { - off = buf.Uint32(off, uint32(addPCTable(p, buf, file, pcdata))) - } - - // funcdata - if len(f.FuncData) > 0 { - off += -off & (p.ptrsize - 1) // must be pointer-aligned - for _, funcdata := range f.FuncData { - if funcdata.Sym.Name == "" { - off = buf.Uint(off, uint64(funcdata.Offset), p.ptrsize) - } else { - off = buf.Addr(off, funcdata.Sym, funcdata.Offset) - } - } - } - - if off != end { - p.errorf("internal error: invalid math in pclntab: off=%#x end=%#x", off, end) - break - } - } - if file != nil { - file.Close() - } - - // Final entry of index is end PC of last function. - indexOff = buf.Addr(indexOff, lastSym.SymID, int64(lastSym.Size)) - - // Start file table. - // Function index is immediately followed by offset to file table. - off = (buf.Size() + p.ptrsize - 1) &^ (p.ptrsize - 1) - buf.Uint32(indexOff, uint32(off)) - - // File table is an array of uint32s. - // The first entry gives 1+n, the size of the array. - // The following n entries hold offsets to string data. - // File number n uses the string pointed at by entry n. - // File number 0 is invalid. - buf.SetSize(off + (1+len(files))*4) - buf.Uint32(off, uint32(1+len(files))) - var filestr []string - for file := range files { - filestr = append(filestr, file) - } - sort.Strings(filestr) - for _, file := range filestr { - id := files[file] - buf.Uint32(off+4*id, uint32(addString(buf, file))) - } - - pclntab := &Sym{ - Sym: &goobj.Sym{ - SymID: goobj.SymID{Name: "runtime.pclntab"}, - Kind: goobj.SPCLNTAB, - Size: buf.Size(), - Reloc: buf.Reloc(), - }, - Bytes: buf.Bytes(), - } - p.addSym(pclntab) -} - -// addString appends the string s to the buffer b. -// It returns the offset of the beginning of the string in the buffer. -func addString(b *SymBuffer, s string) int { - off := b.Size() - b.SetSize(off + len(s) + 1) - copy(b.data[off:], s) - return off -} - -// addPCTable appends the PC-data table stored in the file f at the location loc -// to the symbol buffer b. It returns the offset of the beginning of the table -// in the buffer. -func addPCTable(p *Prog, b *SymBuffer, f *os.File, loc goobj.Data) int { - if loc.Size == 0 { - return 0 - } - off := b.Size() - b.SetSize(off + int(loc.Size)) - _, err := f.ReadAt(b.data[off:off+int(loc.Size)], loc.Offset) - if err != nil { - p.errorf("%v", err) - } - return off -} - -// addPCFileTable is like addPCTable, but it renumbers the file names referred to by the table -// to use the global numbering maintained in the files map. It adds new files to the -// map as necessary. -func addPCFileTable(p *Prog, b *SymBuffer, f *os.File, loc goobj.Data, sym *Sym, files map[string]int) int { - if loc.Size == 0 { - return 0 - } - off := b.Size() - - src := make([]byte, loc.Size) - _, err := f.ReadAt(src, loc.Offset) - if err != nil { - p.errorf("%v", err) - return 0 - } - - filenum := make([]int, len(sym.Func.File)) - for i, name := range sym.Func.File { - num := files[name] - if num == 0 { - num = len(files) + 1 - files[name] = num - } - filenum[i] = num - } - - var dst []byte - newval := int32(-1) - var it PCIter - for it.Init(p, src); !it.Done; it.Next() { - // value delta - oldval := it.Value - val := oldval - if oldval != -1 { - if oldval < 0 || int(oldval) >= len(filenum) { - p.errorf("%s: corrupt pc-file table", sym) - break - } - val = int32(filenum[oldval]) - } - dv := val - newval - newval = val - uv := uint32(dv<<1) ^ uint32(dv>>31) - dst = appendVarint(dst, uv) - - // pc delta - dst = appendVarint(dst, it.NextPC-it.PC) - } - if it.Corrupt { - p.errorf("%s: corrupt pc-file table", sym) - } - - // terminating value delta - dst = appendVarint(dst, 0) - - b.SetSize(off + len(dst)) - copy(b.data[off:], dst) - return off -} - -// A SymBuffer is a buffer for preparing the data image of a -// linker-generated symbol. -type SymBuffer struct { - data []byte - reloc []goobj.Reloc - order binary.ByteOrder - ptrsize int -} - -// Init initializes the buffer for writing. -func (b *SymBuffer) Init(p *Prog) { - b.data = nil - b.reloc = nil - b.order = p.byteorder - b.ptrsize = p.ptrsize -} - -// Bytes returns the buffer data. -func (b *SymBuffer) Bytes() []byte { - return b.data -} - -// SetSize sets the buffer's data size to n bytes. -func (b *SymBuffer) SetSize(n int) { - for cap(b.data) < n { - b.data = append(b.data[:cap(b.data)], 0) - } - b.data = b.data[:n] -} - -// Size returns the buffer's data size. -func (b *SymBuffer) Size() int { - return len(b.data) -} - -// Reloc returns the buffered relocations. -func (b *SymBuffer) Reloc() []goobj.Reloc { - return b.reloc -} - -// Uint8 sets the uint8 at offset off to v. -// It returns the offset just beyond v. -func (b *SymBuffer) Uint8(off int, v uint8) int { - b.data[off] = v - return off + 1 -} - -// Uint16 sets the uint16 at offset off to v. -// It returns the offset just beyond v. -func (b *SymBuffer) Uint16(off int, v uint16) int { - b.order.PutUint16(b.data[off:], v) - return off + 2 -} - -// Uint32 sets the uint32 at offset off to v. -// It returns the offset just beyond v. -func (b *SymBuffer) Uint32(off int, v uint32) int { - b.order.PutUint32(b.data[off:], v) - return off + 4 -} - -// Uint64 sets the uint64 at offset off to v. -// It returns the offset just beyond v. -func (b *SymBuffer) Uint64(off int, v uint64) int { - b.order.PutUint64(b.data[off:], v) - return off + 8 -} - -// Uint sets the size-byte unsigned integer at offset off to v. -// It returns the offset just beyond v. -func (b *SymBuffer) Uint(off int, v uint64, size int) int { - switch size { - case 1: - return b.Uint8(off, uint8(v)) - case 2: - return b.Uint16(off, uint16(v)) - case 4: - return b.Uint32(off, uint32(v)) - case 8: - return b.Uint64(off, v) - } - panic("invalid use of SymBuffer.SetUint") -} - -// Addr sets the pointer-sized address at offset off to refer -// to symoff bytes past the start of sym. It returns the offset -// just beyond the address. -func (b *SymBuffer) Addr(off int, sym goobj.SymID, symoff int64) int { - b.reloc = append(b.reloc, goobj.Reloc{ - Offset: off, - Size: b.ptrsize, - Sym: sym, - Add: int(symoff), - Type: obj.R_ADDR, - }) - return off + b.ptrsize -} - -// A PCIter implements iteration over PC-data tables. -// -// var it PCIter -// for it.Init(p, data); !it.Done; it.Next() { -// it.Value holds from it.PC up to (but not including) it.NextPC -// } -// if it.Corrupt { -// data was malformed -// } -// -type PCIter struct { - PC uint32 - NextPC uint32 - Value int32 - Done bool - Corrupt bool - p []byte - start bool - pcquantum uint32 -} - -// Init initializes the iteration. -// On return, if it.Done is true, the iteration is over. -// Otherwise it.Value applies in the pc range [it.PC, it.NextPC). -func (it *PCIter) Init(p *Prog, buf []byte) { - it.p = buf - it.PC = 0 - it.NextPC = 0 - it.Value = -1 - it.start = true - it.pcquantum = uint32(p.pcquantum) - it.Done = false - it.Next() -} - -// Next steps forward one entry in the table. -// On return, if it.Done is true, the iteration is over. -// Otherwise it.Value applies in the pc range [it.PC, it.NextPC). -func (it *PCIter) Next() { - it.PC = it.NextPC - if it.Done { - return - } - if len(it.p) == 0 { - it.Done = true - return - } - - // value delta - uv, p, ok := decodeVarint(it.p) - if !ok { - it.Done = true - it.Corrupt = true - return - } - it.p = p - if uv == 0 && !it.start { - it.Done = true - return - } - it.start = false - sv := int32(uv>>1) ^ int32(uv<<31)>>31 - it.Value += sv - - // pc delta - uv, it.p, ok = decodeVarint(it.p) - if !ok { - it.Done = true - it.Corrupt = true - return - } - it.NextPC = it.PC + uv*it.pcquantum -} - -// decodeVarint decodes an unsigned varint from p, -// reporting the value, the remainder of the data, and -// whether the decoding was successful. -func decodeVarint(p []byte) (v uint32, rest []byte, ok bool) { - for shift := uint(0); ; shift += 7 { - if len(p) == 0 { - return - } - c := uint32(p[0]) - p = p[1:] - v |= (c & 0x7F) << shift - if c&0x80 == 0 { - break - } - } - return v, p, true -} - -// appendVarint appends an unsigned varint encoding of v to p -// and returns the resulting slice. -func appendVarint(p []byte, v uint32) []byte { - for ; v >= 0x80; v >>= 7 { - p = append(p, byte(v)|0x80) - } - p = append(p, byte(v)) - return p -} |