github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/pkg/compiler/types.go (about)

     1  // Copyright 2017 syzkaller project authors. All rights reserved.
     2  // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
     3  
     4  package compiler
     5  
     6  import (
     7  	"bytes"
     8  	"encoding/binary"
     9  	"fmt"
    10  	"sort"
    11  	"strconv"
    12  
    13  	"github.com/google/syzkaller/pkg/ast"
    14  	"github.com/google/syzkaller/prog"
    15  )
    16  
    17  // typeDesc is arg/field type descriptor.
    18  type typeDesc struct {
    19  	Names             []string
    20  	CanBeTypedef      bool            // can be type alias target?
    21  	CantBeOpt         bool            // can't be marked as opt?
    22  	CantBeOut         bool            // can't be used as an explicitly output argument?
    23  	CantHaveOut       bool            // everything inside can only be in
    24  	NeedBase          bool            // needs base type when used as field?
    25  	MaxColon          int             // max number of colons (int8:2) on fields
    26  	OptArgs           int             // number of optional arguments in Args array
    27  	Args              []namedArg      // type arguments
    28  	RequiresCallAttrs map[string]bool // calls using this type must have these attrs.
    29  	// CanBeArgRet returns if this type can be syscall argument/return (false if nil).
    30  	CanBeArgRet func(comp *compiler, t *ast.Type) (bool, bool)
    31  	// CanBeResourceBase returns if this type can be a resource base type (false if nil.
    32  	CanBeResourceBase func(comp *compiler, t *ast.Type) bool
    33  	// Check does custom verification of the type (optional, consts are not patched yet).
    34  	Check func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon)
    35  	// CheckConsts does custom verification of the type (optional, consts are patched).
    36  	CheckConsts func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon)
    37  	// Varlen returns if the type is variable-length (false if not set).
    38  	Varlen func(comp *compiler, t *ast.Type, args []*ast.Type) bool
    39  	// ZeroSize returns if the type has static 0 size (false if not set).
    40  	ZeroSize func(comp *compiler, t *ast.Type, args []*ast.Type) bool
    41  	// Gen generates corresponding prog.Type.
    42  	Gen func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type
    43  }
    44  
    45  // typeArg describes a type argument.
    46  type typeArg struct {
    47  	Names    []string
    48  	Kind     int // int/ident/string
    49  	MaxArgs  int // maxiumum number of subargs
    50  	MaxColon int // max number of colons (2:3:4)
    51  	// Check does custom verification of the arg (optional).
    52  	Check       func(comp *compiler, t *ast.Type)
    53  	CheckConsts func(comp *compiler, t *ast.Type)
    54  }
    55  
    56  type namedArg struct {
    57  	Name  string
    58  	Type  *typeArg
    59  	IsArg bool // does not need base type
    60  }
    61  
    62  const (
    63  	kindAny = 0
    64  	kindInt = 1 << iota
    65  	kindIdent
    66  	kindString
    67  )
    68  
    69  func canBeArg(comp *compiler, t *ast.Type) (bool, bool)    { return true, false }
    70  func canBeArgRet(comp *compiler, t *ast.Type) (bool, bool) { return true, true }
    71  
    72  var typeInt = &typeDesc{
    73  	Names:        typeArgBase.Type.Names,
    74  	CanBeArgRet:  canBeArg,
    75  	CanBeTypedef: true,
    76  	MaxColon:     1,
    77  	OptArgs:      2,
    78  	Args: []namedArg{
    79  		{Name: "value", Type: typeArgIntValue},
    80  		{Name: "align", Type: typeArgIntAlign},
    81  	},
    82  	CanBeResourceBase: func(comp *compiler, t *ast.Type) bool {
    83  		// Big-endian resources can always be converted to non-big-endian,
    84  		// since we will always revert bytes during copyout and during copyin,
    85  		// so the result is the same as not reverting at all.
    86  		// Big-endian resources are also not implemented and don't have tests.
    87  		_, be := comp.parseIntType(t.Ident)
    88  		return !be
    89  	},
    90  	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
    91  		typeArgBase.Type.Check(comp, t)
    92  		if len(args) > 1 && len(args[0].Colon) == 0 {
    93  			comp.error(args[1].Pos, "align argument of %v is not supported unless first argument is a range",
    94  				t.Ident)
    95  		}
    96  	},
    97  	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
    98  		if len(args) > 0 && len(args[0].Colon) != 0 {
    99  			begin := args[0].Value
   100  			end := args[0].Colon[0].Value
   101  			size, _ := comp.parseIntType(t.Ident)
   102  			size = size * 8
   103  			if len(t.Colon) != 0 {
   104  				// Integer is bitfield.
   105  				size = t.Colon[0].Value
   106  			}
   107  			maxUInt := uint64(1<<size - 1)
   108  			maxSInt := uint64(1<<(size-1) - 1)
   109  			if len(args) > 1 && begin == 0 && int64(end) == -1 {
   110  				// intN[0:-1, align] is a special value for 'all possible values', but aligned.
   111  				end = maxUInt
   112  			} else if end-begin > 1<<64-1<<32 {
   113  				comp.error(args[0].Pos, "bad int range [%v:%v]", begin, end)
   114  				return
   115  			}
   116  			// The range fits into the size if treated as unsigned [0:MAX_UINT].
   117  			inUnsignedBase := begin <= maxUInt && end <= maxUInt
   118  			// The range fits into the size if treated as signed [-MIN_SINT:MAX_SINT].
   119  			inSignedBase := begin+maxSInt <= maxUInt && end+maxSInt <= maxUInt
   120  			if size < 64 && !inUnsignedBase && !inSignedBase {
   121  				comp.error(args[0].Colon[0].Pos, "int range [%v:%v] is too large for base type of size %v",
   122  					begin, end, size)
   123  				return
   124  			}
   125  			if len(args) > 1 && args[1].Value != 0 && (end-begin)/args[1].Value == 0 {
   126  				comp.error(args[1].Pos, "int alignment %v is too large for range [%v:%v]",
   127  					args[1].Value, begin, end)
   128  			}
   129  		}
   130  	},
   131  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   132  		size, be := comp.parseIntType(t.Ident)
   133  		var bitLen uint64
   134  		if len(t.Colon) != 0 {
   135  			bitLen = t.Colon[0].Value
   136  		}
   137  		base.TypeSize = size
   138  		base.TypeAlign = getIntAlignment(comp, base)
   139  		base = genIntCommon(base.TypeCommon, bitLen, be)
   140  
   141  		kind, rangeBegin, rangeEnd, align := prog.IntPlain, uint64(0), uint64(0), uint64(0)
   142  		if len(args) > 0 {
   143  			rangeArg := args[0]
   144  			if _, isIntFlag := comp.intFlags[rangeArg.Ident]; isIntFlag {
   145  				return generateFlagsType(comp, base, rangeArg.Ident)
   146  			}
   147  			if len(rangeArg.Colon) == 0 {
   148  				// If we have an argument that is not a range, then it's a const.
   149  				return &prog.ConstType{
   150  					IntTypeCommon: base,
   151  					Val:           args[0].Value,
   152  				}
   153  			}
   154  			kind, rangeBegin, rangeEnd = prog.IntRange, rangeArg.Value, rangeArg.Colon[0].Value
   155  			if len(args) > 1 {
   156  				align = args[1].Value
   157  			}
   158  		}
   159  		return &prog.IntType{
   160  			IntTypeCommon: base,
   161  			Kind:          kind,
   162  			RangeBegin:    rangeBegin,
   163  			RangeEnd:      rangeEnd,
   164  			Align:         align,
   165  		}
   166  	},
   167  }
   168  
   169  func generateFlagsType(comp *compiler, base prog.IntTypeCommon, name string) prog.Type {
   170  	base.TypeName = name
   171  	f := comp.intFlags[name]
   172  	values := genIntArray(f.Values)
   173  	if len(values) == 0 || len(values) == 1 && values[0] == 0 {
   174  		// We can get this if all values are unsupported consts.
   175  		// Also generate const[0] if we have only 1 flags value which is 0,
   176  		// this is the intention in all existing cases (e.g. an enum with types
   177  		// of something, but there is really only 1 type exists).
   178  		return &prog.ConstType{
   179  			IntTypeCommon: base,
   180  			Val:           0,
   181  		}
   182  	}
   183  	sort.Slice(values, func(i, j int) bool {
   184  		return values[i] < values[j]
   185  	})
   186  	return &prog.FlagsType{
   187  		IntTypeCommon: base,
   188  		Vals:          values,
   189  		BitMask:       isBitmask(values),
   190  	}
   191  }
   192  
   193  func getIntAlignment(comp *compiler, base prog.IntTypeCommon) uint64 {
   194  	align := base.UnitSize()
   195  	if align == 8 && comp.target.Int64Alignment != 0 {
   196  		align = comp.target.Int64Alignment
   197  	}
   198  	return align
   199  }
   200  
   201  var typePtr = &typeDesc{
   202  	Names:        []string{"ptr", "ptr64"},
   203  	CanBeArgRet:  canBeArg,
   204  	CantBeOut:    true,
   205  	CanBeTypedef: true,
   206  	Args:         []namedArg{{Name: "direction", Type: typeArgDir}, {Name: "type", Type: typeArgType}},
   207  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   208  		base.TypeSize = comp.ptrSize
   209  		if t.Ident == "ptr64" {
   210  			base.TypeSize = 8
   211  		}
   212  		base.TypeAlign = getIntAlignment(comp, base)
   213  		elem := comp.genType(args[1], 0)
   214  		elemDir := genDir(args[0])
   215  		return &prog.PtrType{
   216  			TypeCommon: base.TypeCommon,
   217  			Elem:       elem,
   218  			ElemDir:    elemDir,
   219  		}
   220  	},
   221  }
   222  
   223  func isSquashableElem(elem prog.Type, dir prog.Dir) bool {
   224  	if dir != prog.DirIn {
   225  		return false
   226  	}
   227  	// Check if the pointer element contains something that can be complex, and does not contain
   228  	// anything unsupported we don't want to sqaush. Prog package later checks at runtime
   229  	// if a concrete arg actually contains something complex. But we look at the whole type
   230  	// to understand if it contains anything unsupported b/c a union may contain e.g. a complex struct
   231  	// and a filename we don't want to squash, or an array may contain something unsupported,
   232  	// but has 0 size in a concrete argument.
   233  	complex, unsupported := false, false
   234  	prog.ForeachArgType(elem, func(t prog.Type, ctx *prog.TypeCtx) {
   235  		switch typ := t.(type) {
   236  		case *prog.StructType:
   237  			if typ.Varlen() {
   238  				complex = true
   239  			}
   240  			if typ.OverlayField != 0 {
   241  				// Squashing of structs with out_overlay is not supported.
   242  				// If we do it, we need to be careful to either squash out part as well,
   243  				// or remove any resources in the out part from the prog.
   244  				unsupported = true
   245  			}
   246  		case *prog.UnionType:
   247  			if typ.Varlen() && len(typ.Fields) > 5 {
   248  				complex = true
   249  			}
   250  		case *prog.PtrType:
   251  			// Squashing of pointers is not supported b/c if we do it
   252  			// we will pass random garbage as pointers.
   253  			unsupported = true
   254  		case *prog.BufferType:
   255  			switch typ.Kind {
   256  			case prog.BufferFilename, prog.BufferGlob, prog.BufferCompressed:
   257  				// Squashing file names may lead to unwanted escaping paths (e.g. "/"),
   258  				// squashing compressed buffers is not useful since we uncompress them ourselves
   259  				// (not the kernel).
   260  				unsupported = true
   261  			}
   262  		}
   263  		ctx.Stop = unsupported
   264  	})
   265  	return complex && !unsupported
   266  }
   267  
   268  var typeVoid = &typeDesc{
   269  	Names:     []string{"void"},
   270  	CantBeOpt: true,
   271  	ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   272  		return true
   273  	},
   274  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   275  		base.TypeSize = 0 // the only type with static size 0
   276  		base.TypeAlign = 1
   277  		return &prog.BufferType{
   278  			TypeCommon: base.TypeCommon,
   279  			Kind:       prog.BufferBlobRange,
   280  			RangeBegin: 0,
   281  			RangeEnd:   0,
   282  		}
   283  	},
   284  }
   285  
   286  var typeArray = &typeDesc{
   287  	Names:        []string{"array"},
   288  	CanBeTypedef: true,
   289  	CantBeOpt:    true,
   290  	OptArgs:      1,
   291  	Args:         []namedArg{{Name: "type", Type: typeArgType}, {Name: "size", Type: typeArgSizeRange}},
   292  	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   293  		if len(args) > 1 && args[1].Value == 0 && (len(args[1].Colon) == 0 || args[1].Colon[0].Value == 0) {
   294  			comp.error(args[1].Pos, "arrays of size 0 are not supported")
   295  		}
   296  	},
   297  	Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   298  		if comp.isZeroSize(args[0]) {
   299  			return false
   300  		}
   301  		if comp.isVarlen(args[0]) {
   302  			return true
   303  		}
   304  		if len(args) > 1 {
   305  			return len(args[1].Colon) != 0 && args[1].Value != args[1].Colon[0].Value
   306  		}
   307  		return true
   308  	},
   309  	ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   310  		return comp.isZeroSize(args[0])
   311  	},
   312  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   313  		elemType := comp.genType(args[0], 0)
   314  		kind, begin, end := prog.ArrayRandLen, uint64(0), uint64(0)
   315  		if len(args) > 1 {
   316  			kind, begin, end = prog.ArrayRangeLen, args[1].Value, args[1].Value
   317  			if len(args[1].Colon) != 0 {
   318  				end = args[1].Colon[0].Value
   319  			}
   320  		}
   321  		if it, ok := elemType.(*prog.IntType); ok && it.Kind == prog.IntPlain && it.TypeSize == 1 {
   322  			// Special case: buffer is better mutated.
   323  			bufKind := prog.BufferBlobRand
   324  			base.TypeSize = 0
   325  			if kind == prog.ArrayRangeLen {
   326  				bufKind = prog.BufferBlobRange
   327  				if begin == end {
   328  					base.TypeSize = begin * elemType.Size()
   329  				}
   330  			}
   331  			base.TypeAlign = 1
   332  			return &prog.BufferType{
   333  				TypeCommon: base.TypeCommon,
   334  				Kind:       bufKind,
   335  				RangeBegin: begin,
   336  				RangeEnd:   end,
   337  			}
   338  		}
   339  		if ct, ok := elemType.(*prog.ConstType); ok &&
   340  			(ct.ArgFormat == prog.FormatNative || ct.ArgFormat == prog.FormatBigEndian) &&
   341  			kind == prog.ArrayRangeLen && begin == end {
   342  			// Special case: const string takes less space in C programs.
   343  			base.TypeSize = begin * ct.Size()
   344  			base.TypeAlign = ct.TypeAlign
   345  			val := make([]byte, 8)
   346  			if ct.ArgFormat == prog.FormatBigEndian {
   347  				binary.BigEndian.PutUint64(val, ct.Val)
   348  				val = val[8-ct.Size():]
   349  			} else {
   350  				binary.LittleEndian.PutUint64(val, ct.Val)
   351  				val = val[:ct.Size()]
   352  			}
   353  			val = bytes.Repeat(val, int(begin))
   354  			return &prog.BufferType{
   355  				TypeCommon: base.TypeCommon,
   356  				Kind:       prog.BufferString,
   357  				Values:     []string{string(val)},
   358  				NoZ:        true,
   359  			}
   360  		}
   361  		// TypeSize is assigned later in layoutArray.
   362  		base.TypeAlign = elemType.Alignment()
   363  		return &prog.ArrayType{
   364  			TypeCommon: base.TypeCommon,
   365  			Elem:       elemType,
   366  			Kind:       kind,
   367  			RangeBegin: begin,
   368  			RangeEnd:   end,
   369  		}
   370  	},
   371  }
   372  
   373  var typeLen = &typeDesc{
   374  	Names:       []string{"len", "bytesize", "bytesize2", "bytesize4", "bytesize8", "bitsize", "offsetof"},
   375  	CanBeArgRet: canBeArg,
   376  	CantBeOpt:   true,
   377  	CantBeOut:   true,
   378  	NeedBase:    true,
   379  	Args:        []namedArg{{Name: "len target", Type: typeArgLenTarget}},
   380  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   381  		var bitSize uint64
   382  		var offset bool
   383  		switch t.Ident {
   384  		case "bytesize":
   385  			bitSize = 8
   386  		case "bytesize2", "bytesize4", "bytesize8":
   387  			byteSize, _ := strconv.ParseUint(t.Ident[8:], 10, 8)
   388  			bitSize = byteSize * 8
   389  		case "bitsize":
   390  			bitSize = 1
   391  		case "offsetof":
   392  			bitSize = 8
   393  			offset = true
   394  		}
   395  		path := []string{args[0].Ident}
   396  		for _, col := range args[0].Colon {
   397  			path = append(path, col.Ident)
   398  		}
   399  		base.TypeAlign = getIntAlignment(comp, base)
   400  		return &prog.LenType{
   401  			IntTypeCommon: base,
   402  			Path:          path,
   403  			BitSize:       bitSize,
   404  			Offset:        offset,
   405  		}
   406  	},
   407  }
   408  
   409  var typeConst = &typeDesc{
   410  	Names:        []string{"const"},
   411  	CanBeArgRet:  canBeArg,
   412  	CanBeTypedef: true,
   413  	CantBeOpt:    true,
   414  	CantBeOut:    true,
   415  	NeedBase:     true,
   416  	Args:         []namedArg{{Name: "value", Type: typeArgInt}},
   417  	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   418  		v := args[0].Value
   419  		bitSize := base.TypeBitSize()
   420  		if constOverflowsBase(v, base) {
   421  			comp.error(args[0].Pos, "const val 0x%x does not fit into %v bits", v, bitSize)
   422  		}
   423  		args[0].Value = v & (uint64(1)<<bitSize - 1)
   424  	},
   425  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   426  		base.TypeAlign = getIntAlignment(comp, base)
   427  		return &prog.ConstType{
   428  			IntTypeCommon: base,
   429  			Val:           args[0].Value,
   430  		}
   431  	},
   432  }
   433  
   434  func constOverflowsBase(v uint64, base prog.IntTypeCommon) bool {
   435  	size := base.TypeBitSize()
   436  	if size == 64 {
   437  		return false
   438  	}
   439  	mask := uint64(1)<<size - 1
   440  	v1 := v & mask
   441  	if int64(v1<<(64-size)) < 0 && int64(v) < 0 {
   442  		v1 |= ^mask
   443  	}
   444  	return v1 != v
   445  }
   446  
   447  var typeArgLenTarget = &typeArg{
   448  	Kind:     kindIdent,
   449  	MaxColon: 10,
   450  }
   451  
   452  var typeFlags = &typeDesc{
   453  	Names:        []string{"flags"},
   454  	CanBeArgRet:  canBeArg,
   455  	CanBeTypedef: true,
   456  	CantBeOpt:    true,
   457  	CantBeOut:    true,
   458  	NeedBase:     true,
   459  	Args:         []namedArg{{Name: "flags", Type: typeArgFlags}},
   460  	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   461  		name := args[0].Ident
   462  		if name == "xdp_mmap_offsets" && comp.ptrSize == 4 {
   463  			// TODO(dvyukov): this sucks a lot. It seems that out 32-bit mmap is wrong.
   464  			// The syscall accepts number of pages as int32, but we pass offset in bytes.
   465  			// As the result large XDP consts don't fit into the arg.
   466  			return
   467  		}
   468  		f := comp.intFlags[name]
   469  		for _, val := range f.Values {
   470  			if constOverflowsBase(val.Value, base) {
   471  				comp.error(args[0].Pos, "%v %v=0x%x doesn't fit into %v bits",
   472  					name, val.Ident, val.Value, base.TypeBitSize())
   473  			}
   474  		}
   475  	},
   476  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   477  		base.TypeAlign = getIntAlignment(comp, base)
   478  		return generateFlagsType(comp, base, args[0].Ident)
   479  	},
   480  }
   481  
   482  func isBitmask(values []uint64) bool {
   483  	if values[0] == 0 {
   484  		// 0 can't be part of bitmask, this helps to handle important
   485  		// case like "0, 1" and "0, 1, 2" that would be detected
   486  		// as bitmask otherwise.
   487  		return false
   488  	}
   489  	var combined uint64
   490  	for _, v := range values {
   491  		if v&combined != 0 {
   492  			return false
   493  		}
   494  		combined |= v
   495  	}
   496  	return true
   497  }
   498  
   499  var typeArgFlags = &typeArg{
   500  	Kind: kindIdent,
   501  	Check: func(comp *compiler, t *ast.Type) {
   502  		if comp.intFlags[t.Ident] == nil {
   503  			comp.error(t.Pos, "unknown flags %v", t.Ident)
   504  			return
   505  		}
   506  	},
   507  }
   508  
   509  var typeVMA = &typeDesc{
   510  	Names:       []string{"vma", "vma64"},
   511  	CanBeArgRet: canBeArg,
   512  	OptArgs:     1,
   513  	Args:        []namedArg{{Name: "size range", Type: typeArgSizeRange}},
   514  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   515  		var begin, end uint64
   516  		if len(args) > 0 {
   517  			begin, end = args[0].Value, args[0].Value
   518  			if len(args[0].Colon) != 0 {
   519  				end = args[0].Colon[0].Value
   520  			}
   521  		}
   522  		base.TypeSize = comp.ptrSize
   523  		if t.Ident == "vma64" {
   524  			base.TypeSize = 8
   525  		}
   526  		base.TypeAlign = getIntAlignment(comp, base)
   527  		return &prog.VmaType{
   528  			TypeCommon: base.TypeCommon,
   529  			RangeBegin: begin,
   530  			RangeEnd:   end,
   531  		}
   532  	},
   533  }
   534  
   535  var typeCsum = &typeDesc{
   536  	Names:     []string{"csum"},
   537  	NeedBase:  true,
   538  	CantBeOpt: true,
   539  	CantBeOut: true,
   540  	OptArgs:   1,
   541  	Args: []namedArg{
   542  		{Name: "csum target", Type: typeArgLenTarget},
   543  		{Name: "kind", Type: typeArgCsumType},
   544  		{Name: "proto", Type: typeArgInt},
   545  	},
   546  	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   547  		if len(args) > 2 && genCsumKind(args[1]) != prog.CsumPseudo {
   548  			comp.error(args[2].Pos, "only pseudo csum can have proto")
   549  		}
   550  		if len(args[0].Colon) != 0 {
   551  			comp.error(args[0].Colon[0].Pos, "path expressions are not implemented for csum")
   552  		}
   553  	},
   554  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   555  		var proto uint64
   556  		if len(args) > 2 {
   557  			proto = args[2].Value
   558  		}
   559  		base.TypeAlign = getIntAlignment(comp, base)
   560  		return &prog.CsumType{
   561  			IntTypeCommon: base,
   562  			Buf:           args[0].Ident,
   563  			Kind:          genCsumKind(args[1]),
   564  			Protocol:      proto,
   565  		}
   566  	},
   567  }
   568  
   569  var typeArgCsumType = &typeArg{
   570  	Kind:  kindIdent,
   571  	Names: []string{"inet", "pseudo"},
   572  }
   573  
   574  func genCsumKind(t *ast.Type) prog.CsumKind {
   575  	switch t.Ident {
   576  	case "inet":
   577  		return prog.CsumInet
   578  	case "pseudo":
   579  		return prog.CsumPseudo
   580  	default:
   581  		panic(fmt.Sprintf("unknown csum kind %q", t.Ident))
   582  	}
   583  }
   584  
   585  var typeProc = &typeDesc{
   586  	Names:        []string{"proc"},
   587  	CanBeArgRet:  canBeArg,
   588  	CantBeOut:    true,
   589  	CanBeTypedef: true,
   590  	NeedBase:     true,
   591  	Args: []namedArg{
   592  		{Name: "range start", Type: typeArgInt},
   593  		{Name: "per-proc values", Type: typeArgInt},
   594  	},
   595  	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   596  		start := args[0].Value
   597  		perProc := args[1].Value
   598  		if perProc == 0 {
   599  			comp.error(args[1].Pos, "proc per-process values must not be 0")
   600  			return
   601  		}
   602  		size := base.TypeSize * 8
   603  		max := uint64(1) << size
   604  		if size == 64 {
   605  			max = ^uint64(0)
   606  		}
   607  		if start >= max {
   608  			comp.error(args[0].Pos, "values starting from %v overflow base type", start)
   609  		} else if perProc > (max-start)/prog.MaxPids {
   610  			comp.error(args[0].Pos, "values starting from %v with step %v overflow base type for %v procs",
   611  				start, perProc, prog.MaxPids)
   612  		}
   613  	},
   614  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   615  		base.TypeAlign = getIntAlignment(comp, base)
   616  		return &prog.ProcType{
   617  			IntTypeCommon: base,
   618  			ValuesStart:   args[0].Value,
   619  			ValuesPerProc: args[1].Value,
   620  		}
   621  	},
   622  }
   623  
   624  var typeText = &typeDesc{
   625  	Names:     []string{"text"},
   626  	CantBeOpt: true,
   627  	CantBeOut: true,
   628  	Args:      []namedArg{{Name: "kind", Type: typeArgTextType}},
   629  	Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   630  		return true
   631  	},
   632  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   633  		base.TypeSize = 0
   634  		base.TypeAlign = 1
   635  		return &prog.BufferType{
   636  			TypeCommon: base.TypeCommon,
   637  			Kind:       prog.BufferText,
   638  			Text:       genTextType(args[0]),
   639  		}
   640  	},
   641  }
   642  
   643  var typeArgTextType = &typeArg{
   644  	Kind:  kindIdent,
   645  	Names: []string{"target", "x86_real", "x86_16", "x86_32", "x86_64", "arm64", "ppc64"},
   646  }
   647  
   648  func genTextType(t *ast.Type) prog.TextKind {
   649  	switch t.Ident {
   650  	case "target":
   651  		return prog.TextTarget
   652  	case "x86_real":
   653  		return prog.TextX86Real
   654  	case "x86_16":
   655  		return prog.TextX86bit16
   656  	case "x86_32":
   657  		return prog.TextX86bit32
   658  	case "x86_64":
   659  		return prog.TextX86bit64
   660  	case "arm64":
   661  		return prog.TextArm64
   662  	case "ppc64":
   663  		return prog.TextPpc64
   664  	default:
   665  		panic(fmt.Sprintf("unknown text type %q", t.Ident))
   666  	}
   667  }
   668  
   669  const (
   670  	stringnoz = "stringnoz"
   671  	glob      = "glob"
   672  )
   673  
   674  var typeString = &typeDesc{
   675  	Names:        []string{"string", glob, stringnoz},
   676  	CanBeTypedef: true,
   677  	OptArgs:      2,
   678  	Args: []namedArg{
   679  		{Name: "literal or flags", Type: typeArgStringFlags},
   680  		{Name: "size", Type: typeArgInt},
   681  	},
   682  	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   683  		if t.Ident == stringnoz && len(args) > 1 {
   684  			comp.error(args[0].Pos, "fixed-size string can't be non-zero-terminated")
   685  		}
   686  		if t.Ident == glob && len(args) != 1 {
   687  			comp.error(t.Pos, "glob only accepts 1 arg, provided %v", len(args))
   688  		}
   689  	},
   690  	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   691  		if len(args) > 1 {
   692  			size := args[1].Value
   693  			vals := comp.genStrings(t, args)
   694  			for _, s := range vals {
   695  				if uint64(len(s)) > size {
   696  					comp.error(args[0].Pos, "string value %q exceeds buffer length %v",
   697  						s, size)
   698  				}
   699  			}
   700  		}
   701  	},
   702  	Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   703  		if t.Ident == glob {
   704  			return true
   705  		}
   706  		return comp.stringSize(t, args) == varlenString
   707  	},
   708  	ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   709  		return comp.stringSize(t, args) == 0
   710  	},
   711  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   712  		base.TypeAlign = 1
   713  		if len(args) > 0 && args[0].Ident == "filename" {
   714  			base.TypeName = "filename"
   715  			base.TypeSize = 0
   716  			if len(args) >= 2 {
   717  				base.TypeSize = args[1].Value
   718  			}
   719  			return &prog.BufferType{
   720  				TypeCommon: base.TypeCommon,
   721  				Kind:       prog.BufferFilename,
   722  				NoZ:        t.Ident == stringnoz,
   723  			}
   724  		}
   725  		if len(args) > 0 && t.Ident == glob {
   726  			base.TypeSize = 0
   727  			return &prog.BufferType{
   728  				TypeCommon: base.TypeCommon,
   729  				Kind:       prog.BufferGlob,
   730  				SubKind:    args[0].String,
   731  				NoZ:        false,
   732  			}
   733  		}
   734  		subkind := ""
   735  		if len(args) > 0 && args[0].Ident != "" {
   736  			subkind = args[0].Ident
   737  		}
   738  		vals := comp.genStrings(t, args)
   739  		base.TypeSize = comp.stringSize(t, args)
   740  		if base.TypeSize == varlenString {
   741  			base.TypeSize = 0
   742  		}
   743  		return &prog.BufferType{
   744  			TypeCommon: base.TypeCommon,
   745  			Kind:       prog.BufferString,
   746  			SubKind:    subkind,
   747  			Values:     vals,
   748  			NoZ:        t.Ident == stringnoz,
   749  		}
   750  	},
   751  }
   752  
   753  func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string {
   754  	var vals []string
   755  	if len(args) > 0 {
   756  		if args[0].HasString {
   757  			vals = append(vals, args[0].String)
   758  		} else {
   759  			vals = genStrArray(comp.strFlags[args[0].Ident].Values)
   760  		}
   761  	}
   762  	if t.Ident == stringnoz {
   763  		return vals
   764  	}
   765  	var size uint64
   766  	if len(args) > 1 {
   767  		size = args[1].Value
   768  	}
   769  	for i, s := range vals {
   770  		s += "\x00"
   771  		for uint64(len(s)) < size {
   772  			s += "\x00"
   773  		}
   774  		vals[i] = s
   775  	}
   776  	return vals
   777  }
   778  
   779  const varlenString = ^uint64(0)
   780  
   781  // stringSize returns static string size, or varlenString if it is variable length.
   782  func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 {
   783  	switch len(args) {
   784  	case 0:
   785  		return varlenString // a random string
   786  	case 1:
   787  		var z uint64
   788  		if t.Ident == "string" {
   789  			z = 1
   790  		}
   791  		if args[0].HasString {
   792  			return uint64(len(args[0].String)) + z // string constant
   793  		}
   794  		size := varlenString
   795  		for _, s := range comp.strFlags[args[0].Ident].Values {
   796  			s1 := uint64(len(s.Value)) + z
   797  			if size != varlenString && size != s1 {
   798  				return varlenString // strings of different lengths
   799  			}
   800  			size = s1
   801  		}
   802  		return size // all strings have the same length
   803  	case 2:
   804  		return args[1].Value // have explicit length
   805  	default:
   806  		panic("too many string args")
   807  	}
   808  }
   809  
   810  var typeArgStringFlags = &typeArg{
   811  	Kind: kindIdent | kindString,
   812  	Check: func(comp *compiler, t *ast.Type) {
   813  		if t.Ident != "" && comp.strFlags[t.Ident] == nil {
   814  			comp.error(t.Pos, "unknown string flags %v", t.Ident)
   815  			return
   816  		}
   817  	},
   818  }
   819  
   820  var typeFmt = &typeDesc{
   821  	Names:        []string{"fmt"},
   822  	CanBeTypedef: true,
   823  	CantBeOpt:    true,
   824  	CantBeOut:    true,
   825  	CantHaveOut:  true,
   826  	Args: []namedArg{
   827  		{Name: "format", Type: typeFmtFormat},
   828  		{Name: "value", Type: typeArgType, IsArg: true},
   829  	},
   830  	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
   831  		desc, _, _ := comp.getArgsBase(args[1], true)
   832  		switch desc {
   833  		case typeResource, typeInt, typeLen, typeFlags, typeProc:
   834  		default:
   835  			comp.error(t.Pos, "bad fmt value %v, expect an integer", args[1].Ident)
   836  			return
   837  		}
   838  	},
   839  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   840  		var format prog.BinaryFormat
   841  		var size uint64
   842  		switch args[0].Ident {
   843  		case "dec":
   844  			format = prog.FormatStrDec
   845  			size = 20
   846  		case "hex":
   847  			format = prog.FormatStrHex
   848  			size = 18
   849  		case "oct":
   850  			format = prog.FormatStrOct
   851  			size = 23
   852  		}
   853  		typ := comp.genType(args[1], comp.ptrSize)
   854  		switch t := typ.(type) {
   855  		case *prog.ResourceType:
   856  			t.ArgFormat = format
   857  			t.TypeSize = size
   858  			t.TypeAlign = 1
   859  		case *prog.IntType:
   860  			t.ArgFormat = format
   861  			t.TypeSize = size
   862  			t.TypeAlign = 1
   863  		case *prog.LenType:
   864  			t.ArgFormat = format
   865  			t.TypeSize = size
   866  			t.TypeAlign = 1
   867  		case *prog.FlagsType:
   868  			t.ArgFormat = format
   869  			t.TypeSize = size
   870  			t.TypeAlign = 1
   871  		case *prog.ProcType:
   872  			t.ArgFormat = format
   873  			t.TypeSize = size
   874  			t.TypeAlign = 1
   875  		case *prog.ConstType:
   876  			// We don't allow fmt[const] directly, but flags with only 1 value
   877  			// are transformed to ConstType.
   878  			t.ArgFormat = format
   879  			t.TypeSize = size
   880  			t.TypeAlign = 1
   881  		default:
   882  			panic(fmt.Sprintf("unexpected type: %#v", typ))
   883  		}
   884  		return typ
   885  	},
   886  }
   887  
   888  var typeFmtFormat = &typeArg{
   889  	Names: []string{"dec", "hex", "oct"},
   890  	Kind:  kindIdent,
   891  }
   892  
   893  // typeCompressedImage is used for compressed disk images.
   894  var typeCompressedImage = &typeDesc{
   895  	Names:     []string{"compressed_image"},
   896  	CantBeOpt: true,
   897  	CantBeOut: true,
   898  	RequiresCallAttrs: map[string]bool{
   899  		"no_generate": true,
   900  		"no_minimize": true,
   901  	},
   902  	CanBeArgRet: func(comp *compiler, t *ast.Type) (bool, bool) {
   903  		return true, false
   904  	},
   905  	Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   906  		return true
   907  	},
   908  	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   909  		base.TypeSize = 0
   910  		base.TypeAlign = 1
   911  		return &prog.BufferType{
   912  			TypeCommon: base.TypeCommon,
   913  			Kind:       prog.BufferCompressed,
   914  		}
   915  	},
   916  }
   917  
   918  // typeArgType is used as placeholder for any type (e.g. ptr target type).
   919  var typeArgType = &typeArg{}
   920  
   921  var typeResource = &typeDesc{
   922  	// No Names, but getTypeDesc knows how to match it.
   923  	CanBeArgRet: canBeArgRet,
   924  	CanBeResourceBase: func(comp *compiler, t *ast.Type) bool {
   925  		return true
   926  	},
   927  	// Gen is assigned below to avoid initialization loop.
   928  }
   929  
   930  func init() {
   931  	typeResource.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   932  		// Find and generate base type to get its size.
   933  		var baseType *ast.Type
   934  		for r := comp.resources[t.Ident]; r != nil; {
   935  			baseType = r.Base
   936  			r = comp.resources[r.Base.Ident]
   937  		}
   938  		baseProgType := comp.genType(baseType, 0)
   939  		base.TypeSize = baseProgType.Size()
   940  		base.TypeAlign = getIntAlignment(comp, base)
   941  		return &prog.ResourceType{
   942  			TypeCommon: base.TypeCommon,
   943  			ArgFormat:  baseProgType.Format(),
   944  		}
   945  	}
   946  }
   947  
   948  var typeStruct = &typeDesc{
   949  	// No Names, but getTypeDesc knows how to match it.
   950  	CantBeOpt:    true,
   951  	CanBeTypedef: true,
   952  	// Varlen/Gen are assigned below due to initialization cycle.
   953  }
   954  
   955  func init() {
   956  	typeStruct.CanBeArgRet = func(comp *compiler, t *ast.Type) (bool, bool) {
   957  		// Allow unions to be arg if all options can be arg.
   958  		s := comp.structs[t.Ident]
   959  		if !s.IsUnion {
   960  			return false, false
   961  		}
   962  		canBeArg := true
   963  		for _, fld := range s.Fields {
   964  			desc := comp.getTypeDesc(fld.Type)
   965  			if desc == nil || desc == typeStruct || desc.CanBeArgRet == nil {
   966  				return false, false
   967  			}
   968  			canBeArg1, _ := desc.CanBeArgRet(comp, fld.Type)
   969  			if !canBeArg1 {
   970  				canBeArg = false
   971  			}
   972  		}
   973  		return canBeArg, false
   974  	}
   975  	typeStruct.Varlen = func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   976  		return comp.structIsVarlen(t.Ident)
   977  	}
   978  	typeStruct.ZeroSize = func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
   979  		for _, fld := range comp.structs[t.Ident].Fields {
   980  			if !comp.isZeroSize(fld.Type) {
   981  				return false
   982  			}
   983  		}
   984  		return true
   985  	}
   986  	typeStruct.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
   987  		if typ := comp.structTypes[t.Ident]; typ != nil {
   988  			return typ
   989  		}
   990  		s := comp.structs[t.Ident]
   991  		common := genCommon(t.Ident, sizeUnassigned, false)
   992  		common.IsVarlen = typeStruct.Varlen(comp, t, args)
   993  		var typ prog.Type
   994  		if s.IsUnion {
   995  			typ = &prog.UnionType{
   996  				TypeCommon: common,
   997  			}
   998  		} else {
   999  			typ = &prog.StructType{
  1000  				TypeCommon: common,
  1001  			}
  1002  		}
  1003  		// Need to cache type in structTypes before generating fields to break recursion.
  1004  		comp.structTypes[t.Ident] = typ
  1005  		fields, overlayField := comp.genFieldArray(s.Fields, make([]uint64, len(s.Fields)))
  1006  		switch typ1 := typ.(type) {
  1007  		case *prog.UnionType:
  1008  			typ1.Fields = fields
  1009  			for _, f := range fields {
  1010  				if a := f.Type.Alignment(); typ1.TypeAlign < a {
  1011  					typ1.TypeAlign = a
  1012  				}
  1013  			}
  1014  		case *prog.StructType:
  1015  			typ1.Fields = fields
  1016  			for i, field := range fields {
  1017  				if field.Condition != nil {
  1018  					fields[i] = comp.wrapConditionalField(t.Ident, field)
  1019  				}
  1020  			}
  1021  			if overlayField >= 0 {
  1022  				typ1.OverlayField = overlayField
  1023  			}
  1024  			attrs := comp.parseIntAttrs(structAttrs, s, s.Attrs)
  1025  			if align := attrs[attrAlign]; align != 0 {
  1026  				typ1.TypeAlign = align
  1027  			} else if attrs[attrPacked] != 0 {
  1028  				typ1.TypeAlign = 1
  1029  			} else {
  1030  				for _, f := range fields {
  1031  					a := f.Type.Alignment()
  1032  					if typ1.TypeAlign < a {
  1033  						typ1.TypeAlign = a
  1034  					}
  1035  				}
  1036  			}
  1037  		}
  1038  		return typ
  1039  	}
  1040  }
  1041  
  1042  var typeTypedef = &typeDesc{
  1043  	// No Names, but getTypeDesc knows how to match it.
  1044  	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
  1045  		panic("must not be called")
  1046  	},
  1047  }
  1048  
  1049  var typeArgDir = &typeArg{
  1050  	Kind:  kindIdent,
  1051  	Names: []string{"in", "out", "inout"},
  1052  }
  1053  
  1054  func genDir(t *ast.Type) prog.Dir {
  1055  	switch t.Ident {
  1056  	case "in":
  1057  		return prog.DirIn
  1058  	case "out":
  1059  		return prog.DirOut
  1060  	case "inout":
  1061  		return prog.DirInOut
  1062  	default:
  1063  		panic(fmt.Sprintf("unknown direction %q", t.Ident))
  1064  	}
  1065  }
  1066  
  1067  var typeArgInt = &typeArg{
  1068  	Kind: kindInt,
  1069  }
  1070  
  1071  var typeArgIntValue = &typeArg{
  1072  	Kind:     kindInt | kindIdent,
  1073  	MaxColon: 1,
  1074  	CheckConsts: func(comp *compiler, t *ast.Type) {
  1075  		// If the first arg is not a range, then it should be a valid flags.
  1076  		if len(t.Colon) == 0 && t.Ident != "" && comp.intFlags[t.Ident] == nil {
  1077  			comp.error(t.Pos, "unknown flags %v", t.Ident)
  1078  			return
  1079  		}
  1080  	},
  1081  }
  1082  
  1083  var typeArgIntAlign = &typeArg{
  1084  	Kind:     kindInt,
  1085  	MaxColon: 0,
  1086  	CheckConsts: func(comp *compiler, t *ast.Type) {
  1087  		if t.Value <= 1 {
  1088  			comp.error(t.Pos, "bad int alignment %v", t.Value)
  1089  		}
  1090  	},
  1091  }
  1092  
  1093  // Size of array and vma's.
  1094  var typeArgSizeRange = &typeArg{
  1095  	Kind:     kindInt,
  1096  	MaxColon: 1,
  1097  	CheckConsts: func(comp *compiler, t *ast.Type) {
  1098  		end := t.Value
  1099  		if len(t.Colon) != 0 {
  1100  			end = t.Colon[0].Value
  1101  		}
  1102  		const maxVal = 1e6
  1103  		if t.Value > end || t.Value > maxVal || end > maxVal {
  1104  			comp.error(t.Pos, "bad size range [%v:%v]", t.Value, end)
  1105  		}
  1106  	},
  1107  }
  1108  
  1109  // Base type of const/len/etc. Same as typeInt, but can't have range.
  1110  var typeArgBase = namedArg{
  1111  	Name: "base type",
  1112  	Type: &typeArg{
  1113  		Names:    []string{"int8", "int16", "int32", "int64", "int16be", "int32be", "int64be", "intptr"},
  1114  		MaxColon: 1,
  1115  		Check: func(comp *compiler, t *ast.Type) {
  1116  			if len(t.Colon) != 0 {
  1117  				col := t.Colon[0]
  1118  				if col.Ident != "" {
  1119  					comp.error(col.Pos, "literal const bitfield sizes are not supported")
  1120  					return
  1121  				}
  1122  				if col.Value == 0 {
  1123  					// This was not supported historically
  1124  					// and does not work the way C bitfields of size 0 work.
  1125  					// We could allow this, but then we need to make
  1126  					// this work the way C bitfields work.
  1127  					comp.error(col.Pos, "bitfields of size 0 are not supported")
  1128  				}
  1129  				size, _ := comp.parseIntType(t.Ident)
  1130  				if col.Value > size*8 {
  1131  					comp.error(col.Pos, "bitfield of size %v is too large for base type of size %v",
  1132  						col.Value, size*8)
  1133  				}
  1134  			}
  1135  		},
  1136  	},
  1137  }
  1138  
  1139  var (
  1140  	builtinTypes = make(map[string]*typeDesc)
  1141  	builtinDescs *ast.Description
  1142  
  1143  	// To avoid weird cases like ptr[in, in] and ptr[out, opt].
  1144  	reservedName = map[string]bool{
  1145  		"opt":   true,
  1146  		"in":    true,
  1147  		"out":   true,
  1148  		"inout": true,
  1149  	}
  1150  )
  1151  
  1152  const builtinDefs = `
  1153  type bool8 int8[0:1]
  1154  type bool16 int16[0:1]
  1155  type bool32 int32[0:1]
  1156  type bool64 int64[0:1]
  1157  type boolptr intptr[0:1]
  1158  
  1159  type fileoff[BASE] BASE
  1160  
  1161  type filename string[filename]
  1162  filename = "", "."
  1163  
  1164  type buffer[DIR] ptr[DIR, array[int8]]
  1165  
  1166  type optional[T] [
  1167  	val	T
  1168  	void	void
  1169  ] [varlen]
  1170  
  1171  # prog/any.go knows layout of these types.
  1172  ANYUNION [
  1173  	ANYBLOB		array[int8]
  1174  	ANYRES8		ANYRES8
  1175  	ANYRES16	ANYRES16
  1176  	ANYRES32	ANYRES32
  1177  	ANYRES64	ANYRES64
  1178  	ANYRESDEC	fmt[dec, ANYRES64] (in)
  1179  	ANYRESHEX	fmt[hex, ANYRES64] (in)
  1180  	ANYRESOCT	fmt[oct, ANYRES64] (in)
  1181  ] [varlen]
  1182  
  1183  ANYPTRS [
  1184  	ANYPTR		ptr[inout, array[ANYUNION]]
  1185  	ANYPTR64	ptr64[inout, array[ANYUNION]]
  1186  ]
  1187  
  1188  resource ANYRES8[int8]: -1, 0
  1189  resource ANYRES16[int16]: -1, 0
  1190  resource ANYRES32[int32]: -1, 0
  1191  resource ANYRES64[int64]: -1, 0
  1192  
  1193  syz_builtin0(a ptr[in, ANYPTRS]) (disabled)
  1194  syz_builtin1(a ptr[inout, ANYUNION]) (disabled)
  1195  syz_builtin2() ANYRES8 (disabled)
  1196  syz_builtin3() ANYRES16 (disabled)
  1197  syz_builtin4() ANYRES32 (disabled)
  1198  syz_builtin5() ANYRES64 (disabled)
  1199  `
  1200  
  1201  func init() {
  1202  	builtins := []*typeDesc{
  1203  		typeInt,
  1204  		typePtr,
  1205  		typeVoid,
  1206  		typeArray,
  1207  		typeLen,
  1208  		typeConst,
  1209  		typeFlags,
  1210  		typeVMA,
  1211  		typeCsum,
  1212  		typeProc,
  1213  		typeText,
  1214  		typeString,
  1215  		typeFmt,
  1216  		typeCompressedImage,
  1217  	}
  1218  	for _, desc := range builtins {
  1219  		for _, name := range desc.Names {
  1220  			if builtinTypes[name] != nil {
  1221  				panic(fmt.Sprintf("duplicate builtin type %q", name))
  1222  			}
  1223  			builtinTypes[name] = desc
  1224  		}
  1225  	}
  1226  	builtinDescs = ast.Parse([]byte(builtinDefs), ast.BuiltinFile, func(pos ast.Pos, msg string) {
  1227  		panic(fmt.Sprintf("failed to parse builtins: %v: %v", pos, msg))
  1228  	})
  1229  }