github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/pkg/compiler/attrs.go (about) 1 // Copyright 2020 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 compiler 5 6 import ( 7 "reflect" 8 9 "github.com/google/syzkaller/pkg/ast" 10 "github.com/google/syzkaller/prog" 11 ) 12 13 type attrDescAttrType int 14 15 const ( 16 flagAttr attrDescAttrType = iota 17 // TODO: Ultimately we want to replace intAttr with exprAttr. 18 // This will facilitate const expressions in e.g. size[] or align[]. 19 intAttr 20 exprAttr 21 stringAttr 22 ) 23 24 type attrDesc struct { 25 Name string 26 // For now we assume attributes can have only 1 argument and it's either an 27 // integer or an expression. 28 Type attrDescAttrType 29 // This function is not invoked for per-field attributes, only for whole 30 // structs/unions. 31 CheckConsts func(comp *compiler, parent ast.Node, attr *ast.Type) 32 } 33 34 var ( 35 attrPacked = &attrDesc{Name: "packed"} 36 attrVarlen = &attrDesc{Name: "varlen"} 37 attrSize = &attrDesc{Name: "size", Type: intAttr} 38 attrAlign = &attrDesc{Name: "align", Type: intAttr} 39 attrIn = &attrDesc{Name: "in"} 40 attrOut = &attrDesc{Name: "out"} 41 attrInOut = &attrDesc{Name: "inout"} 42 attrOutOverlay = &attrDesc{Name: "out_overlay"} 43 attrIf = &attrDesc{Name: "if", Type: exprAttr} 44 45 structAttrs = makeAttrs(attrPacked, attrSize, attrAlign) 46 unionAttrs = makeAttrs(attrVarlen, attrSize) 47 structFieldAttrs = makeAttrs(attrIn, attrOut, attrInOut, attrOutOverlay, attrIf) 48 unionFieldAttrs = makeAttrs(attrIn, attrIf) // attrIn is safe. 49 callAttrs = make(map[string]*attrDesc) 50 ) 51 52 func init() { 53 initCallAttrs() 54 55 attrSize.CheckConsts = func(comp *compiler, parent ast.Node, attr *ast.Type) { 56 _, typ, name := parent.Info() 57 if comp.structIsVarlen(name) { 58 comp.error(attr.Pos, "varlen %v %v has size attribute", typ, name) 59 } 60 sz := attr.Args[0].Value 61 if sz == 0 || sz > 1<<20 { 62 comp.error(attr.Args[0].Pos, "size attribute has bad value %v"+ 63 ", expect [1, 1<<20]", sz) 64 } 65 } 66 attrAlign.CheckConsts = func(comp *compiler, parent ast.Node, attr *ast.Type) { 67 _, _, name := parent.Info() 68 a := attr.Args[0].Value 69 if a&(a-1) != 0 || a == 0 || a > 1<<30 { 70 comp.error(attr.Pos, "bad struct %v alignment %v (must be a sane power of 2)", name, a) 71 } 72 } 73 } 74 75 func initCallAttrs() { 76 attrs := reflect.TypeOf(prog.SyscallAttrs{}) 77 for i := 0; i < attrs.NumField(); i++ { 78 attr := attrs.Field(i) 79 desc := &attrDesc{Name: attr.Name} 80 switch attr.Type.Kind() { 81 case reflect.Bool: 82 case reflect.Uint64: 83 desc.Type = intAttr 84 case reflect.String: 85 desc.Type = stringAttr 86 default: 87 panic("unsupported syscall attribute type") 88 } 89 callAttrs[prog.CppName(desc.Name)] = desc 90 } 91 } 92 93 func structOrUnionAttrs(n *ast.Struct) map[string]*attrDesc { 94 if n.IsUnion { 95 return unionAttrs 96 } 97 return structAttrs 98 } 99 100 func structOrUnionFieldAttrs(n *ast.Struct) map[string]*attrDesc { 101 if n.IsUnion { 102 return unionFieldAttrs 103 } 104 return structFieldAttrs 105 } 106 107 func makeAttrs(attrs ...*attrDesc) map[string]*attrDesc { 108 m := make(map[string]*attrDesc) 109 for _, attr := range attrs { 110 m[attr.Name] = attr 111 } 112 return m 113 }