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