funcinfo.go 6.2 KB

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