diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2015-12-23 19:18:13 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2015-12-23 19:18:13 +0100 |
| commit | 1c801e8512cc5a40ec13ea8b80c87836f5222781 (patch) | |
| tree | 1d0b8007d2142186a4774c9a395aeb707274aebd | |
| parent | 2eb388c0f81bfc3acf0c147654905c6d5c03df0d (diff) | |
prog: factor out execution log parsing functionality
It will be needed to reproduction tool.
| -rw-r--r-- | prog/parse.go | 68 | ||||
| -rw-r--r-- | prog/parse_test.go | 81 | ||||
| -rw-r--r-- | tools/syz-execprog/execprog.go | 44 |
3 files changed, 158 insertions, 35 deletions
diff --git a/prog/parse.go b/prog/parse.go new file mode 100644 index 000000000..e4a4e15ad --- /dev/null +++ b/prog/parse.go @@ -0,0 +1,68 @@ +// Copyright 2015 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 ( + "bytes" + "strconv" +) + +// LogEntry describes one program in execution log. +type LogEntry struct { + P *Prog + Proc int // index of parallel proc + Start int // start offset in log + End int // end offset in log +} + +func ParseLog(data []byte) []*LogEntry { + var entries []*LogEntry + ent := &LogEntry{} + var cur []byte + for pos := 0; pos < len(data); { + nl := bytes.IndexByte(data[pos:], '\n') + if nl == -1 { + nl = len(data) + } else { + nl += pos + } + line := data[pos : nl+1] + pos0 := pos + pos = nl + 1 + const delim = "executing program " + if delimPos := bytes.Index(line, []byte(delim)); delimPos != -1 { + if ent.P != nil && len(ent.P.Calls) != 0 { + ent.End = pos0 + entries = append(entries, ent) + } + procStart := delimPos + len(delim) + procEnd := procStart + for procEnd != len(line) && line[procEnd] >= '0' && line[procEnd] <= '9' { + procEnd++ + } + proc, _ := strconv.Atoi(string(line[procStart:procEnd])) + ent = &LogEntry{ + Proc: proc, + Start: pos0, + } + cur = nil + continue + } + if ent == nil { + continue + } + tmp := append(cur, line...) + p, err := Deserialize(tmp) + if err != nil { + continue + } + cur = tmp + ent.P = p + } + if ent.P != nil && len(ent.P.Calls) != 0 { + ent.End = len(data) + entries = append(entries, ent) + } + return entries +} diff --git a/prog/parse_test.go b/prog/parse_test.go new file mode 100644 index 000000000..93aa770cd --- /dev/null +++ b/prog/parse_test.go @@ -0,0 +1,81 @@ +// Copyright 2015 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 ( + "testing" +) + +func TestParseSingle(t *testing.T) { + const execLog = `getpid() +gettid() +` + entries := ParseLog([]byte(execLog)) + if len(entries) != 1 { + t.Fatalf("got %v programs, want 1", len(entries)) + } + ent := entries[0] + if ent.Start != 0 { + t.Fatalf("start offset %v, want 0", ent.Start) + } + if ent.End != len(execLog) { + t.Fatalf("end offset %v, want %v", ent.End, len(execLog)) + } + if ent.Proc != 0 { + t.Fatalf("proc %v, want 0", ent.Proc) + } + want := "getpid-gettid" + got := ent.P.String() + if got != want { + t.Fatalf("bad program: %s, want %s", got, want) + } +} + +func TestParseMulti(t *testing.T) { + entries := ParseLog([]byte(execLog)) + if len(entries) != 4 { + t.Fatalf("got %v programs, want 4") + } + off := 0 + for _, ent := range entries { + if off > ent.Start || ent.Start > ent.End || ent.End > len(execLog) { + t.Fatalf("bad offsets") + } + } + if entries[0].Proc != 1 || entries[1].Proc != 2 || entries[2].Proc != 33 || entries[3].Proc != 9 { + t.Fatalf("bad procs") + } + if s := entries[0].P.String(); s != "getpid-gettid-munlockall" { + t.Fatalf("bad program 0: %s", s) + } + if s := entries[1].P.String(); s != "getpid-gettid" { + t.Fatalf("bad program 1: %s", s) + } + if s := entries[2].P.String(); s != "gettid-getpid" { + t.Fatalf("bad program 2: %s", s) + } + if s := entries[3].P.String(); s != "munlockall" { + t.Fatalf("bad program 3: %s", s) + } +} + +const execLog = ` +getpid() +getpid() +2015/12/21 12:18:05 executing program 1: +getpid() +[ 2351.935478] Modules linked in: +gettid() +munlockall() +2015/12/21 12:18:05 executing program 2: +[ 2351.935478] Modules linked in: +getpid() +gettid() +2015/12/21 12:18:05 executing program 33: +gettid() +getpid() +[ 2351.935478] Modules linked in: +2015/12/21 12:18:05 executing program 9: +munlockall() +` diff --git a/tools/syz-execprog/execprog.go b/tools/syz-execprog/execprog.go index b8dd6ee9a..a637d47ff 100644 --- a/tools/syz-execprog/execprog.go +++ b/tools/syz-execprog/execprog.go @@ -6,7 +6,6 @@ package main import ( - "bufio" "bytes" "encoding/binary" "flag" @@ -41,14 +40,21 @@ var ( func main() { flag.Parse() if len(flag.Args()) == 0 { - fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs*\n") + fmt.Fprintf(os.Stderr, "usage: execprog [flags] file-with-programs+\n") flag.PrintDefaults() os.Exit(1) } var progs []*prog.Prog for _, fn := range flag.Args() { - progs = append(progs, parseFile(fn)...) + data, err := ioutil.ReadFile(fn) + if err != nil { + log.Fatalf("failed to read log file: %v", err) + } + entries := prog.ParseLog(data) + for _, ent := range entries { + progs = append(progs, ent.P) + } } log.Printf("parsed %v programs", len(progs)) if len(progs) == 0 { @@ -142,35 +148,3 @@ func main() { } wg.Wait() } - -func parseFile(fn string) []*prog.Prog { - logf, err := os.Open(fn) - if err != nil { - log.Fatalf("failed to open log file: %v", err) - } - log.Printf("parsing log %v", fn) - s := bufio.NewScanner(logf) - var cur []byte - var last *prog.Prog - var progs []*prog.Prog - for s.Scan() { - ln := s.Text() - tmp := append(cur, ln...) - tmp = append(tmp, '\n') - p, err := prog.Deserialize(tmp) - if err == nil { - cur = tmp - last = p - continue - } - if last != nil { - progs = append(progs, last) - last = nil - cur = cur[:0] - } - } - if last != nil { - progs = append(progs, last) - } - return progs -} |
