2015-10-12 08:16:57 +00:00
|
|
|
// 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 main
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"bytes"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
2017-12-12 08:13:35 +00:00
|
|
|
"path/filepath"
|
2015-10-12 08:16:57 +00:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2018-06-21 12:38:08 +00:00
|
|
|
"sync"
|
2017-11-16 11:42:30 +00:00
|
|
|
"time"
|
2015-10-13 12:58:50 +00:00
|
|
|
|
2017-06-17 10:40:18 +00:00
|
|
|
"github.com/google/syzkaller/pkg/cover"
|
2017-11-16 11:42:30 +00:00
|
|
|
"github.com/google/syzkaller/pkg/osutil"
|
2015-10-12 08:16:57 +00:00
|
|
|
)
|
|
|
|
|
2016-09-06 17:35:48 +00:00
|
|
|
var (
|
2018-06-21 12:38:08 +00:00
|
|
|
initCoverOnce sync.Once
|
|
|
|
initCoverError error
|
|
|
|
initCoverVMOffset uint32
|
2018-12-09 14:32:10 +00:00
|
|
|
reportGenerator *cover.ReportGenerator
|
2016-09-06 17:35:48 +00:00
|
|
|
)
|
|
|
|
|
2018-12-09 14:32:10 +00:00
|
|
|
func initCover(kernelObj, kernelObjName, kernelSrc, arch string) error {
|
2018-06-21 12:38:08 +00:00
|
|
|
if kernelObj == "" {
|
|
|
|
return fmt.Errorf("kernel_obj is not specified")
|
|
|
|
}
|
2018-08-31 19:30:18 +00:00
|
|
|
vmlinux := filepath.Join(kernelObj, kernelObjName)
|
2018-12-09 14:32:10 +00:00
|
|
|
var err error
|
|
|
|
reportGenerator, err = cover.MakeReportGenerator(vmlinux, kernelSrc, arch)
|
2018-06-21 12:38:08 +00:00
|
|
|
if err != nil {
|
2018-12-09 14:32:10 +00:00
|
|
|
return err
|
2018-06-21 12:38:08 +00:00
|
|
|
}
|
|
|
|
initCoverVMOffset, err = getVMOffset(vmlinux)
|
|
|
|
return err
|
2016-09-06 17:35:48 +00:00
|
|
|
}
|
|
|
|
|
2018-08-31 19:30:18 +00:00
|
|
|
func generateCoverHTML(w io.Writer, kernelObj, kernelObjName, kernelSrc, arch string, cov cover.Cover) error {
|
2016-02-18 20:48:45 +00:00
|
|
|
if len(cov) == 0 {
|
2018-06-21 12:38:08 +00:00
|
|
|
return fmt.Errorf("no coverage data available")
|
2016-02-18 20:48:45 +00:00
|
|
|
}
|
2018-12-09 14:32:10 +00:00
|
|
|
initCoverOnce.Do(func() { initCoverError = initCover(kernelObj, kernelObjName, kernelSrc, arch) })
|
2018-06-21 12:38:08 +00:00
|
|
|
if initCoverError != nil {
|
|
|
|
return initCoverError
|
2016-09-06 17:35:48 +00:00
|
|
|
}
|
2018-02-20 19:44:04 +00:00
|
|
|
pcs := make([]uint64, 0, len(cov))
|
|
|
|
for pc := range cov {
|
2018-12-09 14:32:10 +00:00
|
|
|
pcs = append(pcs, cover.RestorePC(pc, initCoverVMOffset))
|
2015-10-12 08:16:57 +00:00
|
|
|
}
|
2018-12-09 14:32:10 +00:00
|
|
|
return reportGenerator.Do(w, pcs)
|
2015-10-12 08:16:57 +00:00
|
|
|
}
|
|
|
|
|
2018-03-08 17:48:26 +00:00
|
|
|
func getVMOffset(vmlinux string) (uint32, error) {
|
2017-11-23 08:21:00 +00:00
|
|
|
out, err := osutil.RunCmd(time.Hour, "", "readelf", "-SW", vmlinux)
|
2016-04-27 15:37:54 +00:00
|
|
|
if err != nil {
|
2017-11-16 11:42:30 +00:00
|
|
|
return 0, err
|
2016-04-27 15:37:54 +00:00
|
|
|
}
|
|
|
|
s := bufio.NewScanner(bytes.NewReader(out))
|
|
|
|
var addr uint32
|
|
|
|
for s.Scan() {
|
|
|
|
ln := s.Text()
|
|
|
|
pieces := strings.Fields(ln)
|
|
|
|
for i := 0; i < len(pieces); i++ {
|
|
|
|
if pieces[i] != "PROGBITS" {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
v, err := strconv.ParseUint("0x"+pieces[i+1], 0, 64)
|
|
|
|
if err != nil {
|
|
|
|
return 0, fmt.Errorf("failed to parse addr in readelf output: %v", err)
|
|
|
|
}
|
|
|
|
if v == 0 {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
v32 := (uint32)(v >> 32)
|
|
|
|
if addr == 0 {
|
|
|
|
addr = v32
|
|
|
|
}
|
|
|
|
if addr != v32 {
|
|
|
|
return 0, fmt.Errorf("different section offsets in a single binary")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return addr, nil
|
|
|
|
}
|