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