2018-12-09 14:37:35 +00:00
|
|
|
// Copyright 2018 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.
|
|
|
|
|
|
|
|
// syz-cover generates coverage HTML report from raw coverage files.
|
|
|
|
// Raw coverage files are text files with one PC in hex form per line, e.g.:
|
|
|
|
//
|
|
|
|
// 0xffffffff8398658d
|
|
|
|
// 0xffffffff839862fc
|
|
|
|
// 0xffffffff8398633f
|
|
|
|
//
|
|
|
|
// Raw coverage files can be obtained either from /rawcover manager HTTP handler,
|
|
|
|
// or from syz-execprog with -coverfile flag.
|
|
|
|
//
|
|
|
|
// Usage:
|
|
|
|
// syz-cover [-os=OS -arch=ARCH -kernel_src=. -kernel_obj=.] rawcover.file*
|
|
|
|
package main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"flag"
|
|
|
|
"fmt"
|
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"os/exec"
|
|
|
|
"path/filepath"
|
|
|
|
"runtime"
|
|
|
|
"strconv"
|
2019-07-18 07:36:03 +00:00
|
|
|
"strings"
|
2018-12-09 14:37:35 +00:00
|
|
|
|
2020-09-22 12:19:46 +00:00
|
|
|
"github.com/google/syzkaller/pkg/cmdprof"
|
2018-12-09 14:37:35 +00:00
|
|
|
"github.com/google/syzkaller/pkg/cover"
|
|
|
|
"github.com/google/syzkaller/pkg/osutil"
|
|
|
|
"github.com/google/syzkaller/sys/targets"
|
|
|
|
)
|
|
|
|
|
|
|
|
func main() {
|
|
|
|
var (
|
2019-07-17 09:58:23 +00:00
|
|
|
flagOS = flag.String("os", runtime.GOOS, "target os")
|
|
|
|
flagArch = flag.String("arch", runtime.GOARCH, "target arch")
|
|
|
|
flagKernelSrc = flag.String("kernel_src", "", "path to kernel sources")
|
|
|
|
flagKernelBuildSrc = flag.String("kernel_build_src", "", "path to kernel image's build dir (optional)")
|
|
|
|
flagKernelObj = flag.String("kernel_obj", "", "path to kernel build/obj dir")
|
2020-08-23 20:28:48 +00:00
|
|
|
flagExport = flag.String("csv", "", "export coverage data in csv format (optional)")
|
2018-12-09 14:37:35 +00:00
|
|
|
)
|
|
|
|
flag.Parse()
|
2020-09-22 12:19:46 +00:00
|
|
|
defer cmdprof.Install()()
|
2018-12-09 14:37:35 +00:00
|
|
|
|
|
|
|
if len(flag.Args()) == 0 {
|
|
|
|
fmt.Fprintf(os.Stderr, "usage: syz-cover [flags] rawcover.file\n")
|
|
|
|
flag.PrintDefaults()
|
|
|
|
os.Exit(1)
|
|
|
|
}
|
|
|
|
if *flagKernelSrc == "" {
|
|
|
|
*flagKernelSrc = "."
|
|
|
|
}
|
|
|
|
if *flagKernelObj == "" {
|
|
|
|
*flagKernelObj = *flagKernelSrc
|
|
|
|
}
|
2019-07-17 09:58:23 +00:00
|
|
|
if *flagKernelBuildSrc == "" {
|
|
|
|
*flagKernelBuildSrc = *flagKernelSrc
|
|
|
|
}
|
2018-12-09 14:37:35 +00:00
|
|
|
target := targets.Get(*flagOS, *flagArch)
|
|
|
|
if target == nil {
|
|
|
|
failf("unknown target %v/%v", *flagOS, *flagArch)
|
|
|
|
}
|
|
|
|
pcs, err := readPCs(flag.Args())
|
|
|
|
if err != nil {
|
|
|
|
failf("%v", err)
|
|
|
|
}
|
|
|
|
kernelObj := filepath.Join(*flagKernelObj, target.KernelObject)
|
2020-05-27 12:26:00 +00:00
|
|
|
rg, err := cover.MakeReportGenerator(target, kernelObj, *flagKernelSrc, *flagKernelBuildSrc)
|
2018-12-09 14:37:35 +00:00
|
|
|
if err != nil {
|
|
|
|
failf("%v", err)
|
|
|
|
}
|
2019-05-26 11:55:37 +00:00
|
|
|
progs := []cover.Prog{{PCs: pcs}}
|
2018-12-09 14:37:35 +00:00
|
|
|
buf := new(bytes.Buffer)
|
2020-08-23 20:28:48 +00:00
|
|
|
if *flagExport != "" {
|
|
|
|
if err := rg.DoCSV(buf, progs); err != nil {
|
|
|
|
failf("%v", err)
|
|
|
|
}
|
|
|
|
if err := osutil.WriteFile(*flagExport, buf.Bytes()); err != nil {
|
|
|
|
failf("%v", err)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
2020-08-14 12:08:54 +00:00
|
|
|
if err := rg.DoHTML(buf, progs); err != nil {
|
2018-12-09 14:37:35 +00:00
|
|
|
failf("%v", err)
|
|
|
|
}
|
|
|
|
fn, err := osutil.TempFile("syz-cover")
|
|
|
|
if err != nil {
|
|
|
|
failf("%v", err)
|
|
|
|
}
|
|
|
|
fn += ".html"
|
|
|
|
if err := osutil.WriteFile(fn, buf.Bytes()); err != nil {
|
|
|
|
failf("%v", err)
|
|
|
|
}
|
|
|
|
if err := exec.Command("xdg-open", fn).Start(); err != nil {
|
|
|
|
failf("failed to start browser: %v", err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func readPCs(files []string) ([]uint64, error) {
|
|
|
|
var pcs []uint64
|
|
|
|
for _, file := range files {
|
|
|
|
data, err := ioutil.ReadFile(file)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
for s := bufio.NewScanner(bytes.NewReader(data)); s.Scan(); {
|
2019-07-18 07:36:03 +00:00
|
|
|
line := strings.TrimSpace(s.Text())
|
|
|
|
if line == "" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
pc, err := strconv.ParseUint(line, 0, 64)
|
2018-12-09 14:37:35 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
pcs = append(pcs, pc)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return pcs, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func failf(msg string, args ...interface{}) {
|
|
|
|
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
|
|
|
os.Exit(1)
|
|
|
|
}
|