summaryrefslogtreecommitdiffstats
path: root/src/cmd/internal/goobj/funcinfo.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal/goobj/funcinfo.go')
-rw-r--r--src/cmd/internal/goobj/funcinfo.go239
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
+}