...

Source file src/github.com/cilium/ebpf/btf/format.go

Documentation: github.com/cilium/ebpf/btf

     1  package btf
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"strings"
     7  )
     8  
     9  var errNestedTooDeep = errors.New("nested too deep")
    10  
    11  // GoFormatter converts a Type to Go syntax.
    12  //
    13  // A zero GoFormatter is valid to use.
    14  type GoFormatter struct {
    15  	w strings.Builder
    16  
    17  	// Types present in this map are referred to using the given name if they
    18  	// are encountered when outputting another type.
    19  	Names map[Type]string
    20  
    21  	// Identifier is called for each field of struct-like types. By default the
    22  	// field name is used as is.
    23  	Identifier func(string) string
    24  
    25  	// EnumIdentifier is called for each element of an enum. By default the
    26  	// name of the enum type is concatenated with Identifier(element).
    27  	EnumIdentifier func(name, element string) string
    28  }
    29  
    30  // TypeDeclaration generates a Go type declaration for a BTF type.
    31  func (gf *GoFormatter) TypeDeclaration(name string, typ Type) (string, error) {
    32  	gf.w.Reset()
    33  	if err := gf.writeTypeDecl(name, typ); err != nil {
    34  		return "", err
    35  	}
    36  	return gf.w.String(), nil
    37  }
    38  
    39  func (gf *GoFormatter) identifier(s string) string {
    40  	if gf.Identifier != nil {
    41  		return gf.Identifier(s)
    42  	}
    43  
    44  	return s
    45  }
    46  
    47  func (gf *GoFormatter) enumIdentifier(name, element string) string {
    48  	if gf.EnumIdentifier != nil {
    49  		return gf.EnumIdentifier(name, element)
    50  	}
    51  
    52  	return name + gf.identifier(element)
    53  }
    54  
    55  // writeTypeDecl outputs a declaration of the given type.
    56  //
    57  // It encodes https://golang.org/ref/spec#Type_declarations:
    58  //
    59  //     type foo struct { bar uint32; }
    60  //     type bar int32
    61  func (gf *GoFormatter) writeTypeDecl(name string, typ Type) error {
    62  	if name == "" {
    63  		return fmt.Errorf("need a name for type %s", typ)
    64  	}
    65  
    66  	switch v := skipQualifiers(typ).(type) {
    67  	case *Enum:
    68  		fmt.Fprintf(&gf.w, "type %s ", name)
    69  		switch v.Size {
    70  		case 1:
    71  			gf.w.WriteString("int8")
    72  		case 2:
    73  			gf.w.WriteString("int16")
    74  		case 4:
    75  			gf.w.WriteString("int32")
    76  		case 8:
    77  			gf.w.WriteString("int64")
    78  		default:
    79  			return fmt.Errorf("%s: invalid enum size %d", typ, v.Size)
    80  		}
    81  
    82  		if len(v.Values) == 0 {
    83  			return nil
    84  		}
    85  
    86  		gf.w.WriteString("; const ( ")
    87  		for _, ev := range v.Values {
    88  			id := gf.enumIdentifier(name, ev.Name)
    89  			fmt.Fprintf(&gf.w, "%s %s = %d; ", id, name, ev.Value)
    90  		}
    91  		gf.w.WriteString(")")
    92  
    93  		return nil
    94  
    95  	default:
    96  		fmt.Fprintf(&gf.w, "type %s ", name)
    97  		return gf.writeTypeLit(v, 0)
    98  	}
    99  }
   100  
   101  // writeType outputs the name of a named type or a literal describing the type.
   102  //
   103  // It encodes https://golang.org/ref/spec#Types.
   104  //
   105  //     foo                  (if foo is a named type)
   106  //     uint32
   107  func (gf *GoFormatter) writeType(typ Type, depth int) error {
   108  	typ = skipQualifiers(typ)
   109  
   110  	name := gf.Names[typ]
   111  	if name != "" {
   112  		gf.w.WriteString(name)
   113  		return nil
   114  	}
   115  
   116  	return gf.writeTypeLit(typ, depth)
   117  }
   118  
   119  // writeTypeLit outputs a literal describing the type.
   120  //
   121  // The function ignores named types.
   122  //
   123  // It encodes https://golang.org/ref/spec#TypeLit.
   124  //
   125  //     struct { bar uint32; }
   126  //     uint32
   127  func (gf *GoFormatter) writeTypeLit(typ Type, depth int) error {
   128  	depth++
   129  	if depth > maxTypeDepth {
   130  		return errNestedTooDeep
   131  	}
   132  
   133  	var err error
   134  	switch v := skipQualifiers(typ).(type) {
   135  	case *Int:
   136  		gf.writeIntLit(v)
   137  
   138  	case *Enum:
   139  		gf.w.WriteString("int32")
   140  
   141  	case *Typedef:
   142  		err = gf.writeType(v.Type, depth)
   143  
   144  	case *Array:
   145  		fmt.Fprintf(&gf.w, "[%d]", v.Nelems)
   146  		err = gf.writeType(v.Type, depth)
   147  
   148  	case *Struct:
   149  		err = gf.writeStructLit(v.Size, v.Members, depth)
   150  
   151  	case *Union:
   152  		// Always choose the first member to represent the union in Go.
   153  		err = gf.writeStructLit(v.Size, v.Members[:1], depth)
   154  
   155  	case *Datasec:
   156  		err = gf.writeDatasecLit(v, depth)
   157  
   158  	default:
   159  		return fmt.Errorf("type %T: %w", v, ErrNotSupported)
   160  	}
   161  
   162  	if err != nil {
   163  		return fmt.Errorf("%s: %w", typ, err)
   164  	}
   165  
   166  	return nil
   167  }
   168  
   169  func (gf *GoFormatter) writeIntLit(i *Int) {
   170  	// NB: Encoding.IsChar is ignored.
   171  	if i.Encoding.IsBool() && i.Size == 1 {
   172  		gf.w.WriteString("bool")
   173  		return
   174  	}
   175  
   176  	bits := i.Size * 8
   177  	if i.Encoding.IsSigned() {
   178  		fmt.Fprintf(&gf.w, "int%d", bits)
   179  	} else {
   180  		fmt.Fprintf(&gf.w, "uint%d", bits)
   181  	}
   182  }
   183  
   184  func (gf *GoFormatter) writeStructLit(size uint32, members []Member, depth int) error {
   185  	gf.w.WriteString("struct { ")
   186  
   187  	prevOffset := uint32(0)
   188  	skippedBitfield := false
   189  	for i, m := range members {
   190  		if m.BitfieldSize > 0 {
   191  			skippedBitfield = true
   192  			continue
   193  		}
   194  
   195  		offset := m.Offset.Bytes()
   196  		if n := offset - prevOffset; skippedBitfield && n > 0 {
   197  			fmt.Fprintf(&gf.w, "_ [%d]byte /* unsupported bitfield */; ", n)
   198  		} else {
   199  			gf.writePadding(n)
   200  		}
   201  
   202  		size, err := Sizeof(m.Type)
   203  		if err != nil {
   204  			return fmt.Errorf("field %d: %w", i, err)
   205  		}
   206  		prevOffset = offset + uint32(size)
   207  
   208  		if err := gf.writeStructField(m, depth); err != nil {
   209  			return fmt.Errorf("field %d: %w", i, err)
   210  		}
   211  	}
   212  
   213  	gf.writePadding(size - prevOffset)
   214  	gf.w.WriteString("}")
   215  	return nil
   216  }
   217  
   218  func (gf *GoFormatter) writeStructField(m Member, depth int) error {
   219  	if m.BitfieldSize > 0 {
   220  		return fmt.Errorf("bitfields are not supported")
   221  	}
   222  	if m.Offset%8 != 0 {
   223  		return fmt.Errorf("unsupported offset %d", m.Offset)
   224  	}
   225  
   226  	if m.Name == "" {
   227  		// Special case a nested anonymous union like
   228  		//     struct foo { union { int bar; int baz }; }
   229  		// by replacing the whole union with its first member.
   230  		union, ok := m.Type.(*Union)
   231  		if !ok {
   232  			return fmt.Errorf("anonymous fields are not supported")
   233  
   234  		}
   235  
   236  		if len(union.Members) == 0 {
   237  			return errors.New("empty anonymous union")
   238  		}
   239  
   240  		depth++
   241  		if depth > maxTypeDepth {
   242  			return errNestedTooDeep
   243  		}
   244  
   245  		m := union.Members[0]
   246  		size, err := Sizeof(m.Type)
   247  		if err != nil {
   248  			return err
   249  		}
   250  
   251  		if err := gf.writeStructField(m, depth); err != nil {
   252  			return err
   253  		}
   254  
   255  		gf.writePadding(union.Size - uint32(size))
   256  		return nil
   257  
   258  	}
   259  
   260  	fmt.Fprintf(&gf.w, "%s ", gf.identifier(m.Name))
   261  
   262  	if err := gf.writeType(m.Type, depth); err != nil {
   263  		return err
   264  	}
   265  
   266  	gf.w.WriteString("; ")
   267  	return nil
   268  }
   269  
   270  func (gf *GoFormatter) writeDatasecLit(ds *Datasec, depth int) error {
   271  	gf.w.WriteString("struct { ")
   272  
   273  	prevOffset := uint32(0)
   274  	for i, vsi := range ds.Vars {
   275  		v := vsi.Type.(*Var)
   276  		if v.Linkage != GlobalVar {
   277  			// Ignore static, extern, etc. for now.
   278  			continue
   279  		}
   280  
   281  		if v.Name == "" {
   282  			return fmt.Errorf("variable %d: empty name", i)
   283  		}
   284  
   285  		gf.writePadding(vsi.Offset - prevOffset)
   286  		prevOffset = vsi.Offset + vsi.Size
   287  
   288  		fmt.Fprintf(&gf.w, "%s ", gf.identifier(v.Name))
   289  
   290  		if err := gf.writeType(v.Type, depth); err != nil {
   291  			return fmt.Errorf("variable %d: %w", i, err)
   292  		}
   293  
   294  		gf.w.WriteString("; ")
   295  	}
   296  
   297  	gf.writePadding(ds.Size - prevOffset)
   298  	gf.w.WriteString("}")
   299  	return nil
   300  }
   301  
   302  func (gf *GoFormatter) writePadding(bytes uint32) {
   303  	if bytes > 0 {
   304  		fmt.Fprintf(&gf.w, "_ [%d]byte; ", bytes)
   305  	}
   306  }
   307  
   308  func skipQualifiers(typ Type) Type {
   309  	result := typ
   310  	for depth := 0; depth <= maxTypeDepth; depth++ {
   311  		switch v := (result).(type) {
   312  		case qualifier:
   313  			result = v.qualify()
   314  		default:
   315  			return result
   316  		}
   317  	}
   318  	return &cycle{typ}
   319  }
   320  

View as plain text