func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) { if typ.Dir() == sys.DirOut { // No need to generate something interesting for output scalar arguments. // But we still need to generate the argument itself so that it can be referenced // in subsequent calls. For the same reason we do generate pointer/array/struct // output arguments (their elements can be referenced in subsequent calls). switch typ.(type) { case *sys.IntType, *sys.FlagsType, *sys.ConstType, *sys.ResourceType, *sys.VmaType, *sys.ProcType: return constArg(typ, typ.Default()), nil } } if typ.Optional() && r.oneOf(5) { if _, ok := typ.(*sys.BufferType); ok { panic("impossible") // parent PtrType must be Optional instead } return constArg(typ, typ.Default()), nil } switch a := typ.(type) { case *sys.ResourceType: r.choose( 1, func() { special := a.SpecialValues() arg = constArg(a, special[r.Intn(len(special))]) }, 90, func() { // Get an existing resource. var allres []*Arg for name1, res1 := range s.resources { if sys.IsCompatibleResource(a.Desc.Name, name1) || r.oneOf(20) && sys.IsCompatibleResource(a.Desc.Kind[0], name1) { allres = append(allres, res1...) } } if len(allres) != 0 { arg = resultArg(a, allres[r.Intn(len(allres))]) } else { arg, calls = r.createResource(s, a) } }, 5, func() { // Create a new resource. arg, calls = r.createResource(s, a) }, ) return arg, calls case *sys.BufferType: switch a.Kind { case sys.BufferBlobRand, sys.BufferBlobRange: sz := r.randBufLen() if a.Kind == sys.BufferBlobRange { sz = r.randRange(int(a.RangeBegin), int(a.RangeEnd)) } data := make([]byte, sz) if a.Dir() != sys.DirOut { for i := range data { data[i] = byte(r.Intn(256)) } } return dataArg(a, data), nil case sys.BufferString: data := r.randString(s, a.Values, a.Dir()) return dataArg(a, data), nil case sys.BufferFilename: filename := r.filename(s) return dataArg(a, []byte(filename)), nil default: panic("unknown buffer kind") } case *sys.VmaType: npages := r.randPageCount() arg := r.randPageAddr(s, a, npages, nil, true) return arg, nil case *sys.FlagsType: return constArg(a, r.flags(a.Vals)), nil case *sys.ConstType: return constArg(a, a.Val), nil case *sys.IntType: v := r.randInt() switch a.Kind { case sys.IntSignalno: v %= 130 case sys.IntFileoff: r.choose( 90, func() { v = 0 }, 10, func() { v = r.rand(100) }, 1, func() { v = r.randInt() }, ) case sys.IntRange: v = r.randRangeInt(a.RangeBegin, a.RangeEnd) } return constArg(a, v), nil case *sys.ProcType: return constArg(a, r.rand(int(a.ValuesPerProc))), nil case *sys.ArrayType: count := uintptr(0) switch a.Kind { case sys.ArrayRandLen: count = r.rand(6) case sys.ArrayRangeLen: count = r.randRange(int(a.RangeBegin), int(a.RangeEnd)) } var inner []*Arg var calls []*Call for i := uintptr(0); i < count; i++ { arg1, calls1 := r.generateArg(s, a.Type) inner = append(inner, arg1) calls = append(calls, calls1...) } return groupArg(a, inner), calls case *sys.StructType: if ctor := isSpecialStruct(a); ctor != nil && a.Dir() != sys.DirOut { arg, calls = ctor(r, s) return } args, calls := r.generateArgs(s, a.Fields) group := groupArg(a, args) return group, calls case *sys.UnionType: optType := a.Options[r.Intn(len(a.Options))] opt, calls := r.generateArg(s, optType) return unionArg(a, opt, optType), calls case *sys.PtrType: inner, calls := r.generateArg(s, a.Type) if a.Dir() == sys.DirOut && inner == nil { // No data, but we should have got size. arg, calls1 := r.addr(s, a, inner.Size(), nil) calls = append(calls, calls1...) return arg, calls } if a.Type.Name() == "iocb" && len(s.resources["iocbptr"]) != 0 { // It is weird, but these are actually identified by kernel by address. // So try to reuse a previously used address. addrs := s.resources["iocbptr"] addr := addrs[r.Intn(len(addrs))] arg = pointerArg(a, addr.AddrPage, addr.AddrOffset, addr.AddrPagesNum, inner) return arg, calls } arg, calls1 := r.addr(s, a, inner.Size(), inner) calls = append(calls, calls1...) return arg, calls case *sys.LenType: // Return placeholder value of 0 while generating len args. return constArg(a, 0), nil default: panic("unknown argument type") } }