144 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			144 lines
		
	
	
		
			4.2 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/**
 | 
						|
 * 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:]
 | 
						|
} |