github.com/cilium/ebpf@v0.10.0/btf/marshal.go (about)

     1  package btf
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"math"
     9  
    10  	"github.com/cilium/ebpf/internal"
    11  )
    12  
    13  type encoderOptions struct {
    14  	ByteOrder binary.ByteOrder
    15  	// Remove function linkage information for compatibility with <5.6 kernels.
    16  	StripFuncLinkage bool
    17  }
    18  
    19  // kernelEncoderOptions will generate BTF suitable for the current kernel.
    20  var kernelEncoderOptions encoderOptions
    21  
    22  func init() {
    23  	kernelEncoderOptions = encoderOptions{
    24  		ByteOrder:        internal.NativeEndian,
    25  		StripFuncLinkage: haveFuncLinkage() != nil,
    26  	}
    27  }
    28  
    29  // encoder turns Types into raw BTF.
    30  type encoder struct {
    31  	opts encoderOptions
    32  
    33  	buf          *bytes.Buffer
    34  	strings      *stringTableBuilder
    35  	allocatedIDs map[Type]TypeID
    36  	nextID       TypeID
    37  	// Temporary storage for Add.
    38  	pending internal.Deque[Type]
    39  	// Temporary storage for deflateType.
    40  	raw rawType
    41  }
    42  
    43  // newEncoder returns a new builder for the given byte order.
    44  //
    45  // See [KernelEncoderOptions] to build BTF for the current system.
    46  func newEncoder(opts encoderOptions, strings *stringTableBuilder) *encoder {
    47  	enc := &encoder{
    48  		opts: opts,
    49  		buf:  bytes.NewBuffer(make([]byte, btfHeaderLen)),
    50  	}
    51  	enc.reset(strings)
    52  	return enc
    53  }
    54  
    55  // Reset internal state to be able to reuse the Encoder.
    56  func (e *encoder) Reset() {
    57  	e.reset(nil)
    58  }
    59  
    60  func (e *encoder) reset(strings *stringTableBuilder) {
    61  	if strings == nil {
    62  		strings = newStringTableBuilder()
    63  	}
    64  
    65  	e.buf.Truncate(btfHeaderLen)
    66  	e.strings = strings
    67  	e.allocatedIDs = make(map[Type]TypeID)
    68  	e.nextID = 1
    69  }
    70  
    71  // Add a Type.
    72  //
    73  // Adding the same Type multiple times is valid and will return a stable ID.
    74  //
    75  // Calling the method has undefined behaviour if it previously returned an error.
    76  func (e *encoder) Add(typ Type) (TypeID, error) {
    77  	if typ == nil {
    78  		return 0, errors.New("cannot Add a nil Type")
    79  	}
    80  
    81  	hasID := func(t Type) (skip bool) {
    82  		_, isVoid := t.(*Void)
    83  		_, alreadyEncoded := e.allocatedIDs[t]
    84  		return isVoid || alreadyEncoded
    85  	}
    86  
    87  	e.pending.Reset()
    88  
    89  	allocateID := func(typ Type) {
    90  		e.pending.Push(typ)
    91  		e.allocatedIDs[typ] = e.nextID
    92  		e.nextID++
    93  	}
    94  
    95  	iter := postorderTraversal(typ, hasID)
    96  	for iter.Next() {
    97  		if hasID(iter.Type) {
    98  			// This type is part of a cycle and we've already deflated it.
    99  			continue
   100  		}
   101  
   102  		// Allocate an ID for the next type.
   103  		allocateID(iter.Type)
   104  
   105  		for !e.pending.Empty() {
   106  			t := e.pending.Shift()
   107  
   108  			// Ensure that all direct descendants have been allocated an ID
   109  			// before calling deflateType.
   110  			walkType(t, func(child *Type) {
   111  				if !hasID(*child) {
   112  					// t refers to a type which hasn't been allocated an ID
   113  					// yet, which only happens for circular types.
   114  					allocateID(*child)
   115  				}
   116  			})
   117  
   118  			if err := e.deflateType(t); err != nil {
   119  				return 0, fmt.Errorf("deflate %s: %w", t, err)
   120  			}
   121  		}
   122  	}
   123  
   124  	return e.allocatedIDs[typ], nil
   125  }
   126  
   127  // Encode the raw BTF blob.
   128  //
   129  // The returned slice is valid until the next call to Add.
   130  func (e *encoder) Encode() ([]byte, error) {
   131  	length := e.buf.Len()
   132  
   133  	// Truncate the string table on return to allow adding more types.
   134  	defer e.buf.Truncate(length)
   135  
   136  	typeLen := uint32(length - btfHeaderLen)
   137  
   138  	// Reserve space for the string table.
   139  	stringLen := e.strings.Length()
   140  	e.buf.Grow(stringLen)
   141  
   142  	buf := e.buf.Bytes()[:length+stringLen]
   143  	e.strings.MarshalBuffer(buf[length:])
   144  
   145  	// Fill out the header, and write it out.
   146  	header := &btfHeader{
   147  		Magic:     btfMagic,
   148  		Version:   1,
   149  		Flags:     0,
   150  		HdrLen:    uint32(btfHeaderLen),
   151  		TypeOff:   0,
   152  		TypeLen:   typeLen,
   153  		StringOff: typeLen,
   154  		StringLen: uint32(stringLen),
   155  	}
   156  
   157  	err := binary.Write(sliceWriter(buf[:btfHeaderLen]), e.opts.ByteOrder, header)
   158  	if err != nil {
   159  		return nil, fmt.Errorf("can't write header: %v", err)
   160  	}
   161  
   162  	return buf, nil
   163  }
   164  
   165  func (e *encoder) deflateType(typ Type) (err error) {
   166  	raw := &e.raw
   167  	*raw = rawType{}
   168  	raw.NameOff, err = e.strings.Add(typ.TypeName())
   169  	if err != nil {
   170  		return err
   171  	}
   172  
   173  	switch v := typ.(type) {
   174  	case *Int:
   175  		raw.SetKind(kindInt)
   176  		raw.SetSize(v.Size)
   177  
   178  		var bi btfInt
   179  		bi.SetEncoding(v.Encoding)
   180  		// We need to set bits in addition to size, since btf_type_int_is_regular
   181  		// otherwise flags this as a bitfield.
   182  		bi.SetBits(byte(v.Size) * 8)
   183  		raw.data = bi
   184  
   185  	case *Pointer:
   186  		raw.SetKind(kindPointer)
   187  		raw.SetType(e.allocatedIDs[v.Target])
   188  
   189  	case *Array:
   190  		raw.SetKind(kindArray)
   191  		raw.data = &btfArray{
   192  			e.allocatedIDs[v.Type],
   193  			e.allocatedIDs[v.Index],
   194  			v.Nelems,
   195  		}
   196  
   197  	case *Struct:
   198  		raw.SetKind(kindStruct)
   199  		raw.SetSize(v.Size)
   200  		raw.data, err = e.convertMembers(&raw.btfType, v.Members)
   201  
   202  	case *Union:
   203  		raw.SetKind(kindUnion)
   204  		raw.SetSize(v.Size)
   205  		raw.data, err = e.convertMembers(&raw.btfType, v.Members)
   206  
   207  	case *Enum:
   208  		raw.SetSize(v.size())
   209  		raw.SetVlen(len(v.Values))
   210  		raw.SetSigned(v.Signed)
   211  
   212  		if v.has64BitValues() {
   213  			raw.SetKind(kindEnum64)
   214  			raw.data, err = e.deflateEnum64Values(v.Values)
   215  		} else {
   216  			raw.SetKind(kindEnum)
   217  			raw.data, err = e.deflateEnumValues(v.Values)
   218  		}
   219  
   220  	case *Fwd:
   221  		raw.SetKind(kindForward)
   222  		raw.SetFwdKind(v.Kind)
   223  
   224  	case *Typedef:
   225  		raw.SetKind(kindTypedef)
   226  		raw.SetType(e.allocatedIDs[v.Type])
   227  
   228  	case *Volatile:
   229  		raw.SetKind(kindVolatile)
   230  		raw.SetType(e.allocatedIDs[v.Type])
   231  
   232  	case *Const:
   233  		raw.SetKind(kindConst)
   234  		raw.SetType(e.allocatedIDs[v.Type])
   235  
   236  	case *Restrict:
   237  		raw.SetKind(kindRestrict)
   238  		raw.SetType(e.allocatedIDs[v.Type])
   239  
   240  	case *Func:
   241  		raw.SetKind(kindFunc)
   242  		raw.SetType(e.allocatedIDs[v.Type])
   243  		if !e.opts.StripFuncLinkage {
   244  			raw.SetLinkage(v.Linkage)
   245  		}
   246  
   247  	case *FuncProto:
   248  		raw.SetKind(kindFuncProto)
   249  		raw.SetType(e.allocatedIDs[v.Return])
   250  		raw.SetVlen(len(v.Params))
   251  		raw.data, err = e.deflateFuncParams(v.Params)
   252  
   253  	case *Var:
   254  		raw.SetKind(kindVar)
   255  		raw.SetType(e.allocatedIDs[v.Type])
   256  		raw.data = btfVariable{uint32(v.Linkage)}
   257  
   258  	case *Datasec:
   259  		raw.SetKind(kindDatasec)
   260  		raw.SetSize(v.Size)
   261  		raw.SetVlen(len(v.Vars))
   262  		raw.data = e.deflateVarSecinfos(v.Vars)
   263  
   264  	case *Float:
   265  		raw.SetKind(kindFloat)
   266  		raw.SetSize(v.Size)
   267  
   268  	case *declTag:
   269  		raw.SetKind(kindDeclTag)
   270  		raw.data = &btfDeclTag{uint32(v.Index)}
   271  
   272  	case *typeTag:
   273  		raw.SetKind(kindTypeTag)
   274  		raw.NameOff, err = e.strings.Add(v.Value)
   275  
   276  	default:
   277  		return fmt.Errorf("don't know how to deflate %T", v)
   278  	}
   279  
   280  	if err != nil {
   281  		return err
   282  	}
   283  
   284  	return raw.Marshal(e.buf, e.opts.ByteOrder)
   285  }
   286  
   287  func (e *encoder) convertMembers(header *btfType, members []Member) ([]btfMember, error) {
   288  	bms := make([]btfMember, 0, len(members))
   289  	isBitfield := false
   290  	for _, member := range members {
   291  		isBitfield = isBitfield || member.BitfieldSize > 0
   292  
   293  		offset := member.Offset
   294  		if isBitfield {
   295  			offset = member.BitfieldSize<<24 | (member.Offset & 0xffffff)
   296  		}
   297  
   298  		nameOff, err := e.strings.Add(member.Name)
   299  		if err != nil {
   300  			return nil, err
   301  		}
   302  
   303  		bms = append(bms, btfMember{
   304  			nameOff,
   305  			e.allocatedIDs[member.Type],
   306  			uint32(offset),
   307  		})
   308  	}
   309  
   310  	header.SetVlen(len(members))
   311  	header.SetBitfield(isBitfield)
   312  	return bms, nil
   313  }
   314  
   315  func (e *encoder) deflateEnumValues(values []EnumValue) ([]btfEnum, error) {
   316  	bes := make([]btfEnum, 0, len(values))
   317  	for _, value := range values {
   318  		nameOff, err := e.strings.Add(value.Name)
   319  		if err != nil {
   320  			return nil, err
   321  		}
   322  
   323  		if value.Value > math.MaxUint32 {
   324  			return nil, fmt.Errorf("value of enum %q exceeds 32 bits", value.Name)
   325  		}
   326  
   327  		bes = append(bes, btfEnum{
   328  			nameOff,
   329  			uint32(value.Value),
   330  		})
   331  	}
   332  
   333  	return bes, nil
   334  }
   335  
   336  func (e *encoder) deflateEnum64Values(values []EnumValue) ([]btfEnum64, error) {
   337  	bes := make([]btfEnum64, 0, len(values))
   338  	for _, value := range values {
   339  		nameOff, err := e.strings.Add(value.Name)
   340  		if err != nil {
   341  			return nil, err
   342  		}
   343  
   344  		bes = append(bes, btfEnum64{
   345  			nameOff,
   346  			uint32(value.Value),
   347  			uint32(value.Value >> 32),
   348  		})
   349  	}
   350  
   351  	return bes, nil
   352  }
   353  
   354  func (e *encoder) deflateFuncParams(params []FuncParam) ([]btfParam, error) {
   355  	bps := make([]btfParam, 0, len(params))
   356  	for _, param := range params {
   357  		nameOff, err := e.strings.Add(param.Name)
   358  		if err != nil {
   359  			return nil, err
   360  		}
   361  
   362  		bps = append(bps, btfParam{
   363  			nameOff,
   364  			e.allocatedIDs[param.Type],
   365  		})
   366  	}
   367  	return bps, nil
   368  }
   369  
   370  func (e *encoder) deflateVarSecinfos(vars []VarSecinfo) []btfVarSecinfo {
   371  	vsis := make([]btfVarSecinfo, 0, len(vars))
   372  	for _, v := range vars {
   373  		vsis = append(vsis, btfVarSecinfo{
   374  			e.allocatedIDs[v.Type],
   375  			v.Offset,
   376  			v.Size,
   377  		})
   378  	}
   379  	return vsis
   380  }
   381  
   382  // MarshalMapKV creates a BTF object containing a map key and value.
   383  //
   384  // The function is intended for the use of the ebpf package and may be removed
   385  // at any point in time.
   386  func MarshalMapKV(key, value Type) (_ *Handle, keyID, valueID TypeID, _ error) {
   387  	enc := nativeEncoderPool.Get().(*encoder)
   388  	defer nativeEncoderPool.Put(enc)
   389  
   390  	enc.Reset()
   391  
   392  	var err error
   393  	if key != nil {
   394  		keyID, err = enc.Add(key)
   395  		if err != nil {
   396  			return nil, 0, 0, fmt.Errorf("adding map key to BTF encoder: %w", err)
   397  		}
   398  	}
   399  
   400  	if value != nil {
   401  		valueID, err = enc.Add(value)
   402  		if err != nil {
   403  			return nil, 0, 0, fmt.Errorf("adding map value to BTF encoder: %w", err)
   404  		}
   405  	}
   406  
   407  	btf, err := enc.Encode()
   408  	if err != nil {
   409  		return nil, 0, 0, fmt.Errorf("marshal BTF: %w", err)
   410  	}
   411  
   412  	handle, err := newHandleFromRawBTF(btf)
   413  	if err != nil {
   414  		// Check for 'full' map BTF support, since kernels between 4.18 and 5.2
   415  		// already support BTF blobs for maps without Var or Datasec just fine.
   416  		if err := haveMapBTF(); err != nil {
   417  			return nil, 0, 0, err
   418  		}
   419  	}
   420  
   421  	return handle, keyID, valueID, err
   422  }