/** * Copyright 2023 ByteDance Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package loader import ( `encoding` `encoding/binary` `fmt` `reflect` `strings` `sync` `unsafe` ) const ( _MinLC uint8 = 1 _PtrSize uint8 = 8 ) const ( _N_FUNCDATA = 8 _INVALID_FUNCDATA_OFFSET = ^uint32(0) _FUNC_SIZE = unsafe.Sizeof(_func{}) _MINFUNC = 16 // minimum size for a function _BUCKETSIZE = 256 * _MINFUNC _SUBBUCKETS = 16 _SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS ) // PCDATA and FUNCDATA table indexes. // // See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go. const ( _FUNCDATA_ArgsPointerMaps = 0 _FUNCDATA_LocalsPointerMaps = 1 _FUNCDATA_StackObjects = 2 _FUNCDATA_InlTree = 3 _FUNCDATA_OpenCodedDeferInfo = 4 _FUNCDATA_ArgInfo = 5 _FUNCDATA_ArgLiveInfo = 6 _FUNCDATA_WrapInfo = 7 // ArgsSizeUnknown is set in Func.argsize to mark all functions // whose argument size is unknown (C vararg functions, and // assembly code without an explicit specification). // This value is generated by the compiler, assembler, or linker. ArgsSizeUnknown = -0x80000000 ) // moduledata used to cache the funcdata and findfuncbucket of one module var moduleCache = struct { m map[*moduledata][]byte sync.Mutex }{ m: make(map[*moduledata][]byte), } // Func contains information about a function. type Func struct { ID uint8 // see runtime/symtab.go Flag uint8 // see runtime/symtab.go ArgsSize int32 // args byte size EntryOff uint32 // start pc, offset to moduledata.text TextSize uint32 // size of func text DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any. FileIndex uint32 // index into filetab Name string // name of function // PC data Pcsp *Pcdata // PC -> SP delta Pcfile *Pcdata // PC -> file index Pcline *Pcdata // PC -> line number PcUnsafePoint *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps PcInlTreeIndex *Pcdata // PC -> inlining tree index, relative to InlTree PcArgLiveIndex *Pcdata // PC -> arg live index, relative to ArgLiveInfo // Func data, must implement encoding.BinaryMarshaler ArgsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap LocalsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap StackObjects encoding.BinaryMarshaler InlTree encoding.BinaryMarshaler OpenCodedDeferInfo encoding.BinaryMarshaler ArgInfo encoding.BinaryMarshaler ArgLiveInfo encoding.BinaryMarshaler WrapInfo encoding.BinaryMarshaler } func getOffsetOf(data interface{}, field string) uintptr { t := reflect.TypeOf(data) fv, ok := t.FieldByName(field) if !ok { panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name())) } return fv.Offset } func rnd(v int64, r int64) int64 { if r <= 0 { return v } v += r - 1 c := v % r if c < 0 { c += r } v -= c return v } var ( byteOrder binary.ByteOrder = binary.LittleEndian ) func funcNameParts(name string) (string, string, string) { i := strings.IndexByte(name, '[') if i < 0 { return name, "", "" } // TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5. j := len(name) - 1 for j > i && name[j] != ']' { j-- } if j <= i { return name, "", "" } return name[:i], "[...]", name[j+1:] }