funcinfo.go (6386B)
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 }