funcdata.go raw

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