blob: 4563f107dfb73c8c81e7f5fc372e927102ddb5d7 [file] [log] [blame]
// Copyright 2017 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 prog
import (
"fmt"
"math/rand"
"sort"
)
// Target describes target OS/arch pair.
type Target struct {
OS string
Arch string
Revision string // unique hash representing revision of the descriptions
PtrSize uint64
PageSize uint64
DataOffset uint64
Syscalls []*Syscall
Resources []*ResourceDesc
Structs []*KeyedStruct
Consts []ConstValue
// Syscall used by MakeMmap.
// It has some special meaning because there are usually too many of them.
MmapSyscall *Syscall
// MakeMmap creates call that maps [start, start+npages) page range.
MakeMmap func(start, npages uint64) *Call
// AnalyzeMmap analyzes the call c regarding mapping/unmapping memory.
// If it maps/unmaps any memory returns [start, start+npages) range,
// otherwise returns npages = 0.
AnalyzeMmap func(c *Call) (start, npages uint64, mapped bool)
// SanitizeCall neutralizes harmful calls.
SanitizeCall func(c *Call)
// SpecialStructs allows target to do custom generation/mutation for some struct types.
// Map key is struct name for which custom generation/mutation is required.
// Map value is custom generation/mutation function that will be called
// for the corresponding structs. g is helper object that allows generate random numbers,
// allocate memory, etc. typ is the struct type. old is the old value of the struct
// for mutation, or nil for generation. The function returns a new value of the struct,
// and optionally any calls that need to be inserted before the arg reference.
SpecialStructs map[string]func(g *Gen, typ *StructType, old *GroupArg) (Arg, []*Call)
// Special strings that can matter for the target.
// Used as fallback when string type does not have own dictionary.
StringDictionary []string
// Filled by prog package:
SyscallMap map[string]*Syscall
ConstMap map[string]uint64
resourceMap map[string]*ResourceDesc
// Maps resource name to a list of calls that can create the resource.
resourceCtors map[string][]*Syscall
}
var targets = make(map[string]*Target)
func RegisterTarget(target *Target, initArch func(target *Target)) {
key := target.OS + "/" + target.Arch
if targets[key] != nil {
panic(fmt.Sprintf("duplicate target %v", key))
}
target.SanitizeCall = func(c *Call) {}
initTarget(target)
initArch(target)
target.ConstMap = nil // currently used only by initArch
targets[key] = target
}
func GetTarget(OS, arch string) (*Target, error) {
key := OS + "/" + arch
target := targets[key]
if target == nil {
var supported []string
for _, t := range targets {
supported = append(supported, fmt.Sprintf("%v/%v", t.OS, t.Arch))
}
sort.Strings(supported)
return nil, fmt.Errorf("unknown target: %v (supported: %v)", key, supported)
}
return target, nil
}
func AllTargets() []*Target {
var res []*Target
for _, t := range targets {
res = append(res, t)
}
sort.Slice(res, func(i, j int) bool {
if res[i].OS != res[j].OS {
return res[i].OS < res[j].OS
}
return res[i].Arch < res[j].Arch
})
return res
}
func initTarget(target *Target) {
target.ConstMap = make(map[string]uint64)
for _, c := range target.Consts {
target.ConstMap[c.Name] = c.Value
}
target.resourceMap = make(map[string]*ResourceDesc)
for _, res := range target.Resources {
target.resourceMap[res.Name] = res
}
keyedStructs := make(map[StructKey]*StructDesc)
for _, desc := range target.Structs {
keyedStructs[desc.Key] = desc.Desc
}
target.Structs = nil
target.SyscallMap = make(map[string]*Syscall)
for _, c := range target.Syscalls {
target.SyscallMap[c.Name] = c
ForeachType(c, func(t0 Type) {
switch t := t0.(type) {
case *ResourceType:
t.Desc = target.resourceMap[t.TypeName]
if t.Desc == nil {
panic("no resource desc")
}
case *StructType:
t.StructDesc = keyedStructs[t.Key]
if t.StructDesc == nil {
panic("no struct desc")
}
case *UnionType:
t.StructDesc = keyedStructs[t.Key]
if t.StructDesc == nil {
panic("no union desc")
}
}
})
}
target.resourceCtors = make(map[string][]*Syscall)
for _, res := range target.Resources {
target.resourceCtors[res.Name] = target.calcResourceCtors(res.Kind, false)
}
}
type Gen struct {
r *randGen
s *state
}
func (g *Gen) Rand() *rand.Rand {
return g.r.Rand
}
func (g *Gen) NOutOf(n, outOf int) bool {
return g.r.nOutOf(n, outOf)
}
func (g *Gen) Alloc(ptrType Type, data Arg) (Arg, []*Call) {
return g.r.addr(g.s, ptrType, data.Size(), data)
}
func (g *Gen) GenerateArg(typ Type, pcalls *[]*Call) Arg {
arg, calls := g.r.generateArg(g.s, typ)
*pcalls = append(*pcalls, calls...)
return arg
}