1// Copyright 2015 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// mutates mutates a given program and prints result.
5package main
6
7import (
8	"flag"
9	"fmt"
10	"io/ioutil"
11	"math/rand"
12	"os"
13	"runtime"
14	"strings"
15	"time"
16
17	"github.com/google/syzkaller/pkg/mgrconfig"
18	"github.com/google/syzkaller/prog"
19	_ "github.com/google/syzkaller/sys"
20)
21
22var (
23	flagOS     = flag.String("os", runtime.GOOS, "target os")
24	flagArch   = flag.String("arch", runtime.GOARCH, "target arch")
25	flagSeed   = flag.Int("seed", -1, "prng seed")
26	flagLen    = flag.Int("len", 30, "number of calls in programs")
27	flagEnable = flag.String("enable", "", "comma-separated list of enabled syscalls")
28)
29
30func main() {
31	flag.Parse()
32	target, err := prog.GetTarget(*flagOS, *flagArch)
33	if err != nil {
34		fmt.Fprintf(os.Stderr, "%v", err)
35		os.Exit(1)
36	}
37	var syscalls map[*prog.Syscall]bool
38	if *flagEnable != "" {
39		syscallsIDs, err := mgrconfig.ParseEnabledSyscalls(target, strings.Split(*flagEnable, ","), nil)
40		if err != nil {
41			fmt.Fprintf(os.Stderr, "failed to parse enabled syscalls: %v", err)
42			os.Exit(1)
43		}
44		syscalls = make(map[*prog.Syscall]bool)
45		for id := range syscallsIDs {
46			syscalls[target.Syscalls[id]] = true
47		}
48		var disabled map[*prog.Syscall]string
49		syscalls, disabled = target.TransitivelyEnabledCalls(syscalls)
50		for c, reason := range disabled {
51			fmt.Fprintf(os.Stderr, "disabling %v: %v\n", c.Name, reason)
52		}
53	}
54	seed := time.Now().UnixNano()
55	if *flagSeed != -1 {
56		seed = int64(*flagSeed)
57	}
58	rs := rand.NewSource(seed)
59	prios := target.CalculatePriorities(nil)
60	ct := target.BuildChoiceTable(prios, syscalls)
61	var p *prog.Prog
62	if flag.NArg() == 0 {
63		p = target.Generate(rs, *flagLen, ct)
64	} else {
65		data, err := ioutil.ReadFile(flag.Arg(0))
66		if err != nil {
67			fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err)
68			os.Exit(1)
69		}
70		p, err = target.Deserialize(data)
71		if err != nil {
72			fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err)
73			os.Exit(1)
74		}
75		p.Mutate(rs, *flagLen, ct, nil)
76	}
77	fmt.Printf("%s\n", p.Serialize())
78}
79