github.com/cilium/ebpf@v0.15.1-0.20240517100537-8079b37aa138/btf/marshal.go (about)

     1  package btf
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"maps"
     9  	"math"
    10  	"slices"
    11  	"sync"
    12  
    13  	"github.com/cilium/ebpf/internal"
    14  )
    15  
    16  type MarshalOptions struct {
    17  	// Target byte order. Defaults to the system's native endianness.
    18  	Order binary.ByteOrder
    19  	// Remove function linkage information for compatibility with <5.6 kernels.
    20  	StripFuncLinkage bool
    21  	// Replace Enum64 with a placeholder for compatibility with <6.0 kernels.
    22  	ReplaceEnum64 bool
    23  	// Prevent the "No type found" error when loading BTF without any types.
    24  	PreventNoTypeFound bool
    25  }
    26  
    27  // KernelMarshalOptions will generate BTF suitable for the current kernel.
    28  func KernelMarshalOptions() *MarshalOptions {
    29  	return &MarshalOptions{
    30  		Order:              internal.NativeEndian,
    31  		StripFuncLinkage:   haveFuncLinkage() != nil,
    32  		ReplaceEnum64:      haveEnum64() != nil,
    33  		PreventNoTypeFound: true, // All current kernels require this.
    34  	}
    35  }
    36  
    37  // encoder turns Types into raw BTF.
    38  type encoder struct {
    39  	MarshalOptions
    40  
    41  	pending internal.Deque[Type]
    42  	buf     *bytes.Buffer
    43  	strings *stringTableBuilder
    44  	ids     map[Type]TypeID
    45  	visited map[Type]struct{}
    46  	lastID  TypeID
    47  }
    48  
    49  var bufferPool = sync.Pool{
    50  	New: func() any {
    51  		buf := make([]byte, btfHeaderLen+128)
    52  		return &buf
    53  	},
    54  }
    55  
    56  func getByteSlice() *[]byte {
    57  	return bufferPool.Get().(*[]byte)
    58  }
    59  
    60  func putByteSlice(buf *[]byte) {
    61  	*buf = (*buf)[:0]
    62  	bufferPool.Put(buf)
    63  }
    64  
    65  // Builder turns Types into raw BTF.
    66  //
    67  // The default value may be used and represents an empty BTF blob. Void is
    68  // added implicitly if necessary.
    69  type Builder struct {
    70  	// Explicitly added types.
    71  	types []Type
    72  	// IDs for all added types which the user knows about.
    73  	stableIDs map[Type]TypeID
    74  	// Explicitly added strings.
    75  	strings *stringTableBuilder
    76  }
    77  
    78  // NewBuilder creates a Builder from a list of types.
    79  //
    80  // It is more efficient than calling [Add] individually.
    81  //
    82  // Returns an error if adding any of the types fails.
    83  func NewBuilder(types []Type) (*Builder, error) {
    84  	b := &Builder{
    85  		make([]Type, 0, len(types)),
    86  		make(map[Type]TypeID, len(types)),
    87  		nil,
    88  	}
    89  
    90  	for _, typ := range types {
    91  		_, err := b.Add(typ)
    92  		if err != nil {
    93  			return nil, fmt.Errorf("add %s: %w", typ, err)
    94  		}
    95  	}
    96  
    97  	return b, nil
    98  }
    99  
   100  // Empty returns true if neither types nor strings have been added.
   101  func (b *Builder) Empty() bool {
   102  	return len(b.types) == 0 && (b.strings == nil || b.strings.Length() == 0)
   103  }
   104  
   105  // Add a Type and allocate a stable ID for it.
   106  //
   107  // Adding the identical Type multiple times is valid and will return the same ID.
   108  //
   109  // See [Type] for details on identity.
   110  func (b *Builder) Add(typ Type) (TypeID, error) {
   111  	if b.stableIDs == nil {
   112  		b.stableIDs = make(map[Type]TypeID)
   113  	}
   114  
   115  	if _, ok := typ.(*Void); ok {
   116  		// Equality is weird for void, since it is a zero sized type.
   117  		return 0, nil
   118  	}
   119  
   120  	if ds, ok := typ.(*Datasec); ok {
   121  		if err := datasecResolveWorkaround(b, ds); err != nil {
   122  			return 0, err
   123  		}
   124  	}
   125  
   126  	id, ok := b.stableIDs[typ]
   127  	if ok {
   128  		return id, nil
   129  	}
   130  
   131  	b.types = append(b.types, typ)
   132  
   133  	id = TypeID(len(b.types))
   134  	if int(id) != len(b.types) {
   135  		return 0, fmt.Errorf("no more type IDs")
   136  	}
   137  
   138  	b.stableIDs[typ] = id
   139  	return id, nil
   140  }
   141  
   142  // Marshal encodes all types in the Marshaler into BTF wire format.
   143  //
   144  // opts may be nil.
   145  func (b *Builder) Marshal(buf []byte, opts *MarshalOptions) ([]byte, error) {
   146  	stb := b.strings
   147  	if stb == nil {
   148  		// Assume that most types are named. This makes encoding large BTF like
   149  		// vmlinux a lot cheaper.
   150  		stb = newStringTableBuilder(len(b.types))
   151  	} else {
   152  		// Avoid modifying the Builder's string table.
   153  		stb = b.strings.Copy()
   154  	}
   155  
   156  	if opts == nil {
   157  		opts = &MarshalOptions{Order: internal.NativeEndian}
   158  	}
   159  
   160  	// Reserve space for the BTF header.
   161  	buf = slices.Grow(buf, btfHeaderLen)[:btfHeaderLen]
   162  
   163  	w := internal.NewBuffer(buf)
   164  	defer internal.PutBuffer(w)
   165  
   166  	e := encoder{
   167  		MarshalOptions: *opts,
   168  		buf:            w,
   169  		strings:        stb,
   170  		lastID:         TypeID(len(b.types)),
   171  		visited:        make(map[Type]struct{}, len(b.types)),
   172  		ids:            maps.Clone(b.stableIDs),
   173  	}
   174  
   175  	if e.ids == nil {
   176  		e.ids = make(map[Type]TypeID)
   177  	}
   178  
   179  	types := b.types
   180  	if len(types) == 0 && stb.Length() > 0 && opts.PreventNoTypeFound {
   181  		// We have strings that need to be written out,
   182  		// but no types (besides the implicit Void).
   183  		// Kernels as recent as v6.7 refuse to load such BTF
   184  		// with a "No type found" error in the log.
   185  		// Fix this by adding a dummy type.
   186  		types = []Type{&Int{Size: 0}}
   187  	}
   188  
   189  	// Ensure that types are marshaled in the exact order they were Add()ed.
   190  	// Otherwise the ID returned from Add() won't match.
   191  	e.pending.Grow(len(types))
   192  	for _, typ := range types {
   193  		e.pending.Push(typ)
   194  	}
   195  
   196  	if err := e.deflatePending(); err != nil {
   197  		return nil, err
   198  	}
   199  
   200  	length := e.buf.Len()
   201  	typeLen := uint32(length - btfHeaderLen)
   202  
   203  	stringLen := e.strings.Length()
   204  	buf = e.strings.AppendEncoded(e.buf.Bytes())
   205  
   206  	// Fill out the header, and write it out.
   207  	header := &btfHeader{
   208  		Magic:     btfMagic,
   209  		Version:   1,
   210  		Flags:     0,
   211  		HdrLen:    uint32(btfHeaderLen),
   212  		TypeOff:   0,
   213  		TypeLen:   typeLen,
   214  		StringOff: typeLen,
   215  		StringLen: uint32(stringLen),
   216  	}
   217  
   218  	err := binary.Write(sliceWriter(buf[:btfHeaderLen]), e.Order, header)
   219  	if err != nil {
   220  		return nil, fmt.Errorf("write header: %v", err)
   221  	}
   222  
   223  	return buf, nil
   224  }
   225  
   226  // addString adds a string to the resulting BTF.
   227  //
   228  // Adding the same string multiple times will return the same result.
   229  //
   230  // Returns an identifier into the string table or an error if the string
   231  // contains invalid characters.
   232  func (b *Builder) addString(str string) (uint32, error) {
   233  	if b.strings == nil {
   234  		b.strings = newStringTableBuilder(0)
   235  	}
   236  
   237  	return b.strings.Add(str)
   238  }
   239  
   240  func (e *encoder) allocateIDs(root Type) (err error) {
   241  	visitInPostorder(root, e.visited, func(typ Type) bool {
   242  		if _, ok := typ.(*Void); ok {
   243  			return true
   244  		}
   245  
   246  		if _, ok := e.ids[typ]; ok {
   247  			return true
   248  		}
   249  
   250  		id := e.lastID + 1
   251  		if id < e.lastID {
   252  			err = errors.New("type ID overflow")
   253  			return false
   254  		}
   255  
   256  		e.pending.Push(typ)
   257  		e.ids[typ] = id
   258  		e.lastID = id
   259  		return true
   260  	})
   261  	return
   262  }
   263  
   264  // id returns the ID for the given type or panics with an error.
   265  func (e *encoder) id(typ Type) TypeID {
   266  	if _, ok := typ.(*Void); ok {
   267  		return 0
   268  	}
   269  
   270  	id, ok := e.ids[typ]
   271  	if !ok {
   272  		panic(fmt.Errorf("no ID for type %v", typ))
   273  	}
   274  
   275  	return id
   276  }
   277  
   278  func (e *encoder) deflatePending() error {
   279  	// Declare root outside of the loop to avoid repeated heap allocations.
   280  	var root Type
   281  
   282  	for !e.pending.Empty() {
   283  		root = e.pending.Shift()
   284  
   285  		// Allocate IDs for all children of typ, including transitive dependencies.
   286  		if err := e.allocateIDs(root); err != nil {
   287  			return err
   288  		}
   289  
   290  		if err := e.deflateType(root); err != nil {
   291  			id := e.ids[root]
   292  			return fmt.Errorf("deflate %v with ID %d: %w", root, id, err)
   293  		}
   294  	}
   295  
   296  	return nil
   297  }
   298  
   299  func (e *encoder) deflateType(typ Type) (err error) {
   300  	defer func() {
   301  		if r := recover(); r != nil {
   302  			var ok bool
   303  			err, ok = r.(error)
   304  			if !ok {
   305  				panic(r)
   306  			}
   307  		}
   308  	}()
   309  
   310  	var raw rawType
   311  	raw.NameOff, err = e.strings.Add(typ.TypeName())
   312  	if err != nil {
   313  		return err
   314  	}
   315  
   316  	switch v := typ.(type) {
   317  	case *Void:
   318  		return errors.New("Void is implicit in BTF wire format")
   319  
   320  	case *Int:
   321  		raw.SetKind(kindInt)
   322  		raw.SetSize(v.Size)
   323  
   324  		var bi btfInt
   325  		bi.SetEncoding(v.Encoding)
   326  		// We need to set bits in addition to size, since btf_type_int_is_regular
   327  		// otherwise flags this as a bitfield.
   328  		bi.SetBits(byte(v.Size) * 8)
   329  		raw.data = bi
   330  
   331  	case *Pointer:
   332  		raw.SetKind(kindPointer)
   333  		raw.SetType(e.id(v.Target))
   334  
   335  	case *Array:
   336  		raw.SetKind(kindArray)
   337  		raw.data = &btfArray{
   338  			e.id(v.Type),
   339  			e.id(v.Index),
   340  			v.Nelems,
   341  		}
   342  
   343  	case *Struct:
   344  		raw.SetKind(kindStruct)
   345  		raw.SetSize(v.Size)
   346  		raw.data, err = e.convertMembers(&raw.btfType, v.Members)
   347  
   348  	case *Union:
   349  		err = e.deflateUnion(&raw, v)
   350  
   351  	case *Enum:
   352  		if v.Size == 8 {
   353  			err = e.deflateEnum64(&raw, v)
   354  		} else {
   355  			err = e.deflateEnum(&raw, v)
   356  		}
   357  
   358  	case *Fwd:
   359  		raw.SetKind(kindForward)
   360  		raw.SetFwdKind(v.Kind)
   361  
   362  	case *Typedef:
   363  		raw.SetKind(kindTypedef)
   364  		raw.SetType(e.id(v.Type))
   365  
   366  	case *Volatile:
   367  		raw.SetKind(kindVolatile)
   368  		raw.SetType(e.id(v.Type))
   369  
   370  	case *Const:
   371  		raw.SetKind(kindConst)
   372  		raw.SetType(e.id(v.Type))
   373  
   374  	case *Restrict:
   375  		raw.SetKind(kindRestrict)
   376  		raw.SetType(e.id(v.Type))
   377  
   378  	case *Func:
   379  		raw.SetKind(kindFunc)
   380  		raw.SetType(e.id(v.Type))
   381  		if !e.StripFuncLinkage {
   382  			raw.SetLinkage(v.Linkage)
   383  		}
   384  
   385  	case *FuncProto:
   386  		raw.SetKind(kindFuncProto)
   387  		raw.SetType(e.id(v.Return))
   388  		raw.SetVlen(len(v.Params))
   389  		raw.data, err = e.deflateFuncParams(v.Params)
   390  
   391  	case *Var:
   392  		raw.SetKind(kindVar)
   393  		raw.SetType(e.id(v.Type))
   394  		raw.data = btfVariable{uint32(v.Linkage)}
   395  
   396  	case *Datasec:
   397  		raw.SetKind(kindDatasec)
   398  		raw.SetSize(v.Size)
   399  		raw.SetVlen(len(v.Vars))
   400  		raw.data = e.deflateVarSecinfos(v.Vars)
   401  
   402  	case *Float:
   403  		raw.SetKind(kindFloat)
   404  		raw.SetSize(v.Size)
   405  
   406  	case *declTag:
   407  		raw.SetKind(kindDeclTag)
   408  		raw.SetType(e.id(v.Type))
   409  		raw.data = &btfDeclTag{uint32(v.Index)}
   410  		raw.NameOff, err = e.strings.Add(v.Value)
   411  
   412  	case *typeTag:
   413  		raw.SetKind(kindTypeTag)
   414  		raw.SetType(e.id(v.Type))
   415  		raw.NameOff, err = e.strings.Add(v.Value)
   416  
   417  	default:
   418  		return fmt.Errorf("don't know how to deflate %T", v)
   419  	}
   420  
   421  	if err != nil {
   422  		return err
   423  	}
   424  
   425  	return raw.Marshal(e.buf, e.Order)
   426  }
   427  
   428  func (e *encoder) deflateUnion(raw *rawType, union *Union) (err error) {
   429  	raw.SetKind(kindUnion)
   430  	raw.SetSize(union.Size)
   431  	raw.data, err = e.convertMembers(&raw.btfType, union.Members)
   432  	return
   433  }
   434  
   435  func (e *encoder) convertMembers(header *btfType, members []Member) ([]btfMember, error) {
   436  	bms := make([]btfMember, 0, len(members))
   437  	isBitfield := false
   438  	for _, member := range members {
   439  		isBitfield = isBitfield || member.BitfieldSize > 0
   440  
   441  		offset := member.Offset
   442  		if isBitfield {
   443  			offset = member.BitfieldSize<<24 | (member.Offset & 0xffffff)
   444  		}
   445  
   446  		nameOff, err := e.strings.Add(member.Name)
   447  		if err != nil {
   448  			return nil, err
   449  		}
   450  
   451  		bms = append(bms, btfMember{
   452  			nameOff,
   453  			e.id(member.Type),
   454  			uint32(offset),
   455  		})
   456  	}
   457  
   458  	header.SetVlen(len(members))
   459  	header.SetBitfield(isBitfield)
   460  	return bms, nil
   461  }
   462  
   463  func (e *encoder) deflateEnum(raw *rawType, enum *Enum) (err error) {
   464  	raw.SetKind(kindEnum)
   465  	raw.SetSize(enum.Size)
   466  	raw.SetVlen(len(enum.Values))
   467  	// Signedness appeared together with ENUM64 support.
   468  	raw.SetSigned(enum.Signed && !e.ReplaceEnum64)
   469  	raw.data, err = e.deflateEnumValues(enum)
   470  	return
   471  }
   472  
   473  func (e *encoder) deflateEnumValues(enum *Enum) ([]btfEnum, error) {
   474  	bes := make([]btfEnum, 0, len(enum.Values))
   475  	for _, value := range enum.Values {
   476  		nameOff, err := e.strings.Add(value.Name)
   477  		if err != nil {
   478  			return nil, err
   479  		}
   480  
   481  		if enum.Signed {
   482  			if signedValue := int64(value.Value); signedValue < math.MinInt32 || signedValue > math.MaxInt32 {
   483  				return nil, fmt.Errorf("value %d of enum %q exceeds 32 bits", signedValue, value.Name)
   484  			}
   485  		} else {
   486  			if value.Value > math.MaxUint32 {
   487  				return nil, fmt.Errorf("value %d of enum %q exceeds 32 bits", value.Value, value.Name)
   488  			}
   489  		}
   490  
   491  		bes = append(bes, btfEnum{
   492  			nameOff,
   493  			uint32(value.Value),
   494  		})
   495  	}
   496  
   497  	return bes, nil
   498  }
   499  
   500  func (e *encoder) deflateEnum64(raw *rawType, enum *Enum) (err error) {
   501  	if e.ReplaceEnum64 {
   502  		// Replace the ENUM64 with a union of fields with the correct size.
   503  		// This matches libbpf behaviour on purpose.
   504  		placeholder := &Int{
   505  			"enum64_placeholder",
   506  			enum.Size,
   507  			Unsigned,
   508  		}
   509  		if enum.Signed {
   510  			placeholder.Encoding = Signed
   511  		}
   512  		if err := e.allocateIDs(placeholder); err != nil {
   513  			return fmt.Errorf("add enum64 placeholder: %w", err)
   514  		}
   515  
   516  		members := make([]Member, 0, len(enum.Values))
   517  		for _, v := range enum.Values {
   518  			members = append(members, Member{
   519  				Name: v.Name,
   520  				Type: placeholder,
   521  			})
   522  		}
   523  
   524  		return e.deflateUnion(raw, &Union{enum.Name, enum.Size, members})
   525  	}
   526  
   527  	raw.SetKind(kindEnum64)
   528  	raw.SetSize(enum.Size)
   529  	raw.SetVlen(len(enum.Values))
   530  	raw.SetSigned(enum.Signed)
   531  	raw.data, err = e.deflateEnum64Values(enum.Values)
   532  	return
   533  }
   534  
   535  func (e *encoder) deflateEnum64Values(values []EnumValue) ([]btfEnum64, error) {
   536  	bes := make([]btfEnum64, 0, len(values))
   537  	for _, value := range values {
   538  		nameOff, err := e.strings.Add(value.Name)
   539  		if err != nil {
   540  			return nil, err
   541  		}
   542  
   543  		bes = append(bes, btfEnum64{
   544  			nameOff,
   545  			uint32(value.Value),
   546  			uint32(value.Value >> 32),
   547  		})
   548  	}
   549  
   550  	return bes, nil
   551  }
   552  
   553  func (e *encoder) deflateFuncParams(params []FuncParam) ([]btfParam, error) {
   554  	bps := make([]btfParam, 0, len(params))
   555  	for _, param := range params {
   556  		nameOff, err := e.strings.Add(param.Name)
   557  		if err != nil {
   558  			return nil, err
   559  		}
   560  
   561  		bps = append(bps, btfParam{
   562  			nameOff,
   563  			e.id(param.Type),
   564  		})
   565  	}
   566  	return bps, nil
   567  }
   568  
   569  func (e *encoder) deflateVarSecinfos(vars []VarSecinfo) []btfVarSecinfo {
   570  	vsis := make([]btfVarSecinfo, 0, len(vars))
   571  	for _, v := range vars {
   572  		vsis = append(vsis, btfVarSecinfo{
   573  			e.id(v.Type),
   574  			v.Offset,
   575  			v.Size,
   576  		})
   577  	}
   578  	return vsis
   579  }
   580  
   581  // MarshalMapKV creates a BTF object containing a map key and value.
   582  //
   583  // The function is intended for the use of the ebpf package and may be removed
   584  // at any point in time.
   585  func MarshalMapKV(key, value Type) (_ *Handle, keyID, valueID TypeID, err error) {
   586  	var b Builder
   587  
   588  	if key != nil {
   589  		keyID, err = b.Add(key)
   590  		if err != nil {
   591  			return nil, 0, 0, fmt.Errorf("add key type: %w", err)
   592  		}
   593  	}
   594  
   595  	if value != nil {
   596  		valueID, err = b.Add(value)
   597  		if err != nil {
   598  			return nil, 0, 0, fmt.Errorf("add value type: %w", err)
   599  		}
   600  	}
   601  
   602  	handle, err := NewHandle(&b)
   603  	if err != nil {
   604  		// Check for 'full' map BTF support, since kernels between 4.18 and 5.2
   605  		// already support BTF blobs for maps without Var or Datasec just fine.
   606  		if err := haveMapBTF(); err != nil {
   607  			return nil, 0, 0, err
   608  		}
   609  	}
   610  	return handle, keyID, valueID, err
   611  }