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

     1  // Copyright 2015/2016 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 prog
     5  
     6  import (
     7  	"fmt"
     8  	"strings"
     9  	"unicode"
    10  )
    11  
    12  type Syscall struct {
    13  	ID          int
    14  	NR          uint64 // kernel syscall number
    15  	Name        string
    16  	CallName    string
    17  	MissingArgs int // number of trailing args that should be zero-filled
    18  	Args        []Field
    19  	Ret         Type
    20  	Attrs       SyscallAttrs
    21  
    22  	// Resources that are required for this call to be generated (in/inout).
    23  	inputResources []*ResourceDesc
    24  	// Resources that this call can be used to create (out, but excluding no_generate).
    25  	createsResources []*ResourceDesc
    26  	// Both inputs and output resources (including no_generate).
    27  	usesResources []*ResourceDesc
    28  }
    29  
    30  // SyscallAttrs represents call attributes in syzlang.
    31  //
    32  // This structure is the source of truth for the all other parts of the system.
    33  // pkg/compiler uses this structure to parse descriptions.
    34  // syz-sysgen uses this structure to generate code for executor.
    35  //
    36  // Only `bool`s and `uint64`s are currently supported.
    37  //
    38  // See docs/syscall_descriptions_syntax.md for description of individual attributes.
    39  type SyscallAttrs struct {
    40  	Disabled      bool
    41  	Timeout       uint64
    42  	ProgTimeout   uint64
    43  	IgnoreReturn  bool
    44  	BreaksReturns bool
    45  	NoGenerate    bool
    46  	NoMinimize    bool
    47  }
    48  
    49  // MaxArgs is maximum number of syscall arguments.
    50  // Executor also knows about this value.
    51  const MaxArgs = 9
    52  
    53  type Dir uint8
    54  
    55  const (
    56  	DirIn Dir = iota
    57  	DirOut
    58  	DirInOut
    59  )
    60  
    61  func (dir Dir) String() string {
    62  	switch dir {
    63  	case DirIn:
    64  		return "in"
    65  	case DirOut:
    66  		return "out"
    67  	case DirInOut:
    68  		return "inout"
    69  	default:
    70  		panic("unknown dir")
    71  	}
    72  }
    73  
    74  type Field struct {
    75  	Name string
    76  	Type
    77  	HasDirection bool
    78  	Direction    Dir
    79  	Condition    Expression
    80  }
    81  
    82  func (f *Field) Dir(def Dir) Dir {
    83  	if f.HasDirection {
    84  		return f.Direction
    85  	}
    86  	return def
    87  }
    88  
    89  type ArgFinder func(path []string) Arg
    90  
    91  // Special case reply of ArgFinder.
    92  var SquashedArgFound = &DataArg{}
    93  
    94  type Expression interface {
    95  	fmt.GoStringer
    96  	ForEachValue(func(*Value))
    97  	Clone() Expression
    98  	Evaluate(ArgFinder) (uint64, bool)
    99  }
   100  
   101  type BinaryOperator int
   102  
   103  const (
   104  	OperatorCompareEq BinaryOperator = iota
   105  	OperatorCompareNeq
   106  	OperatorBinaryAnd
   107  )
   108  
   109  type BinaryExpression struct {
   110  	Operator BinaryOperator
   111  	Left     Expression
   112  	Right    Expression
   113  }
   114  
   115  func (bo BinaryExpression) GoString() string {
   116  	return fmt.Sprintf("&prog.BinaryExpression{%#v,%#v,%#v}", bo.Operator, bo.Left, bo.Right)
   117  }
   118  
   119  func (bo BinaryExpression) ForEachValue(cb func(*Value)) {
   120  	bo.Left.ForEachValue(cb)
   121  	bo.Right.ForEachValue(cb)
   122  }
   123  
   124  func (bo *BinaryExpression) Clone() Expression {
   125  	return &BinaryExpression{
   126  		Operator: bo.Operator,
   127  		Left:     bo.Left.Clone(),
   128  		Right:    bo.Right.Clone(),
   129  	}
   130  }
   131  
   132  type Value struct {
   133  	// If Path is empty, Value is to be used.
   134  	Value uint64
   135  	// Path to the field.
   136  	Path []string
   137  }
   138  
   139  func (v Value) GoString() string {
   140  	return fmt.Sprintf("&prog.Value{%#v,%#v}", v.Value, v.Path)
   141  }
   142  
   143  func (v *Value) ForEachValue(cb func(*Value)) {
   144  	cb(v)
   145  }
   146  
   147  func (v *Value) Clone() Expression {
   148  	return &Value{v.Value, append([]string{}, v.Path...)}
   149  }
   150  
   151  type BinaryFormat int
   152  
   153  const (
   154  	FormatNative BinaryFormat = iota
   155  	FormatBigEndian
   156  	FormatStrDec
   157  	FormatStrHex
   158  	FormatStrOct
   159  )
   160  
   161  type Type interface {
   162  	String() string
   163  	Name() string
   164  	TemplateName() string // for template structs name without arguments
   165  	Optional() bool
   166  	Varlen() bool
   167  	Size() uint64
   168  	TypeBitSize() uint64
   169  	Alignment() uint64
   170  	Format() BinaryFormat
   171  	BitfieldOffset() uint64
   172  	BitfieldLength() uint64
   173  	IsBitfield() bool
   174  	// For most of the types UnitSize is equal to Size.
   175  	// These are different only for all but last bitfield in the group,
   176  	// where Size == 0 and UnitSize equals to the underlying bitfield type size.
   177  	UnitSize() uint64
   178  	UnitOffset() uint64
   179  
   180  	DefaultArg(dir Dir) Arg
   181  	isDefaultArg(arg Arg) bool
   182  	generate(r *randGen, s *state, dir Dir) (arg Arg, calls []*Call)
   183  	mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool)
   184  	getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool)
   185  	minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool
   186  	ref() Ref
   187  	setRef(ref Ref)
   188  }
   189  
   190  type Ref uint32
   191  
   192  func (ti Ref) String() string       { panic("prog.Ref method called") }
   193  func (ti Ref) Name() string         { panic("prog.Ref method called") }
   194  func (ti Ref) TemplateName() string { panic("prog.Ref method called") }
   195  
   196  func (ti Ref) Optional() bool                                        { panic("prog.Ref method called") }
   197  func (ti Ref) Varlen() bool                                          { panic("prog.Ref method called") }
   198  func (ti Ref) Size() uint64                                          { panic("prog.Ref method called") }
   199  func (ti Ref) TypeBitSize() uint64                                   { panic("prog.Ref method called") }
   200  func (ti Ref) Alignment() uint64                                     { panic("prog.Ref method called") }
   201  func (ti Ref) Format() BinaryFormat                                  { panic("prog.Ref method called") }
   202  func (ti Ref) BitfieldOffset() uint64                                { panic("prog.Ref method called") }
   203  func (ti Ref) BitfieldLength() uint64                                { panic("prog.Ref method called") }
   204  func (ti Ref) IsBitfield() bool                                      { panic("prog.Ref method called") }
   205  func (ti Ref) UnitSize() uint64                                      { panic("prog.Ref method called") }
   206  func (ti Ref) UnitOffset() uint64                                    { panic("prog.Ref method called") }
   207  func (ti Ref) DefaultArg(dir Dir) Arg                                { panic("prog.Ref method called") }
   208  func (ti Ref) Clone() Type                                           { panic("prog.Ref method called") }
   209  func (ti Ref) isDefaultArg(arg Arg) bool                             { panic("prog.Ref method called") }
   210  func (ti Ref) generate(r *randGen, s *state, dir Dir) (Arg, []*Call) { panic("prog.Ref method called") }
   211  func (ti Ref) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) ([]*Call, bool, bool) {
   212  	panic("prog.Ref method called")
   213  }
   214  func (ti Ref) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (float64, bool) {
   215  	panic("prog.Ref method called")
   216  }
   217  func (ti Ref) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool {
   218  	panic("prog.Ref method called")
   219  }
   220  func (ti Ref) ref() Ref       { panic("prog.Ref method called") }
   221  func (ti Ref) setRef(ref Ref) { panic("prog.Ref method called") }
   222  
   223  func IsPad(t Type) bool {
   224  	if ct, ok := t.(*ConstType); ok && ct.IsPad {
   225  		return true
   226  	}
   227  	return false
   228  }
   229  
   230  type TypeCommon struct {
   231  	TypeName string
   232  	// Static size of the type, or 0 for variable size types and all but last bitfields in the group.
   233  	TypeSize   uint64
   234  	TypeAlign  uint64
   235  	IsOptional bool
   236  	IsVarlen   bool
   237  
   238  	self Ref
   239  }
   240  
   241  func (t *TypeCommon) Name() string {
   242  	return t.TypeName
   243  }
   244  
   245  func (t *TypeCommon) TemplateName() string {
   246  	name := t.TypeName
   247  	if pos := strings.IndexByte(name, '['); pos != -1 {
   248  		name = name[:pos]
   249  	}
   250  	return name
   251  }
   252  
   253  func (t *TypeCommon) Optional() bool {
   254  	return t.IsOptional
   255  }
   256  
   257  func (t *TypeCommon) Size() uint64 {
   258  	if t.IsVarlen {
   259  		panic(fmt.Sprintf("static type size is not known: %#v", t))
   260  	}
   261  	return t.TypeSize
   262  }
   263  
   264  func (t *TypeCommon) TypeBitSize() uint64 {
   265  	panic("cannot get the bitsize for a non-integer type")
   266  }
   267  
   268  func (t *TypeCommon) Varlen() bool {
   269  	return t.IsVarlen
   270  }
   271  
   272  func (t *TypeCommon) Format() BinaryFormat {
   273  	return FormatNative
   274  }
   275  
   276  func (t *TypeCommon) BitfieldOffset() uint64 {
   277  	return 0
   278  }
   279  
   280  func (t *TypeCommon) BitfieldLength() uint64 {
   281  	return 0
   282  }
   283  
   284  func (t *TypeCommon) UnitSize() uint64 {
   285  	return t.Size()
   286  }
   287  
   288  func (t *TypeCommon) UnitOffset() uint64 {
   289  	return 0
   290  }
   291  
   292  func (t *TypeCommon) IsBitfield() bool {
   293  	return false
   294  }
   295  
   296  func (t *TypeCommon) ref() Ref {
   297  	if t.self == 0 {
   298  		panic("ref is not assigned yet")
   299  	}
   300  	return t.self
   301  }
   302  
   303  func (t *TypeCommon) setRef(ref Ref) {
   304  	t.self = ref
   305  }
   306  
   307  func (t *TypeCommon) Alignment() uint64 {
   308  	return t.TypeAlign
   309  }
   310  
   311  type FlagDesc struct {
   312  	Name   string
   313  	Values []string
   314  }
   315  
   316  type ResourceDesc struct {
   317  	Name   string
   318  	Kind   []string
   319  	Values []uint64
   320  	Ctors  []ResourceCtor
   321  }
   322  
   323  type ResourceCtor struct {
   324  	Call    *Syscall
   325  	Precise bool
   326  }
   327  
   328  type ResourceType struct {
   329  	TypeCommon
   330  	ArgFormat BinaryFormat
   331  	Desc      *ResourceDesc
   332  }
   333  
   334  func (t *ResourceType) String() string {
   335  	return t.Name()
   336  }
   337  
   338  func (t *ResourceType) DefaultArg(dir Dir) Arg {
   339  	return MakeResultArg(t, dir, nil, t.Default())
   340  }
   341  
   342  func (t *ResourceType) isDefaultArg(arg Arg) bool {
   343  	a := arg.(*ResultArg)
   344  	return a.Res == nil && a.OpDiv == 0 && a.OpAdd == 0 &&
   345  		len(a.uses) == 0 && a.Val == t.Default()
   346  }
   347  
   348  func (t *ResourceType) Default() uint64 {
   349  	return t.Desc.Values[0]
   350  }
   351  
   352  func (t *ResourceType) SpecialValues() []uint64 {
   353  	return t.Desc.Values
   354  }
   355  
   356  func (t *ResourceType) Format() BinaryFormat {
   357  	return t.ArgFormat
   358  }
   359  
   360  type IntTypeCommon struct {
   361  	TypeCommon
   362  	ArgFormat       BinaryFormat
   363  	BitfieldOff     uint64
   364  	BitfieldLen     uint64
   365  	BitfieldUnit    uint64
   366  	BitfieldUnitOff uint64
   367  }
   368  
   369  func (t *IntTypeCommon) String() string {
   370  	return t.Name()
   371  }
   372  
   373  func (t *IntTypeCommon) Format() BinaryFormat {
   374  	return t.ArgFormat
   375  }
   376  
   377  // Returns the size in bits for integers in binary format or 64 for string-formatted integers. The return
   378  // value is used in computing limits and truncating other values.
   379  func (t *IntTypeCommon) TypeBitSize() uint64 {
   380  	if t.ArgFormat != FormatNative && t.ArgFormat != FormatBigEndian {
   381  		// TODO: add special cases for mutation and generation of string-formatted integers.
   382  		return 64
   383  	}
   384  	if t.BitfieldLen != 0 {
   385  		return t.BitfieldLen
   386  	}
   387  	return t.TypeSize * 8
   388  }
   389  
   390  func (t *IntTypeCommon) BitfieldOffset() uint64 {
   391  	return t.BitfieldOff
   392  }
   393  
   394  func (t *IntTypeCommon) BitfieldLength() uint64 {
   395  	return t.BitfieldLen
   396  }
   397  
   398  func (t *IntTypeCommon) UnitSize() uint64 {
   399  	if t.BitfieldLen != 0 {
   400  		return t.BitfieldUnit
   401  	}
   402  	return t.Size()
   403  }
   404  
   405  func (t *IntTypeCommon) UnitOffset() uint64 {
   406  	return t.BitfieldUnitOff
   407  }
   408  
   409  func (t *IntTypeCommon) IsBitfield() bool {
   410  	return t.BitfieldLen != 0
   411  }
   412  
   413  type ConstType struct {
   414  	IntTypeCommon
   415  	Val   uint64
   416  	IsPad bool
   417  }
   418  
   419  func (t *ConstType) DefaultArg(dir Dir) Arg {
   420  	return MakeConstArg(t, dir, t.Val)
   421  }
   422  
   423  func (t *ConstType) isDefaultArg(arg Arg) bool {
   424  	return arg.(*ConstArg).Val == t.Val
   425  }
   426  
   427  func (t *ConstType) String() string {
   428  	if t.IsPad {
   429  		return fmt.Sprintf("pad[%v]", t.Size())
   430  	}
   431  	return fmt.Sprintf("const[%v, %v]", t.Val, t.IntTypeCommon.String())
   432  }
   433  
   434  type IntKind int
   435  
   436  const (
   437  	IntPlain IntKind = iota
   438  	IntRange
   439  )
   440  
   441  type IntType struct {
   442  	IntTypeCommon
   443  	Kind       IntKind
   444  	RangeBegin uint64
   445  	RangeEnd   uint64
   446  	Align      uint64
   447  }
   448  
   449  func (t *IntType) DefaultArg(dir Dir) Arg {
   450  	return MakeConstArg(t, dir, 0)
   451  }
   452  
   453  func (t *IntType) isDefaultArg(arg Arg) bool {
   454  	return arg.(*ConstArg).Val == 0
   455  }
   456  
   457  type FlagsType struct {
   458  	IntTypeCommon
   459  	Vals    []uint64 // compiler ensures that it's not empty
   460  	BitMask bool
   461  }
   462  
   463  func (t *FlagsType) DefaultArg(dir Dir) Arg {
   464  	return MakeConstArg(t, dir, 0)
   465  }
   466  
   467  func (t *FlagsType) isDefaultArg(arg Arg) bool {
   468  	return arg.(*ConstArg).Val == 0
   469  }
   470  
   471  type LenType struct {
   472  	IntTypeCommon
   473  	BitSize uint64 // want size in multiple of bits instead of array size
   474  	Offset  bool   // offset from the beginning of the parent struct or base object
   475  	Path    []string
   476  }
   477  
   478  func (t *LenType) DefaultArg(dir Dir) Arg {
   479  	return MakeConstArg(t, dir, 0)
   480  }
   481  
   482  func (t *LenType) isDefaultArg(arg Arg) bool {
   483  	return arg.(*ConstArg).Val == 0
   484  }
   485  
   486  type ProcType struct {
   487  	IntTypeCommon
   488  	ValuesStart   uint64
   489  	ValuesPerProc uint64
   490  }
   491  
   492  const (
   493  	MaxPids          = 32
   494  	procDefaultValue = 0xffffffffffffffff // special value denoting 0 for all procs
   495  )
   496  
   497  func (t *ProcType) DefaultArg(dir Dir) Arg {
   498  	return MakeConstArg(t, dir, procDefaultValue)
   499  }
   500  
   501  func (t *ProcType) isDefaultArg(arg Arg) bool {
   502  	return arg.(*ConstArg).Val == procDefaultValue
   503  }
   504  
   505  type CsumKind int
   506  
   507  const (
   508  	CsumInet CsumKind = iota
   509  	CsumPseudo
   510  )
   511  
   512  type CsumType struct {
   513  	IntTypeCommon
   514  	Kind     CsumKind
   515  	Buf      string
   516  	Protocol uint64 // for CsumPseudo
   517  }
   518  
   519  func (t *CsumType) String() string {
   520  	return "csum"
   521  }
   522  
   523  func (t *CsumType) DefaultArg(dir Dir) Arg {
   524  	return MakeConstArg(t, dir, 0)
   525  }
   526  
   527  func (t *CsumType) isDefaultArg(arg Arg) bool {
   528  	return arg.(*ConstArg).Val == 0
   529  }
   530  
   531  type VmaType struct {
   532  	TypeCommon
   533  	RangeBegin uint64 // in pages
   534  	RangeEnd   uint64
   535  }
   536  
   537  func (t *VmaType) String() string {
   538  	return "vma"
   539  }
   540  
   541  func (t *VmaType) DefaultArg(dir Dir) Arg {
   542  	return MakeSpecialPointerArg(t, dir, 0)
   543  }
   544  
   545  func (t *VmaType) isDefaultArg(arg Arg) bool {
   546  	a := arg.(*PointerArg)
   547  	return a.IsSpecial() && a.Address == 0
   548  }
   549  
   550  type BufferKind int
   551  
   552  const (
   553  	BufferBlobRand BufferKind = iota
   554  	BufferBlobRange
   555  	BufferString
   556  	BufferFilename
   557  	BufferText
   558  	BufferGlob
   559  	BufferCompressed
   560  )
   561  
   562  type TextKind int
   563  
   564  const (
   565  	TextTarget TextKind = iota
   566  	TextX86Real
   567  	TextX86bit16
   568  	TextX86bit32
   569  	TextX86bit64
   570  	TextArm64
   571  	TextPpc64
   572  )
   573  
   574  type BufferType struct {
   575  	TypeCommon
   576  	Kind       BufferKind
   577  	RangeBegin uint64   // for BufferBlobRange kind
   578  	RangeEnd   uint64   // for BufferBlobRange kind
   579  	Text       TextKind // for BufferText
   580  	SubKind    string
   581  	Values     []string // possible values for BufferString and BufferGlob kind
   582  	NoZ        bool     // non-zero terminated BufferString/BufferFilename
   583  }
   584  
   585  func (t *BufferType) String() string {
   586  	return "buffer"
   587  }
   588  
   589  func (t *BufferType) DefaultArg(dir Dir) Arg {
   590  	if dir == DirOut {
   591  		var sz uint64
   592  		if !t.Varlen() {
   593  			sz = t.Size()
   594  		}
   595  		return MakeOutDataArg(t, dir, sz)
   596  	}
   597  
   598  	var data []byte
   599  	if len(t.Values) == 1 {
   600  		data = []byte(t.Values[0])
   601  	} else if !t.Varlen() {
   602  		data = make([]byte, t.Size())
   603  	}
   604  	return MakeDataArg(t, dir, data)
   605  }
   606  
   607  func (t *BufferType) isDefaultArg(arg Arg) bool {
   608  	a := arg.(*DataArg)
   609  	sz := uint64(0)
   610  	if !t.Varlen() {
   611  		sz = t.Size()
   612  	}
   613  	if a.Size() != sz {
   614  		return false
   615  	}
   616  	if a.Dir() == DirOut {
   617  		return true
   618  	}
   619  	if len(t.Values) == 1 {
   620  		return string(a.Data()) == t.Values[0]
   621  	}
   622  	for _, v := range a.Data() {
   623  		if v != 0 {
   624  			return false
   625  		}
   626  	}
   627  	return true
   628  }
   629  
   630  func (t *BufferType) IsCompressed() bool {
   631  	return t.Kind == BufferCompressed
   632  }
   633  
   634  type ArrayKind int
   635  
   636  const (
   637  	ArrayRandLen ArrayKind = iota
   638  	ArrayRangeLen
   639  )
   640  
   641  type ArrayType struct {
   642  	TypeCommon
   643  	Elem       Type
   644  	Kind       ArrayKind
   645  	RangeBegin uint64
   646  	RangeEnd   uint64
   647  }
   648  
   649  func (t *ArrayType) String() string {
   650  	return fmt.Sprintf("array[%v]", t.Elem.String())
   651  }
   652  
   653  func (t *ArrayType) DefaultArg(dir Dir) Arg {
   654  	var elems []Arg
   655  	if t.Kind == ArrayRangeLen && t.RangeBegin == t.RangeEnd {
   656  		for i := uint64(0); i < t.RangeBegin; i++ {
   657  			elems = append(elems, t.Elem.DefaultArg(dir))
   658  		}
   659  	}
   660  	return MakeGroupArg(t, dir, elems)
   661  }
   662  
   663  func (t *ArrayType) isDefaultArg(arg Arg) bool {
   664  	a := arg.(*GroupArg)
   665  	if !a.fixedInnerSize() && len(a.Inner) != 0 {
   666  		return false
   667  	}
   668  	for _, elem := range a.Inner {
   669  		if !isDefault(elem) {
   670  			return false
   671  		}
   672  	}
   673  	return true
   674  }
   675  
   676  type PtrType struct {
   677  	TypeCommon
   678  	Elem           Type
   679  	ElemDir        Dir
   680  	SquashableElem bool
   681  }
   682  
   683  func (t *PtrType) String() string {
   684  	return fmt.Sprintf("ptr[%v, %v]", t.ElemDir, t.Elem.String())
   685  }
   686  
   687  func (t *PtrType) DefaultArg(dir Dir) Arg {
   688  	if t.Optional() {
   689  		return MakeSpecialPointerArg(t, dir, 0)
   690  	}
   691  	return MakePointerArg(t, dir, 0, t.Elem.DefaultArg(t.ElemDir))
   692  }
   693  
   694  func (t *PtrType) isDefaultArg(arg Arg) bool {
   695  	a := arg.(*PointerArg)
   696  	if t.Optional() {
   697  		return a.IsSpecial() && a.Address == 0
   698  	}
   699  	return a.Address == 0 && a.Res != nil && isDefault(a.Res)
   700  }
   701  
   702  type StructType struct {
   703  	TypeCommon
   704  	Fields       []Field
   705  	AlignAttr    uint64
   706  	OverlayField int // index of the field marked with out_overlay attribute (0 if no attribute)
   707  }
   708  
   709  func (t *StructType) String() string {
   710  	return t.Name()
   711  }
   712  
   713  func (t *StructType) DefaultArg(dir Dir) Arg {
   714  	inner := make([]Arg, len(t.Fields))
   715  	for i, field := range t.Fields {
   716  		inner[i] = field.DefaultArg(field.Dir(dir))
   717  	}
   718  	return MakeGroupArg(t, dir, inner)
   719  }
   720  
   721  func (t *StructType) isDefaultArg(arg Arg) bool {
   722  	a := arg.(*GroupArg)
   723  	for _, elem := range a.Inner {
   724  		if !isDefault(elem) {
   725  			return false
   726  		}
   727  	}
   728  	return true
   729  }
   730  
   731  type UnionType struct {
   732  	TypeCommon
   733  	Fields []Field
   734  }
   735  
   736  func (t *UnionType) String() string {
   737  	return t.Name()
   738  }
   739  
   740  func (t *UnionType) DefaultArg(dir Dir) Arg {
   741  	idx := t.defaultField()
   742  	f := t.Fields[idx]
   743  	arg := MakeUnionArg(t, dir, f.DefaultArg(f.Dir(dir)), idx)
   744  	arg.transient = t.isConditional()
   745  	return arg
   746  }
   747  
   748  func (t *UnionType) defaultField() int {
   749  	// If it's a conditional union, the last field will be the default value.
   750  	if t.isConditional() {
   751  		return len(t.Fields) - 1
   752  	}
   753  	// Otherwise, just take the first.
   754  	return 0
   755  }
   756  
   757  func (t *UnionType) isConditional() bool {
   758  	// In pkg/compiler, we ensure that either none of the fields have conditions,
   759  	// or all except the last one.
   760  	return t.Fields[0].Condition != nil
   761  }
   762  
   763  func (t *UnionType) isDefaultArg(arg Arg) bool {
   764  	a := arg.(*UnionArg)
   765  	return a.Index == t.defaultField() && isDefault(a.Option)
   766  }
   767  
   768  type ConstValue struct {
   769  	Name  string
   770  	Value uint64
   771  }
   772  
   773  type TypeCtx struct {
   774  	Meta     *Syscall
   775  	Dir      Dir
   776  	Ptr      *Type
   777  	Optional bool
   778  	Stop     bool // If set by the callback, subtypes of this type are not visited.
   779  }
   780  
   781  func ForeachType(syscalls []*Syscall, f func(t Type, ctx *TypeCtx)) {
   782  	for _, meta := range syscalls {
   783  		foreachCallTypeImpl(meta, true, f)
   784  	}
   785  }
   786  
   787  func ForeachTypePost(syscalls []*Syscall, f func(t Type, ctx *TypeCtx)) {
   788  	for _, meta := range syscalls {
   789  		foreachCallTypeImpl(meta, false, f)
   790  	}
   791  }
   792  
   793  func ForeachCallType(meta *Syscall, f func(t Type, ctx *TypeCtx)) {
   794  	foreachCallTypeImpl(meta, true, f)
   795  }
   796  
   797  // We need seen to be keyed by the type, the direction, and the optionality
   798  // bit. Even if the first time we see a type it is optional or DirOut, it
   799  // could be required or DirIn on another path. So to ensure that the
   800  // information we report to the caller is correct, we need to visit both
   801  // occurrences.
   802  type seenKey struct {
   803  	t Type
   804  	d Dir
   805  	o bool
   806  }
   807  
   808  func foreachCallTypeImpl(meta *Syscall, preorder bool, f func(t Type, ctx *TypeCtx)) {
   809  	// Note: we specifically don't create seen in ForeachType.
   810  	// It would prune recursion more (across syscalls), but lots of users need to
   811  	// visit each struct per-syscall (e.g. prio, used resources).
   812  	seen := make(map[seenKey]bool)
   813  	for i := range meta.Args {
   814  		foreachTypeRec(f, meta, seen, &meta.Args[i].Type, DirIn, preorder, false)
   815  	}
   816  	if meta.Ret != nil {
   817  		foreachTypeRec(f, meta, seen, &meta.Ret, DirOut, preorder, false)
   818  	}
   819  }
   820  
   821  func ForeachArgType(typ Type, f func(t Type, ctx *TypeCtx)) {
   822  	foreachTypeRec(f, nil, make(map[seenKey]bool), &typ, DirIn, true, false)
   823  }
   824  
   825  func foreachTypeRec(cb func(t Type, ctx *TypeCtx), meta *Syscall, seen map[seenKey]bool, ptr *Type,
   826  	dir Dir, preorder, optional bool) {
   827  	if _, ref := (*ptr).(Ref); !ref {
   828  		optional = optional || (*ptr).Optional()
   829  	}
   830  	ctx := &TypeCtx{Meta: meta, Dir: dir, Ptr: ptr, Optional: optional}
   831  	if preorder {
   832  		cb(*ptr, ctx)
   833  		if ctx.Stop {
   834  			return
   835  		}
   836  	}
   837  	switch a := (*ptr).(type) {
   838  	case *PtrType:
   839  		foreachTypeRec(cb, meta, seen, &a.Elem, a.ElemDir, preorder, optional)
   840  	case *ArrayType:
   841  		foreachTypeRec(cb, meta, seen, &a.Elem, dir, preorder, optional)
   842  	case *StructType:
   843  		key := seenKey{
   844  			t: a,
   845  			d: dir,
   846  			o: optional,
   847  		}
   848  		if seen[key] {
   849  			break // prune recursion via pointers to structs/unions
   850  		}
   851  		seen[key] = true
   852  		for i, f := range a.Fields {
   853  			foreachTypeRec(cb, meta, seen, &a.Fields[i].Type, f.Dir(dir), preorder, optional)
   854  		}
   855  	case *UnionType:
   856  		key := seenKey{
   857  			t: a,
   858  			d: dir,
   859  			o: optional,
   860  		}
   861  		if seen[key] {
   862  			break // prune recursion via pointers to structs/unions
   863  		}
   864  		seen[key] = true
   865  		for i, f := range a.Fields {
   866  			foreachTypeRec(cb, meta, seen, &a.Fields[i].Type, f.Dir(dir), preorder, optional)
   867  		}
   868  	case *ResourceType, *BufferType, *VmaType, *LenType, *FlagsType,
   869  		*ConstType, *IntType, *ProcType, *CsumType:
   870  	case Ref:
   871  		// This is only needed for pkg/compiler.
   872  	default:
   873  		panic("unknown type")
   874  	}
   875  	if !preorder {
   876  		cb(*ptr, ctx)
   877  		if ctx.Stop {
   878  			panic("Stop is set in post-order iteration")
   879  		}
   880  	}
   881  }
   882  
   883  // CppName transforms PascalStyleNames to cpp_style_names.
   884  func CppName(name string) string {
   885  	var res []byte
   886  	for i := range name {
   887  		c := rune(name[i])
   888  		if unicode.IsUpper(c) && i != 0 && !unicode.IsUpper(rune(name[i-1])) {
   889  			res = append(res, '_')
   890  		}
   891  		res = append(res, byte(unicode.ToLower(c)))
   892  	}
   893  	return string(res)
   894  }