aboutsummaryrefslogtreecommitdiffstats
path: root/sys/decl.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-09-05 13:31:14 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-09-05 15:52:42 +0200
commitffe7e17368d7ae6c2b40da2ce0703d8ad8a116ac (patch)
tree195b7c32977fdaab05acb1282a727fb480593431 /sys/decl.go
parent4fc47026945ebec3fc81d0c897547670034cfb58 (diff)
prog, sys: move types to prog
Large overhaul moves syscalls and arg types from sys to prog. Sys package now depends on prog and contains only generated descriptions of syscalls. Introduce prog.Target type that encapsulates all targer properties, like syscall list, ptr/page size, etc. Also moves OS-dependent pieces like mmap call generation from prog to sys. Update #191
Diffstat (limited to 'sys/decl.go')
-rw-r--r--sys/decl.go522
1 files changed, 0 insertions, 522 deletions
diff --git a/sys/decl.go b/sys/decl.go
deleted file mode 100644
index 82d27e915..000000000
--- a/sys/decl.go
+++ /dev/null
@@ -1,522 +0,0 @@
-// 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 sys
-
-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
-)
-
-type Type interface {
- 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
-}
-
-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
-}
-
-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.Varlen() {
- panic(fmt.Sprintf("static type size is not known: %#v", t))
- }
- return t.TypeSize
-}
-
-func (t *TypeCommon) Varlen() bool {
- return t.TypeSize == 0
-}
-
-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
-}
-
-const (
- InvalidFD = ^uint64(0)
-)
-
-type ResourceDesc struct {
- Name string
- Type Type
- Kind []string
- Values []uint64
-}
-
-type ResourceType struct {
- TypeCommon
- Desc *ResourceDesc
-}
-
-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) 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
-}
-
-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
- ByteSize uint64 // want size in multiple of bytes instead of array size
- Buf string
-}
-
-type ProcType struct {
- IntTypeCommon
- ValuesStart uint64
- ValuesPerProc uint64
-}
-
-type CsumKind int
-
-const (
- CsumInet CsumKind = iota
- CsumPseudo
-)
-
-type CsumType struct {
- IntTypeCommon
- Kind CsumKind
- Buf string
- Protocol uint64 // for CsumPseudo
-}
-
-type VmaType struct {
- TypeCommon
- RangeBegin uint64 // in pages
- RangeEnd uint64
-}
-
-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
-}
-
-type ArrayKind int
-
-const (
- ArrayRandLen ArrayKind = iota
- ArrayRangeLen
-)
-
-type ArrayType struct {
- TypeCommon
- Type Type
- Kind ArrayKind
- RangeBegin uint64
- RangeEnd uint64
-}
-
-type PtrType struct {
- TypeCommon
- Type Type
-}
-
-type StructType struct {
- Key StructKey
- FldName string
- *StructDesc
-}
-
-func (t *StructType) FieldName() string {
- return t.FldName
-}
-
-type UnionType struct {
- Key StructKey
- FldName string
- *StructDesc
-}
-
-func (t *UnionType) FieldName() string {
- return t.FldName
-}
-
-var (
- SyscallMap = make(map[string]*Syscall)
- Resources map[string]*ResourceDesc
- ctors = make(map[string][]*Syscall)
-)
-
-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
-}
-
-func initStructFields() {
- keyedStructs := make(map[StructKey]*StructDesc)
- for _, desc := range structDescs {
- keyedStructs[desc.Key] = desc.Desc
- }
-
- for _, c := range Syscalls {
- ForeachType(c, func(t Type) {
- switch s := t.(type) {
- case *StructType:
- s.StructDesc = keyedStructs[s.Key]
- if s.StructDesc == nil {
- panic("no struct desc")
- }
- case *UnionType:
- s.StructDesc = keyedStructs[s.Key]
- if s.StructDesc == nil {
- panic("no union desc")
- }
- }
- })
- }
-}
-
-// ResourceConstructors returns a list of calls that can create a resource of the given kind.
-func ResourceConstructors(name string) []*Syscall {
- return ctors[name]
-}
-
-func initResources() {
- Resources = make(map[string]*ResourceDesc)
- for _, res := range resourceArray {
- Resources[res.Name] = res
- }
- for _, c := range Syscalls {
- ForeachType(c, func(t Type) {
- if r, ok := t.(*ResourceType); ok {
- r.Desc = Resources[r.TypeName]
- }
- })
- }
- for _, res := range resourceArray {
- ctors[res.Name] = resourceCtors(res.Kind, false)
- }
-}
-
-func resourceCtors(kind []string, precise bool) []*Syscall {
- // Find calls that produce the necessary resources.
- var metas []*Syscall
- for _, meta := range Syscalls {
- // Recurse into arguments to see if there is an out/inout arg of necessary type.
- ok := false
- ForeachType(meta, func(typ Type) {
- if ok {
- return
- }
- switch typ1 := typ.(type) {
- case *ResourceType:
- if typ1.Dir() != DirIn && isCompatibleResource(kind, typ1.Desc.Kind, precise) {
- ok = true
- }
- }
- })
- if ok {
- metas = append(metas, meta)
- }
- }
- return metas
-}
-
-// IsCompatibleResource returns true if resource of kind src can be passed as an argument of kind dst.
-func IsCompatibleResource(dst, src string) bool {
- dstRes := Resources[dst]
- if dstRes == nil {
- panic(fmt.Sprintf("unknown resource '%v'", dst))
- }
- srcRes := Resources[src]
- if srcRes == nil {
- panic(fmt.Sprintf("unknown resource '%v'", src))
- }
- return isCompatibleResource(dstRes.Kind, srcRes.Kind, false)
-}
-
-// isCompatibleResource returns true if resource of kind src can be passed as an argument of kind dst.
-// If precise is true, then it does not allow passing a less specialized resource (e.g. fd)
-// as a more specialized resource (e.g. socket). Otherwise it does.
-func isCompatibleResource(dst, src []string, precise bool) bool {
- if len(dst) > len(src) {
- // dst is more specialized, e.g dst=socket, src=fd.
- if precise {
- return false
- }
- dst = dst[:len(src)]
- }
- if len(src) > len(dst) {
- // src is more specialized, e.g dst=fd, src=socket.
- src = src[:len(dst)]
- }
- for i, k := range dst {
- if k != src[i] {
- return false
- }
- }
- return true
-}
-
-func (c *Syscall) InputResources() []*ResourceType {
- var resources []*ResourceType
- ForeachType(c, func(typ Type) {
- switch typ1 := typ.(type) {
- case *ResourceType:
- if typ1.Dir() != DirOut && !typ1.IsOptional {
- resources = append(resources, typ1)
- }
- }
- })
- return resources
-}
-
-func TransitivelyEnabledCalls(enabled map[*Syscall]bool) map[*Syscall]bool {
- supported := make(map[*Syscall]bool)
- for c := range enabled {
- supported[c] = true
- }
- inputResources := make(map[*Syscall][]*ResourceType)
- ctors := make(map[string][]*Syscall)
- for c := range supported {
- inputs := c.InputResources()
- inputResources[c] = inputs
- for _, res := range inputs {
- if _, ok := ctors[res.Desc.Name]; ok {
- continue
- }
- ctors[res.Desc.Name] = resourceCtors(res.Desc.Kind, true)
- }
- }
- for {
- n := len(supported)
- haveGettime := supported[SyscallMap["clock_gettime"]]
- for c := range supported {
- canCreate := true
- for _, res := range inputResources[c] {
- noctors := true
- for _, ctor := range ctors[res.Desc.Name] {
- if supported[ctor] {
- noctors = false
- break
- }
- }
- if noctors {
- canCreate = false
- break
- }
- }
- // We need to support structs as resources,
- // but for now we just special-case timespec/timeval.
- if canCreate && !haveGettime {
- ForeachType(c, func(typ Type) {
- if a, ok := typ.(*StructType); ok && a.Dir() != DirOut && (a.Name() == "timespec" || a.Name() == "timeval") {
- canCreate = false
- }
- })
- }
- if !canCreate {
- delete(supported, c)
- }
- }
- if n == len(supported) {
- break
- }
- }
- return supported
-}
-
-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)
- }
-}
-
-func init() {
- initStructFields()
- initResources()
- structDescs = nil
-
- for _, c := range Syscalls {
- if SyscallMap[c.Name] != nil {
- println(c.Name)
- panic("duplicate syscall")
- }
- SyscallMap[c.Name] = c
- }
-}