diff options
| author | Andrey Konovalov <andreyknvl@google.com> | 2019-09-23 15:34:59 +0200 |
|---|---|---|
| committer | Andrey Konovalov <andreyknvl@gmail.com> | 2019-09-23 17:13:23 +0200 |
| commit | 2b854f96b1a7be5c5c563fe798aaa2f6835ad2c6 (patch) | |
| tree | 8fe736742849104c860be93b989f4b7cddc28bc2 | |
| parent | 1e9788a0d9bd8fca36978810fd3fc50b6c4f060b (diff) | |
tools: add syz-expand
The syz-expand tools allows to parse a program and print it including all
the default values. This is mainly useful for debugging, like doing manual
program modifications while trying to come up with a reproducer for some
particular kernel behavior.
| -rw-r--r-- | Makefile | 3 | ||||
| -rw-r--r-- | prog/encoding.go | 30 | ||||
| -rw-r--r-- | prog/prog_test.go | 28 | ||||
| -rw-r--r-- | tools/syz-expand/expand.go | 52 |
4 files changed, 99 insertions, 14 deletions
@@ -172,6 +172,9 @@ trace2syz: usbgen: GOOS=$(HOSTOS) GOARCH=$(HOSTARCH) $(HOSTGO) build $(GOHOSTFLAGS) -o ./bin/syz-usbgen github.com/google/syzkaller/tools/syz-usbgen +expand: + GOOS=$(HOSTOS) GOARCH=$(HOSTARCH) $(HOSTGO) build $(GOHOSTFLAGS) -o ./bin/syz-expand github.com/google/syzkaller/tools/syz-expand + # `extract` extracts const files from various kernel sources, and may only # re-generate parts of files. extract: bin/syz-extract diff --git a/prog/encoding.go b/prog/encoding.go index 904a3e11b..1da491186 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -25,11 +25,20 @@ func (p *Prog) String() string { } func (p *Prog) Serialize() []byte { + return p.serialize(false) +} + +func (p *Prog) SerializeVerbose() []byte { + return p.serialize(true) +} + +func (p *Prog) serialize(verbose bool) []byte { p.debugValidate() ctx := &serializer{ - target: p.Target, - buf: new(bytes.Buffer), - vars: make(map[*ResultArg]int), + target: p.Target, + buf: new(bytes.Buffer), + vars: make(map[*ResultArg]int), + verbose: verbose, } for _, c := range p.Calls { ctx.call(c) @@ -38,10 +47,11 @@ func (p *Prog) Serialize() []byte { } type serializer struct { - target *Target - buf *bytes.Buffer - vars map[*ResultArg]int - varSeq int + target *Target + buf *bytes.Buffer + vars map[*ResultArg]int + varSeq int + verbose bool } func (ctx *serializer) printf(text string, args ...interface{}) { @@ -91,7 +101,7 @@ func (a *PointerArg) serialize(ctx *serializer) { } target := ctx.target ctx.printf("&%v", target.serializeAddr(a)) - if a.Res != nil && isDefault(a.Res) && !target.isAnyPtr(a.Type()) { + if a.Res != nil && !ctx.verbose && isDefault(a.Res) && !target.isAnyPtr(a.Type()) { return } ctx.printf("=") @@ -136,7 +146,7 @@ func (a *GroupArg) serialize(ctx *serializer) { } ctx.buf.WriteByte(delims[0]) lastNonDefault := len(a.Inner) - 1 - if a.fixedInnerSize() { + if !ctx.verbose && a.fixedInnerSize() { for ; lastNonDefault >= 0; lastNonDefault-- { if !isDefault(a.Inner[lastNonDefault]) { break @@ -158,7 +168,7 @@ func (a *GroupArg) serialize(ctx *serializer) { func (a *UnionArg) serialize(ctx *serializer) { ctx.printf("@%v", a.Option.Type().FieldName()) - if isDefault(a.Option) { + if !ctx.verbose && isDefault(a.Option) { return } ctx.printf("=") diff --git a/prog/prog_test.go b/prog/prog_test.go index 1605f7991..a07657308 100644 --- a/prog/prog_test.go +++ b/prog/prog_test.go @@ -46,19 +46,31 @@ func TestDefaultCallArgs(t *testing.T) { } } -func TestSerialize(t *testing.T) { +func testSerialize(t *testing.T, verbose bool) { target, rs, iters := initTest(t) for i := 0; i < iters; i++ { p := target.Generate(rs, 10, nil) - data := p.Serialize() - p1, err := target.Deserialize(data, NonStrict) + var data []byte + mode := NonStrict + if verbose { + data = p.SerializeVerbose() + mode = Strict + } else { + data = p.Serialize() + } + p1, err := target.Deserialize(data, mode) if err != nil { t.Fatalf("failed to deserialize program: %v\n%s", err, data) } if p1 == nil { t.Fatalf("deserialized nil program:\n%s", data) } - data1 := p1.Serialize() + var data1 []byte + if verbose { + data1 = p1.SerializeVerbose() + } else { + data1 = p1.Serialize() + } if len(p.Calls) != len(p1.Calls) { t.Fatalf("different number of calls") } @@ -68,6 +80,14 @@ func TestSerialize(t *testing.T) { } } +func TestSerialize(t *testing.T) { + testSerialize(t, false) +} + +func TestSerializeVerbose(t *testing.T) { + testSerialize(t, true) +} + func TestVmaType(t *testing.T) { target, rs, iters := initRandomTargetTest(t, "test", "64") meta := target.SyscallMap["test$vma0"] diff --git a/tools/syz-expand/expand.go b/tools/syz-expand/expand.go new file mode 100644 index 000000000..d90053d9d --- /dev/null +++ b/tools/syz-expand/expand.go @@ -0,0 +1,52 @@ +// Copyright 2019 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. + +// Parses a program and prints it including all default values. + +package main + +import ( + "flag" + "fmt" + "io/ioutil" + "os" + "runtime" + + "github.com/google/syzkaller/prog" + _ "github.com/google/syzkaller/sys" +) + +var ( + flagOS = flag.String("os", runtime.GOOS, "target os") + flagArch = flag.String("arch", runtime.GOARCH, "target arch") + flagProg = flag.String("prog", "", "file with program to expand") + flagStrict = flag.Bool("strict", false, "parse input program in strict mode") +) + +func main() { + flag.Parse() + if *flagProg == "" { + flag.Usage() + os.Exit(1) + } + target, err := prog.GetTarget(*flagOS, *flagArch) + if err != nil { + fmt.Fprintf(os.Stderr, "%v", err) + os.Exit(1) + } + data, err := ioutil.ReadFile(*flagProg) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to read prog file: %v\n", err) + os.Exit(1) + } + mode := prog.NonStrict + if *flagStrict { + mode = prog.Strict + } + p, err := target.Deserialize(data, mode) + if err != nil { + fmt.Fprintf(os.Stderr, "failed to deserialize the program: %v\n", err) + os.Exit(1) + } + fmt.Printf("%s", p.SerializeVerbose()) +} |
