podman
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
17package loader18
19import (20`encoding`21`encoding/binary`22`fmt`23`reflect`24`strings`25`sync`26`unsafe`27)
28
29const (30_MinLC uint8 = 131_PtrSize uint8 = 832)
33
34const (35_N_FUNCDATA = 836_INVALID_FUNCDATA_OFFSET = ^uint32(0)37_FUNC_SIZE = unsafe.Sizeof(_func{})38
39_MINFUNC = 16 // minimum size for a function40_BUCKETSIZE = 256 * _MINFUNC41_SUBBUCKETS = 1642_SUB_BUCKETSIZE = _BUCKETSIZE / _SUBBUCKETS43)
44
45// Note: This list must match the list in runtime/symtab.go.
46const (47FuncFlag_TOPFRAME = 1 << iota48FuncFlag_SPWRITE
49FuncFlag_ASM
50)
51
52// PCDATA and FUNCDATA table indexes.
53//
54// See funcdata.h and $GROOT/src/cmd/internal/objabi/funcdata.go.
55const (56_FUNCDATA_ArgsPointerMaps = 057_FUNCDATA_LocalsPointerMaps = 158_FUNCDATA_StackObjects = 259_FUNCDATA_InlTree = 360_FUNCDATA_OpenCodedDeferInfo = 461_FUNCDATA_ArgInfo = 562_FUNCDATA_ArgLiveInfo = 663_FUNCDATA_WrapInfo = 764
65// ArgsSizeUnknown is set in Func.argsize to mark all functions66// whose argument size is unknown (C vararg functions, and67// assembly code without an explicit specification).68// This value is generated by the compiler, assembler, or linker.69ArgsSizeUnknown = -0x8000000070)
71
72// moduledata used to cache the funcdata and findfuncbucket of one module
73var moduleCache = struct {74m map[*moduledata][]byte75sync.Mutex76}{77m: make(map[*moduledata][]byte),78}
79
80// Func contains information about a function.
81type Func struct {82ID uint8 // see runtime/symtab.go83Flag uint8 // see runtime/symtab.go84ArgsSize int32 // args byte size85EntryOff uint32 // start pc, offset to moduledata.text86TextSize uint32 // size of func text87DeferReturn uint32 // offset of start of a deferreturn call instruction from entry, if any.88FileIndex uint32 // index into filetab89Name string // name of function90
91// PC data92Pcsp *Pcdata // PC -> SP delta93Pcfile *Pcdata // PC -> file index94Pcline *Pcdata // PC -> line number95PcUnsafePoint *Pcdata // PC -> unsafe point, must be PCDATA_UnsafePointSafe or PCDATA_UnsafePointUnsafe96PcStackMapIndex *Pcdata // PC -> stack map index, relative to ArgsPointerMaps and LocalsPointerMaps97PcInlTreeIndex *Pcdata // PC -> inlining tree index, relative to InlTree98PcArgLiveIndex *Pcdata // PC -> arg live index, relative to ArgLiveInfo99
100// Func data, must implement encoding.BinaryMarshaler101ArgsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap102LocalsPointerMaps encoding.BinaryMarshaler // concrete type: *StackMap103StackObjects encoding.BinaryMarshaler104InlTree encoding.BinaryMarshaler105OpenCodedDeferInfo encoding.BinaryMarshaler106ArgInfo encoding.BinaryMarshaler107ArgLiveInfo encoding.BinaryMarshaler108WrapInfo encoding.BinaryMarshaler109}
110
111func getOffsetOf(data interface{}, field string) uintptr {112t := reflect.TypeOf(data)113fv, ok := t.FieldByName(field)114if !ok {115panic(fmt.Sprintf("field %s not found in struct %s", field, t.Name()))116}117return fv.Offset118}
119
120func rnd(v int64, r int64) int64 {121if r <= 0 {122return v123}124v += r - 1125c := v % r126if c < 0 {127c += r128}129v -= c130return v131}
132
133var (134byteOrder binary.ByteOrder = binary.LittleEndian135)
136
137func funcNameParts(name string) (string, string, string) {138i := strings.IndexByte(name, '[')139if i < 0 {140return name, "", ""141}142// TODO: use LastIndexByte once the bootstrap compiler is >= Go 1.5.143j := len(name) - 1144for j > i && name[j] != ']' {145j--146}147if j <= i {148return name, "", ""149}150return 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// ...
158func makeFuncnameTab(funcs []Func) (tab []byte, offs []int32) {159offs = make([]int32, len(funcs))160offset := 1161tab = []byte{0}162
163for i, f := range funcs {164offs[i] = int32(offset)165
166a, b, c := funcNameParts(f.Name)167tab = append(tab, a...)168tab = append(tab, b...)169tab = append(tab, c...)170tab = append(tab, 0)171offset += len(a) + len(b) + len(c) + 1172}173
174return175}
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
188func makeFilenametab(cus []compilationUnit) (cutab []uint32, filetab []byte, cuOffsets []uint32) {189cuOffsets = make([]uint32, len(cus))190cuOffset := 0191fileOffset := 0192
193for i, cu := range cus {194cuOffsets[i] = uint32(cuOffset)195
196for _, name := range cu.fileNames {197cutab = append(cutab, uint32(fileOffset))198
199fileOffset += len(name) + 1200filetab = append(filetab, name...)201filetab = append(filetab, 0)202}203
204cuOffset += len(cu.fileNames)205}206
207return208}
209
210func writeFuncdata(out *[]byte, funcs []Func) (fstart int, funcdataOffs [][]uint32) {211fstart = len(*out)212*out = append(*out, byte(0))213offs := uint32(1)214
215funcdataOffs = make([][]uint32, len(funcs))216for i, f := range funcs {217
218var writer = func(fd encoding.BinaryMarshaler) {219var ab []byte220var err error221if fd != nil {222ab, err = fd.MarshalBinary()223if err != nil {224panic(err)225}226funcdataOffs[i] = append(funcdataOffs[i], offs)227} else {228ab = []byte{0}229funcdataOffs[i] = append(funcdataOffs[i], _INVALID_FUNCDATA_OFFSET)230}231*out = append(*out, ab...)232offs += uint32(len(ab))233}234
235writer(f.ArgsPointerMaps)236writer(f.LocalsPointerMaps)237writer(f.StackObjects)238writer(f.InlTree)239writer(f.OpenCodedDeferInfo)240writer(f.ArgInfo)241writer(f.ArgLiveInfo)242writer(f.WrapInfo)243}244return245}
246