Black Lives Matter. Support the Equal Justice Initiative.

Source file src/cmd/internal/goobj/funcinfo.go

Documentation: cmd/internal/goobj

     1  // Copyright 2019 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package goobj
     6  
     7  import (
     8  	"bytes"
     9  	"cmd/internal/objabi"
    10  	"encoding/binary"
    11  )
    12  
    13  // CUFileIndex is used to index the filenames that are stored in the
    14  // per-package/per-CU FileList.
    15  type CUFileIndex uint32
    16  
    17  // FuncInfo is serialized as a symbol (aux symbol). The symbol data is
    18  // the binary encoding of the struct below.
    19  //
    20  // TODO: make each pcdata a separate symbol?
    21  type FuncInfo struct {
    22  	Args     uint32
    23  	Locals   uint32
    24  	FuncID   objabi.FuncID
    25  	FuncFlag objabi.FuncFlag
    26  
    27  	Pcsp        SymRef
    28  	Pcfile      SymRef
    29  	Pcline      SymRef
    30  	Pcinline    SymRef
    31  	Pcdata      []SymRef
    32  	Funcdataoff []uint32
    33  	File        []CUFileIndex
    34  
    35  	InlTree []InlTreeNode
    36  }
    37  
    38  func (a *FuncInfo) Write(w *bytes.Buffer) {
    39  	writeUint8 := func(x uint8) {
    40  		w.WriteByte(x)
    41  	}
    42  	var b [4]byte
    43  	writeUint32 := func(x uint32) {
    44  		binary.LittleEndian.PutUint32(b[:], x)
    45  		w.Write(b[:])
    46  	}
    47  	writeSymRef := func(s SymRef) {
    48  		writeUint32(s.PkgIdx)
    49  		writeUint32(s.SymIdx)
    50  	}
    51  
    52  	writeUint32(a.Args)
    53  	writeUint32(a.Locals)
    54  	writeUint8(uint8(a.FuncID))
    55  	writeUint8(uint8(a.FuncFlag))
    56  	writeUint8(0) // pad to uint32 boundary
    57  	writeUint8(0)
    58  	writeSymRef(a.Pcsp)
    59  	writeSymRef(a.Pcfile)
    60  	writeSymRef(a.Pcline)
    61  	writeSymRef(a.Pcinline)
    62  	writeUint32(uint32(len(a.Pcdata)))
    63  	for _, sym := range a.Pcdata {
    64  		writeSymRef(sym)
    65  	}
    66  
    67  	writeUint32(uint32(len(a.Funcdataoff)))
    68  	for _, x := range a.Funcdataoff {
    69  		writeUint32(x)
    70  	}
    71  	writeUint32(uint32(len(a.File)))
    72  	for _, f := range a.File {
    73  		writeUint32(uint32(f))
    74  	}
    75  	writeUint32(uint32(len(a.InlTree)))
    76  	for i := range a.InlTree {
    77  		a.InlTree[i].Write(w)
    78  	}
    79  }
    80  
    81  // FuncInfoLengths is a cache containing a roadmap of offsets and
    82  // lengths for things within a serialized FuncInfo. Each length field
    83  // stores the number of items (e.g. files, inltree nodes, etc), and the
    84  // corresponding "off" field stores the byte offset of the start of
    85  // the items in question.
    86  type FuncInfoLengths struct {
    87  	NumPcdata      uint32
    88  	PcdataOff      uint32
    89  	NumFuncdataoff uint32
    90  	FuncdataoffOff uint32
    91  	NumFile        uint32
    92  	FileOff        uint32
    93  	NumInlTree     uint32
    94  	InlTreeOff     uint32
    95  	Initialized    bool
    96  }
    97  
    98  func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
    99  	var result FuncInfoLengths
   100  
   101  	// Offset to the number of pcdata values. This value is determined by counting
   102  	// the number of bytes until we write pcdata to the file.
   103  	const numpcdataOff = 44
   104  	result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
   105  	result.PcdataOff = numpcdataOff + 4
   106  
   107  	numfuncdataoffOff := result.PcdataOff + 8*result.NumPcdata
   108  	result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
   109  	result.FuncdataoffOff = numfuncdataoffOff + 4
   110  
   111  	numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff
   112  	result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:])
   113  	result.FileOff = numfileOff + 4
   114  
   115  	numinltreeOff := result.FileOff + 4*result.NumFile
   116  	result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:])
   117  	result.InlTreeOff = numinltreeOff + 4
   118  
   119  	result.Initialized = true
   120  
   121  	return result
   122  }
   123  
   124  func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
   125  
   126  func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
   127  
   128  func (*FuncInfo) ReadFuncID(b []byte) objabi.FuncID { return objabi.FuncID(b[8]) }
   129  
   130  func (*FuncInfo) ReadFuncFlag(b []byte) objabi.FuncFlag { return objabi.FuncFlag(b[9]) }
   131  
   132  func (*FuncInfo) ReadPcsp(b []byte) SymRef {
   133  	return SymRef{binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])}
   134  }
   135  
   136  func (*FuncInfo) ReadPcfile(b []byte) SymRef {
   137  	return SymRef{binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])}
   138  }
   139  
   140  func (*FuncInfo) ReadPcline(b []byte) SymRef {
   141  	return SymRef{binary.LittleEndian.Uint32(b[28:]), binary.LittleEndian.Uint32(b[32:])}
   142  }
   143  
   144  func (*FuncInfo) ReadPcinline(b []byte) SymRef {
   145  	return SymRef{binary.LittleEndian.Uint32(b[36:]), binary.LittleEndian.Uint32(b[40:])}
   146  }
   147  
   148  func (*FuncInfo) ReadPcdata(b []byte) []SymRef {
   149  	syms := make([]SymRef, binary.LittleEndian.Uint32(b[44:]))
   150  	for i := range syms {
   151  		syms[i] = SymRef{binary.LittleEndian.Uint32(b[48+i*8:]), binary.LittleEndian.Uint32(b[52+i*8:])}
   152  	}
   153  	return syms
   154  }
   155  
   156  func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
   157  	return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
   158  }
   159  
   160  func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex {
   161  	return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:]))
   162  }
   163  
   164  func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode {
   165  	const inlTreeNodeSize = 4 * 6
   166  	var result InlTreeNode
   167  	result.Read(b[inltreeoff+k*inlTreeNodeSize:])
   168  	return result
   169  }
   170  
   171  // InlTreeNode is the serialized form of FileInfo.InlTree.
   172  type InlTreeNode struct {
   173  	Parent   int32
   174  	File     CUFileIndex
   175  	Line     int32
   176  	Func     SymRef
   177  	ParentPC int32
   178  }
   179  
   180  func (inl *InlTreeNode) Write(w *bytes.Buffer) {
   181  	var b [4]byte
   182  	writeUint32 := func(x uint32) {
   183  		binary.LittleEndian.PutUint32(b[:], x)
   184  		w.Write(b[:])
   185  	}
   186  	writeUint32(uint32(inl.Parent))
   187  	writeUint32(uint32(inl.File))
   188  	writeUint32(uint32(inl.Line))
   189  	writeUint32(inl.Func.PkgIdx)
   190  	writeUint32(inl.Func.SymIdx)
   191  	writeUint32(uint32(inl.ParentPC))
   192  }
   193  
   194  // Read an InlTreeNode from b, return the remaining bytes.
   195  func (inl *InlTreeNode) Read(b []byte) []byte {
   196  	readUint32 := func() uint32 {
   197  		x := binary.LittleEndian.Uint32(b)
   198  		b = b[4:]
   199  		return x
   200  	}
   201  	inl.Parent = int32(readUint32())
   202  	inl.File = CUFileIndex(readUint32())
   203  	inl.Line = int32(readUint32())
   204  	inl.Func = SymRef{readUint32(), readUint32()}
   205  	inl.ParentPC = int32(readUint32())
   206  	return b
   207  }
   208  

View as plain text