github.com/dylandreimerink/gobpfld@v0.6.1-0.20220205171531-e79c330ad608/btf.go (about)

     1  package gobpfld
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"errors"
     7  	"fmt"
     8  	"io"
     9  	"math"
    10  	"math/big"
    11  	"strconv"
    12  	"unsafe"
    13  
    14  	"github.com/dylandreimerink/gobpfld/bpfsys"
    15  	"github.com/dylandreimerink/gobpfld/bpftypes"
    16  	"github.com/dylandreimerink/gobpfld/internal/cstr"
    17  	"github.com/dylandreimerink/gobpfld/kernelsupport"
    18  )
    19  
    20  // TODO add field to store kernel structure ID's (for map BTFVMLinuxValueTypeID)
    21  // TODO Add global registry for BTF objects to translate IDs to FDs
    22  // TODO Add fuzzing, we should never get panics only errors, critical for stability of library users. (go 1.18)
    23  // TODO (bonus) make code generators for BTF so we can generate C and Go code like bpftool does
    24  // TODO (bonus) test against VMLinux (/sys/kernel/btf/vmlinux)
    25  // TODO (bonus) implement libbpf compatible CO:RE(Compile Once Run Everywhere).
    26  //   This works by looking at the BTF of the compiled program to see what it wants to access and rewriting
    27  //   the program using the VMLinux on the machine at runtime. This would enable users to compile architecture
    28  //   specific kprobe or uprobe code and run it everywhere.
    29  
    30  // BTF Type and String info
    31  type BTF struct {
    32  	// Parsed type information, the index of the types is equal to their ID's
    33  	Types []BTFType
    34  
    35  	// Parsed Lines information with ELF section relative instruction offsets
    36  	Lines []BTFLine
    37  	// Parsed function information with ELF section relative instruction offsets
    38  	Funcs []BTFFunc
    39  
    40  	// A mapping of BTF types indexed on name, used to find the currect types for BPF Maps
    41  	typesByName map[string]BTFType
    42  
    43  	// The parsed BTF header
    44  	btfHdr *btfHeader
    45  	// Contains the full, raw BTF header, string and type bytes.
    46  	// Used to load into the kernel.
    47  	rawType []byte
    48  
    49  	StringsTbl StringTbl
    50  
    51  	// The parsed BTF EXT header
    52  	btfExtHdr *btfExtHeader
    53  
    54  	// Indicates if the BTF is already loaded into the kernel
    55  	loaded bool
    56  	// The file descriptor of the BTF assigned by the kernel
    57  	fd bpfsys.BPFfd
    58  }
    59  
    60  func NewBTF() *BTF {
    61  	return &BTF{
    62  		typesByName: make(map[string]BTFType),
    63  	}
    64  }
    65  
    66  func (btf *BTF) Fd() (bpfsys.BPFfd, error) {
    67  	if !btf.loaded {
    68  		return 0, fmt.Errorf("btf is not loaded")
    69  	}
    70  
    71  	return btf.fd, nil
    72  }
    73  
    74  type BTFLoadOpts struct {
    75  	LogLevel bpftypes.BPFLogLevel
    76  	LogSize  int
    77  }
    78  
    79  func (btf *BTF) Load(opts BTFLoadOpts) (string, error) {
    80  	if btf.loaded {
    81  		return "", fmt.Errorf("btf is already loaded")
    82  	}
    83  
    84  	if btf.rawType == nil {
    85  		return "", fmt.Errorf("btf has no raw type info")
    86  	}
    87  
    88  	// Set a default log size if none is specified
    89  	if opts.LogSize == 0 {
    90  		opts.LogSize = defaultBPFVerifierLogSize
    91  	}
    92  
    93  	serialized, err := btf.SerializeBTF()
    94  	if err != nil {
    95  		return "", fmt.Errorf("btf serialization: %w", err)
    96  	}
    97  
    98  	verifierLogBytes := make([]byte, opts.LogSize)
    99  
   100  	attr := bpfsys.BPFAttrBTFLoad{
   101  		BTF:         uintptr(unsafe.Pointer(&serialized[0])),
   102  		BTFSize:     uint32(len(serialized)),
   103  		BTFLogBuf:   uintptr(unsafe.Pointer(&verifierLogBytes[0])),
   104  		BTFLogSize:  uint32(opts.LogSize),
   105  		BTFLogLevel: opts.LogLevel,
   106  	}
   107  
   108  	fd, err := bpfsys.BTFLoad(&attr)
   109  	if err != nil {
   110  		return cstr.BytesToString(verifierLogBytes), err
   111  	}
   112  
   113  	btf.fd = fd
   114  	btf.loaded = true
   115  
   116  	return cstr.BytesToString(verifierLogBytes), nil
   117  }
   118  
   119  // ErrMissingBTFData is returned when a datastructure indicates that there should be additional bytes but
   120  //  the given bytes slice doesn't contain any.
   121  var ErrMissingBTFData = errors.New("missing indicated bytes in slice")
   122  
   123  // ParseBTF parses BTF type and string data.
   124  func (btf *BTF) ParseBTF(btfBytes []byte) error {
   125  	btf.rawType = btfBytes
   126  	headerOffset := uint32(0)
   127  
   128  	var err error
   129  	btf.btfHdr, headerOffset, err = parseBTFHeader(btfBytes)
   130  	if err != nil {
   131  		return fmt.Errorf("parse header: %w", err)
   132  	}
   133  
   134  	btfLen := len(btfBytes)
   135  	if btfLen < int(headerOffset+btf.btfHdr.StringOffset+btf.btfHdr.StringLength) {
   136  		return fmt.Errorf("byte sequence shorten than indicated string offset + length")
   137  	}
   138  
   139  	stringsStart := headerOffset + btf.btfHdr.StringOffset
   140  	stringsEnd := headerOffset + btf.btfHdr.StringOffset + btf.btfHdr.StringLength
   141  	btf.StringsTbl = StringTblFromBlob(btfBytes[stringsStart:stringsEnd])
   142  
   143  	if btfLen < int(headerOffset+btf.btfHdr.TypeOffset+btf.btfHdr.TypeLength) {
   144  		return fmt.Errorf("byte sequence shorten than indicated type offset + length")
   145  	}
   146  
   147  	typesStart := headerOffset + btf.btfHdr.TypeOffset
   148  	typesEnd := headerOffset + btf.btfHdr.TypeOffset + btf.btfHdr.TypeLength
   149  	btfTypes := btfBytes[typesStart:typesEnd]
   150  
   151  	var readError error
   152  	off := 0
   153  	read32 := func() uint32 {
   154  		defer func() {
   155  			off = off + 4
   156  		}()
   157  
   158  		// return a 0, instread of panicing
   159  		if off+4 > len(btfTypes) {
   160  			readError = ErrMissingBTFData
   161  			return 0
   162  		}
   163  
   164  		v := btf.btfHdr.byteOrder.Uint32(btfTypes[off : off+4])
   165  		return v
   166  	}
   167  
   168  	// Type ID 0 is reserved for void, this initial item will make it so that the index in this slice
   169  	// is equal to the Type IDs used by other types.
   170  	btf.Types = append(btf.Types, &BTFVoidType{})
   171  
   172  	for off < len(btfTypes) {
   173  		ct := (btfType{
   174  			NameOffset: read32(),
   175  			Info:       read32(),
   176  			SizeType:   read32(),
   177  		}).ToCommonType(&btf.StringsTbl)
   178  
   179  		// The current amount of elements is equal to the index of the next element.
   180  		ct.TypeID = len(btf.Types)
   181  
   182  		var btfType BTFType
   183  		switch ct.Kind {
   184  		case BTF_KIND_INT:
   185  			ct.Size = ct.sizeType
   186  			typeData := read32()
   187  			btfType = &BTFIntType{
   188  				commonType: ct,
   189  				Encoding:   BTFIntEncoding((typeData & 0x0f000000) >> 24),
   190  				Offset:     uint8((typeData & 0x00ff0000) >> 16),
   191  				Bits:       uint8(typeData & 0x000000ff),
   192  			}
   193  
   194  		case BTF_KIND_PTR:
   195  			btfType = &BTFPtrType{
   196  				commonType: ct,
   197  			}
   198  
   199  		case BTF_KIND_ARRAY:
   200  			arr := &BTFArrayType{
   201  				commonType: ct,
   202  			}
   203  			arr.typeID = read32()
   204  			arr.indexTypeID = read32()
   205  			arr.NumElements = read32()
   206  
   207  			btfType = arr
   208  
   209  		case BTF_KIND_STRUCT, BTF_KIND_UNION:
   210  			ct.Size = ct.sizeType
   211  			members := make([]BTFMember, ct.VLen)
   212  			for i := 0; i < int(ct.VLen); i++ {
   213  				members[i].Name = btf.StringsTbl.GetStringAtOffset(int(read32()))
   214  				members[i].typeID = read32()
   215  
   216  				// https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/btf.h#L132
   217  				offset := read32()
   218  				if ct.KindFlag == 1 {
   219  					// If the kind_flag is set, the btf_member.offset contains both member bitfield size and bit offset.
   220  					members[i].BitfieldSize = offset >> 24
   221  					members[i].BitOffset = offset & 0xffffff
   222  				} else {
   223  					// If the type info kind_flag is not set, the offset contains only bit offset of the member.
   224  					members[i].BitOffset = offset
   225  				}
   226  			}
   227  
   228  			if ct.Kind == BTF_KIND_STRUCT {
   229  				btfType = &BTFStructType{
   230  					commonType: ct,
   231  					Members:    members,
   232  				}
   233  				break
   234  			}
   235  
   236  			btfType = &BTFUnionType{
   237  				commonType: ct,
   238  				Members:    members,
   239  			}
   240  		case BTF_KIND_ENUM:
   241  			ct.Size = ct.sizeType
   242  			options := make([]BTFEnumOption, ct.VLen)
   243  			for i := 0; i < int(ct.VLen); i++ {
   244  				options[i].Name = btf.StringsTbl.GetStringAtOffset(int(read32()))
   245  				options[i].Value = int32(read32())
   246  			}
   247  
   248  			btfType = &BTFEnumType{
   249  				commonType: ct,
   250  				Options:    options,
   251  			}
   252  
   253  		case BTF_KIND_FWD:
   254  			btfType = &BTFForwardType{
   255  				commonType: ct,
   256  			}
   257  
   258  		case BTF_KIND_TYPEDEF:
   259  			btfType = &BTFTypeDefType{
   260  				commonType: ct,
   261  			}
   262  
   263  		case BTF_KIND_VOLATILE:
   264  			btfType = &BTFVolatileType{
   265  				commonType: ct,
   266  			}
   267  
   268  		case BTF_KIND_CONST:
   269  			btfType = &BTFConstType{
   270  				commonType: ct,
   271  			}
   272  
   273  		case BTF_KIND_RESTRICT:
   274  			btfType = &BTFRestrictType{
   275  				commonType: ct,
   276  			}
   277  
   278  		case BTF_KIND_FUNC:
   279  			btfType = &BTFFuncType{
   280  				commonType: ct,
   281  			}
   282  
   283  		case BTF_KIND_FUNC_PROTO:
   284  			params := make([]BTFFuncProtoParam, ct.VLen)
   285  			for i := 0; i < int(ct.VLen); i++ {
   286  				params[i].Name = btf.StringsTbl.GetStringAtOffset(int(read32()))
   287  				params[i].typeID = read32()
   288  			}
   289  
   290  			btfType = &BTFFuncProtoType{
   291  				commonType: ct,
   292  				Params:     params,
   293  			}
   294  
   295  		case BTF_KIND_VAR:
   296  			btfType = &BTFVarType{
   297  				commonType: ct,
   298  				Linkage:    read32(),
   299  			}
   300  
   301  		case BTF_KIND_DATASEC:
   302  			// The offset of the SizeType uint32 of common type
   303  			ctSizeTypeOff := off - 4
   304  
   305  			variables := make([]BTFDataSecVariable, ct.VLen)
   306  			for i := 0; i < int(ct.VLen); i++ {
   307  				variables[i].typeID = read32()
   308  				variables[i].offsetOffset = int(typesStart) + off
   309  				variables[i].Offset = read32()
   310  				variables[i].Size = read32()
   311  			}
   312  
   313  			dataSec := &BTFDataSecType{
   314  				commonType: ct,
   315  				Variables:  variables,
   316  				sizeOffset: int(typesStart) + ctSizeTypeOff,
   317  			}
   318  			btfType = dataSec
   319  
   320  		case BTF_KIND_FLOAT:
   321  			ct.Size = ct.sizeType
   322  			btfType = &BTFFloatType{
   323  				commonType: ct,
   324  			}
   325  
   326  		case BTF_KIND_DECL_TAG:
   327  			btfType = &BTFDeclTagType{
   328  				commonType:   ct,
   329  				ComponentIdx: read32(),
   330  			}
   331  
   332  		default:
   333  			return fmt.Errorf("unknown BTF kind: %d", ct.Kind)
   334  		}
   335  
   336  		btf.Types = append(btf.Types, btfType)
   337  
   338  		if ct.Name != "" {
   339  			btf.typesByName[ct.Name] = btfType
   340  		}
   341  	}
   342  	if readError != nil {
   343  		return readError
   344  	}
   345  
   346  	// Range over all types and resolve type references
   347  	for _, btfType := range btf.Types {
   348  		switch t := btfType.(type) {
   349  		case *BTFPtrType:
   350  			t.Type = btf.Types[t.sizeType]
   351  
   352  		case *BTFArrayType:
   353  			t.Type = btf.Types[t.typeID]
   354  			t.IndexType = btf.Types[t.indexTypeID]
   355  
   356  		case *BTFStructType:
   357  			for i, member := range t.Members {
   358  				t.Members[i].Type = btf.Types[member.typeID]
   359  			}
   360  
   361  		case *BTFUnionType:
   362  			for i, member := range t.Members {
   363  				t.Members[i].Type = btf.Types[member.typeID]
   364  			}
   365  
   366  		case *BTFTypeDefType:
   367  			t.Type = btf.Types[t.sizeType]
   368  
   369  		case *BTFVolatileType:
   370  			t.Type = btf.Types[t.sizeType]
   371  
   372  		case *BTFConstType:
   373  			t.Type = btf.Types[t.sizeType]
   374  
   375  		case *BTFRestrictType:
   376  			t.Type = btf.Types[t.sizeType]
   377  
   378  		case *BTFFuncType:
   379  			t.Type = btf.Types[t.sizeType]
   380  
   381  		case *BTFFuncProtoType:
   382  			t.Type = btf.Types[t.sizeType]
   383  			for i, param := range t.Params {
   384  				t.Params[i].Type = btf.Types[param.typeID]
   385  			}
   386  
   387  		case *BTFVarType:
   388  			t.Type = btf.Types[t.sizeType]
   389  
   390  		case *BTFDataSecType:
   391  			for i, variable := range t.Variables {
   392  				t.Variables[i].Type = btf.Types[variable.typeID]
   393  			}
   394  
   395  		case *BTFDeclTagType:
   396  			t.Type = btf.Types[t.sizeType]
   397  		}
   398  	}
   399  
   400  	// Loop over all types again, this time to verify them
   401  	// for _, btfType := range btf.Types {
   402  	// TODO implement verification for all types.
   403  	// TODO call verification
   404  	// }
   405  
   406  	return nil
   407  }
   408  
   409  // ParseBTFExt parses
   410  func (btf *BTF) ParseBTFExt(btfBytes []byte) error {
   411  	var err error
   412  	headerOffset := uint32(0)
   413  
   414  	btf.btfExtHdr, headerOffset, err = parseBTFExtHeader(btfBytes)
   415  	if err != nil {
   416  		return fmt.Errorf("parse header: %w", err)
   417  	}
   418  
   419  	funcsStart := headerOffset + btf.btfExtHdr.FuncOffset
   420  	funcsEnd := headerOffset + btf.btfExtHdr.FuncOffset + btf.btfExtHdr.FuncLength
   421  	funcs := btfBytes[funcsStart:funcsEnd]
   422  
   423  	var readError error
   424  	off := 0
   425  	read32 := func() uint32 {
   426  		defer func() {
   427  			off = off + 4
   428  		}()
   429  
   430  		// return a 0, instread of panicing
   431  		if off+4 > len(funcs) {
   432  			readError = ErrMissingBTFData
   433  			return 0
   434  		}
   435  
   436  		v := btf.btfExtHdr.byteOrder.Uint32(funcs[off : off+4])
   437  		return v
   438  	}
   439  
   440  	funcRecordSize := read32()
   441  	for off < len(funcs) {
   442  		sectionOffset := read32()
   443  		sectionName := btf.StringsTbl.GetStringAtOffset(int(sectionOffset))
   444  		numInfo := read32()
   445  		for i := 0; i < int(numInfo); i++ {
   446  			if funcRecordSize < 8 {
   447  				panic("func record smaller than min expected size")
   448  			}
   449  
   450  			f := BTFFunc{
   451  				Section:       sectionName,
   452  				SectionOffset: sectionOffset,
   453  			}
   454  			f.InstructionOffset = btf.btfExtHdr.byteOrder.Uint32(funcs[off : off+4])
   455  			f.TypeID = btf.btfExtHdr.byteOrder.Uint32(funcs[off+4 : off+8])
   456  			f.Type = btf.Types[f.TypeID]
   457  			btf.Funcs = append(btf.Funcs, f)
   458  
   459  			// Increment by funcRecordSize, since newer version of BTF might start using larger records.
   460  			// This makes the code forward compatible
   461  			off += int(funcRecordSize)
   462  		}
   463  	}
   464  	if readError != nil {
   465  		return err
   466  	}
   467  
   468  	linesStart := headerOffset + btf.btfExtHdr.LineOffset
   469  	linesEnd := headerOffset + btf.btfExtHdr.LineOffset + btf.btfExtHdr.LineLength
   470  	lines := btfBytes[linesStart:linesEnd]
   471  
   472  	off = 0
   473  	read32 = func() uint32 {
   474  		defer func() {
   475  			off = off + 4
   476  		}()
   477  
   478  		// return a 0, instread of panicing
   479  		if off+4 > len(lines) {
   480  			readError = ErrMissingBTFData
   481  			return 0
   482  		}
   483  
   484  		v := btf.btfExtHdr.byteOrder.Uint32(lines[off : off+4])
   485  		return v
   486  	}
   487  
   488  	lineRecordSize := read32()
   489  	for off < len(lines) {
   490  		sectionOffset := read32()
   491  		sectionName := btf.StringsTbl.GetStringAtOffset(int(sectionOffset))
   492  		numInfo := read32()
   493  		for i := 0; i < int(numInfo); i++ {
   494  			if lineRecordSize < 16 {
   495  				panic("line record smaller than min expected size")
   496  			}
   497  
   498  			l := BTFLine{
   499  				Section:       sectionName,
   500  				SectionOffset: sectionOffset,
   501  			}
   502  			l.InstructionOffset = btf.btfExtHdr.byteOrder.Uint32(lines[off : off+4])
   503  			l.FileNameOffset = btf.btfExtHdr.byteOrder.Uint32(lines[off+4 : off+8])
   504  			l.FileName = btf.StringsTbl.GetStringAtOffset(int(l.FileNameOffset))
   505  			l.LineOffset = btf.btfExtHdr.byteOrder.Uint32(lines[off+8 : off+12])
   506  			l.Line = btf.StringsTbl.GetStringAtOffset(int(l.LineOffset))
   507  			col := btf.btfExtHdr.byteOrder.Uint32(lines[off+12 : off+16])
   508  			l.LineNumber = col >> 10
   509  			l.ColumnNumber = col & 0x3FF
   510  			btf.Lines = append(btf.Lines, l)
   511  
   512  			// Increment by lineRecordSize, since newer version of BTF might start using larger records.
   513  			// This makes the code forward compatible
   514  			off += int(lineRecordSize)
   515  		}
   516  	}
   517  	if readError != nil {
   518  		return err
   519  	}
   520  
   521  	return nil
   522  }
   523  
   524  // SerializeBTF takes the contents BTF.Types and serializes it into a byte slice which can be loaded into the kernel
   525  func (btf *BTF) SerializeBTF() ([]byte, error) {
   526  	var buf bytes.Buffer
   527  
   528  	const hdrLen = 6 * 4
   529  
   530  	// Empty header, patched later
   531  	buf.Write(make([]byte, hdrLen))
   532  
   533  	btf.StringsTbl.Serialize()
   534  
   535  	for _, t := range btf.Types[1:] {
   536  		b, err := t.Serialize(&btf.StringsTbl, btf.btfHdr.byteOrder)
   537  		if err != nil {
   538  			return nil, err
   539  		}
   540  		buf.Write(b)
   541  	}
   542  
   543  	typeOff := uint32(0)
   544  	typeLen := uint32(buf.Len() - hdrLen)
   545  	strOff := typeLen
   546  	strLen := uint32(len(btf.StringsTbl.btfStringBlob))
   547  
   548  	buf.Write(btf.StringsTbl.btfStringBlob)
   549  
   550  	bytes := buf.Bytes()
   551  
   552  	btf.btfHdr.byteOrder.PutUint16(bytes[0:2], btfMagic)
   553  	// TODO hard code version/flags or get them from the exported fields in BTF
   554  	bytes[2] = btf.btfHdr.Version
   555  	bytes[3] = btf.btfHdr.Flags
   556  	btf.btfHdr.byteOrder.PutUint32(bytes[4:8], hdrLen)
   557  
   558  	btf.btfHdr.byteOrder.PutUint32(bytes[8:12], typeOff)
   559  	btf.btfHdr.byteOrder.PutUint32(bytes[12:16], typeLen)
   560  	btf.btfHdr.byteOrder.PutUint32(bytes[16:20], strOff)
   561  	btf.btfHdr.byteOrder.PutUint32(bytes[20:24], strLen)
   562  
   563  	return bytes, nil
   564  }
   565  
   566  type StringTbl struct {
   567  	Strings       []string
   568  	offsets       map[string]int
   569  	btfStringBlob []byte
   570  }
   571  
   572  func StringTblFromBlob(blob []byte) StringTbl {
   573  	tbl := StringTbl{
   574  		offsets:       make(map[string]int),
   575  		btfStringBlob: blob,
   576  	}
   577  
   578  	off := 0
   579  	for _, s := range bytes.Split(blob, []byte{0}) {
   580  		name := string(s)
   581  		tbl.Strings = append(tbl.Strings, name)
   582  		tbl.offsets[name] = off
   583  		off += len(s) + 1
   584  	}
   585  	// Dirty fix, since we use split, the last element will register as ""
   586  	// This will reset the map entry so an empty string will always give offset 0
   587  	tbl.offsets[""] = 0
   588  	tbl.Strings = tbl.Strings[:len(tbl.Strings)-1]
   589  
   590  	return tbl
   591  }
   592  
   593  func (st *StringTbl) Serialize() {
   594  	st.offsets = make(map[string]int, len(st.Strings))
   595  	var buf bytes.Buffer
   596  	for _, s := range st.Strings {
   597  		st.offsets[s] = buf.Len()
   598  		buf.WriteString(s)
   599  		buf.WriteByte(0)
   600  	}
   601  	st.btfStringBlob = buf.Bytes()
   602  }
   603  
   604  func (st *StringTbl) GetStringAtOffset(offset int) string {
   605  	// TODO implement stricter parsing and throw errors instead of returning empty strings.
   606  	// NOTE current code relies on the fact that offset == 0 will return a "" which is still valid.
   607  	//   only throw errors on offsets outside of the `strings` bounds
   608  	var name string
   609  	if offset < len(st.btfStringBlob) {
   610  		idx := bytes.IndexByte(st.btfStringBlob[offset:], 0x00)
   611  		if idx == -1 {
   612  			name = string(st.btfStringBlob[offset:])
   613  		} else {
   614  			name = string(st.btfStringBlob[offset : offset+idx])
   615  		}
   616  	}
   617  	return name
   618  }
   619  
   620  func (st *StringTbl) StrToOffset(str string) int {
   621  	return st.offsets[str]
   622  }
   623  
   624  // BTFFunc the go version of bpf_func_info. Which is used to link a instruction offset to a function type.
   625  // https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/bpf.h#L6165
   626  type BTFFunc struct {
   627  	// The ELF section in which the function is defined
   628  	Section string
   629  	// Offset in the strings table to the name of the section
   630  	SectionOffset uint32
   631  	// Offset from the start of the ELF section to the function
   632  	InstructionOffset uint32
   633  	// The resolved Type of the Function
   634  	Type BTFType
   635  	// The TypeID, used to resolve Type
   636  	TypeID uint32
   637  }
   638  
   639  func (bf BTFFunc) ToKernel() BTFKernelFunc {
   640  	return BTFKernelFunc{
   641  		InstructionOffset: bf.InstructionOffset,
   642  		TypeID:            bf.TypeID,
   643  	}
   644  }
   645  
   646  // BTFKernelFuncSize size of BTFKernelFunc in bytes
   647  var BTFKernelFuncSize = int(unsafe.Sizeof(BTFKernelFunc{}))
   648  
   649  // BTFKernelFunc is the version of the BTFFunc struct the way the kernel want to see it.
   650  type BTFKernelFunc struct {
   651  	InstructionOffset uint32
   652  	TypeID            uint32
   653  }
   654  
   655  // BTFLine the go version of bpf_line_info. Which maps an instruction to a source code.
   656  // https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/bpf.h#L6173
   657  type BTFLine struct {
   658  	// The ELF section in which the line is defined
   659  	Section string
   660  	// The offset into the strings table for the section name
   661  	SectionOffset uint32
   662  	// Offset from the start of the ELF section to the function
   663  	InstructionOffset uint32
   664  	// The name and path of the source file
   665  	FileName string
   666  	// The offset into the strings table for the file name
   667  	FileNameOffset uint32
   668  	// The full line of source code
   669  	Line string
   670  	// The offset into the strings table for the line.
   671  	LineOffset uint32
   672  	// The line number within the file
   673  	LineNumber uint32
   674  	// The column number within Line of the instruction
   675  	ColumnNumber uint32
   676  }
   677  
   678  func (bl BTFLine) ToKernel() BTFKernelLine {
   679  	return BTFKernelLine{
   680  		InstructionOffset: bl.InstructionOffset,
   681  		FileNameOffset:    bl.FileNameOffset,
   682  		LineOffset:        bl.LineOffset,
   683  		LineCol:           (bl.LineNumber << 10) & bl.ColumnNumber,
   684  	}
   685  }
   686  
   687  // BTFKernelLineSize size of BTFKernelLine in bytes
   688  var BTFKernelLineSize = int(unsafe.Sizeof(BTFKernelLine{}))
   689  
   690  // BTFKernelLine is the version of the BTFLine struct the way the kernel want to see it.
   691  type BTFKernelLine struct {
   692  	InstructionOffset uint32
   693  	FileNameOffset    uint32
   694  	LineOffset        uint32
   695  	LineCol           uint32
   696  }
   697  
   698  // BTFMap is a struct which describes a BPF map
   699  type BTFMap struct {
   700  	Key   BTFType
   701  	Value BTFType
   702  }
   703  
   704  // BTFType is a BTF type, each Kind has its own corresponding BTFType.
   705  type BTFType interface {
   706  	// Returns the TypeID of the type, which is determined by the position of the type within the encoded
   707  	// BTF bytes sequence.
   708  	GetID() int
   709  	GetKind() BTFKind
   710  	GetName() string
   711  	// Serialize to BTF binary representation
   712  	Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error)
   713  }
   714  
   715  type BTFValueFormater interface {
   716  	// Format a byteslice of data to something human-readable using the BTF type information.
   717  	// The resulting output is written to `w``, if `pretty` is true the output is pretty printed(with whitespace).
   718  	// The func returns the remaining bytes and/or an error.
   719  	FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error)
   720  }
   721  
   722  var _ BTFValueFormater = (*BTFIntType)(nil)
   723  
   724  // BTFIntType is the type of KIND_INT, it represents a integer type.
   725  type BTFIntType struct {
   726  	commonType
   727  	// Extra information, mainly useful for pretty printing
   728  	Encoding BTFIntEncoding
   729  	// specifies the starting bit offset to calculate values for this int
   730  	Offset uint8
   731  	// The number of actual bits held by this int type
   732  	Bits uint8
   733  }
   734  
   735  func (t *BTFIntType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
   736  	commonBytes := (commonType{
   737  		Name:     t.Name,
   738  		KindFlag: 0,
   739  		Kind:     BTF_KIND_INT,
   740  		VLen:     0,
   741  		sizeType: t.Size,
   742  	}.ToBTFType(strTbl).ToBytes(order))
   743  
   744  	// TODO validate t.Encoding, t.Offset, t.Bits
   745  
   746  	typeBytes := uint32sToBytes(order, uint32(t.Encoding)<<24|uint32(t.Offset)<<16|uint32(t.Bits))
   747  
   748  	return append(commonBytes, typeBytes...), nil
   749  }
   750  
   751  func (t *BTFIntType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
   752  	bytes := (t.Bits / 8)
   753  	if bytes == 0 {
   754  		bytes = 1
   755  	}
   756  
   757  	if len(b) < int(bytes) {
   758  		return nil, fmt.Errorf("'%s' not enough bytes, want '%d' got '%d'", t.Name, bytes, len(b))
   759  	}
   760  
   761  	if t.Offset != 0 {
   762  		return nil, fmt.Errorf("'%s' non-0 offset int formatting not implemented", t.Name)
   763  	}
   764  
   765  	switch t.Bits {
   766  	case 128:
   767  		var i big.Int
   768  		_, err := fmt.Fprint(w, i.SetBytes(b[:bytes]).Text(10))
   769  		if err != nil {
   770  			return nil, fmt.Errorf("'%s' error writing bigint: %w", t.Name, err)
   771  		}
   772  
   773  		switch t.Encoding {
   774  		case 0:
   775  			_, err := fmt.Fprint(w, i)
   776  			if err != nil {
   777  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   778  			}
   779  
   780  		case INT_SIGNED:
   781  			return nil, fmt.Errorf("'%s' signed printing of 128 bit number not implemented", t.Name)
   782  		case INT_CHAR:
   783  			_, err := fmt.Fprintf(w, "%032x", i.Bytes())
   784  			if err != nil {
   785  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   786  			}
   787  
   788  		case INT_BOOL:
   789  			_, err := fmt.Fprint(w, i.Sign() > 0)
   790  			if err != nil {
   791  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   792  			}
   793  
   794  		default:
   795  			return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding)
   796  		}
   797  
   798  	case 64:
   799  		i := binary.LittleEndian.Uint64(b[:bytes])
   800  
   801  		switch t.Encoding {
   802  		case 0:
   803  			_, err := fmt.Fprint(w, i)
   804  			if err != nil {
   805  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   806  			}
   807  
   808  		case INT_SIGNED:
   809  			_, err := fmt.Fprint(w, int64(i))
   810  			if err != nil {
   811  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   812  			}
   813  
   814  		case INT_CHAR:
   815  			_, err := fmt.Fprintf(w, "%016x", i)
   816  			if err != nil {
   817  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   818  			}
   819  
   820  		case INT_BOOL:
   821  			_, err := fmt.Fprint(w, i > 0)
   822  			if err != nil {
   823  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   824  			}
   825  
   826  		default:
   827  			return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding)
   828  		}
   829  
   830  	case 32:
   831  		i := binary.LittleEndian.Uint32(b[:bytes])
   832  
   833  		switch t.Encoding {
   834  		case 0:
   835  			_, err := fmt.Fprint(w, i)
   836  			if err != nil {
   837  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   838  			}
   839  
   840  		case INT_SIGNED:
   841  			_, err := fmt.Fprint(w, int32(i))
   842  			if err != nil {
   843  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   844  			}
   845  
   846  		case INT_CHAR:
   847  			_, err := fmt.Fprintf(w, "%08x", i)
   848  			if err != nil {
   849  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   850  			}
   851  
   852  		case INT_BOOL:
   853  			_, err := fmt.Fprint(w, i > 0)
   854  			if err != nil {
   855  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   856  			}
   857  
   858  		default:
   859  			return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding)
   860  		}
   861  
   862  	case 16:
   863  		i := binary.LittleEndian.Uint16(b[:bytes])
   864  
   865  		switch t.Encoding {
   866  		case 0:
   867  			_, err := fmt.Fprint(w, i)
   868  			if err != nil {
   869  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   870  			}
   871  
   872  		case INT_SIGNED:
   873  			_, err := fmt.Fprint(w, int16(i))
   874  			if err != nil {
   875  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   876  			}
   877  
   878  		case INT_CHAR:
   879  			_, err := fmt.Fprintf(w, "%04x", i)
   880  			if err != nil {
   881  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   882  			}
   883  
   884  		case INT_BOOL:
   885  			_, err := fmt.Fprint(w, i > 0)
   886  			if err != nil {
   887  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   888  			}
   889  
   890  		default:
   891  			return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding)
   892  		}
   893  
   894  	case 8:
   895  		switch t.Encoding {
   896  		case 0:
   897  			_, err := fmt.Fprint(w, b[0])
   898  			if err != nil {
   899  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   900  			}
   901  
   902  		case INT_SIGNED:
   903  			_, err := fmt.Fprint(w, int8(b[0]))
   904  			if err != nil {
   905  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   906  			}
   907  
   908  		case INT_CHAR:
   909  			_, err := fmt.Fprintf(w, "%02x", b[0])
   910  			if err != nil {
   911  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   912  			}
   913  
   914  		case INT_BOOL:
   915  			_, err := fmt.Fprint(w, b[0] > 0)
   916  			if err != nil {
   917  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   918  			}
   919  
   920  		default:
   921  			return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding)
   922  		}
   923  
   924  	case 1:
   925  		i := b[0] & 1
   926  		switch t.Encoding {
   927  		case 0, INT_SIGNED:
   928  			_, err := fmt.Fprint(w, i)
   929  			if err != nil {
   930  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   931  			}
   932  
   933  		case INT_CHAR:
   934  			_, err := fmt.Fprintf(w, "%02x", b[0])
   935  			if err != nil {
   936  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   937  			}
   938  
   939  		case INT_BOOL:
   940  			_, err := fmt.Fprint(w, b[0] > 0)
   941  			if err != nil {
   942  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   943  			}
   944  
   945  		default:
   946  			return nil, fmt.Errorf("'%s' unsupported encoding '%d'", t.Name, t.Encoding)
   947  		}
   948  	default:
   949  		return nil, fmt.Errorf("'%s' int bitsize '%d' formatting not implemented", t.Name, t.Bits)
   950  	}
   951  
   952  	return b[bytes:], nil
   953  }
   954  
   955  // BTFIntEncoding is used to indicate what the integer encodes, used to determine how to pretty print an integer.
   956  type BTFIntEncoding uint8
   957  
   958  const (
   959  	// INT_SIGNED the int should be printed at a signed integer
   960  	INT_SIGNED BTFIntEncoding = 1 << iota
   961  	// INT_CHAR the int should be printed as hex encoded
   962  	INT_CHAR
   963  	// INT_BOOL the int should be printed as a boolean
   964  	INT_BOOL
   965  )
   966  
   967  var btfIntEncToStr = map[BTFIntEncoding]string{
   968  	0:          "(none)",
   969  	INT_SIGNED: "Signed",
   970  	INT_CHAR:   "Char",
   971  	INT_BOOL:   "Bool",
   972  }
   973  
   974  func (ie BTFIntEncoding) String() string {
   975  	return fmt.Sprintf("%s (%d)", btfIntEncToStr[ie], ie)
   976  }
   977  
   978  var _ BTFValueFormater = (*BTFPtrType)(nil)
   979  
   980  // BTFPtrType is the type for KIND_PTR, which represents a pointer type which points to some other type.
   981  type BTFPtrType struct {
   982  	commonType
   983  }
   984  
   985  func (t *BTFPtrType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
   986  	return (commonType{
   987  		Name:     "",
   988  		KindFlag: 0,
   989  		Kind:     BTF_KIND_PTR,
   990  		VLen:     0,
   991  		sizeType: uint32(t.Type.GetID()),
   992  	}.ToBTFType(strTbl).ToBytes(order)), nil
   993  }
   994  
   995  func (t *BTFPtrType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
   996  	_, err := fmt.Fprint(w, "*")
   997  	if err != nil {
   998  		return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
   999  	}
  1000  
  1001  	if bfmt, ok := t.Type.(BTFValueFormater); ok {
  1002  		return bfmt.FormatValue(b, w, pretty)
  1003  	}
  1004  
  1005  	return nil, fmt.Errorf("'%s' ptr to unformatable type '%T'", t.Name, t.Type)
  1006  }
  1007  
  1008  var _ BTFValueFormater = (*BTFArrayType)(nil)
  1009  
  1010  // BTFArrayType is the type for KIND_ARR, which represents a array
  1011  type BTFArrayType struct {
  1012  	commonType
  1013  	// The type of the array values
  1014  	Type   BTFType
  1015  	typeID uint32
  1016  	// The type of the array index
  1017  	IndexType   BTFType
  1018  	indexTypeID uint32
  1019  	// The number of elements in the array
  1020  	NumElements uint32
  1021  }
  1022  
  1023  func (t *BTFArrayType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1024  	commonBytes := (commonType{
  1025  		Name:     "",
  1026  		KindFlag: 0,
  1027  		Kind:     BTF_KIND_ARRAY,
  1028  		VLen:     0,
  1029  		sizeType: 0,
  1030  	}.ToBTFType(strTbl).ToBytes(order))
  1031  
  1032  	// TODO Perform lookup of t.Type and t.IndexType, since structs created without parting ELF can't set the
  1033  	//      non-exported values.
  1034  
  1035  	return append(commonBytes, uint32sToBytes(order, t.typeID, t.indexTypeID, t.NumElements)...), nil
  1036  }
  1037  
  1038  func (t *BTFArrayType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1039  	var err error
  1040  	if pretty {
  1041  		_, err = fmt.Fprint(w, "[\n  ")
  1042  	} else {
  1043  		_, err = fmt.Fprint(w, "[")
  1044  	}
  1045  	if err != nil {
  1046  		return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
  1047  	}
  1048  
  1049  	bfmt, ok := t.Type.(BTFValueFormater)
  1050  	if !ok {
  1051  		return nil, fmt.Errorf("'%s' array contains nonformattable type '%T'", t.Name, t.Type)
  1052  	}
  1053  
  1054  	for i := 0; i < int(t.NumElements); i++ {
  1055  		b, err = bfmt.FormatValue(b, w, pretty)
  1056  		if err != nil {
  1057  			return nil, fmt.Errorf("'%s'[%d]: %w", t.Name, i, err)
  1058  		}
  1059  		if i+1 != int(t.NumElements) || pretty {
  1060  			if pretty {
  1061  				if i+1 == int(t.NumElements) {
  1062  					_, err = fmt.Fprint(w, ",\n")
  1063  				} else {
  1064  					_, err = fmt.Fprint(w, ",\n  ")
  1065  				}
  1066  			} else {
  1067  				_, err = fmt.Fprint(w, ", ")
  1068  			}
  1069  			if err != nil {
  1070  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
  1071  			}
  1072  		}
  1073  	}
  1074  
  1075  	_, err = fmt.Fprint(w, "]")
  1076  	if err != nil {
  1077  		return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
  1078  	}
  1079  
  1080  	return b, nil
  1081  }
  1082  
  1083  var _ BTFValueFormater = (*BTFStructType)(nil)
  1084  
  1085  // BTFStructType is the type for KIND_STRUCT, which represents a structure.
  1086  type BTFStructType struct {
  1087  	commonType
  1088  	// The individual members / fields of the struct.
  1089  	Members []BTFMember
  1090  }
  1091  
  1092  func (t *BTFStructType) Verify() error {
  1093  	for i, member := range t.Members {
  1094  		// Recursively follow type definitions to find the actual int type, or not
  1095  		// TODO move to separate functionality so it can be reused for union as well
  1096  		asInt := func() (*BTFIntType, bool) {
  1097  			curType := member.Type
  1098  			for {
  1099  				switch ct := curType.(type) {
  1100  				case *BTFIntType:
  1101  					return ct, true
  1102  				case *BTFTypeDefType:
  1103  					curType = ct.Type
  1104  					continue
  1105  				default:
  1106  					return nil, false
  1107  				}
  1108  			}
  1109  		}
  1110  		// Recursively follow type definitions to find the actual enum type, or not
  1111  		// TODO move to separate functionality so it can be reused for union as well
  1112  		asEnum := func() (*BTFEnumType, bool) {
  1113  			curType := member.Type
  1114  			for {
  1115  				switch ct := curType.(type) {
  1116  				case *BTFEnumType:
  1117  					return ct, true
  1118  				case *BTFTypeDefType:
  1119  					curType = ct.Type
  1120  					continue
  1121  				default:
  1122  					return nil, false
  1123  				}
  1124  			}
  1125  		}
  1126  		if t.KindFlag == 1 {
  1127  			// If the kind_flag is set,
  1128  
  1129  			// In this case, if the base type is an int type, it must be a regular int type:
  1130  			mt, ok := asInt()
  1131  			if !ok {
  1132  				// TODO make nice error message, instead of panicing
  1133  				panic("invalid member type")
  1134  			}
  1135  
  1136  			// BTF_INT_OFFSET() must be 0.
  1137  			if mt.Offset != 0 {
  1138  				// TODO make nice error message, instead of panicing
  1139  				panic("invalid int offset in struct member")
  1140  			}
  1141  
  1142  			// BTF_INT_BITS() must be equal to {1,2,4,8,16} * 8
  1143  			switch mt.Bits {
  1144  			case 1 * 8, 2 * 8, 4 * 8, 8 * 8, 16 * 8:
  1145  			default:
  1146  				// TODO make nice error message, instead of panicing
  1147  				panic("invalid bits in int struct member")
  1148  			}
  1149  
  1150  		} else {
  1151  			// If the type info kind_flag is not set,
  1152  
  1153  			// the base type of the bitfield can only be int or enum type. If the bitfield size is 32,
  1154  			// the base type can be either int or enum type.
  1155  			if member.BitfieldSize == 32 {
  1156  				_, ok := asInt()
  1157  				if !ok {
  1158  					_, ok = asEnum()
  1159  					if !ok {
  1160  						// TODO make nice error message, instead of panicing
  1161  						panic("invalid struct member type, must be int or enum with 32 bitfield")
  1162  					}
  1163  				}
  1164  			} else {
  1165  				// If the bitfield size is not 32,
  1166  				// the base type must be int, and int type BTF_INT_BITS() encodes the bitfield size.
  1167  
  1168  				// Recursively figure out if actual type is an int.
  1169  				mt, ok := asInt()
  1170  				if !ok {
  1171  					// TODO Move these checks to a 3rd iteration, since to verify this we need to be able to
  1172  					// follow type declarations. Currently it fails the
  1173  					panic("invalid struct member type, must be int for non-32 bitfield")
  1174  				}
  1175  
  1176  				t.Members[i].BitfieldSize = uint32(mt.Bits)
  1177  			}
  1178  		}
  1179  	}
  1180  
  1181  	return nil
  1182  }
  1183  
  1184  func (t *BTFStructType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1185  	var buf bytes.Buffer
  1186  
  1187  	const sizeOfMember = 4
  1188  	buf.Write((commonType{
  1189  		Name:     t.Name,
  1190  		KindFlag: t.KindFlag,
  1191  		Kind:     BTF_KIND_STRUCT,
  1192  		VLen:     uint16(len(t.Members)),
  1193  		sizeType: t.sizeType,
  1194  	}.ToBTFType(strTbl).ToBytes(order)))
  1195  
  1196  	for _, member := range t.Members {
  1197  		var offset uint32
  1198  		if t.KindFlag == 1 {
  1199  			offset = member.BitfieldSize<<24 | (member.BitOffset & 0xffffff)
  1200  		} else {
  1201  			offset = member.BitOffset
  1202  		}
  1203  
  1204  		buf.Write(uint32sToBytes(
  1205  			order,
  1206  			uint32(strTbl.StrToOffset(member.Name)),
  1207  			member.typeID, // TODO resolve from member.Type instead of relying on internal type
  1208  			offset,
  1209  		))
  1210  	}
  1211  
  1212  	return buf.Bytes(), nil
  1213  }
  1214  
  1215  func (t *BTFStructType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1216  	var err error
  1217  	if pretty {
  1218  		_, err = fmt.Fprint(w, "{\n  ")
  1219  	} else {
  1220  		_, err = fmt.Fprint(w, "{")
  1221  	}
  1222  	if err != nil {
  1223  		return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
  1224  	}
  1225  
  1226  	for _, m := range t.Members {
  1227  		_, err = fmt.Fprint(w, m.Name, ": ")
  1228  		if err != nil {
  1229  			return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
  1230  		}
  1231  
  1232  		bfmt, ok := m.Type.(BTFValueFormater)
  1233  		if !ok {
  1234  			return nil, fmt.Errorf(
  1235  				"'%s' struct contains nonformattable field '%s' of type '%T'",
  1236  				t.Name,
  1237  				m.Name,
  1238  				m.Type,
  1239  			)
  1240  		}
  1241  
  1242  		b, err = bfmt.FormatValue(b, w, pretty)
  1243  		if err != nil {
  1244  			return nil, fmt.Errorf("'%s'[%s]: %w", t.Name, m.Name, err)
  1245  		}
  1246  
  1247  		if m != t.Members[len(t.Members)-1] || pretty {
  1248  			if pretty {
  1249  				if m == t.Members[len(t.Members)-1] {
  1250  					_, err = fmt.Fprint(w, ",\n")
  1251  				} else {
  1252  					_, err = fmt.Fprint(w, ",\n  ")
  1253  				}
  1254  			} else {
  1255  				_, err = fmt.Fprint(w, ", ")
  1256  			}
  1257  			if err != nil {
  1258  				return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
  1259  			}
  1260  		}
  1261  	}
  1262  
  1263  	_, err = fmt.Fprint(w, "}")
  1264  	if err != nil {
  1265  		return nil, fmt.Errorf("'%s' write error: %w", t.Name, err)
  1266  	}
  1267  
  1268  	return b, nil
  1269  }
  1270  
  1271  var _ BTFValueFormater = (*BTFUnionType)(nil)
  1272  
  1273  // BTFUnionType is the type for KIND_UNION, which represents a union, where all members occupy the same memory.
  1274  type BTFUnionType struct {
  1275  	commonType
  1276  	// The individual members / fields of the union.
  1277  	Members []BTFMember
  1278  }
  1279  
  1280  func (t *BTFUnionType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1281  	var buf bytes.Buffer
  1282  
  1283  	const sizeOfMember = 4
  1284  	buf.Write((commonType{
  1285  		Name:     t.Name,
  1286  		KindFlag: t.KindFlag,
  1287  		Kind:     BTF_KIND_UNION,
  1288  		VLen:     uint16(len(t.Members)),
  1289  		sizeType: t.sizeType,
  1290  	}.ToBTFType(strTbl).ToBytes(order)))
  1291  
  1292  	for _, member := range t.Members {
  1293  		var offset uint32
  1294  		if t.KindFlag == 1 {
  1295  			offset = member.BitfieldSize<<24 | (member.BitOffset & 0xffffff)
  1296  		} else {
  1297  			offset = member.BitOffset
  1298  		}
  1299  
  1300  		buf.Write(uint32sToBytes(
  1301  			order,
  1302  			uint32(strTbl.StrToOffset(member.Name)),
  1303  			member.typeID, // TODO resolve from member.Type instead of relying on internal type
  1304  			offset,
  1305  		))
  1306  	}
  1307  
  1308  	return buf.Bytes(), nil
  1309  }
  1310  
  1311  func (t *BTFUnionType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1312  	return nil, errors.New("not yet implemented")
  1313  }
  1314  
  1315  var _ BTFValueFormater = (*BTFMember)(nil)
  1316  
  1317  // BTFMember is a member of a struct or union.
  1318  type BTFMember struct {
  1319  	// Name of the member/field
  1320  	Name string
  1321  	// Type of the member/field
  1322  	Type         BTFType
  1323  	typeID       uint32
  1324  	BitfieldSize uint32
  1325  	BitOffset    uint32
  1326  }
  1327  
  1328  func (t *BTFMember) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1329  	return nil, errors.New("not yet implemented")
  1330  }
  1331  
  1332  var _ BTFValueFormater = (*BTFEnumType)(nil)
  1333  
  1334  type BTFEnumType struct {
  1335  	commonType
  1336  	Options []BTFEnumOption
  1337  }
  1338  
  1339  func (t *BTFEnumType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1340  	var buf bytes.Buffer
  1341  	buf.Write((commonType{
  1342  		Name:     t.Name,
  1343  		KindFlag: 0,
  1344  		Kind:     BTF_KIND_ENUM,
  1345  		VLen:     uint16(len(t.Options)),
  1346  		sizeType: 4,
  1347  	}.ToBTFType(strTbl).ToBytes(order)))
  1348  
  1349  	for _, option := range t.Options {
  1350  		buf.Write(uint32sToBytes(
  1351  			order,
  1352  			uint32(strTbl.StrToOffset(option.Name)),
  1353  			uint32(option.Value),
  1354  		))
  1355  	}
  1356  
  1357  	return buf.Bytes(), nil
  1358  }
  1359  
  1360  func (t *BTFEnumType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1361  	return nil, errors.New("not yet implemented")
  1362  }
  1363  
  1364  type BTFEnumOption struct {
  1365  	Name  string
  1366  	Value int32
  1367  }
  1368  
  1369  var _ BTFValueFormater = (*BTFForwardType)(nil)
  1370  
  1371  type BTFForwardType struct {
  1372  	commonType
  1373  }
  1374  
  1375  func (t *BTFForwardType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1376  	return (commonType{
  1377  		Name:     t.Name,
  1378  		KindFlag: t.KindFlag,
  1379  		Kind:     BTF_KIND_FWD,
  1380  		VLen:     0,
  1381  		sizeType: 0,
  1382  	}.ToBTFType(strTbl).ToBytes(order)), nil
  1383  }
  1384  
  1385  func (t *BTFForwardType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1386  	return nil, errors.New("not yet implemented")
  1387  }
  1388  
  1389  var _ BTFValueFormater = (*BTFTypeDefType)(nil)
  1390  
  1391  type BTFTypeDefType struct {
  1392  	commonType
  1393  }
  1394  
  1395  func (t *BTFTypeDefType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1396  	return (commonType{
  1397  		Name:     t.Name,
  1398  		KindFlag: 0,
  1399  		Kind:     BTF_KIND_TYPEDEF,
  1400  		VLen:     0,
  1401  		sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types
  1402  	}.ToBTFType(strTbl).ToBytes(order)), nil
  1403  }
  1404  
  1405  func (t *BTFTypeDefType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1406  	if bfmt, ok := t.Type.(BTFValueFormater); ok {
  1407  		return bfmt.FormatValue(b, w, pretty)
  1408  	}
  1409  
  1410  	return nil, fmt.Errorf("'%s' typedef to unformatable type '%T'", t.Name, t.Type)
  1411  }
  1412  
  1413  var _ BTFValueFormater = (*BTFVolatileType)(nil)
  1414  
  1415  type BTFVolatileType struct {
  1416  	commonType
  1417  }
  1418  
  1419  func (t *BTFVolatileType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1420  	return (commonType{
  1421  		Name:     "",
  1422  		KindFlag: 0,
  1423  		Kind:     BTF_KIND_VOLATILE,
  1424  		VLen:     0,
  1425  		sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types
  1426  	}.ToBTFType(strTbl).ToBytes(order)), nil
  1427  }
  1428  
  1429  func (t *BTFVolatileType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1430  	// Volatile is a modifier, doesn't change anything to the value formatting of the underlaying type
  1431  	if bfmt, ok := t.Type.(BTFValueFormater); ok {
  1432  		return bfmt.FormatValue(b, w, pretty)
  1433  	}
  1434  
  1435  	return nil, fmt.Errorf("'%s' volatile type to unformatable type '%T'", t.Name, t.Type)
  1436  }
  1437  
  1438  var _ BTFValueFormater = (*BTFConstType)(nil)
  1439  
  1440  type BTFConstType struct {
  1441  	commonType
  1442  }
  1443  
  1444  func (t *BTFConstType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1445  	return (commonType{
  1446  		Name:     "",
  1447  		KindFlag: 0,
  1448  		Kind:     BTF_KIND_CONST,
  1449  		VLen:     0,
  1450  		sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types
  1451  	}.ToBTFType(strTbl).ToBytes(order)), nil
  1452  }
  1453  
  1454  func (t *BTFConstType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1455  	// Const is a modifier, doesn't change anything to the value formatting of the underlaying type
  1456  	if bfmt, ok := t.Type.(BTFValueFormater); ok {
  1457  		return bfmt.FormatValue(b, w, pretty)
  1458  	}
  1459  
  1460  	return nil, fmt.Errorf("'%s' const type to unformatable type '%T'", t.Name, t.Type)
  1461  }
  1462  
  1463  var _ BTFValueFormater = (*BTFRestrictType)(nil)
  1464  
  1465  type BTFRestrictType struct {
  1466  	commonType
  1467  }
  1468  
  1469  func (t *BTFRestrictType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1470  	return (commonType{
  1471  		Name:     "",
  1472  		KindFlag: 0,
  1473  		Kind:     BTF_KIND_RESTRICT,
  1474  		VLen:     0,
  1475  		sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types
  1476  	}.ToBTFType(strTbl).ToBytes(order)), nil
  1477  }
  1478  
  1479  func (t *BTFRestrictType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1480  	// Restrict is a modifier, doesn't change anything to the value formatting of the underlaying type
  1481  	if bfmt, ok := t.Type.(BTFValueFormater); ok {
  1482  		return bfmt.FormatValue(b, w, pretty)
  1483  	}
  1484  
  1485  	return nil, fmt.Errorf("'%s' restrict type to unformatable type '%T'", t.Name, t.Type)
  1486  }
  1487  
  1488  // A BTFFuncType defines not a type, but a subprogram (function) whose signature is defined by type.
  1489  // The subprogram is thus an instance of that type.
  1490  // The KIND_FUNC may in turn be referenced by a func_info in the 4.2 .BTF.ext section (ELF) or in the arguments
  1491  // to 3.3 BPF_PROG_LOAD (ABI).
  1492  type BTFFuncType struct {
  1493  	commonType
  1494  }
  1495  
  1496  func (t *BTFFuncType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1497  	vlen := uint16(0)
  1498  	if kernelsupport.CurrentFeatures.Misc.Has(kernelsupport.KFeatBTFFuncScope) {
  1499  		vlen = t.VLen
  1500  	}
  1501  
  1502  	return (commonType{
  1503  		Name:     t.Name,
  1504  		KindFlag: 0,
  1505  		Kind:     BTF_KIND_FUNC,
  1506  		VLen:     vlen,
  1507  		sizeType: uint32(t.Type.GetID()), // TODO resolve ID based on index in BTF.Types
  1508  	}.ToBTFType(strTbl).ToBytes(order)), nil
  1509  }
  1510  
  1511  type BTFFuncProtoType struct {
  1512  	commonType
  1513  	Params []BTFFuncProtoParam
  1514  }
  1515  
  1516  func (t *BTFFuncProtoType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1517  	var buf bytes.Buffer
  1518  
  1519  	buf.Write((commonType{
  1520  		Name:     t.Name,
  1521  		KindFlag: t.KindFlag,
  1522  		Kind:     BTF_KIND_FUNC_PROTO,
  1523  		VLen:     uint16(len(t.Params)),
  1524  		sizeType: uint32(t.Type.GetID()),
  1525  	}.ToBTFType(strTbl).ToBytes(order)))
  1526  
  1527  	for _, param := range t.Params {
  1528  		buf.Write(uint32sToBytes(
  1529  			order,
  1530  			uint32(strTbl.StrToOffset(param.Name)),
  1531  		))
  1532  
  1533  		if param.Type == nil {
  1534  			buf.Write(uint32sToBytes(
  1535  				order,
  1536  				0,
  1537  			))
  1538  		} else {
  1539  			buf.Write(uint32sToBytes(
  1540  				order,
  1541  				uint32(param.Type.GetID()),
  1542  			))
  1543  		}
  1544  	}
  1545  
  1546  	return buf.Bytes(), nil
  1547  }
  1548  
  1549  type BTFFuncProtoParam struct {
  1550  	Name   string
  1551  	Type   BTFType
  1552  	typeID uint32
  1553  }
  1554  
  1555  type BTFVarType struct {
  1556  	commonType
  1557  	Linkage uint32
  1558  }
  1559  
  1560  func (t *BTFVarType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1561  	commonBytes := (commonType{
  1562  		Name:     t.Name,
  1563  		KindFlag: 0,
  1564  		Kind:     BTF_KIND_VAR,
  1565  		VLen:     0,
  1566  		sizeType: uint32(t.Type.GetID()),
  1567  	}.ToBTFType(strTbl).ToBytes(order))
  1568  
  1569  	return append(commonBytes, uint32sToBytes(order, t.Linkage)...), nil
  1570  }
  1571  
  1572  func (t *BTFVarType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1573  	if bfmt, ok := t.Type.(BTFValueFormater); ok {
  1574  		return bfmt.FormatValue(b, w, pretty)
  1575  	}
  1576  
  1577  	return nil, fmt.Errorf("'%s' variable to unformatable type '%T'", t.Name, t.Type)
  1578  }
  1579  
  1580  type BTFDataSecType struct {
  1581  	commonType
  1582  	Variables []BTFDataSecVariable
  1583  
  1584  	// Offset from the start of the types byte slice to the SizeType field
  1585  	sizeOffset int
  1586  }
  1587  
  1588  func (t *BTFDataSecType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1589  	var buf bytes.Buffer
  1590  
  1591  	buf.Write((commonType{
  1592  		Name:     t.Name,
  1593  		KindFlag: 0,
  1594  		Kind:     BTF_KIND_DATASEC,
  1595  		VLen:     uint16(len(t.Variables)),
  1596  		sizeType: t.Size,
  1597  	}.ToBTFType(strTbl).ToBytes(order)))
  1598  
  1599  	for _, v := range t.Variables {
  1600  		buf.Write(uint32sToBytes(
  1601  			order,
  1602  			uint32(v.Type.GetID()),
  1603  			v.Offset,
  1604  			v.Size,
  1605  		))
  1606  	}
  1607  
  1608  	return buf.Bytes(), nil
  1609  }
  1610  
  1611  type BTFDataSecVariable struct {
  1612  	Type   BTFType
  1613  	typeID uint32
  1614  	Offset uint32
  1615  	Size   uint32
  1616  
  1617  	// Offset from the start of the types byte slice to the Offset field
  1618  	offsetOffset int
  1619  }
  1620  
  1621  var _ BTFValueFormater = (*BTFFloatType)(nil)
  1622  
  1623  type BTFFloatType struct {
  1624  	commonType
  1625  }
  1626  
  1627  func (t *BTFFloatType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1628  	return (commonType{
  1629  		Name:     t.Name,
  1630  		KindFlag: 0,
  1631  		Kind:     BTF_KIND_FLOAT,
  1632  		VLen:     0,
  1633  		sizeType: t.Size,
  1634  	}.ToBTFType(strTbl).ToBytes(order)), nil
  1635  }
  1636  
  1637  func (t *BTFFloatType) FormatValue(b []byte, w io.Writer, pretty bool) ([]byte, error) {
  1638  	if len(b) < int(t.Size) {
  1639  		return nil, fmt.Errorf("%s not enough bytes to decode float of size '%d'", t.Name, t.Size)
  1640  	}
  1641  
  1642  	switch t.Size {
  1643  	case 2:
  1644  		// Go doesn't have native 16 bit floating point numbers, maybe use https://pkg.go.dev/github.com/x448/float16?
  1645  		// Then again, how common is this?
  1646  		return nil, fmt.Errorf("%s ieee754 binary16 floating point not supported", t.Name)
  1647  
  1648  	case 4:
  1649  		bits := binary.LittleEndian.Uint32(b[:4])
  1650  		float := math.Float32frombits(bits)
  1651  		_, err := fmt.Fprint(w, strconv.FormatFloat(float64(float), 'g', -1, 32))
  1652  		if err != nil {
  1653  			return nil, fmt.Errorf("%s write error: %w", t.Name, err)
  1654  		}
  1655  
  1656  		return b[4:], nil
  1657  
  1658  	case 8:
  1659  		bits := binary.LittleEndian.Uint32(b[:8])
  1660  		float := math.Float32frombits(bits)
  1661  		_, err := fmt.Fprint(w, strconv.FormatFloat(float64(float), 'g', -1, 64))
  1662  		if err != nil {
  1663  			return nil, fmt.Errorf("%s write error: %w", t.Name, err)
  1664  		}
  1665  
  1666  		return b[8:], nil
  1667  
  1668  	case 16:
  1669  		// Go doesn't have native 128 bit floating point numbers, can we use big.Int here?
  1670  		// Then again, how common is this?
  1671  		return nil, fmt.Errorf("%s ieee754 binary128 floating point not supported", t.Name)
  1672  	}
  1673  
  1674  	return nil, fmt.Errorf("%s '%d'-byte floating point number not supported", t.Name, t.Size)
  1675  }
  1676  
  1677  // BTFDeclTagType The name_off encodes btf_decl_tag attribute string.
  1678  // The type should be struct, union, func, var or typedef.
  1679  // For var or typedef type, btf_decl_tag.component_idx must be -1.
  1680  // For the other three types, if the btf_decl_tag attribute is applied to the struct,
  1681  // union or func itself, btf_decl_tag.component_idx must be -1.
  1682  // Otherwise, the attribute is applied to a struct/union member or a func argument,
  1683  // and btf_decl_tag.component_idx should be a valid index (starting from 0) pointing to a member or an argument.
  1684  type BTFDeclTagType struct {
  1685  	commonType
  1686  	ComponentIdx uint32
  1687  }
  1688  
  1689  func (t *BTFDeclTagType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1690  	commonBytes := (commonType{
  1691  		Name:     t.Name,
  1692  		KindFlag: 0,
  1693  		Kind:     BTF_KIND_DECL_TAG,
  1694  		VLen:     0,
  1695  		sizeType: uint32(t.Type.GetID()),
  1696  	}.ToBTFType(strTbl).ToBytes(order))
  1697  
  1698  	return append(commonBytes, uint32sToBytes(order, t.ComponentIdx)...), nil
  1699  }
  1700  
  1701  // BTFVoidType is not an actual type in BTF, it is used as type ID 0.
  1702  type BTFVoidType struct{}
  1703  
  1704  func (vt *BTFVoidType) GetID() int {
  1705  	return 0
  1706  }
  1707  
  1708  func (vt *BTFVoidType) GetKind() BTFKind {
  1709  	return BTF_KIND_UNKN
  1710  }
  1711  
  1712  func (vt *BTFVoidType) GetName() string {
  1713  	return ""
  1714  }
  1715  
  1716  func (vt *BTFVoidType) Serialize(strTbl *StringTbl, order binary.ByteOrder) ([]byte, error) {
  1717  	return nil, nil
  1718  }
  1719  
  1720  // BTFKind is an enum indicating what kind of type is indicated
  1721  type BTFKind uint8
  1722  
  1723  const (
  1724  	// BTF_KIND_UNKN Unknown
  1725  	BTF_KIND_UNKN BTFKind = iota
  1726  	// BTF_KIND_INT Integer
  1727  	BTF_KIND_INT
  1728  	// BTF_KIND_PTR Pointer
  1729  	BTF_KIND_PTR
  1730  	// BTF_KIND_ARRAY Array
  1731  	BTF_KIND_ARRAY
  1732  	// BTF_KIND_STRUCT Struct
  1733  	BTF_KIND_STRUCT
  1734  	// BTF_KIND_UNION Union
  1735  	BTF_KIND_UNION
  1736  	// BTF_KIND_ENUM Enumeration
  1737  	BTF_KIND_ENUM
  1738  	// BTF_KIND_FWD Forward
  1739  	BTF_KIND_FWD
  1740  	// BTF_KIND_TYPEDEF Typedef
  1741  	BTF_KIND_TYPEDEF
  1742  	// BTF_KIND_VOLATILE Volatile
  1743  	BTF_KIND_VOLATILE
  1744  	// BTF_KIND_CONST Const
  1745  	BTF_KIND_CONST
  1746  	// BTF_KIND_RESTRICT Restrict
  1747  	BTF_KIND_RESTRICT
  1748  	// BTF_KIND_FUNC Function
  1749  	BTF_KIND_FUNC
  1750  	// BTF_KIND_FUNC_PROTO Function Proto
  1751  	BTF_KIND_FUNC_PROTO
  1752  	// BTF_KIND_VAR Variable
  1753  	BTF_KIND_VAR
  1754  	// BTF_KIND_DATASEC Section
  1755  	BTF_KIND_DATASEC
  1756  	// BTF_KIND_FLOAT Floating point
  1757  	BTF_KIND_FLOAT
  1758  	// BTF_KIND_DECL_TAG Decl Tag
  1759  	BTF_KIND_DECL_TAG
  1760  
  1761  	// Not an actual value, must always be last in const block
  1762  	//nolint:deadcode,varcheck // used in unit test
  1763  	btfKindMax
  1764  )
  1765  
  1766  var btfKindToStr = map[BTFKind]string{
  1767  	BTF_KIND_UNKN:       "Unknown",
  1768  	BTF_KIND_INT:        "Integer",
  1769  	BTF_KIND_PTR:        "Pointer",
  1770  	BTF_KIND_ARRAY:      "Array",
  1771  	BTF_KIND_STRUCT:     "Struct",
  1772  	BTF_KIND_UNION:      "Union",
  1773  	BTF_KIND_ENUM:       "Enumeration",
  1774  	BTF_KIND_FWD:        "Forward",
  1775  	BTF_KIND_TYPEDEF:    "Typedef",
  1776  	BTF_KIND_VOLATILE:   "Volatile",
  1777  	BTF_KIND_CONST:      "Const",
  1778  	BTF_KIND_RESTRICT:   "Restrict",
  1779  	BTF_KIND_FUNC:       "Function",
  1780  	BTF_KIND_FUNC_PROTO: "Proto function",
  1781  	BTF_KIND_VAR:        "Variable",
  1782  	BTF_KIND_DATASEC:    "Data section",
  1783  	BTF_KIND_FLOAT:      "Floating point",
  1784  	BTF_KIND_DECL_TAG:   "Decl tag",
  1785  }
  1786  
  1787  func (bk BTFKind) String() string {
  1788  	return btfKindToStr[bk]
  1789  }
  1790  
  1791  // The length of the Magic, Version, Flags, and HeaderLength fields
  1792  const commonLength = 8
  1793  
  1794  // commonHeader is shared between the .BTF header and .BTF.ext header
  1795  type commonHeader struct {
  1796  	// Magic is always 0xeB9F, can be used to tell if the data is little or bigendian
  1797  	Magic     uint16
  1798  	byteOrder binary.ByteOrder
  1799  	// BTF version number
  1800  	Version uint8
  1801  	// Flags is unused (AFAIK)
  1802  	Flags uint8
  1803  	// HeaderLength is the size of this struct. Here for forwards/backwards compatibility since the size of this
  1804  	// header may change in the future.
  1805  	HeaderLength uint32
  1806  }
  1807  
  1808  // Magic number of BTF
  1809  // https://elixir.bootlin.com/linux/v5.15.3/source/include/uapi/linux/btf.h#L8
  1810  const btfMagic = 0xEB9F
  1811  
  1812  func parseCommonHeader(btf []byte) (commonHeader, uint32, error) {
  1813  	btfLen := len(btf)
  1814  	if btfLen < 8 {
  1815  		return commonHeader{}, 0, errors.New("not enough bytes to parse BTF header")
  1816  	}
  1817  
  1818  	hdr := commonHeader{
  1819  		byteOrder: binary.LittleEndian,
  1820  	}
  1821  	off := 0
  1822  
  1823  	read8 := func() uint8 {
  1824  		v := btf[off]
  1825  		off = off + 1
  1826  		return v
  1827  	}
  1828  	read32 := func() uint32 {
  1829  		v := hdr.byteOrder.Uint32(btf[off : off+4])
  1830  		off = off + 4
  1831  		return v
  1832  	}
  1833  
  1834  	magic := hdr.byteOrder.Uint16(btf[off : off+2])
  1835  	// If the read magic number doesn't match, switch encoding
  1836  	if magic != btfMagic {
  1837  		hdr.byteOrder = binary.BigEndian
  1838  
  1839  		// Read it again, if it still doesn't match the data is not right
  1840  		magic = hdr.byteOrder.Uint16(btf[off : off+2])
  1841  		if magic != btfMagic {
  1842  			return commonHeader{}, 0, errors.New("byte sequence doesn't contain valid BTF magic number")
  1843  		}
  1844  	}
  1845  	off += 2
  1846  
  1847  	// Set outside init, since the code is order dependant, and I don't know if struct init happens in defined order.
  1848  	hdr.Version = read8()
  1849  	hdr.Flags = read8()
  1850  	hdr.HeaderLength = read32()
  1851  
  1852  	return hdr, commonLength, nil
  1853  }
  1854  
  1855  // btfHeader is the header of the ELF .BTF section
  1856  type btfHeader struct {
  1857  	commonHeader
  1858  
  1859  	// The offset from the end of this header to the start of the type info
  1860  	TypeOffset uint32
  1861  	// The amount of bytes of type info there is
  1862  	TypeLength uint32
  1863  	// The offset for the end of this header to the start fo the strings
  1864  	StringOffset uint32
  1865  	// The length of the strings
  1866  	StringLength uint32
  1867  }
  1868  
  1869  // parseBTFHeader parses the .BTF header of an ELF file, it returns the header, and the amount of bytes read.
  1870  // Or it resturn only an error.
  1871  func parseBTFHeader(btf []byte) (*btfHeader, uint32, error) {
  1872  	var err error
  1873  	hdr := btfHeader{}
  1874  	off := uint32(0)
  1875  
  1876  	hdr.commonHeader, off, err = parseCommonHeader(btf)
  1877  	if err != nil {
  1878  		return nil, off, fmt.Errorf("parse common header: %w", err)
  1879  	}
  1880  
  1881  	btfLen := len(btf)
  1882  	if btfLen < int(hdr.HeaderLength)-commonLength {
  1883  		return nil, off, errors.New("byte sequence smaller than indicated header size")
  1884  	}
  1885  
  1886  	read32 := func() uint32 {
  1887  		v := hdr.byteOrder.Uint32(btf[off : off+4])
  1888  		off = off + 4
  1889  		return v
  1890  	}
  1891  
  1892  	hdr.TypeOffset = read32()
  1893  	hdr.TypeLength = read32()
  1894  	hdr.StringOffset = read32()
  1895  	hdr.StringLength = read32()
  1896  
  1897  	// Return slice of indicated length, in case it is longer than the struct we know
  1898  	return &hdr, hdr.HeaderLength, nil
  1899  }
  1900  
  1901  // btfExtHeader is the header of the ELF .BTF.ext section
  1902  type btfExtHeader struct {
  1903  	commonHeader
  1904  
  1905  	// The offset from the end of this header to the start of the func info
  1906  	FuncOffset uint32
  1907  	// The amount of bytes of func info there is
  1908  	FuncLength uint32
  1909  	// The offset for the end of this header to the start fo the lines
  1910  	LineOffset uint32
  1911  	// The length of the lines
  1912  	LineLength uint32
  1913  }
  1914  
  1915  // parseBTFExtHeader parses the .BTF.ext header of an ELF File, it return the header and the amount of bytes read,
  1916  // or and error
  1917  func parseBTFExtHeader(btf []byte) (*btfExtHeader, uint32, error) {
  1918  	var err error
  1919  	hdr := btfExtHeader{}
  1920  	off := uint32(0)
  1921  
  1922  	hdr.commonHeader, off, err = parseCommonHeader(btf)
  1923  	if err != nil {
  1924  		return nil, off, fmt.Errorf("parse common header: %w", err)
  1925  	}
  1926  
  1927  	btfLen := len(btf)
  1928  	if btfLen < int(hdr.HeaderLength)-commonLength {
  1929  		return nil, off, errors.New("byte sequence smaller than indicated header size")
  1930  	}
  1931  
  1932  	read32 := func() uint32 {
  1933  		v := hdr.byteOrder.Uint32(btf[off : off+4])
  1934  		off = off + 4
  1935  		return v
  1936  	}
  1937  
  1938  	hdr.FuncOffset = read32()
  1939  	hdr.FuncLength = read32()
  1940  	hdr.LineOffset = read32()
  1941  	hdr.LineLength = read32()
  1942  
  1943  	// Return slice of indicated length, in case it is longer than the struct we know
  1944  	return &hdr, hdr.HeaderLength, nil
  1945  }
  1946  
  1947  // btfType is the type as you would find it on disk
  1948  type btfType struct {
  1949  	NameOffset uint32
  1950  
  1951  	/* "info" bits arrangement
  1952  	 * bits  0-15: vlen (e.g. # of struct's members)
  1953  	 * bits 16-23: unused
  1954  	 * bits 24-28: kind (e.g. int, ptr, array...etc)
  1955  	 * bits 29-30: unused
  1956  	 * bit     31: kind_flag, currently used by
  1957  	 *             struct, union and fwd
  1958  	 */
  1959  	Info uint32
  1960  
  1961  	// SizeType is a union of "size" and "type"
  1962  	// "size" is used by INT, ENUM, STRUCT and UNION.
  1963  	// "size" tells the size of the type it is describing.
  1964  	//
  1965  	// "type" is used by PTR, TYPEDEF, VOLATILE, CONST, RESTRICT,
  1966  	// FUNC, FUNC_PROTO and DECL_TAG.
  1967  	// "type" is a type_id referring to another type.
  1968  	//
  1969  	SizeType uint32
  1970  }
  1971  
  1972  func (bt btfType) ToCommonType(strTbl *StringTbl) commonType {
  1973  	// TODO add links to clarify shifts and masks
  1974  	return commonType{
  1975  		Name:     strTbl.GetStringAtOffset(int(bt.NameOffset)),
  1976  		VLen:     uint16((bt.Info) & 0xffff),
  1977  		Kind:     BTFKind(((bt.Info) >> 24) & 0x1f),
  1978  		KindFlag: uint8(bt.Info >> 31),
  1979  		sizeType: bt.SizeType,
  1980  	}
  1981  }
  1982  
  1983  func (bt btfType) ToBytes(order binary.ByteOrder) []byte {
  1984  	ret := make([]byte, 12)
  1985  	order.PutUint32(ret[0:4], bt.NameOffset)
  1986  	order.PutUint32(ret[4:8], bt.Info)
  1987  	order.PutUint32(ret[8:12], bt.SizeType)
  1988  	return ret
  1989  }
  1990  
  1991  type commonType struct {
  1992  	Name     string
  1993  	VLen     uint16
  1994  	Kind     BTFKind
  1995  	KindFlag uint8
  1996  	Type     BTFType
  1997  	Size     uint32
  1998  	sizeType uint32
  1999  	TypeID   int
  2000  }
  2001  
  2002  func (ct *commonType) GetKind() BTFKind {
  2003  	return ct.Kind
  2004  }
  2005  
  2006  func (ct *commonType) GetID() int {
  2007  	return ct.TypeID
  2008  }
  2009  
  2010  func (ct *commonType) GetName() string {
  2011  	return ct.Name
  2012  }
  2013  
  2014  func (ct commonType) ToBTFType(strTbl *StringTbl) btfType {
  2015  	bt := btfType{
  2016  		NameOffset: uint32(strTbl.StrToOffset(ct.Name)),
  2017  		Info: (uint32(ct.KindFlag&0b00000001) << 31) |
  2018  			(uint32(ct.Kind&0x1f) << 24) |
  2019  			uint32(ct.VLen),
  2020  		SizeType: ct.sizeType,
  2021  	}
  2022  	return bt
  2023  }
  2024  
  2025  func uint32sToBytes(bo binary.ByteOrder, ints ...uint32) []byte {
  2026  	b := make([]byte, 4*len(ints))
  2027  	for i := 0; i < len(ints); i++ {
  2028  		bo.PutUint32(b[i*4:(i+1)*4], ints[i])
  2029  	}
  2030  	return b
  2031  }