2017-09-05 11:31:14 +00:00
|
|
|
// 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"
|
2017-11-22 10:42:10 +00:00
|
|
|
"math/rand"
|
2017-09-14 19:27:56 +00:00
|
|
|
"sort"
|
2017-12-13 10:58:10 +00:00
|
|
|
"sync"
|
prog: use Ref as Arg type
Use Ref in Arg instead of full Type interface.
This reduces size of all args. In partiuclar the most common
ConstArg is reduces from 32 bytes to 16 and now does not
contain any pointers (better for GC).
Running syz-db bench on a beefy corpus: before:
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.704699958s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.873792394s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.820479906s
after:
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 8.938939937s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1087 MB, live allocs 379 MB (8 M), time 9.410243167s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 9.38225806s
Max heap and live heap are reduced by 20%.
Update #1580
2020-04-25 13:05:19 +00:00
|
|
|
"sync/atomic"
|
2017-09-05 11:31:14 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// Target describes target OS/arch pair.
|
|
|
|
type Target struct {
|
2020-06-23 15:46:15 +00:00
|
|
|
OS string
|
|
|
|
Arch string
|
|
|
|
Revision string // unique hash representing revision of the descriptions
|
|
|
|
PtrSize uint64
|
|
|
|
PageSize uint64
|
|
|
|
NumPages uint64
|
|
|
|
DataOffset uint64
|
|
|
|
LittleEndian bool
|
2017-09-05 11:31:14 +00:00
|
|
|
|
|
|
|
Syscalls []*Syscall
|
|
|
|
Resources []*ResourceDesc
|
2017-09-20 19:18:36 +00:00
|
|
|
Consts []ConstValue
|
2017-09-05 11:31:14 +00:00
|
|
|
|
2020-04-18 10:36:52 +00:00
|
|
|
// MakeDataMmap creates calls that mmaps target data memory range.
|
|
|
|
MakeDataMmap func() []*Call
|
2017-09-05 11:31:14 +00:00
|
|
|
|
2020-03-14 15:42:00 +00:00
|
|
|
// Neutralize neutralizes harmful calls by transforming them into non-harmful ones
|
|
|
|
// (e.g. an ioctl that turns off console output is turned into ioctl that turns on output).
|
|
|
|
Neutralize func(c *Call)
|
2017-09-05 11:31:14 +00:00
|
|
|
|
pkg/csource: add ability to annotate syscalls using comments in C reproducers
Providing additional info, especially regarding syscall arguments, in reproducers
can be helpful. An example is device numbers passed to mknod(2).
This commit introduces an optional annotate function on a per target basis.
Example for the OpenBSD target:
$ cat prog.in
mknod(0x0, 0x0, 0x4503)
getpid()
$ syz-prog2c -prog prog.in
int main(void)
{
syscall(SYS_mmap, 0x20000000, 0x1000000, 3, 0x1012, -1, 0, 0);
syscall(SYS_mknod, 0, 0, 0x4503); /* major = 69, minor = 3 */
syscall(SYS_getpid);
return 0;
}
2019-05-21 21:17:22 +00:00
|
|
|
// AnnotateCall annotates a syscall invocation in C reproducers.
|
|
|
|
// The returned string will be placed inside a comment except for the
|
|
|
|
// empty string which will omit the comment.
|
|
|
|
AnnotateCall func(c ExecCall) string
|
|
|
|
|
2018-01-24 18:28:36 +00:00
|
|
|
// SpecialTypes allows target to do custom generation/mutation for some struct's and union's.
|
|
|
|
// Map key is struct/union name for which custom generation/mutation is required.
|
2017-09-05 11:31:14 +00:00
|
|
|
// Map value is custom generation/mutation function that will be called
|
2018-01-24 18:28:36 +00:00
|
|
|
// for the corresponding type. g is helper object that allows generate random numbers,
|
|
|
|
// allocate memory, etc. typ is the struct/union type. old is the old value of the struct/union
|
|
|
|
// for mutation, or nil for generation. The function returns a new value of the struct/union,
|
2017-09-05 11:31:14 +00:00
|
|
|
// and optionally any calls that need to be inserted before the arg reference.
|
2020-04-26 12:14:14 +00:00
|
|
|
SpecialTypes map[string]func(g *Gen, typ Type, dir Dir, old Arg) (Arg, []*Call)
|
2017-09-05 11:31:14 +00:00
|
|
|
|
2019-12-30 10:41:20 +00:00
|
|
|
// Resources that play auxiliary role, but widely used throughout all syscalls (e.g. pid/uid).
|
|
|
|
AuxResources map[string]bool
|
|
|
|
|
2018-08-30 21:17:47 +00:00
|
|
|
// Additional special invalid pointer values besides NULL to use.
|
|
|
|
SpecialPointers []uint64
|
|
|
|
|
2017-09-14 17:25:01 +00:00
|
|
|
// Filled by prog package:
|
2020-05-03 14:53:36 +00:00
|
|
|
SyscallMap map[string]*Syscall
|
|
|
|
ConstMap map[string]uint64
|
|
|
|
|
2017-12-13 10:58:10 +00:00
|
|
|
init sync.Once
|
|
|
|
initArch func(target *Target)
|
2020-05-03 14:53:36 +00:00
|
|
|
types []Type
|
2017-09-05 14:32:32 +00:00
|
|
|
resourceMap map[string]*ResourceDesc
|
|
|
|
// Maps resource name to a list of calls that can create the resource.
|
2017-09-05 11:31:14 +00:00
|
|
|
resourceCtors map[string][]*Syscall
|
2018-03-08 17:48:26 +00:00
|
|
|
any anyTypes
|
2020-05-04 06:58:32 +00:00
|
|
|
|
|
|
|
// The default ChoiceTable is used only by tests and utilities, so we initialize it lazily.
|
|
|
|
defaultOnce sync.Once
|
|
|
|
defaultChoiceTable *ChoiceTable
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
|
|
|
|
2018-08-30 21:17:47 +00:00
|
|
|
const maxSpecialPointers = 16
|
|
|
|
|
2017-09-05 11:31:14 +00:00
|
|
|
var targets = make(map[string]*Target)
|
|
|
|
|
2020-05-03 14:53:36 +00:00
|
|
|
func RegisterTarget(target *Target, types []Type, initArch func(target *Target)) {
|
2017-09-05 11:31:14 +00:00
|
|
|
key := target.OS + "/" + target.Arch
|
|
|
|
if targets[key] != nil {
|
|
|
|
panic(fmt.Sprintf("duplicate target %v", key))
|
|
|
|
}
|
2017-12-13 10:58:10 +00:00
|
|
|
target.initArch = initArch
|
2020-05-03 14:53:36 +00:00
|
|
|
target.types = types
|
2017-09-05 11:31:14 +00:00
|
|
|
targets[key] = target
|
2017-09-13 13:15:36 +00:00
|
|
|
}
|
2017-09-05 11:31:14 +00:00
|
|
|
|
2017-09-14 17:25:01 +00:00
|
|
|
func GetTarget(OS, arch string) (*Target, error) {
|
2018-10-08 22:57:53 +00:00
|
|
|
if OS == "android" {
|
|
|
|
OS = "linux"
|
|
|
|
}
|
2017-09-13 13:15:36 +00:00
|
|
|
key := OS + "/" + arch
|
|
|
|
target := targets[key]
|
|
|
|
if target == nil {
|
2017-09-13 18:40:27 +00:00
|
|
|
var supported []string
|
|
|
|
for _, t := range targets {
|
|
|
|
supported = append(supported, fmt.Sprintf("%v/%v", t.OS, t.Arch))
|
|
|
|
}
|
2017-09-14 19:27:56 +00:00
|
|
|
sort.Strings(supported)
|
2017-09-14 17:25:01 +00:00
|
|
|
return nil, fmt.Errorf("unknown target: %v (supported: %v)", key, supported)
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
2017-12-13 10:58:10 +00:00
|
|
|
target.init.Do(target.lazyInit)
|
2017-09-14 17:25:01 +00:00
|
|
|
return target, nil
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
|
|
|
|
2017-09-14 19:27:56 +00:00
|
|
|
func AllTargets() []*Target {
|
|
|
|
var res []*Target
|
2017-12-13 10:58:10 +00:00
|
|
|
for _, target := range targets {
|
|
|
|
target.init.Do(target.lazyInit)
|
|
|
|
res = append(res, target)
|
2017-09-14 19:27:56 +00:00
|
|
|
}
|
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2017-12-13 10:58:10 +00:00
|
|
|
func (target *Target) lazyInit() {
|
2020-03-14 15:42:00 +00:00
|
|
|
target.Neutralize = func(c *Call) {}
|
pkg/csource: add ability to annotate syscalls using comments in C reproducers
Providing additional info, especially regarding syscall arguments, in reproducers
can be helpful. An example is device numbers passed to mknod(2).
This commit introduces an optional annotate function on a per target basis.
Example for the OpenBSD target:
$ cat prog.in
mknod(0x0, 0x0, 0x4503)
getpid()
$ syz-prog2c -prog prog.in
int main(void)
{
syscall(SYS_mmap, 0x20000000, 0x1000000, 3, 0x1012, -1, 0, 0);
syscall(SYS_mknod, 0, 0, 0x4503); /* major = 69, minor = 3 */
syscall(SYS_getpid);
return 0;
}
2019-05-21 21:17:22 +00:00
|
|
|
target.AnnotateCall = func(c ExecCall) string { return "" }
|
2017-12-13 10:58:10 +00:00
|
|
|
target.initTarget()
|
|
|
|
target.initArch(target)
|
2018-08-30 21:17:47 +00:00
|
|
|
// Give these 2 known addresses fixed positions and prepend target-specific ones at the end.
|
|
|
|
target.SpecialPointers = append([]uint64{
|
|
|
|
0x0000000000000000, // NULL pointer (keep this first because code uses special index=0 as NULL)
|
|
|
|
0xffffffffffffffff, // unmapped kernel address (keep second because serialized value will match actual pointer value)
|
|
|
|
0x9999999999999999, // non-canonical address
|
|
|
|
}, target.SpecialPointers...)
|
|
|
|
if len(target.SpecialPointers) > maxSpecialPointers {
|
|
|
|
panic("too many special pointers")
|
|
|
|
}
|
2020-05-03 14:53:36 +00:00
|
|
|
// These are used only during lazyInit.
|
|
|
|
target.ConstMap = nil
|
|
|
|
target.types = nil
|
2017-12-13 10:58:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (target *Target) initTarget() {
|
2017-09-20 19:18:36 +00:00
|
|
|
target.ConstMap = make(map[string]uint64)
|
|
|
|
for _, c := range target.Consts {
|
|
|
|
target.ConstMap[c.Name] = c.Value
|
|
|
|
}
|
|
|
|
|
2020-05-03 14:53:36 +00:00
|
|
|
target.resourceMap = restoreLinks(target.Syscalls, target.Resources, target.types)
|
|
|
|
target.initAnyTypes()
|
2017-09-20 19:18:36 +00:00
|
|
|
|
2017-09-14 17:25:01 +00:00
|
|
|
target.SyscallMap = make(map[string]*Syscall)
|
2018-02-25 13:31:40 +00:00
|
|
|
for i, c := range target.Syscalls {
|
|
|
|
c.ID = i
|
2017-09-14 17:25:01 +00:00
|
|
|
target.SyscallMap[c.Name] = c
|
2019-12-30 10:41:20 +00:00
|
|
|
c.inputResources = target.getInputResources(c)
|
|
|
|
c.outputResources = target.getOutputResources(c)
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
2017-09-20 19:18:36 +00:00
|
|
|
|
2019-08-21 18:05:22 +00:00
|
|
|
target.populateResourceCtors()
|
2017-09-05 11:31:14 +00:00
|
|
|
target.resourceCtors = make(map[string][]*Syscall)
|
2017-09-20 19:18:36 +00:00
|
|
|
for _, res := range target.Resources {
|
2019-08-21 18:05:22 +00:00
|
|
|
target.resourceCtors[res.Name] = target.calcResourceCtors(res, false)
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-19 18:08:19 +00:00
|
|
|
func (target *Target) GetConst(name string) uint64 {
|
|
|
|
if target.ConstMap == nil {
|
|
|
|
panic("GetConst can only be used during target initialization")
|
|
|
|
}
|
|
|
|
v, ok := target.ConstMap[name]
|
|
|
|
if !ok {
|
|
|
|
panic(fmt.Sprintf("const %v is not defined for %v/%v", name, target.OS, target.Arch))
|
|
|
|
}
|
|
|
|
return v
|
|
|
|
}
|
|
|
|
|
2020-03-14 15:42:00 +00:00
|
|
|
func (target *Target) sanitize(c *Call, fix bool) error {
|
|
|
|
target.Neutralize(c)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-05-03 09:29:12 +00:00
|
|
|
func RestoreLinks(syscalls []*Syscall, resources []*ResourceDesc, types []Type) {
|
|
|
|
restoreLinks(syscalls, resources, types)
|
2019-12-17 16:34:47 +00:00
|
|
|
}
|
|
|
|
|
prog: use Ref as Arg type
Use Ref in Arg instead of full Type interface.
This reduces size of all args. In partiuclar the most common
ConstArg is reduces from 32 bytes to 16 and now does not
contain any pointers (better for GC).
Running syz-db bench on a beefy corpus: before:
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.704699958s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.873792394s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.820479906s
after:
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 8.938939937s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1087 MB, live allocs 379 MB (8 M), time 9.410243167s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 9.38225806s
Max heap and live heap are reduced by 20%.
Update #1580
2020-04-25 13:05:19 +00:00
|
|
|
var (
|
|
|
|
typeRefMu sync.Mutex
|
|
|
|
typeRefs atomic.Value // []Type
|
|
|
|
)
|
|
|
|
|
2020-05-03 09:29:12 +00:00
|
|
|
func restoreLinks(syscalls []*Syscall, resources []*ResourceDesc, types []Type) map[string]*ResourceDesc {
|
prog: use Ref as Arg type
Use Ref in Arg instead of full Type interface.
This reduces size of all args. In partiuclar the most common
ConstArg is reduces from 32 bytes to 16 and now does not
contain any pointers (better for GC).
Running syz-db bench on a beefy corpus: before:
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.704699958s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.873792394s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.820479906s
after:
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 8.938939937s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1087 MB, live allocs 379 MB (8 M), time 9.410243167s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 9.38225806s
Max heap and live heap are reduced by 20%.
Update #1580
2020-04-25 13:05:19 +00:00
|
|
|
typeRefMu.Lock()
|
|
|
|
defer typeRefMu.Unlock()
|
|
|
|
refs := []Type{nil}
|
|
|
|
if old := typeRefs.Load(); old != nil {
|
|
|
|
refs = old.([]Type)
|
|
|
|
}
|
|
|
|
for _, typ := range types {
|
|
|
|
typ.setRef(Ref(len(refs)))
|
|
|
|
refs = append(refs, typ)
|
|
|
|
}
|
|
|
|
typeRefs.Store(refs)
|
|
|
|
|
2019-12-17 16:34:47 +00:00
|
|
|
resourceMap := make(map[string]*ResourceDesc)
|
|
|
|
for _, res := range resources {
|
|
|
|
resourceMap[res.Name] = res
|
|
|
|
}
|
prog: use Ref as Arg type
Use Ref in Arg instead of full Type interface.
This reduces size of all args. In partiuclar the most common
ConstArg is reduces from 32 bytes to 16 and now does not
contain any pointers (better for GC).
Running syz-db bench on a beefy corpus: before:
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.704699958s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.873792394s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.820479906s
after:
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 8.938939937s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1087 MB, live allocs 379 MB (8 M), time 9.410243167s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 9.38225806s
Max heap and live heap are reduced by 20%.
Update #1580
2020-04-25 13:05:19 +00:00
|
|
|
|
|
|
|
ForeachType(syscalls, func(typ Type, ctx TypeCtx) {
|
|
|
|
if ref, ok := typ.(Ref); ok {
|
|
|
|
typ = types[ref]
|
|
|
|
*ctx.Ptr = typ
|
2020-04-25 08:06:37 +00:00
|
|
|
}
|
prog: use Ref as Arg type
Use Ref in Arg instead of full Type interface.
This reduces size of all args. In partiuclar the most common
ConstArg is reduces from 32 bytes to 16 and now does not
contain any pointers (better for GC).
Running syz-db bench on a beefy corpus: before:
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.704699958s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.873792394s
allocs 7262 MB (18 M), next GC 958 MB, sys heap 1279 MB, live allocs 479 MB (8 M), time 9.820479906s
after:
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 8.938939937s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1087 MB, live allocs 379 MB (8 M), time 9.410243167s
allocs 7163 MB (18 M), next GC 759 MB, sys heap 1023 MB, live allocs 379 MB (8 M), time 9.38225806s
Max heap and live heap are reduced by 20%.
Update #1580
2020-04-25 13:05:19 +00:00
|
|
|
switch t := typ.(type) {
|
2020-05-03 09:29:12 +00:00
|
|
|
case *ResourceType:
|
|
|
|
t.Desc = resourceMap[t.TypeName]
|
|
|
|
if t.Desc == nil {
|
|
|
|
panic("no resource desc")
|
2019-12-17 16:34:47 +00:00
|
|
|
}
|
2020-05-03 09:29:12 +00:00
|
|
|
}
|
|
|
|
})
|
2019-12-17 16:34:47 +00:00
|
|
|
return resourceMap
|
|
|
|
}
|
|
|
|
|
2020-05-04 06:58:32 +00:00
|
|
|
func (target *Target) DefaultChoiceTable() *ChoiceTable {
|
|
|
|
target.defaultOnce.Do(func() {
|
|
|
|
target.defaultChoiceTable = target.BuildChoiceTable(nil, nil)
|
|
|
|
})
|
|
|
|
return target.defaultChoiceTable
|
|
|
|
}
|
|
|
|
|
2017-09-05 11:31:14 +00:00
|
|
|
type Gen struct {
|
|
|
|
r *randGen
|
|
|
|
s *state
|
|
|
|
}
|
|
|
|
|
2018-02-17 16:17:56 +00:00
|
|
|
func (g *Gen) Target() *Target {
|
|
|
|
return g.r.target
|
|
|
|
}
|
|
|
|
|
2017-11-22 10:42:10 +00:00
|
|
|
func (g *Gen) Rand() *rand.Rand {
|
|
|
|
return g.r.Rand
|
|
|
|
}
|
|
|
|
|
2017-09-05 11:31:14 +00:00
|
|
|
func (g *Gen) NOutOf(n, outOf int) bool {
|
|
|
|
return g.r.nOutOf(n, outOf)
|
|
|
|
}
|
|
|
|
|
2020-04-26 12:14:14 +00:00
|
|
|
func (g *Gen) Alloc(ptrType Type, dir Dir, data Arg) (Arg, []*Call) {
|
|
|
|
return g.r.allocAddr(g.s, ptrType, dir, data.Size(), data), nil
|
2017-09-05 11:31:14 +00:00
|
|
|
}
|
2017-11-22 10:42:10 +00:00
|
|
|
|
2020-04-26 12:14:14 +00:00
|
|
|
func (g *Gen) GenerateArg(typ Type, dir Dir, pcalls *[]*Call) Arg {
|
|
|
|
return g.generateArg(typ, dir, pcalls, false)
|
2018-01-24 18:28:36 +00:00
|
|
|
}
|
|
|
|
|
2020-04-26 12:14:14 +00:00
|
|
|
func (g *Gen) GenerateSpecialArg(typ Type, dir Dir, pcalls *[]*Call) Arg {
|
|
|
|
return g.generateArg(typ, dir, pcalls, true)
|
2018-01-24 18:28:36 +00:00
|
|
|
}
|
|
|
|
|
2020-04-26 12:14:14 +00:00
|
|
|
func (g *Gen) generateArg(typ Type, dir Dir, pcalls *[]*Call, ignoreSpecial bool) Arg {
|
|
|
|
arg, calls := g.r.generateArgImpl(g.s, typ, dir, ignoreSpecial)
|
2017-11-22 10:42:10 +00:00
|
|
|
*pcalls = append(*pcalls, calls...)
|
2020-05-01 15:19:27 +00:00
|
|
|
g.r.target.assignSizesArray([]Arg{arg}, []Field{{Name: "", Type: arg.Type()}}, nil)
|
2017-11-22 10:42:10 +00:00
|
|
|
return arg
|
|
|
|
}
|
2018-01-24 18:28:36 +00:00
|
|
|
|
|
|
|
func (g *Gen) MutateArg(arg0 Arg) (calls []*Call) {
|
|
|
|
updateSizes := true
|
|
|
|
for stop := false; !stop; stop = g.r.oneOf(3) {
|
2018-02-18 13:45:32 +00:00
|
|
|
ma := &mutationArgs{target: g.r.target, ignoreSpecial: true}
|
|
|
|
ForeachSubArg(arg0, ma.collectArg)
|
|
|
|
if len(ma.args) == 0 {
|
2018-01-24 18:28:36 +00:00
|
|
|
// TODO(dvyukov): probably need to return this condition
|
|
|
|
// and updateSizes to caller so that Mutate can act accordingly.
|
|
|
|
return
|
|
|
|
}
|
2020-05-17 09:18:15 +00:00
|
|
|
arg, ctx := ma.chooseArg(g.r.Rand)
|
2018-02-18 12:49:48 +00:00
|
|
|
newCalls, ok := g.r.target.mutateArg(g.r, g.s, arg, ctx, &updateSizes)
|
2018-01-24 18:28:36 +00:00
|
|
|
if !ok {
|
|
|
|
continue
|
|
|
|
}
|
2018-02-01 14:20:37 +00:00
|
|
|
calls = append(calls, newCalls...)
|
2018-01-24 18:28:36 +00:00
|
|
|
}
|
|
|
|
return calls
|
|
|
|
}
|
2018-12-07 11:44:45 +00:00
|
|
|
|
2018-12-08 07:40:03 +00:00
|
|
|
type Builder struct {
|
2018-12-07 11:44:45 +00:00
|
|
|
target *Target
|
|
|
|
ma *memAlloc
|
|
|
|
p *Prog
|
|
|
|
}
|
|
|
|
|
2018-12-08 07:40:03 +00:00
|
|
|
func MakeProgGen(target *Target) *Builder {
|
|
|
|
return &Builder{
|
2018-12-07 11:44:45 +00:00
|
|
|
target: target,
|
|
|
|
ma: newMemAlloc(target.NumPages * target.PageSize),
|
|
|
|
p: &Prog{
|
|
|
|
Target: target,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-08 07:40:03 +00:00
|
|
|
func (pg *Builder) Append(c *Call) error {
|
2018-12-07 11:44:45 +00:00
|
|
|
pg.target.assignSizesCall(c)
|
2020-03-14 15:42:00 +00:00
|
|
|
pg.target.sanitize(c, true)
|
2018-12-07 11:44:45 +00:00
|
|
|
pg.p.Calls = append(pg.p.Calls, c)
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2020-07-14 07:47:26 +00:00
|
|
|
func (pg *Builder) Allocate(size, alignment uint64) uint64 {
|
|
|
|
return pg.ma.alloc(nil, size, alignment)
|
2018-12-07 11:44:45 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 07:40:03 +00:00
|
|
|
func (pg *Builder) AllocateVMA(npages uint64) uint64 {
|
2020-07-14 07:47:26 +00:00
|
|
|
return pg.ma.alloc(nil, npages*pg.target.PageSize, pg.target.PageSize)
|
2018-12-07 11:48:59 +00:00
|
|
|
}
|
|
|
|
|
2018-12-08 07:40:03 +00:00
|
|
|
func (pg *Builder) Finalize() (*Prog, error) {
|
2018-12-07 11:44:45 +00:00
|
|
|
if err := pg.p.validate(); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
if _, err := pg.p.SerializeForExec(make([]byte, ExecBufferSize)); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
p := pg.p
|
|
|
|
pg.p = nil
|
|
|
|
return p, nil
|
|
|
|
}
|