• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
4package compiler
5
6import (
7	"fmt"
8	"strconv"
9
10	"github.com/google/syzkaller/pkg/ast"
11	"github.com/google/syzkaller/prog"
12)
13
14// typeDesc is arg/field type descriptor.
15type typeDesc struct {
16	Names        []string
17	CanBeTypedef bool       // can be type alias target?
18	CantBeOpt    bool       // can't be marked as opt?
19	NeedBase     bool       // needs base type when used as field?
20	AllowColon   bool       // allow colon (int8:2) on fields?
21	ResourceBase bool       // can be resource base type?
22	OptArgs      int        // number of optional arguments in Args array
23	Args         []namedArg // type arguments
24	// CanBeArgRet returns if this type can be syscall argument/return (false if nil).
25	CanBeArgRet func(comp *compiler, t *ast.Type) (bool, bool)
26	// Check does custom verification of the type (optional, consts are not patched yet).
27	Check func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon)
28	// CheckConsts does custom verification of the type (optional, consts are patched).
29	CheckConsts func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon)
30	// Varlen returns if the type is variable-length (false if not set).
31	Varlen func(comp *compiler, t *ast.Type, args []*ast.Type) bool
32	// ZeroSize returns if the type has static 0 size (false if not set).
33	ZeroSize func(comp *compiler, t *ast.Type, args []*ast.Type) bool
34	// Gen generates corresponding prog.Type.
35	Gen func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type
36}
37
38// typeArg describes a type argument.
39type typeArg struct {
40	Names      []string
41	Kind       int  // int/ident/string
42	MaxArgs    int  // maxiumum number of subargs
43	AllowColon bool // allow colon (2:3)?
44	// Check does custom verification of the arg (optional).
45	Check       func(comp *compiler, t *ast.Type)
46	CheckConsts func(comp *compiler, t *ast.Type)
47}
48
49type namedArg struct {
50	Name  string
51	Type  *typeArg
52	IsArg bool // does not need base type
53}
54
55const (
56	kindAny = iota
57	kindInt
58	kindIdent
59	kindString
60)
61
62func canBeArg(comp *compiler, t *ast.Type) (bool, bool)    { return true, false }
63func canBeArgRet(comp *compiler, t *ast.Type) (bool, bool) { return true, true }
64
65var typeInt = &typeDesc{
66	Names:        typeArgBase.Type.Names,
67	CanBeArgRet:  canBeArg,
68	CanBeTypedef: true,
69	AllowColon:   true,
70	ResourceBase: true,
71	OptArgs:      1,
72	Args:         []namedArg{{Name: "range", Type: typeArgIntRange}},
73	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
74		typeArgBase.Type.Check(comp, t)
75	},
76	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
77		size, be := comp.parseIntType(t.Ident)
78		kind, rangeBegin, rangeEnd := prog.IntPlain, uint64(0), uint64(0)
79		if len(args) > 0 {
80			kind, rangeBegin, rangeEnd = prog.IntRange, args[0].Value, args[0].Value2
81		}
82		base.TypeSize = size
83		return &prog.IntType{
84			IntTypeCommon: genIntCommon(base.TypeCommon, t.Value2, be),
85			Kind:          kind,
86			RangeBegin:    rangeBegin,
87			RangeEnd:      rangeEnd,
88		}
89	},
90}
91
92var typePtr = &typeDesc{
93	Names:        []string{"ptr", "ptr64"},
94	CanBeArgRet:  canBeArg,
95	CanBeTypedef: true,
96	Args:         []namedArg{{Name: "direction", Type: typeArgDir}, {Name: "type", Type: typeArgType}},
97	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
98		base.ArgDir = prog.DirIn // pointers are always in
99		base.TypeSize = comp.ptrSize
100		if t.Ident == "ptr64" {
101			base.TypeSize = 8
102		}
103		return &prog.PtrType{
104			TypeCommon: base.TypeCommon,
105			Type:       comp.genType(args[1], "", genDir(args[0]), false),
106		}
107	},
108}
109
110var typeVoid = &typeDesc{
111	Names:     []string{"void"},
112	CantBeOpt: true,
113	ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
114		return true
115	},
116	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
117		base.TypeSize = 0 // the only type with static size 0
118		return &prog.BufferType{
119			TypeCommon: base.TypeCommon,
120			Kind:       prog.BufferBlobRange,
121			RangeBegin: 0,
122			RangeEnd:   0,
123		}
124	},
125}
126
127var typeArray = &typeDesc{
128	Names:        []string{"array"},
129	CanBeTypedef: true,
130	CantBeOpt:    true,
131	OptArgs:      1,
132	Args:         []namedArg{{Name: "type", Type: typeArgType}, {Name: "size", Type: typeArgSizeRange}},
133	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
134		if len(args) > 1 && args[1].Value == 0 && args[1].Value2 == 0 {
135			comp.error(args[1].Pos, "arrays of size 0 are not supported")
136		}
137	},
138	Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
139		if comp.isZeroSize(args[0]) {
140			return false
141		}
142		if comp.isVarlen(args[0]) {
143			return true
144		}
145		if len(args) > 1 {
146			return args[1].Value != args[1].Value2
147		}
148		return true
149	},
150	ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
151		return comp.isZeroSize(args[0])
152	},
153	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
154		elemType := comp.genType(args[0], "", base.ArgDir, false)
155		kind, begin, end := prog.ArrayRandLen, uint64(0), uint64(0)
156		if len(args) > 1 {
157			kind, begin, end = prog.ArrayRangeLen, args[1].Value, args[1].Value2
158		}
159		if it, ok := elemType.(*prog.IntType); ok && it.Kind == prog.IntPlain && it.TypeSize == 1 {
160			// Special case: buffer is better mutated.
161			bufKind := prog.BufferBlobRand
162			base.TypeSize = 0
163			if kind == prog.ArrayRangeLen {
164				bufKind = prog.BufferBlobRange
165				if begin == end {
166					base.TypeSize = begin * elemType.Size()
167				}
168			}
169			return &prog.BufferType{
170				TypeCommon: base.TypeCommon,
171				Kind:       bufKind,
172				RangeBegin: begin,
173				RangeEnd:   end,
174			}
175		}
176		// TypeSize is assigned later in genStructDescs.
177		return &prog.ArrayType{
178			TypeCommon: base.TypeCommon,
179			Type:       elemType,
180			Kind:       kind,
181			RangeBegin: begin,
182			RangeEnd:   end,
183		}
184	},
185}
186
187var typeLen = &typeDesc{
188	Names:       []string{"len", "bytesize", "bytesize2", "bytesize4", "bytesize8", "bitsize"},
189	CanBeArgRet: canBeArg,
190	CantBeOpt:   true,
191	NeedBase:    true,
192	Args:        []namedArg{{Name: "len target", Type: typeArgLenTarget}},
193	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
194		var bitSize uint64
195		switch t.Ident {
196		case "bytesize":
197			bitSize = 8
198		case "bytesize2", "bytesize4", "bytesize8":
199			byteSize, _ := strconv.ParseUint(t.Ident[8:], 10, 8)
200			bitSize = byteSize * 8
201		case "bitsize":
202			bitSize = 1
203		}
204		return &prog.LenType{
205			IntTypeCommon: base,
206			Buf:           args[0].Ident,
207			BitSize:       bitSize,
208		}
209	},
210}
211
212var typeConst = &typeDesc{
213	Names:        []string{"const"},
214	CanBeArgRet:  canBeArg,
215	CanBeTypedef: true,
216	CantBeOpt:    true,
217	NeedBase:     true,
218	Args:         []namedArg{{Name: "value", Type: typeArgInt}},
219	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
220		return &prog.ConstType{
221			IntTypeCommon: base,
222			Val:           args[0].Value,
223		}
224	},
225}
226
227var typeArgLenTarget = &typeArg{
228	Kind: kindIdent,
229}
230
231var typeFlags = &typeDesc{
232	Names:        []string{"flags"},
233	CanBeArgRet:  canBeArg,
234	CanBeTypedef: true,
235	CantBeOpt:    true,
236	NeedBase:     true,
237	Args:         []namedArg{{Name: "flags", Type: typeArgFlags}},
238	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
239		name := args[0].Ident
240		base.TypeName = name
241		f := comp.intFlags[name]
242		if len(f.Values) == 0 {
243			// We can get this if all values are unsupported consts.
244			return &prog.IntType{
245				IntTypeCommon: base,
246				Kind:          prog.IntPlain,
247			}
248		}
249		bitmask := true
250		var combined uint64
251		values := genIntArray(f.Values)
252		for _, v := range values {
253			if v&combined != 0 {
254				bitmask = false
255				break
256			}
257			combined |= v
258		}
259		return &prog.FlagsType{
260			IntTypeCommon: base,
261			Vals:          values,
262			BitMask:       bitmask,
263		}
264	},
265}
266
267var typeArgFlags = &typeArg{
268	Kind: kindIdent,
269	Check: func(comp *compiler, t *ast.Type) {
270		if comp.intFlags[t.Ident] == nil {
271			comp.error(t.Pos, "unknown flags %v", t.Ident)
272			return
273		}
274	},
275}
276
277var typeFileoff = &typeDesc{
278	Names:       []string{"fileoff"},
279	CanBeArgRet: canBeArg,
280	CantBeOpt:   true,
281	NeedBase:    true,
282	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
283		return &prog.IntType{
284			IntTypeCommon: base,
285			Kind:          prog.IntFileoff,
286		}
287	},
288}
289
290var typeVMA = &typeDesc{
291	Names:       []string{"vma"},
292	CanBeArgRet: canBeArg,
293	OptArgs:     1,
294	Args:        []namedArg{{Name: "size range", Type: typeArgSizeRange}},
295	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
296		begin, end := uint64(0), uint64(0)
297		if len(args) > 0 {
298			begin, end = args[0].Value, args[0].Value2
299		}
300		base.TypeSize = comp.ptrSize
301		return &prog.VmaType{
302			TypeCommon: base.TypeCommon,
303			RangeBegin: begin,
304			RangeEnd:   end,
305		}
306	},
307}
308
309var typeCsum = &typeDesc{
310	Names:     []string{"csum"},
311	NeedBase:  true,
312	CantBeOpt: true,
313	OptArgs:   1,
314	Args: []namedArg{
315		{Name: "csum target", Type: typeArgLenTarget},
316		{Name: "kind", Type: typeArgCsumType},
317		{Name: "proto", Type: typeArgInt},
318	},
319	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
320		if len(args) > 2 && genCsumKind(args[1]) != prog.CsumPseudo {
321			comp.error(args[2].Pos, "only pseudo csum can have proto")
322		}
323	},
324	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
325		var proto uint64
326		if len(args) > 2 {
327			proto = args[2].Value
328		}
329		return &prog.CsumType{
330			IntTypeCommon: base,
331			Buf:           args[0].Ident,
332			Kind:          genCsumKind(args[1]),
333			Protocol:      proto,
334		}
335	},
336}
337
338var typeArgCsumType = &typeArg{
339	Kind:  kindIdent,
340	Names: []string{"inet", "pseudo"},
341}
342
343func genCsumKind(t *ast.Type) prog.CsumKind {
344	switch t.Ident {
345	case "inet":
346		return prog.CsumInet
347	case "pseudo":
348		return prog.CsumPseudo
349	default:
350		panic(fmt.Sprintf("unknown csum kind %q", t.Ident))
351	}
352}
353
354var typeProc = &typeDesc{
355	Names:        []string{"proc"},
356	CanBeArgRet:  canBeArg,
357	CanBeTypedef: true,
358	NeedBase:     true,
359	Args: []namedArg{
360		{Name: "range start", Type: typeArgInt},
361		{Name: "per-proc values", Type: typeArgInt},
362	},
363	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
364		start := args[0].Value
365		perProc := args[1].Value
366		if perProc == 0 {
367			comp.error(args[1].Pos, "proc per-process values must not be 0")
368			return
369		}
370		size := base.TypeSize * 8
371		max := uint64(1) << size
372		if size == 64 {
373			max = ^uint64(0)
374		}
375		if start >= max {
376			comp.error(args[0].Pos, "values starting from %v overflow base type", start)
377		} else if perProc > (max-start)/prog.MaxPids {
378			comp.error(args[0].Pos, "values starting from %v with step %v overflow base type for %v procs",
379				start, perProc, prog.MaxPids)
380		}
381	},
382	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
383		return &prog.ProcType{
384			IntTypeCommon: base,
385			ValuesStart:   args[0].Value,
386			ValuesPerProc: args[1].Value,
387		}
388	},
389}
390
391var typeText = &typeDesc{
392	Names:     []string{"text"},
393	CantBeOpt: true,
394	Args:      []namedArg{{Name: "kind", Type: typeArgTextType}},
395	Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
396		return true
397	},
398	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
399		base.TypeSize = 0
400		return &prog.BufferType{
401			TypeCommon: base.TypeCommon,
402			Kind:       prog.BufferText,
403			Text:       genTextType(args[0]),
404		}
405	},
406}
407
408var typeArgTextType = &typeArg{
409	Kind:  kindIdent,
410	Names: []string{"x86_real", "x86_16", "x86_32", "x86_64", "arm64"},
411}
412
413func genTextType(t *ast.Type) prog.TextKind {
414	switch t.Ident {
415	case "x86_real":
416		return prog.TextX86Real
417	case "x86_16":
418		return prog.TextX86bit16
419	case "x86_32":
420		return prog.TextX86bit32
421	case "x86_64":
422		return prog.TextX86bit64
423	case "arm64":
424		return prog.TextArm64
425	default:
426		panic(fmt.Sprintf("unknown text type %q", t.Ident))
427	}
428}
429
430var typeBuffer = &typeDesc{
431	Names:       []string{"buffer"},
432	CanBeArgRet: canBeArg,
433	Args:        []namedArg{{Name: "direction", Type: typeArgDir}},
434	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
435		base.TypeSize = comp.ptrSize
436		common := genCommon("", "", 0, genDir(args[0]), false)
437		// BufferBlobRand is always varlen.
438		common.IsVarlen = true
439		return &prog.PtrType{
440			TypeCommon: base.TypeCommon,
441			Type: &prog.BufferType{
442				TypeCommon: common,
443				Kind:       prog.BufferBlobRand,
444			},
445		}
446	},
447}
448
449const (
450	stringnoz = "stringnoz"
451)
452
453var typeString = &typeDesc{
454	Names:        []string{"string", stringnoz},
455	CanBeTypedef: true,
456	OptArgs:      2,
457	Args: []namedArg{
458		{Name: "literal or flags", Type: typeArgStringFlags},
459		{Name: "size", Type: typeArgInt},
460	},
461	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
462		if t.Ident == stringnoz && len(args) > 1 {
463			comp.error(args[0].Pos, "fixed-size string can't be non-zero-terminated")
464		}
465	},
466	CheckConsts: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
467		if len(args) > 1 {
468			size := args[1].Value
469			vals := comp.genStrings(t, args)
470			for _, s := range vals {
471				if uint64(len(s)) > size {
472					comp.error(args[0].Pos, "string value %q exceeds buffer length %v",
473						s, size)
474				}
475			}
476		}
477	},
478	Varlen: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
479		return comp.stringSize(t, args) == varlenString
480	},
481	ZeroSize: func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
482		return comp.stringSize(t, args) == 0
483	},
484	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
485		if len(args) > 0 && args[0].Ident == "filename" {
486			base.TypeName = "filename"
487			base.TypeSize = 0
488			if len(args) >= 2 {
489				base.TypeSize = args[1].Value
490			}
491			return &prog.BufferType{
492				TypeCommon: base.TypeCommon,
493				Kind:       prog.BufferFilename,
494				NoZ:        t.Ident == stringnoz,
495			}
496		}
497		subkind := ""
498		if len(args) > 0 && args[0].Ident != "" {
499			subkind = args[0].Ident
500		}
501		vals := comp.genStrings(t, args)
502		base.TypeSize = comp.stringSize(t, args)
503		if base.TypeSize == varlenString {
504			base.TypeSize = 0
505		}
506		return &prog.BufferType{
507			TypeCommon: base.TypeCommon,
508			Kind:       prog.BufferString,
509			SubKind:    subkind,
510			Values:     vals,
511			NoZ:        t.Ident == stringnoz,
512		}
513	},
514}
515
516func (comp *compiler) genStrings(t *ast.Type, args []*ast.Type) []string {
517	var vals []string
518	if len(args) > 0 {
519		if args[0].HasString {
520			vals = append(vals, args[0].String)
521		} else {
522			vals = genStrArray(comp.strFlags[args[0].Ident].Values)
523		}
524	}
525	if t.Ident == stringnoz {
526		return vals
527	}
528	var size uint64
529	if len(args) > 1 {
530		size = args[1].Value
531	}
532	for i, s := range vals {
533		s += "\x00"
534		for uint64(len(s)) < size {
535			s += "\x00"
536		}
537		vals[i] = s
538	}
539	return vals
540}
541
542const varlenString = ^uint64(0)
543
544// stringSize returns static string size, or varlenString if it is variable length.
545func (comp *compiler) stringSize(t *ast.Type, args []*ast.Type) uint64 {
546	switch len(args) {
547	case 0:
548		return varlenString // a random string
549	case 1:
550		var z uint64
551		if t.Ident == "string" {
552			z = 1
553		}
554		if args[0].HasString {
555			return uint64(len(args[0].String)) + z // string constant
556		}
557		size := varlenString
558		for _, s := range comp.strFlags[args[0].Ident].Values {
559			s1 := uint64(len(s.Value)) + z
560			if size != varlenString && size != s1 {
561				return varlenString // strings of different lengths
562			}
563			size = s1
564		}
565		return size // all strings have the same length
566	case 2:
567		return args[1].Value // have explicit length
568	default:
569		panic("too many string args")
570	}
571}
572
573var typeArgStringFlags = &typeArg{
574	Check: func(comp *compiler, t *ast.Type) {
575		if !t.HasString && t.Ident == "" {
576			comp.error(t.Pos, "unexpected int %v, string arg must be a string literal or string flags", t.Value)
577			return
578		}
579		if t.Ident != "" && comp.strFlags[t.Ident] == nil {
580			comp.error(t.Pos, "unknown string flags %v", t.Ident)
581			return
582		}
583	},
584}
585
586var typeFmt = &typeDesc{
587	Names:        []string{"fmt"},
588	CanBeTypedef: true,
589	CantBeOpt:    true,
590	Args: []namedArg{
591		{Name: "format", Type: typeFmtFormat},
592		{Name: "value", Type: typeArgType, IsArg: true},
593	},
594	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
595		desc, _, _ := comp.getArgsBase(args[1], "", base.TypeCommon.ArgDir, true)
596		switch desc {
597		case typeResource, typeInt, typeLen, typeFlags, typeProc:
598		default:
599			comp.error(t.Pos, "bad fmt value %v, expect an integer", args[1].Ident)
600			return
601		}
602	},
603	Gen: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
604		var format prog.BinaryFormat
605		var size uint64
606		switch args[0].Ident {
607		case "dec":
608			format = prog.FormatStrDec
609			size = 20
610		case "hex":
611			format = prog.FormatStrHex
612			size = 18
613		case "oct":
614			format = prog.FormatStrOct
615			size = 23
616		}
617		typ := comp.genType(args[1], "", base.TypeCommon.ArgDir, true)
618		switch t := typ.(type) {
619		case *prog.ResourceType:
620			t.ArgFormat = format
621			t.TypeSize = size
622		case *prog.IntType:
623			t.ArgFormat = format
624			t.TypeSize = size
625		case *prog.LenType:
626			t.ArgFormat = format
627			t.TypeSize = size
628		case *prog.FlagsType:
629			t.ArgFormat = format
630			t.TypeSize = size
631		case *prog.ProcType:
632			t.ArgFormat = format
633			t.TypeSize = size
634		default:
635			panic(fmt.Sprintf("unexpected type: %#v", typ))
636		}
637		return typ
638	},
639}
640
641var typeFmtFormat = &typeArg{
642	Names: []string{"dec", "hex", "oct"},
643	Kind:  kindIdent,
644}
645
646// typeArgType is used as placeholder for any type (e.g. ptr target type).
647var typeArgType = &typeArg{}
648
649var typeResource = &typeDesc{
650	// No Names, but getTypeDesc knows how to match it.
651	CanBeArgRet:  canBeArgRet,
652	ResourceBase: true,
653	// Gen is assigned below to avoid initialization loop.
654}
655
656func init() {
657	typeResource.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
658		// Find and generate base type to get its size.
659		var baseType *ast.Type
660		for r := comp.resources[t.Ident]; r != nil; {
661			baseType = r.Base
662			r = comp.resources[r.Base.Ident]
663		}
664		baseProgType := comp.genType(baseType, "", prog.DirIn, false)
665		base.TypeSize = baseProgType.Size()
666		return &prog.ResourceType{
667			TypeCommon: base.TypeCommon,
668			ArgFormat:  baseProgType.Format(),
669		}
670	}
671}
672
673var typeStruct = &typeDesc{
674	// No Names, but getTypeDesc knows how to match it.
675	CantBeOpt:    true,
676	CanBeTypedef: true,
677	// Varlen/Gen are assigned below due to initialization cycle.
678}
679
680func init() {
681	typeStruct.CanBeArgRet = func(comp *compiler, t *ast.Type) (bool, bool) {
682		// Allow unions to be arg if all options can be arg.
683		s := comp.structs[t.Ident]
684		if !s.IsUnion {
685			return false, false
686		}
687		canBeArg := true
688		for _, fld := range s.Fields {
689			desc := comp.getTypeDesc(fld.Type)
690			if desc == nil || desc.CanBeArgRet == nil {
691				return false, false
692			}
693			canBeArg1, _ := desc.CanBeArgRet(comp, fld.Type)
694			if !canBeArg1 {
695				canBeArg = false
696			}
697		}
698		return canBeArg, false
699	}
700	typeStruct.Varlen = func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
701		return comp.structIsVarlen(t.Ident)
702	}
703	typeStruct.ZeroSize = func(comp *compiler, t *ast.Type, args []*ast.Type) bool {
704		for _, fld := range comp.structs[t.Ident].Fields {
705			if !comp.isZeroSize(fld.Type) {
706				return false
707			}
708		}
709		return true
710	}
711	typeStruct.Gen = func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) prog.Type {
712		s := comp.structs[t.Ident]
713		key := prog.StructKey{
714			Name: t.Ident,
715			Dir:  base.ArgDir,
716		}
717		desc := comp.structDescs[key]
718		if desc == nil {
719			// Need to assign to structDescs before calling genStructDesc to break recursion.
720			desc = new(prog.StructDesc)
721			comp.structDescs[key] = desc
722			comp.genStructDesc(desc, s, base.ArgDir, typeStruct.Varlen(comp, t, args))
723		}
724		if s.IsUnion {
725			return &prog.UnionType{
726				Key:        key,
727				FldName:    base.FldName,
728				StructDesc: desc,
729			}
730		}
731		return &prog.StructType{
732			Key:        key,
733			FldName:    base.FldName,
734			StructDesc: desc,
735		}
736	}
737}
738
739var typeTypedef = &typeDesc{
740	// No Names, but getTypeDesc knows how to match it.
741	Check: func(comp *compiler, t *ast.Type, args []*ast.Type, base prog.IntTypeCommon) {
742		panic("must not be called")
743	},
744}
745
746var typeArgDir = &typeArg{
747	Kind:  kindIdent,
748	Names: []string{"in", "out", "inout"},
749}
750
751func genDir(t *ast.Type) prog.Dir {
752	switch t.Ident {
753	case "in":
754		return prog.DirIn
755	case "out":
756		return prog.DirOut
757	case "inout":
758		return prog.DirInOut
759	default:
760		panic(fmt.Sprintf("unknown direction %q", t.Ident))
761	}
762}
763
764var typeArgInt = &typeArg{
765	Kind: kindInt,
766}
767
768var typeArgIntRange = &typeArg{
769	Kind:       kindInt,
770	AllowColon: true,
771	CheckConsts: func(comp *compiler, t *ast.Type) {
772		if !t.HasColon {
773			t.Value2 = t.Value
774			t.Value2Fmt = t.ValueFmt
775		}
776		if t.Value2-t.Value > 1<<64-1<<32 {
777			comp.error(t.Pos, "bad int range [%v:%v]", t.Value, t.Value2)
778		}
779	},
780}
781
782// Size of array and vma's.
783var typeArgSizeRange = &typeArg{
784	Kind:       kindInt,
785	AllowColon: true,
786	CheckConsts: func(comp *compiler, t *ast.Type) {
787		if !t.HasColon {
788			t.Value2 = t.Value
789		}
790		const maxVal = 1e6
791		if t.Value > t.Value2 || t.Value > maxVal || t.Value2 > maxVal {
792			comp.error(t.Pos, "bad size range [%v:%v]", t.Value, t.Value2)
793		}
794	},
795}
796
797// Base type of const/len/etc. Same as typeInt, but can't have range.
798var typeArgBase = namedArg{
799	Name: "base type",
800	Type: &typeArg{
801		Names:      []string{"int8", "int16", "int32", "int64", "int16be", "int32be", "int64be", "intptr"},
802		AllowColon: true,
803		Check: func(comp *compiler, t *ast.Type) {
804			if t.HasColon {
805				if t.Ident2 != "" {
806					comp.error(t.Pos2, "literal const bitfield sizes are not supported")
807					return
808				}
809				if t.Value2 == 0 {
810					// This was not supported historically
811					// and does not work the way C bitfields of size 0 work.
812					// We could allow this, but then we need to make
813					// this work the way C bitfields work.
814					comp.error(t.Pos2, "bitfields of size 0 are not supported")
815				}
816				size, _ := comp.parseIntType(t.Ident)
817				if t.Value2 > size*8 {
818					comp.error(t.Pos2, "bitfield of size %v is too large for base type of size %v",
819						t.Value2, size*8)
820				}
821			}
822		},
823	},
824}
825
826var (
827	builtinTypes    = make(map[string]*typeDesc)
828	builtinTypedefs = make(map[string]*ast.TypeDef)
829	builtinStrFlags = make(map[string]*ast.StrFlags)
830
831	// To avoid weird cases like ptr[in, in] and ptr[out, opt].
832	reservedName = map[string]bool{
833		"opt":   true,
834		"in":    true,
835		"out":   true,
836		"inout": true,
837	}
838)
839
840const builtinDefs = `
841type bool8 int8[0:1]
842type bool16 int16[0:1]
843type bool32 int32[0:1]
844type bool64 int64[0:1]
845type boolptr intptr[0:1]
846
847type filename string[filename]
848filename = "", "."
849
850type optional[T] [
851	val	T
852	void	void
853] [varlen]
854`
855
856func init() {
857	builtins := []*typeDesc{
858		typeInt,
859		typePtr,
860		typeVoid,
861		typeArray,
862		typeLen,
863		typeConst,
864		typeFlags,
865		typeFileoff,
866		typeVMA,
867		typeCsum,
868		typeProc,
869		typeText,
870		typeBuffer,
871		typeString,
872		typeFmt,
873	}
874	for _, desc := range builtins {
875		for _, name := range desc.Names {
876			if builtinTypes[name] != nil {
877				panic(fmt.Sprintf("duplicate builtin type %q", name))
878			}
879			builtinTypes[name] = desc
880		}
881	}
882	builtinDesc := ast.Parse([]byte(builtinDefs), "builtins", func(pos ast.Pos, msg string) {
883		panic(fmt.Sprintf("failed to parse builtins: %v: %v", pos, msg))
884	})
885	for _, decl := range builtinDesc.Nodes {
886		switch n := decl.(type) {
887		case *ast.TypeDef:
888			builtinTypedefs[n.Name.Name] = n
889		case *ast.StrFlags:
890			builtinStrFlags[n.Name.Name] = n
891		case *ast.NewLine:
892		default:
893			panic(fmt.Sprintf("unexpected node in builtins: %#v", n))
894		}
895	}
896}
897