diff options
Diffstat (limited to 'src/cmd/internal/goobj/funcinfo.go')
-rw-r--r-- | src/cmd/internal/goobj/funcinfo.go | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/cmd/internal/goobj/funcinfo.go b/src/cmd/internal/goobj/funcinfo.go new file mode 100644 index 0000000..2cca8f6 --- /dev/null +++ b/src/cmd/internal/goobj/funcinfo.go @@ -0,0 +1,239 @@ +// Copyright 2019 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. + +package goobj + +import ( + "bytes" + "cmd/internal/objabi" + "encoding/binary" +) + +// CUFileIndex is used to index the filenames that are stored in the +// per-package/per-CU FileList. +type CUFileIndex uint32 + +// FuncInfo is serialized as a symbol (aux symbol). The symbol data is +// the binary encoding of the struct below. +// +// TODO: make each pcdata a separate symbol? +type FuncInfo struct { + Args uint32 + Locals uint32 + FuncID objabi.FuncID + + Pcsp SymRef + Pcfile SymRef + Pcline SymRef + Pcinline SymRef + Pcdata []SymRef + Funcdataoff []uint32 + File []CUFileIndex + + InlTree []InlTreeNode +} + +func (a *FuncInfo) Write(w *bytes.Buffer) { + var b [4]byte + writeUint32 := func(x uint32) { + binary.LittleEndian.PutUint32(b[:], x) + w.Write(b[:]) + } + writeSymRef := func(s SymRef) { + writeUint32(s.PkgIdx) + writeUint32(s.SymIdx) + } + + writeUint32(a.Args) + writeUint32(a.Locals) + writeUint32(uint32(a.FuncID)) + + writeSymRef(a.Pcsp) + writeSymRef(a.Pcfile) + writeSymRef(a.Pcline) + writeSymRef(a.Pcinline) + writeUint32(uint32(len(a.Pcdata))) + for _, sym := range a.Pcdata { + writeSymRef(sym) + } + + writeUint32(uint32(len(a.Funcdataoff))) + for _, x := range a.Funcdataoff { + writeUint32(x) + } + writeUint32(uint32(len(a.File))) + for _, f := range a.File { + writeUint32(uint32(f)) + } + writeUint32(uint32(len(a.InlTree))) + for i := range a.InlTree { + a.InlTree[i].Write(w) + } +} + +func (a *FuncInfo) Read(b []byte) { + readUint32 := func() uint32 { + x := binary.LittleEndian.Uint32(b) + b = b[4:] + return x + } + readSymIdx := func() SymRef { + return SymRef{readUint32(), readUint32()} + } + + a.Args = readUint32() + a.Locals = readUint32() + a.FuncID = objabi.FuncID(readUint32()) + + a.Pcsp = readSymIdx() + a.Pcfile = readSymIdx() + a.Pcline = readSymIdx() + a.Pcinline = readSymIdx() + a.Pcdata = make([]SymRef, readUint32()) + for i := range a.Pcdata { + a.Pcdata[i] = readSymIdx() + } + + funcdataofflen := readUint32() + a.Funcdataoff = make([]uint32, funcdataofflen) + for i := range a.Funcdataoff { + a.Funcdataoff[i] = readUint32() + } + filelen := readUint32() + a.File = make([]CUFileIndex, filelen) + for i := range a.File { + a.File[i] = CUFileIndex(readUint32()) + } + inltreelen := readUint32() + a.InlTree = make([]InlTreeNode, inltreelen) + for i := range a.InlTree { + b = a.InlTree[i].Read(b) + } +} + +// FuncInfoLengths is a cache containing a roadmap of offsets and +// lengths for things within a serialized FuncInfo. Each length field +// stores the number of items (e.g. files, inltree nodes, etc), and the +// corresponding "off" field stores the byte offset of the start of +// the items in question. +type FuncInfoLengths struct { + NumPcdata uint32 + PcdataOff uint32 + NumFuncdataoff uint32 + FuncdataoffOff uint32 + NumFile uint32 + FileOff uint32 + NumInlTree uint32 + InlTreeOff uint32 + Initialized bool +} + +func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths { + var result FuncInfoLengths + + // Offset to the number of pcdata values. This value is determined by counting + // the number of bytes until we write pcdata to the file. + const numpcdataOff = 44 + result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:]) + result.PcdataOff = numpcdataOff + 4 + + numfuncdataoffOff := result.PcdataOff + 8*result.NumPcdata + result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:]) + result.FuncdataoffOff = numfuncdataoffOff + 4 + + numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff + result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:]) + result.FileOff = numfileOff + 4 + + numinltreeOff := result.FileOff + 4*result.NumFile + result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:]) + result.InlTreeOff = numinltreeOff + 4 + + result.Initialized = true + + return result +} + +func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) } + +func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) } + +func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) } + +func (*FuncInfo) ReadPcsp(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])} +} + +func (*FuncInfo) ReadPcfile(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])} +} + +func (*FuncInfo) ReadPcline(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[28:]), binary.LittleEndian.Uint32(b[32:])} +} + +func (*FuncInfo) ReadPcinline(b []byte) SymRef { + return SymRef{binary.LittleEndian.Uint32(b[36:]), binary.LittleEndian.Uint32(b[40:])} +} + +func (*FuncInfo) ReadPcdata(b []byte) []SymRef { + syms := make([]SymRef, binary.LittleEndian.Uint32(b[44:])) + for i := range syms { + syms[i] = SymRef{binary.LittleEndian.Uint32(b[48+i*8:]), binary.LittleEndian.Uint32(b[52+i*8:])} + } + return syms +} + +func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 { + return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:])) +} + +func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex { + return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:])) +} + +func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode { + const inlTreeNodeSize = 4 * 6 + var result InlTreeNode + result.Read(b[inltreeoff+k*inlTreeNodeSize:]) + return result +} + +// InlTreeNode is the serialized form of FileInfo.InlTree. +type InlTreeNode struct { + Parent int32 + File CUFileIndex + Line int32 + Func SymRef + ParentPC int32 +} + +func (inl *InlTreeNode) Write(w *bytes.Buffer) { + var b [4]byte + writeUint32 := func(x uint32) { + binary.LittleEndian.PutUint32(b[:], x) + w.Write(b[:]) + } + writeUint32(uint32(inl.Parent)) + writeUint32(uint32(inl.File)) + writeUint32(uint32(inl.Line)) + writeUint32(inl.Func.PkgIdx) + writeUint32(inl.Func.SymIdx) + writeUint32(uint32(inl.ParentPC)) +} + +// Read an InlTreeNode from b, return the remaining bytes. +func (inl *InlTreeNode) Read(b []byte) []byte { + readUint32 := func() uint32 { + x := binary.LittleEndian.Uint32(b) + b = b[4:] + return x + } + inl.Parent = int32(readUint32()) + inl.File = CUFileIndex(readUint32()) + inl.Line = int32(readUint32()) + inl.Func = SymRef{readUint32(), readUint32()} + inl.ParentPC = int32(readUint32()) + return b +} |