aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cover/cover.go4
-rw-r--r--manager/cover.go4
-rw-r--r--tools/execprog/execprog.go30
3 files changed, 34 insertions, 4 deletions
diff --git a/cover/cover.go b/cover/cover.go
index c55f328e6..4c07314af 100644
--- a/cover/cover.go
+++ b/cover/cover.go
@@ -20,6 +20,10 @@ func Copy(cov Cover) Cover {
return append(Cover{}, cov...)
}
+func RestorePC(pc uint32) uint64 {
+ return uint64(0xffffffff)<<32 + uint64(pc)
+}
+
/* Canonicalize sorts and removes duplicates. */
func Canonicalize(cov []uint32) Cover {
sort.Sort(Cover(cov))
diff --git a/manager/cover.go b/manager/cover.go
index accc230f9..190fb6038 100644
--- a/manager/cover.go
+++ b/manager/cover.go
@@ -15,6 +15,8 @@ import (
"strconv"
"strings"
"sync"
+
+ "github.com/google/syzkaller/cover"
)
type LineInfo struct {
@@ -171,7 +173,7 @@ func symbolize(vmlinux string, cov []uint32) error {
defer cmd.Wait()
go func() {
for _, pc := range cov {
- fmt.Fprintf(stdin, "0xffffffff%x\n", pc-1)
+ fmt.Fprintf(stdin, "0x%x\n", cover.RestorePC(pc)-1)
}
stdin.Close()
}()
diff --git a/tools/execprog/execprog.go b/tools/execprog/execprog.go
index 9e0ac16a9..2521426f8 100644
--- a/tools/execprog/execprog.go
+++ b/tools/execprog/execprog.go
@@ -1,15 +1,20 @@
// 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.
+// execprog executes a single program passed via a flag
+// and prints information about execution.
package main
import (
+ "bytes"
+ "encoding/binary"
"flag"
"fmt"
"io/ioutil"
"os"
"time"
+ "github.com/google/syzkaller/cover"
"github.com/google/syzkaller/ipc"
"github.com/google/syzkaller/prog"
)
@@ -20,7 +25,7 @@ var (
flagThreaded = flag.Bool("threaded", false, "use threaded mode in executor")
flagDebug = flag.Bool("debug", true, "debug output from executor")
flagStrace = flag.Bool("strace", false, "run executor under strace")
- flagCover = flag.Bool("cover", false, "collect coverage")
+ flagCover = flag.String("cover", "", "collect coverage and write to the file")
)
func main() {
@@ -45,7 +50,7 @@ func main() {
if *flagStrace {
flags |= ipc.FlagStrace
}
- if *flagCover {
+ if *flagCover != "" {
flags |= ipc.FlagCover
}
env, err := ipc.MakeEnv(*flagExecutor, 3*time.Second, flags)
@@ -53,9 +58,28 @@ 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, cov, 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)
}
+ // Coverage is dumped in sanitizer format.
+ // github.com/google/sanitizers/tools/sancov command can be used to dump PCs,
+ // then they can be piped via addr2line to symbolize.
+ for i, c := range cov {
+ fmt.Printf("call #%v: coverage %v\n", i, len(c))
+ if len(c) == 0 {
+ continue
+ }
+ buf := new(bytes.Buffer)
+ binary.Write(buf, binary.LittleEndian, uint64(0xC0BFFFFFFFFFFF64))
+ for _, pc := range c {
+ binary.Write(buf, binary.LittleEndian, cover.RestorePC(pc))
+ }
+ err := ioutil.WriteFile(fmt.Sprintf("%v.%v", *flagCover, i), buf.Bytes(), 0660)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "failed to write coverage file: %v\n", err)
+ os.Exit(1)
+ }
+ }
}