funcinfo.go raw

   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  	"github.com/twitchyliquid64/golang-asm/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  
  26  	Pcsp        uint32
  27  	Pcfile      uint32
  28  	Pcline      uint32
  29  	Pcinline    uint32
  30  	Pcdata      []uint32
  31  	PcdataEnd   uint32
  32  	Funcdataoff []uint32
  33  	File        []CUFileIndex
  34  
  35  	InlTree []InlTreeNode
  36  }
  37  
  38  func (a *FuncInfo) Write(w *bytes.Buffer) {
  39  	var b [4]byte
  40  	writeUint32 := func(x uint32) {
  41  		binary.LittleEndian.PutUint32(b[:], x)
  42  		w.Write(b[:])
  43  	}
  44  
  45  	writeUint32(a.Args)
  46  	writeUint32(a.Locals)
  47  	writeUint32(uint32(a.FuncID))
  48  
  49  	writeUint32(a.Pcsp)
  50  	writeUint32(a.Pcfile)
  51  	writeUint32(a.Pcline)
  52  	writeUint32(a.Pcinline)
  53  	writeUint32(uint32(len(a.Pcdata)))
  54  	for _, x := range a.Pcdata {
  55  		writeUint32(x)
  56  	}
  57  	writeUint32(a.PcdataEnd)
  58  	writeUint32(uint32(len(a.Funcdataoff)))
  59  	for _, x := range a.Funcdataoff {
  60  		writeUint32(x)
  61  	}
  62  	writeUint32(uint32(len(a.File)))
  63  	for _, f := range a.File {
  64  		writeUint32(uint32(f))
  65  	}
  66  	writeUint32(uint32(len(a.InlTree)))
  67  	for i := range a.InlTree {
  68  		a.InlTree[i].Write(w)
  69  	}
  70  }
  71  
  72  func (a *FuncInfo) Read(b []byte) {
  73  	readUint32 := func() uint32 {
  74  		x := binary.LittleEndian.Uint32(b)
  75  		b = b[4:]
  76  		return x
  77  	}
  78  
  79  	a.Args = readUint32()
  80  	a.Locals = readUint32()
  81  	a.FuncID = objabi.FuncID(readUint32())
  82  
  83  	a.Pcsp = readUint32()
  84  	a.Pcfile = readUint32()
  85  	a.Pcline = readUint32()
  86  	a.Pcinline = readUint32()
  87  	pcdatalen := readUint32()
  88  	a.Pcdata = make([]uint32, pcdatalen)
  89  	for i := range a.Pcdata {
  90  		a.Pcdata[i] = readUint32()
  91  	}
  92  	a.PcdataEnd = readUint32()
  93  	funcdataofflen := readUint32()
  94  	a.Funcdataoff = make([]uint32, funcdataofflen)
  95  	for i := range a.Funcdataoff {
  96  		a.Funcdataoff[i] = readUint32()
  97  	}
  98  	filelen := readUint32()
  99  	a.File = make([]CUFileIndex, filelen)
 100  	for i := range a.File {
 101  		a.File[i] = CUFileIndex(readUint32())
 102  	}
 103  	inltreelen := readUint32()
 104  	a.InlTree = make([]InlTreeNode, inltreelen)
 105  	for i := range a.InlTree {
 106  		b = a.InlTree[i].Read(b)
 107  	}
 108  }
 109  
 110  // FuncInfoLengths is a cache containing a roadmap of offsets and
 111  // lengths for things within a serialized FuncInfo. Each length field
 112  // stores the number of items (e.g. files, inltree nodes, etc), and the
 113  // corresponding "off" field stores the byte offset of the start of
 114  // the items in question.
 115  type FuncInfoLengths struct {
 116  	NumPcdata      uint32
 117  	PcdataOff      uint32
 118  	NumFuncdataoff uint32
 119  	FuncdataoffOff uint32
 120  	NumFile        uint32
 121  	FileOff        uint32
 122  	NumInlTree     uint32
 123  	InlTreeOff     uint32
 124  	Initialized    bool
 125  }
 126  
 127  func (*FuncInfo) ReadFuncInfoLengths(b []byte) FuncInfoLengths {
 128  	var result FuncInfoLengths
 129  
 130  	const numpcdataOff = 28
 131  	result.NumPcdata = binary.LittleEndian.Uint32(b[numpcdataOff:])
 132  	result.PcdataOff = numpcdataOff + 4
 133  
 134  	numfuncdataoffOff := result.PcdataOff + 4*(result.NumPcdata+1)
 135  	result.NumFuncdataoff = binary.LittleEndian.Uint32(b[numfuncdataoffOff:])
 136  	result.FuncdataoffOff = numfuncdataoffOff + 4
 137  
 138  	numfileOff := result.FuncdataoffOff + 4*result.NumFuncdataoff
 139  	result.NumFile = binary.LittleEndian.Uint32(b[numfileOff:])
 140  	result.FileOff = numfileOff + 4
 141  
 142  	numinltreeOff := result.FileOff + 4*result.NumFile
 143  	result.NumInlTree = binary.LittleEndian.Uint32(b[numinltreeOff:])
 144  	result.InlTreeOff = numinltreeOff + 4
 145  
 146  	result.Initialized = true
 147  
 148  	return result
 149  }
 150  
 151  func (*FuncInfo) ReadArgs(b []byte) uint32 { return binary.LittleEndian.Uint32(b) }
 152  
 153  func (*FuncInfo) ReadLocals(b []byte) uint32 { return binary.LittleEndian.Uint32(b[4:]) }
 154  
 155  func (*FuncInfo) ReadFuncID(b []byte) uint32 { return binary.LittleEndian.Uint32(b[8:]) }
 156  
 157  // return start and end offsets.
 158  func (*FuncInfo) ReadPcsp(b []byte) (uint32, uint32) {
 159  	return binary.LittleEndian.Uint32(b[12:]), binary.LittleEndian.Uint32(b[16:])
 160  }
 161  
 162  // return start and end offsets.
 163  func (*FuncInfo) ReadPcfile(b []byte) (uint32, uint32) {
 164  	return binary.LittleEndian.Uint32(b[16:]), binary.LittleEndian.Uint32(b[20:])
 165  }
 166  
 167  // return start and end offsets.
 168  func (*FuncInfo) ReadPcline(b []byte) (uint32, uint32) {
 169  	return binary.LittleEndian.Uint32(b[20:]), binary.LittleEndian.Uint32(b[24:])
 170  }
 171  
 172  // return start and end offsets.
 173  func (*FuncInfo) ReadPcinline(b []byte, pcdataoffset uint32) (uint32, uint32) {
 174  	return binary.LittleEndian.Uint32(b[24:]), binary.LittleEndian.Uint32(b[pcdataoffset:])
 175  }
 176  
 177  // return start and end offsets.
 178  func (*FuncInfo) ReadPcdata(b []byte, pcdataoffset uint32, k uint32) (uint32, uint32) {
 179  	return binary.LittleEndian.Uint32(b[pcdataoffset+4*k:]), binary.LittleEndian.Uint32(b[pcdataoffset+4+4*k:])
 180  }
 181  
 182  func (*FuncInfo) ReadFuncdataoff(b []byte, funcdataofffoff uint32, k uint32) int64 {
 183  	return int64(binary.LittleEndian.Uint32(b[funcdataofffoff+4*k:]))
 184  }
 185  
 186  func (*FuncInfo) ReadFile(b []byte, filesoff uint32, k uint32) CUFileIndex {
 187  	return CUFileIndex(binary.LittleEndian.Uint32(b[filesoff+4*k:]))
 188  }
 189  
 190  func (*FuncInfo) ReadInlTree(b []byte, inltreeoff uint32, k uint32) InlTreeNode {
 191  	const inlTreeNodeSize = 4 * 6
 192  	var result InlTreeNode
 193  	result.Read(b[inltreeoff+k*inlTreeNodeSize:])
 194  	return result
 195  }
 196  
 197  // InlTreeNode is the serialized form of FileInfo.InlTree.
 198  type InlTreeNode struct {
 199  	Parent   int32
 200  	File     CUFileIndex
 201  	Line     int32
 202  	Func     SymRef
 203  	ParentPC int32
 204  }
 205  
 206  func (inl *InlTreeNode) Write(w *bytes.Buffer) {
 207  	var b [4]byte
 208  	writeUint32 := func(x uint32) {
 209  		binary.LittleEndian.PutUint32(b[:], x)
 210  		w.Write(b[:])
 211  	}
 212  	writeUint32(uint32(inl.Parent))
 213  	writeUint32(uint32(inl.File))
 214  	writeUint32(uint32(inl.Line))
 215  	writeUint32(inl.Func.PkgIdx)
 216  	writeUint32(inl.Func.SymIdx)
 217  	writeUint32(uint32(inl.ParentPC))
 218  }
 219  
 220  // Read an InlTreeNode from b, return the remaining bytes.
 221  func (inl *InlTreeNode) Read(b []byte) []byte {
 222  	readUint32 := func() uint32 {
 223  		x := binary.LittleEndian.Uint32(b)
 224  		b = b[4:]
 225  		return x
 226  	}
 227  	inl.Parent = int32(readUint32())
 228  	inl.File = CUFileIndex(readUint32())
 229  	inl.Line = int32(readUint32())
 230  	inl.Func = SymRef{readUint32(), readUint32()}
 231  	inl.ParentPC = int32(readUint32())
 232  	return b
 233  }
 234