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:]
|
|
} |