funcdata.go 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. /**
  2. * Copyright 2023 ByteDance Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package loader
  17. import (
  18. `encoding`
  19. `encoding/binary`
  20. `fmt`
  21. `reflect`
  22. `strings`
  23. `sync`
  24. `unsafe`
  25. )
  26. const (
  27. _MinLC uint8 = 1
  28. _PtrSize uint8 = 8
  29. )
  30. const (
  31. _N_FUNCDATA = 8
  32. _INVALID_FUNCDATA_OFFSET = ^uint32(0)
  33. _FUNC_SIZE = unsafe.Sizeof(_func{})
  34. _MINFUNC = 16 // minimum size for a function
  35. _BUCKETSIZE = 256 * _MINFUNC
  36. _SUBBUCKETS = 16
  37. _SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS
  38. )
  39. // Note: This list must match the list in runtime/symtab.go.
  40. const (
  41. FuncFlag_TOPFRAME = 1 << iota
  42. FuncFlag_SPWRITE
  43. FuncFlag_ASM
  44. )
  45. // PCDATA and FUNCDATA table indexes.
  46. //
  47. // See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
  48. const (
  49. _FUNCDATA_ArgsPointerMaps = 0
  50. _FUNCDATA_LocalsPointerMaps = 1
  51. _FUNCDATA_StackObjects = 2
  52. _FUNCDATA_InlTree = 3
  53. _FUNCDATA_OpenCodedDeferInfo = 4
  54. _FUNCDATA_ArgInfo = 5
  55. _FUNCDATA_ArgLiveInfo = 6
  56. _FUNCDATA_WrapInfo = 7
  57. // ArgsSizeUnknown is set in Func.argsize to mark all functions
  58. // whose argument size is unknown (C vararg functions, and
  59. // assembly code without an explicit specification).
  60. // This value is generated by the compiler, assembler, or linker.
  61. ArgsSizeUnknown = -0x80000000
  62. )
  63. // moduledata used to cache the funcdata and findfuncbucket of one module
  64. var moduleCache = struct {
  65. m map[*moduledata][]byte
  66. sync.Mutex
  67. }{
  68. m: make(map[*moduledata][]byte),
  69. }
  70. // Func contains information about a function.
  71. type Func struct {
  72. ID uint8 // see runtime/symtab.go
  73. Flag uint8 // see runtime/symtab.go
  74. ArgsSize int32 // args byte size
  75. EntryOff uint32 // start pc, offset to moduledata.text
  76. TextSize uint32 // size of func text
  77. DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
  78. FileIndex uint32 // index into filetab
  79. Name string // name of function
  80. // PC data
  81. Pcsp *Pcdata // PC -> SP delta
  82. Pcfile *Pcdata // PC -> file index
  83. Pcline *Pcdata // PC -> line number
  84. PcUnsafePoint *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe
  85. PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps
  86. PcInlTreeIndex *Pcdata // PC -> inlining tree index, relative to InlTree
  87. PcArgLiveIndex *Pcdata // PC -> arg live index, relative to ArgLiveInfo
  88. // Func data, must implement encoding.BinaryMarshaler
  89. ArgsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap
  90. LocalsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap
  91. StackObjects encoding.BinaryMarshaler
  92. InlTree encoding.BinaryMarshaler
  93. OpenCodedDeferInfo encoding.BinaryMarshaler
  94. ArgInfo encoding.BinaryMarshaler
  95. ArgLiveInfo encoding.BinaryMarshaler
  96. WrapInfo encoding.BinaryMarshaler
  97. }
  98. func getOffsetOf(data interface{}, field string) uintptr {
  99. t := reflect.TypeOf(data)
  100. fv, ok := t.FieldByName(field)
  101. if !ok {
  102. panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name()))
  103. }
  104. return fv.Offset
  105. }
  106. func rnd(v int64, r int64) int64 {
  107. if r <= 0 {
  108. return v
  109. }
  110. v += r - 1
  111. c := v % r
  112. if c < 0 {
  113. c += r
  114. }
  115. v -= c
  116. return v
  117. }
  118. var (
  119. byteOrder binary.ByteOrder = binary.LittleEndian
  120. )
  121. func funcNameParts(name string) (string, string, string) {
  122. i := strings.IndexByte(name, '[')
  123. if i < 0 {
  124. return name, "", ""
  125. }
  126. // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.
  127. j := len(name) - 1
  128. for j > i && name[j] != ']' {
  129. j--
  130. }
  131. if j <= i {
  132. return name, "", ""
  133. }
  134. return name[:i], "[...]", name[j+1:]
  135. }
  136. // func name table format:
  137. // nameOff[0] -> namePartA namePartB namePartC \x00
  138. // nameOff[1] -> namePartA namePartB namePartC \x00
  139. // ...
  140. func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
  141. offs = make([]int32, len(funcs))
  142. offset := 1
  143. tab = []byte{0}
  144. for i, f := range funcs {
  145. offs[i] = int32(offset)
  146. a, b, c := funcNameParts(f.Name)
  147. tab = append(tab, a...)
  148. tab = append(tab, b...)
  149. tab = append(tab, c...)
  150. tab = append(tab, 0)
  151. offset += len(a) + len(b) + len(c) + 1
  152. }
  153. return
  154. }
  155. // CU table format:
  156. // cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
  157. // cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
  158. // ...
  159. //
  160. // file name table format:
  161. // filetabOffset[0] -> CUs[0].fileNames[0] \x00
  162. // ...
  163. // filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
  164. // ...
  165. // filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
  166. func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
  167. cuOffsets = make([]uint32, len(cus))
  168. cuOffset := 0
  169. fileOffset := 0
  170. for i, cu := range cus {
  171. cuOffsets[i] = uint32(cuOffset)
  172. for _, name := range cu.fileNames {
  173. cutab = append(cutab, uint32(fileOffset))
  174. fileOffset += len(name) + 1
  175. filetab = append(filetab, name...)
  176. filetab = append(filetab, 0)
  177. }
  178. cuOffset += len(cu.fileNames)
  179. }
  180. return
  181. }
  182. func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
  183. fstart = len(*out)
  184. *out = append(*out, byte(0))
  185. offs := uint32(1)
  186. funcdataOffs = make([][]uint32, len(funcs))
  187. for i, f := range funcs {
  188. var writer = func(fd encoding.BinaryMarshaler) {
  189. var ab []byte
  190. var err error
  191. if fd != nil {
  192. ab, err = fd.MarshalBinary()
  193. if err != nil {
  194. panic(err)
  195. }
  196. funcdataOffs[i] = append(funcdataOffs[i], offs)
  197. } else {
  198. ab = []byte{0}
  199. funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
  200. }
  201. *out = append(*out, ab...)
  202. offs += uint32(len(ab))
  203. }
  204. writer(f.ArgsPointerMaps)
  205. writer(f.LocalsPointerMaps)
  206. writer(f.StackObjects)
  207. writer(f.InlTree)
  208. writer(f.OpenCodedDeferInfo)
  209. writer(f.ArgInfo)
  210. writer(f.ArgLiveInfo)
  211. writer(f.WrapInfo)
  212. }
  213. return
  214. }