// Copyright 2015/2016 syzkaller project authors. All rights reserved. // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. package prog import ( "fmt" ) type Syscall struct { ID int NR uint64 // kernel syscall number Name string CallName string Args []Type Ret Type } type Dir int const ( DirIn Dir = iota DirOut DirInOut ) func (dir Dir) String() string { switch dir { case DirIn: return "in" case DirOut: return "out" case DirInOut: return "inout" default: panic("unknown dir") } } type Type interface { String() string Name() string FieldName() string Dir() Dir Optional() bool Default() uint64 Varlen() bool Size() uint64 BitfieldOffset() uint64 BitfieldLength() uint64 BitfieldMiddle() bool // returns true for all but last bitfield in a group generate(r *randGen, s *state) (arg Arg, calls []*Call) mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) } func IsPad(t Type) bool { if ct, ok := t.(*ConstType); ok && ct.IsPad { return true } return false } type TypeCommon struct { TypeName string FldName string // for struct fields and named args TypeSize uint64 // static size of the type, or 0 for variable size types ArgDir Dir IsOptional bool IsVarlen bool } func (t *TypeCommon) Name() string { return t.TypeName } func (t *TypeCommon) FieldName() string { return t.FldName } func (t *TypeCommon) Optional() bool { return t.IsOptional } func (t *TypeCommon) Default() uint64 { return 0 } func (t *TypeCommon) Size() uint64 { if t.IsVarlen { panic(fmt.Sprintf("static type size is not known: %#v", t)) } return t.TypeSize } func (t *TypeCommon) Varlen() bool { return t.IsVarlen } func (t *TypeCommon) BitfieldOffset() uint64 { return 0 } func (t *TypeCommon) BitfieldLength() uint64 { return 0 } func (t *TypeCommon) BitfieldMiddle() bool { return false } func (t TypeCommon) Dir() Dir { return t.ArgDir } type ResourceDesc struct { Name string Type Type Kind []string Values []uint64 } type ResourceType struct { TypeCommon Desc *ResourceDesc } func (t *ResourceType) String() string { return t.Name() } func (t *ResourceType) Default() uint64 { return t.Desc.Values[0] } func (t *ResourceType) SpecialValues() []uint64 { return t.Desc.Values } type IntTypeCommon struct { TypeCommon BitfieldOff uint64 BitfieldLen uint64 BigEndian bool BitfieldMdl bool } func (t *IntTypeCommon) String() string { return t.Name() } func (t *IntTypeCommon) BitfieldOffset() uint64 { return t.BitfieldOff } func (t *IntTypeCommon) BitfieldLength() uint64 { return t.BitfieldLen } func (t *IntTypeCommon) BitfieldMiddle() bool { return t.BitfieldMdl } type ConstType struct { IntTypeCommon Val uint64 IsPad bool } func (t *ConstType) String() string { if t.IsPad { return fmt.Sprintf("pad[%v]", t.Size()) } return fmt.Sprintf("const[%v, %v]", t.Val, t.IntTypeCommon.String()) } type IntKind int const ( IntPlain IntKind = iota IntFileoff // offset within a file IntRange ) type IntType struct { IntTypeCommon Kind IntKind RangeBegin uint64 RangeEnd uint64 } type FlagsType struct { IntTypeCommon Vals []uint64 } type LenType struct { IntTypeCommon BitSize uint64 // want size in multiple of bits instead of array size Buf string } type ProcType struct { IntTypeCommon ValuesStart uint64 ValuesPerProc uint64 } func (t *ProcType) Default() uint64 { // Special value denoting 0 for all procs. return 0xffffffffffffffff } type CsumKind int const ( CsumInet CsumKind = iota CsumPseudo ) type CsumType struct { IntTypeCommon Kind CsumKind Buf string Protocol uint64 // for CsumPseudo } func (t *CsumType) String() string { return "csum" } type VmaType struct { TypeCommon RangeBegin uint64 // in pages RangeEnd uint64 } func (t *VmaType) String() string { return "vma" } type BufferKind int const ( BufferBlobRand BufferKind = iota BufferBlobRange BufferString BufferFilename BufferText ) type TextKind int const ( Text_x86_real TextKind = iota Text_x86_16 Text_x86_32 Text_x86_64 Text_arm64 ) type BufferType struct { TypeCommon Kind BufferKind RangeBegin uint64 // for BufferBlobRange kind RangeEnd uint64 // for BufferBlobRange kind Text TextKind // for BufferText SubKind string Values []string // possible values for BufferString kind NoZ bool // non-zero terminated BufferString/BufferFilename } func (t *BufferType) String() string { return "buffer" } type ArrayKind int const ( ArrayRandLen ArrayKind = iota ArrayRangeLen ) type ArrayType struct { TypeCommon Type Type Kind ArrayKind RangeBegin uint64 RangeEnd uint64 } func (t *ArrayType) String() string { return fmt.Sprintf("array[%v]", t.Type.String()) } type PtrType struct { TypeCommon Type Type } func (t *PtrType) String() string { return fmt.Sprintf("ptr[%v, %v]", t.Dir(), t.Type.String()) } type StructType struct { Key StructKey FldName string *StructDesc } func (t *StructType) String() string { return t.Name() } func (t *StructType) FieldName() string { return t.FldName } type UnionType struct { Key StructKey FldName string *StructDesc } func (t *UnionType) String() string { return t.Name() } func (t *UnionType) FieldName() string { return t.FldName } type StructDesc struct { TypeCommon Fields []Type AlignAttr uint64 } func (t *StructDesc) FieldName() string { panic("must not be called") } type StructKey struct { Name string Dir Dir } type KeyedStruct struct { Key StructKey Desc *StructDesc } type ConstValue struct { Name string Value uint64 } func ForeachType(meta *Syscall, f func(Type)) { seen := make(map[*StructDesc]bool) var rec func(t Type) rec = func(t Type) { f(t) switch a := t.(type) { case *PtrType: rec(a.Type) case *ArrayType: rec(a.Type) case *StructType: if seen[a.StructDesc] { return // prune recursion via pointers to structs/unions } seen[a.StructDesc] = true for _, f := range a.Fields { rec(f) } case *UnionType: if seen[a.StructDesc] { return // prune recursion via pointers to structs/unions } seen[a.StructDesc] = true for _, opt := range a.Fields { rec(opt) } case *ResourceType, *BufferType, *VmaType, *LenType, *FlagsType, *ConstType, *IntType, *ProcType, *CsumType: default: panic("unknown type") } } for _, t := range meta.Args { rec(t) } if meta.Ret != nil { rec(meta.Ret) } }