gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

funcdata_go120.go (17902B)


      1 //go:build go1.20 && !go1.21
      2 // +build go1.20,!go1.21
      3 
      4 /*
      5  * Copyright 2021 ByteDance Inc.
      6  *
      7  * Licensed under the Apache License, Version 2.0 (the "License");
      8  * you may not use this file except in compliance with the License.
      9  * You may obtain a copy of the License at
     10  *
     11  *     http://www.apache.org/licenses/LICENSE-2.0
     12  *
     13  * Unless required by applicable law or agreed to in writing, software
     14  * distributed under the License is distributed on an "AS IS" BASIS,
     15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16  * See the License for the specific language governing permissions and
     17  * limitations under the License.
     18  */
     19 
     20 package loader
     21 
     22 import (
     23     `encoding`
     24     `os`
     25     `unsafe`
     26 
     27     `github.com/bytedance/sonic/internal/rt`
     28 )
     29 
     30 const (
     31     _Magic uint32 = 0xFFFFFFF1
     32 )
     33 
     34 type moduledata struct {
     35     pcHeader     *pcHeader
     36     funcnametab  []byte
     37     cutab        []uint32
     38     filetab      []byte
     39     pctab        []byte
     40     pclntable    []byte
     41     ftab         []funcTab
     42     findfunctab  uintptr
     43     minpc, maxpc uintptr // first func address, last func address + last func size
     44 
     45     text, etext           uintptr // start/end of text, (etext-text) must be greater than MIN_FUNC
     46     noptrdata, enoptrdata uintptr
     47     data, edata           uintptr
     48     bss, ebss             uintptr
     49     noptrbss, enoptrbss   uintptr
     50     covctrs, ecovctrs     uintptr
     51     end, gcdata, gcbss    uintptr
     52     types, etypes         uintptr
     53     rodata                uintptr
     54 
     55     // TODO: generate funcinfo object to memory
     56     gofunc                uintptr // go.func.* is actual funcinfo object in image
     57 
     58     textsectmap []textSection // see runtime/symtab.go: textAddr()
     59     typelinks   []int32 // offsets from types
     60     itablinks   []*rt.GoItab
     61 
     62     ptab []ptabEntry
     63 
     64     pluginpath string
     65     pkghashes  []modulehash
     66 
     67     modulename   string
     68     modulehashes []modulehash
     69 
     70     hasmain uint8 // 1 if module contains the main function, 0 otherwise
     71 
     72     gcdatamask, gcbssmask bitVector
     73 
     74     typemap map[int32]*rt.GoType // offset to *_rtype in previous module
     75 
     76     bad bool // module failed to load and should be ignored
     77 
     78     next *moduledata
     79 }
     80 
     81 type _func struct {
     82     entryOff uint32 // start pc, as offset from moduledata.text/pcHeader.textStart
     83     nameOff  int32  // function name, as index into moduledata.funcnametab.
     84 
     85     args        int32  // in/out args size
     86     deferreturn uint32 // offset of start of a deferreturn call instruction from entry, if any.
     87 
     88     pcsp      uint32 
     89     pcfile    uint32
     90     pcln      uint32
     91     npcdata   uint32
     92     cuOffset  uint32 // runtime.cutab offset of this function's CU
     93     startLine int32  // line number of start of function (func keyword/TEXT directive)
     94     funcID    uint8 // set for certain special runtime functions
     95     flag      uint8
     96     _         [1]byte // pad
     97     nfuncdata uint8   // 
     98     
     99     // The end of the struct is followed immediately by two variable-length
    100     // arrays that reference the pcdata and funcdata locations for this
    101     // function.
    102 
    103     // pcdata contains the offset into moduledata.pctab for the start of
    104     // that index's table. e.g.,
    105     // &moduledata.pctab[_func.pcdata[_PCDATA_UnsafePoint]] is the start of
    106     // the unsafe point table.
    107     //
    108     // An offset of 0 indicates that there is no table.
    109     //
    110     // pcdata [npcdata]uint32
    111 
    112     // funcdata contains the offset past moduledata.gofunc which contains a
    113     // pointer to that index's funcdata. e.g.,
    114     // *(moduledata.gofunc +  _func.funcdata[_FUNCDATA_ArgsPointerMaps]) is
    115     // the argument pointer map.
    116     //
    117     // An offset of ^uint32(0) indicates that there is no entry.
    118     //
    119     // funcdata [nfuncdata]uint32
    120 }
    121 
    122 type funcTab struct {
    123     entry   uint32
    124     funcoff uint32
    125 }
    126 
    127 type pcHeader struct {
    128     magic          uint32  // 0xFFFFFFF0
    129     pad1, pad2     uint8   // 0,0
    130     minLC          uint8   // min instruction size
    131     ptrSize        uint8   // size of a ptr in bytes
    132     nfunc          int     // number of functions in the module
    133     nfiles         uint    // number of entries in the file tab
    134     textStart      uintptr // base for function entry PC offsets in this module, equal to moduledata.text
    135     funcnameOffset uintptr // offset to the funcnametab variable from pcHeader
    136     cuOffset       uintptr // offset to the cutab variable from pcHeader
    137     filetabOffset  uintptr // offset to the filetab variable from pcHeader
    138     pctabOffset    uintptr // offset to the pctab variable from pcHeader
    139     pclnOffset     uintptr // offset to the pclntab variable from pcHeader
    140 }
    141 
    142 type bitVector struct {
    143     n        int32 // # of bits
    144     bytedata *uint8
    145 }
    146 
    147 type ptabEntry struct {
    148     name int32
    149     typ  int32
    150 }
    151 
    152 type textSection struct {
    153     vaddr    uintptr // prelinked section vaddr
    154     end      uintptr // vaddr + section length
    155     baseaddr uintptr // relocated section address
    156 }
    157 
    158 type modulehash struct {
    159     modulename   string
    160     linktimehash string
    161     runtimehash  *string
    162 }
    163 
    164 // findfuncbucket is an array of these structures.
    165 // Each bucket represents 4096 bytes of the text segment.
    166 // Each subbucket represents 256 bytes of the text segment.
    167 // To find a function given a pc, locate the bucket and subbucket for
    168 // that pc. Add together the idx and subbucket value to obtain a
    169 // function index. Then scan the functab array starting at that
    170 // index to find the target function.
    171 // This table uses 20 bytes for every 4096 bytes of code, or ~0.5% overhead.
    172 type findfuncbucket struct {
    173     idx        uint32
    174     _SUBBUCKETS [16]byte
    175 }
    176 
    177 // func name table format: 
    178 //   nameOff[0] -> namePartA namePartB namePartC \x00 
    179 //   nameOff[1] -> namePartA namePartB namePartC \x00
    180 //  ...
    181 func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {
    182     offs = make([]int32, len(funcs))
    183     offset := 0
    184 
    185     for i, f := range funcs {
    186         offs[i] = int32(offset)
    187 
    188         a, b, c := funcNameParts(f.Name)
    189         tab = append(tab, a...)
    190         tab = append(tab, b...)
    191         tab = append(tab, c...)
    192         tab = append(tab, 0)
    193         offset += len(a) + len(b) + len(c) + 1
    194     }
    195 
    196     return
    197 }
    198 
    199 type compilationUnit struct {
    200     fileNames []string
    201 }
    202 
    203 // CU table format:
    204 //  cuOffsets[0] -> filetabOffset[0] filetabOffset[1] ... filetabOffset[len(CUs[0].fileNames)-1]
    205 //  cuOffsets[1] -> filetabOffset[len(CUs[0].fileNames)] ... filetabOffset[len(CUs[0].fileNames) + len(CUs[1].fileNames)-1]
    206 //  ...
    207 //
    208 // file name table format:
    209 //  filetabOffset[0] -> CUs[0].fileNames[0] \x00
    210 //  ...
    211 //  filetabOffset[len(CUs[0]-1)] -> CUs[0].fileNames[len(CUs[0].fileNames)-1] \x00
    212 //  ...
    213 //  filetabOffset[SUM(CUs,fileNames)-1] -> CUs[len(CU)-1].fileNames[len(CUs[len(CU)-1].fileNames)-1] \x00
    214 func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {
    215     cuOffsets = make([]uint32, len(cus))
    216     cuOffset := 0
    217     fileOffset := 0
    218 
    219     for i, cu := range cus {
    220         cuOffsets[i] = uint32(cuOffset)
    221 
    222         for _, name := range cu.fileNames {
    223             cutab = append(cutab, uint32(fileOffset))
    224 
    225             fileOffset += len(name) + 1
    226             filetab = append(filetab, name...)
    227             filetab = append(filetab, 0)
    228         }
    229 
    230         cuOffset += len(cu.fileNames)
    231     }
    232 
    233     return
    234 }
    235 
    236 func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {
    237     fstart = len(*out)
    238     *out = append(*out, byte(0))
    239     offs := uint32(1)
    240 
    241     funcdataOffs = make([][]uint32, len(funcs))
    242     for i, f := range funcs {
    243 
    244         var writer = func(fd encoding.BinaryMarshaler) {
    245             var ab []byte
    246             var err error
    247             if fd != nil {
    248                 ab, err = fd.MarshalBinary()
    249                 if err != nil {
    250                     panic(err)
    251                 }
    252                 funcdataOffs[i] = append(funcdataOffs[i], offs)
    253             } else {
    254                 ab = []byte{0}
    255                 funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)
    256             }
    257             *out = append(*out, ab...)
    258             offs += uint32(len(ab))
    259         }
    260 
    261         writer(f.ArgsPointerMaps)
    262         writer(f.LocalsPointerMaps)
    263         writer(f.StackObjects)
    264         writer(f.InlTree)
    265         writer(f.OpenCodedDeferInfo)
    266         writer(f.ArgInfo)
    267         writer(f.ArgLiveInfo)
    268         writer(f.WrapInfo)
    269     }
    270     return 
    271 }
    272 
    273 func makeFtab(funcs []_func, lastFuncSize uint32) (ftab []funcTab) {
    274     // Allocate space for the pc->func table. This structure consists of a pc offset
    275     // and an offset to the func structure. After that, we have a single pc
    276     // value that marks the end of the last function in the binary.
    277     var size int64 = int64(len(funcs)*2*4 + 4)
    278     var startLocations = make([]uint32, len(funcs))
    279     for i, f := range funcs {
    280         size = rnd(size, int64(_PtrSize))
    281         //writePCToFunc
    282         startLocations[i] = uint32(size)
    283         size += int64(uint8(_FUNC_SIZE)+f.nfuncdata*4+uint8(f.npcdata)*4)
    284     }
    285 
    286     ftab = make([]funcTab, 0, len(funcs)+1)
    287 
    288     // write a map of pc->func info offsets 
    289     for i, f := range funcs {
    290         ftab = append(ftab, funcTab{uint32(f.entryOff), uint32(startLocations[i])})
    291     }
    292 
    293     // Final entry of table is just end pc offset.
    294     lastFunc := funcs[len(funcs)-1]
    295     ftab = append(ftab, funcTab{uint32(lastFunc.entryOff + lastFuncSize), 0})
    296 
    297     return
    298 }
    299 
    300 // Pcln table format: [...]funcTab + [...]_Func
    301 func makePclntable(funcs []_func, lastFuncSize uint32, pcdataOffs [][]uint32, funcdataOffs [][]uint32) (pclntab []byte) {
    302     // Allocate space for the pc->func table. This structure consists of a pc offset
    303     // and an offset to the func structure. After that, we have a single pc
    304     // value that marks the end of the last function in the binary.
    305     var size int64 = int64(len(funcs)*2*4 + 4)
    306     var startLocations = make([]uint32, len(funcs))
    307     for i := range funcs {
    308         size = rnd(size, int64(_PtrSize))
    309         //writePCToFunc
    310         startLocations[i] = uint32(size)
    311         size += int64(int(_FUNC_SIZE)+len(funcdataOffs[i])*4+len(pcdataOffs[i])*4)
    312     }
    313 
    314     pclntab = make([]byte, size, size)
    315 
    316     // write a map of pc->func info offsets 
    317     offs := 0
    318     for i, f := range funcs {
    319         byteOrder.PutUint32(pclntab[offs:offs+4], uint32(f.entryOff))
    320         byteOrder.PutUint32(pclntab[offs+4:offs+8], uint32(startLocations[i]))
    321         offs += 8
    322     }
    323     // Final entry of table is just end pc offset.
    324     lastFunc := funcs[len(funcs)-1]
    325     byteOrder.PutUint32(pclntab[offs:offs+4], uint32(lastFunc.entryOff+lastFuncSize))
    326 
    327     // write func info table
    328     for i, f := range funcs {
    329         off := startLocations[i]
    330 
    331         // write _func structure to pclntab
    332         fb := rt.BytesFrom(unsafe.Pointer(&f), int(_FUNC_SIZE), int(_FUNC_SIZE))
    333         copy(pclntab[off:off+uint32(_FUNC_SIZE)], fb)
    334         off += uint32(_FUNC_SIZE)
    335 
    336         // NOTICE: _func.pcdata always starts from PcUnsafePoint, which is index 3
    337         for j := 3; j < len(pcdataOffs[i]); j++ {
    338             byteOrder.PutUint32(pclntab[off:off+4], uint32(pcdataOffs[i][j]))
    339             off += 4
    340         }
    341 
    342         // funcdata refs as offsets from gofunc
    343         for _, funcdata := range funcdataOffs[i] {
    344             byteOrder.PutUint32(pclntab[off:off+4], uint32(funcdata))
    345             off += 4
    346         }
    347 
    348     }
    349 
    350     return
    351 }
    352 
    353 // findfunc table used to map pc to belonging func, 
    354 // returns the index in the func table.
    355 //
    356 // All text section are divided into buckets sized _BUCKETSIZE(4K):
    357 //   every bucket is divided into _SUBBUCKETS sized _SUB_BUCKETSIZE(64),
    358 //   and it has a base idx to plus the offset stored in jth subbucket.
    359 // see findfunc() in runtime/symtab.go
    360 func writeFindfunctab(out *[]byte, ftab []funcTab) (start int) {
    361     start = len(*out)
    362 
    363     max := ftab[len(ftab)-1].entry
    364     min := ftab[0].entry
    365     nbuckets := (max - min + _BUCKETSIZE - 1) / _BUCKETSIZE
    366     n := (max - min + _SUB_BUCKETSIZE - 1) / _SUB_BUCKETSIZE
    367 
    368     tab := make([]findfuncbucket, 0, nbuckets)
    369     var s, e = 0, 0
    370     for i := 0; i<int(nbuckets); i++ {
    371         var pc = min + uint32((i+1)*_BUCKETSIZE)
    372         // find the end func of the bucket
    373         for ; e < len(ftab)-1 && ftab[e+1].entry <= pc; e++ {}
    374         // store the start func of the bucket
    375         var fb = findfuncbucket{idx: uint32(s)}
    376 
    377         for j := 0; j<_SUBBUCKETS && (i*_SUBBUCKETS+j)<int(n); j++ {
    378             pc = min + uint32(i*_BUCKETSIZE) + uint32((j+1)*_SUB_BUCKETSIZE)
    379             var ss = s
    380             // find the end func of the subbucket
    381             for ; ss < len(ftab)-1 && ftab[ss+1].entry <= pc; ss++ {}
    382             // store the start func of the subbucket
    383             fb._SUBBUCKETS[j] = byte(uint32(s) - fb.idx)
    384             s = ss
    385         }
    386         s = e
    387         tab = append(tab, fb)
    388     }
    389 
    390     // write findfuncbucket
    391     if len(tab) > 0 {
    392         size := int(unsafe.Sizeof(findfuncbucket{}))*len(tab)
    393         *out = append(*out, rt.BytesFrom(unsafe.Pointer(&tab[0]), size, size)...)
    394     }
    395     return 
    396 }
    397 
    398 func makeModuledata(name string, filenames []string, funcs []Func, text []byte) (mod *moduledata) {
    399     mod = new(moduledata)
    400     mod.modulename = name
    401 
    402     // make filename table
    403     cu := make([]string, 0, len(filenames))
    404     for _, f := range filenames {
    405         cu = append(cu, f)
    406     }
    407     cutab, filetab, cuOffs := makeFilenametab([]compilationUnit{{cu}})
    408     mod.cutab = cutab
    409     mod.filetab = filetab
    410 
    411     // make funcname table
    412     funcnametab, nameOffs := makeFuncnameTab(funcs)
    413     mod.funcnametab = funcnametab
    414 
    415     // make pcdata table
    416     // NOTICE: _func only use offset to index pcdata, thus no need mmap() pcdata 
    417     pctab, pcdataOffs, _funcs := makePctab(funcs, cuOffs, nameOffs)
    418     mod.pctab = pctab
    419 
    420     // write func data
    421     // NOTICE: _func use mod.gofunc+offset to directly point funcdata, thus need cache funcdata
    422     // TODO: estimate accurate capacity
    423     cache := make([]byte, 0, len(funcs)*int(_PtrSize)) 
    424     fstart, funcdataOffs := writeFuncdata(&cache, funcs)
    425 
    426     // make pc->func (binary search) func table
    427     lastFuncsize := funcs[len(funcs)-1].TextSize
    428     ftab := makeFtab(_funcs, lastFuncsize)
    429     mod.ftab = ftab
    430 
    431     // write pc->func (modmap) findfunc table
    432     ffstart := writeFindfunctab(&cache, ftab)
    433 
    434     // make pclnt table
    435     pclntab := makePclntable(_funcs, lastFuncsize, pcdataOffs, funcdataOffs)
    436     mod.pclntable = pclntab
    437 
    438     // mmap() text and funcdata segements
    439     p := os.Getpagesize()
    440     size := int(rnd(int64(len(text)), int64(p)))
    441     addr := mmap(size)
    442     // copy the machine code
    443     s := rt.BytesFrom(unsafe.Pointer(addr), len(text), size)
    444     copy(s, text)
    445     // make it executable
    446     mprotect(addr, size)
    447 
    448     // assign addresses
    449     mod.text = addr
    450     mod.etext = addr + uintptr(size)
    451     mod.minpc = addr
    452     mod.maxpc = addr + uintptr(len(text))
    453 
    454     // cache funcdata and findfuncbucket
    455     moduleCache.Lock()
    456     moduleCache.m[mod] = cache
    457     moduleCache.Unlock()
    458     mod.gofunc = uintptr(unsafe.Pointer(&cache[fstart]))
    459     mod.findfunctab = uintptr(unsafe.Pointer(&cache[ffstart]))
    460 
    461     // make pc header
    462     mod.pcHeader = &pcHeader {
    463         magic   : _Magic,
    464         minLC   : _MinLC,
    465         ptrSize : _PtrSize,
    466         nfunc   : len(funcs),
    467         nfiles: uint(len(cu)),
    468         textStart: mod.text,
    469         funcnameOffset: getOffsetOf(moduledata{}, "funcnametab"),
    470         cuOffset: getOffsetOf(moduledata{}, "cutab"),
    471         filetabOffset: getOffsetOf(moduledata{}, "filetab"),
    472         pctabOffset: getOffsetOf(moduledata{}, "pctab"),
    473         pclnOffset: getOffsetOf(moduledata{}, "pclntable"),
    474     }
    475 
    476     // sepecial case: gcdata and gcbss must by non-empty
    477     mod.gcdata = uintptr(unsafe.Pointer(&emptyByte))
    478     mod.gcbss = uintptr(unsafe.Pointer(&emptyByte))
    479 
    480     return
    481 }
    482 
    483 // makePctab generates pcdelta->valuedelta tables for functions,
    484 // and returns the table and the entry offset of every kind pcdata in the table.
    485 func makePctab(funcs []Func, cuOffset []uint32, nameOffset []int32) (pctab []byte, pcdataOffs [][]uint32, _funcs []_func) {
    486     _funcs = make([]_func, len(funcs))
    487 
    488     // Pctab offsets of 0 are considered invalid in the runtime. We respect
    489     // that by just padding a single byte at the beginning of runtime.pctab,
    490     // that way no real offsets can be zero.
    491     pctab = make([]byte, 1, 12*len(funcs)+1)
    492     pcdataOffs = make([][]uint32, len(funcs))
    493 
    494     for i, f := range funcs {
    495         _f := &_funcs[i]
    496 
    497         var writer = func(pc *Pcdata) {
    498             var ab []byte
    499             var err error
    500             if pc != nil {
    501                 ab, err = pc.MarshalBinary()
    502                 if err != nil {
    503                     panic(err)
    504                 }
    505                 pcdataOffs[i] = append(pcdataOffs[i], uint32(len(pctab)))
    506             } else {
    507                 ab = []byte{0}
    508                 pcdataOffs[i] = append(pcdataOffs[i], _PCDATA_INVALID_OFFSET)
    509             }
    510             pctab = append(pctab, ab...)
    511         }
    512 
    513         if f.Pcsp != nil {
    514             _f.pcsp = uint32(len(pctab))
    515         }
    516         writer(f.Pcsp)
    517         if f.Pcfile != nil {
    518             _f.pcfile = uint32(len(pctab))
    519         }
    520         writer(f.Pcfile)
    521         if f.Pcline != nil {
    522             _f.pcln = uint32(len(pctab))
    523         }
    524         writer(f.Pcline)
    525         writer(f.PcUnsafePoint)
    526         writer(f.PcStackMapIndex)
    527         writer(f.PcInlTreeIndex)
    528         writer(f.PcArgLiveIndex)
    529         
    530         _f.entryOff = f.EntryOff
    531         _f.nameOff = nameOffset[i]
    532         _f.args = f.ArgsSize
    533         _f.deferreturn = f.DeferReturn
    534         // NOTICE: _func.pcdata is always as [PCDATA_UnsafePoint(0) : PCDATA_ArgLiveIndex(3)]
    535         _f.npcdata = uint32(_N_PCDATA)
    536         _f.cuOffset = cuOffset[i]
    537         _f.funcID = f.ID
    538         _f.flag = f.Flag
    539         _f.nfuncdata = uint8(_N_FUNCDATA)
    540     }
    541 
    542     return
    543 }
    544 
    545 func registerFunction(name string, pc uintptr, textSize uintptr, fp int, args int, size uintptr, argptrs uintptr, localptrs uintptr) {}