aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-10-13 11:55:19 +0200
committerDmitry Vyukov <dvyukov@google.com>2015-10-13 15:29:07 +0200
commit29e95fbb262d0f19ee1f04a59bafda4bf8f97b63 (patch)
tree1b6e37f78ef2c60bef518fd95b2c2fd2f8798fd6
parent9145be6961b3b50eb682416c71e7c1b02b64cf33 (diff)
process covereage in ipc package instead of fuzzer
-rw-r--r--fuzzer/fuzzer.go46
-rw-r--r--ipc/ipc.go80
-rw-r--r--ipc/ipc_test.go13
-rw-r--r--tools/execlog/execlog.go2
-rw-r--r--tools/execprog/execprog.go2
-rw-r--r--tools/stress/stress.go2
6 files changed, 89 insertions, 56 deletions
diff --git a/fuzzer/fuzzer.go b/fuzzer/fuzzer.go
index e0ee11abd..d27196786 100644
--- a/fuzzer/fuzzer.go
+++ b/fuzzer/fuzzer.go
@@ -8,9 +8,7 @@ package main
// i.e. aim at cracking new branches and triggering bugs in that new piece of code.
import (
- "bytes"
"crypto/sha1"
- "encoding/binary"
"flag"
"fmt"
"log"
@@ -342,7 +340,7 @@ func execute1(env *ipc.Env, p *prog.Prog, workerId int) []cover.Cover {
try := 0
retry:
- output, strace, failed, hanged, err := env.Exec(p)
+ output, strace, rawCover, failed, hanged, err := env.Exec(p)
if err != nil {
if try > 10 {
panic(err)
@@ -356,47 +354,9 @@ retry:
if len(strace) != 0 {
logf(4, "strace:\n%s\n", strace)
}
- r := bytes.NewReader(env.Out)
- var ncmd uint32
- if err := binary.Read(r, binary.LittleEndian, &ncmd); err != nil {
- panic(err)
- }
cov := make([]cover.Cover, len(p.Calls))
- for i := uint32(0); i < ncmd; i++ {
- var callIndex, callNum, coverSize, pc uint32
- if err := binary.Read(r, binary.LittleEndian, &callIndex); err != nil {
- panic(err)
- }
- if err := binary.Read(r, binary.LittleEndian, &callNum); err != nil {
- panic(err)
- }
- if err := binary.Read(r, binary.LittleEndian, &coverSize); err != nil {
- panic(err)
- }
- if int(callIndex) > len(cov) {
- panic(fmt.Sprintf("expect index %v, got %v", i, callIndex))
- }
- c := p.Calls[callIndex]
- if num := c.Meta.ID; uint32(num) != callNum {
- logf(0, "ERROR: call %v: expect syscall %v, got %v, executed %v", callIndex, num, callNum, ncmd)
- logf(0, "program:\n%s", p.Serialize())
- logf(0, "output:\n%s", output)
- }
- cover1 := make([]uint32, 0, coverSize)
- for j := uint32(0); j < coverSize; j++ {
- if err := binary.Read(r, binary.LittleEndian, &pc); err != nil {
- panic(err)
- }
- cover1 = append(cover1, pc)
- }
- if *flagV >= 4 {
- log.Printf("%v:", c.Meta.Name)
- for _, pc := range cover1 {
- log.Printf(" 0x%x", (1<<32-1)<<32|uint64(pc))
- }
- log.Printf("\n")
- }
- cov[callIndex] = cover.Canonicalize(cover1)
+ for i, c := range rawCover {
+ cov[i] = cover.Canonicalize(c)
}
return cov
}
diff --git a/ipc/ipc.go b/ipc/ipc.go
index 678e79636..7702bba66 100644
--- a/ipc/ipc.go
+++ b/ipc/ipc.go
@@ -4,6 +4,8 @@
package ipc
import (
+ "bytes"
+ "encoding/binary"
"fmt"
"io/ioutil"
"os"
@@ -76,19 +78,87 @@ func (env *Env) Close() error {
}
}
-func (env *Env) Exec(p *prog.Prog) (output, strace []byte, failed, hanged bool, err0 error) {
+// Exec starts executor binary to execute program p and returns information about the execution:
+// output: process output
+// strace: strace output if env is created with FlagStrace
+// cov: per-call coverage, len(cov) == len(p.Calls)
+// failed: true if executor has detected a kernel bug
+// hanged: program hanged and was killed
+// err0: failed to start process, or executor has detected a logical error
+func (env *Env) Exec(p *prog.Prog) (output, strace []byte, cov [][]uint32, failed, hanged bool, err0 error) {
if p != nil {
+ // Copy-in serialized program.
progData := p.SerializeForExec()
if len(progData) > len(env.In) {
panic("program is too long")
}
copy(env.In, progData)
}
- // Zero out the first word (ncmd), so that we don't have garbage there
- // if executor crashes before writing non-garbage there.
- for i := 0; i < 4; i++ {
- env.Out[i] = 0
+ if env.flags&FlagCover != 0 {
+ // Zero out the first word (ncmd), so that we don't have garbage there
+ // if executor crashes before writing non-garbage there.
+ for i := 0; i < 4; i++ {
+ env.Out[i] = 0
+ }
+ }
+
+ output, strace, failed, hanged, err0 = env.execBin()
+ if err0 != nil {
+ return
+ }
+
+ if env.flags&FlagCover == 0 || p == nil {
+ return
+ }
+ // Read out coverage information.
+ r := bytes.NewReader(env.Out)
+ var ncmd uint32
+ if err := binary.Read(r, binary.LittleEndian, &ncmd); err != nil {
+ err0 = fmt.Errorf("failed to read output coverage: %v", err)
+ return
+ }
+ cov = make([][]uint32, len(p.Calls))
+ for i := uint32(0); i < ncmd; i++ {
+ var callIndex, callNum, coverSize, pc uint32
+ if err := binary.Read(r, binary.LittleEndian, &callIndex); err != nil {
+ err0 = fmt.Errorf("failed to read output coverage: %v", err)
+ return
+ }
+ if err := binary.Read(r, binary.LittleEndian, &callNum); err != nil {
+ err0 = fmt.Errorf("failed to read output coverage: %v", err)
+ return
+ }
+ if err := binary.Read(r, binary.LittleEndian, &coverSize); err != nil {
+ err0 = fmt.Errorf("failed to read output coverage: %v", err)
+ return
+ }
+ if int(callIndex) > len(cov) {
+ err0 = fmt.Errorf("failed to read output coverage: expect index %v, got %v", i, callIndex)
+ return
+ }
+ if cov[callIndex] != nil {
+ err0 = fmt.Errorf("failed to read output coverage: double coverage for call %v", callIndex)
+ return
+ }
+ c := p.Calls[callIndex]
+ if num := c.Meta.ID; uint32(num) != callNum {
+ err0 = fmt.Errorf("failed to read output coverage: call %v: expect syscall %v, got %v, executed %v", callIndex, num, callNum, ncmd)
+ return
+ }
+ cov1 := make([]uint32, coverSize)
+ for j := uint32(0); j < coverSize; j++ {
+ if err := binary.Read(r, binary.LittleEndian, &pc); err != nil {
+ err0 = fmt.Errorf("failed to read output coverage: expect index %v, got %v", i, callIndex)
+ return
+ }
+ cov1[j] = pc
+ }
+ cov[callIndex] = cov1
}
+ return
+}
+
+func (env *Env) execBin() (output, strace []byte, failed, hanged bool, err0 error) {
dir, err := ioutil.TempDir("./", "syzkaller-testdir")
if err != nil {
err0 = fmt.Errorf("failed to create temp dir: %v", err)
diff --git a/ipc/ipc_test.go b/ipc/ipc_test.go
index 87a57d232..b87bf4d2a 100644
--- a/ipc/ipc_test.go
+++ b/ipc/ipc_test.go
@@ -73,7 +73,7 @@ func TestEmptyProg(t *testing.T) {
defer env.Close()
p := new(prog.Prog)
- output, strace, failed, hanged, err := env.Exec(p)
+ output, strace, cov, failed, hanged, err := env.Exec(p)
if err != nil {
t.Fatalf("failed to run executor: %v", err)
}
@@ -83,6 +83,9 @@ func TestEmptyProg(t *testing.T) {
if len(strace) != 0 {
t.Fatalf("strace output when not stracing")
}
+ if cov != nil {
+ t.Fatalf("haven't asked for coverage, but got it")
+ }
if failed || hanged {
t.Fatalf("empty program failed")
}
@@ -99,7 +102,7 @@ func TestStrace(t *testing.T) {
defer env.Close()
p := new(prog.Prog)
- _, strace, failed, hanged, err := env.Exec(p)
+ _, strace, _, failed, hanged, err := env.Exec(p)
if err != nil {
t.Fatalf("failed to run executor: %v", err)
}
@@ -126,7 +129,7 @@ func TestExecute(t *testing.T) {
for i := 0; i < iters/len(flags); i++ {
p := prog.Generate(rs, 10, nil)
- _, _, _, _, err := env.Exec(p)
+ _, _, _, _, _, err := env.Exec(p)
if err != nil {
t.Fatalf("failed to run executor: %v", err)
}
@@ -160,7 +163,7 @@ func TestCompare(t *testing.T) {
rs, iters := initTest(t)
for i := 0; i < iters; i++ {
p := prog.Generate(rs, 10, nil)
- _, strace1, _, _, err := env1.Exec(p)
+ _, strace1, _, _, _, err := env1.Exec(p)
if err != nil {
t.Fatalf("failed to run executor: %v", err)
}
@@ -175,7 +178,7 @@ func TestCompare(t *testing.T) {
}
defer env2.Close() // yes, that's defer in a loop
- _, strace2, _, _, err := env2.Exec(nil)
+ _, strace2, _, _, _, err := env2.Exec(nil)
if err != nil {
t.Fatalf("failed to run c binary: %v", err)
}
diff --git a/tools/execlog/execlog.go b/tools/execlog/execlog.go
index a9081761e..f09ca7e56 100644
--- a/tools/execlog/execlog.go
+++ b/tools/execlog/execlog.go
@@ -71,7 +71,7 @@ func main() {
if idx%1000 == 0 {
log.Printf("executing %v\n", idx)
}
- _, _, _, _, err := env.Exec(progs[idx%len(progs)])
+ _, _, _, _, _, err := env.Exec(progs[idx%len(progs)])
if err != nil {
log.Printf("failed to execute program: %v", err)
}
diff --git a/tools/execprog/execprog.go b/tools/execprog/execprog.go
index d82ea514e..9e0ac16a9 100644
--- a/tools/execprog/execprog.go
+++ b/tools/execprog/execprog.go
@@ -53,7 +53,7 @@ func main() {
fmt.Fprintf(os.Stderr, "failed to create execution environment: %v\n", err)
os.Exit(1)
}
- output, strace, failed, hanged, err := env.Exec(p)
+ output, strace, _, failed, hanged, err := env.Exec(p)
fmt.Printf("result: failed=%v hanged=%v err=%v\n\n%s", failed, hanged, err, output)
if *flagStrace {
fmt.Printf("strace output:\n%s", strace)
diff --git a/tools/stress/stress.go b/tools/stress/stress.go
index 05bd5153b..388e2767d 100644
--- a/tools/stress/stress.go
+++ b/tools/stress/stress.go
@@ -59,7 +59,7 @@ func execute(env *ipc.Env, p *prog.Prog) {
if *flagExecutor == "" {
return
}
- output, _, _, _, err := env.Exec(p)
+ output, _, _, _, _, err := env.Exec(p)
if err != nil {
fmt.Printf("failed to execute executor: %v\n", err)
}