Skip to content
Permalink
Browse files

pkg/cover: fix prefix computation

* pkg/cover: Modify parsing logic
1. Remove prefix computation
2. Add a mgrconfig for kernel build directory

* pkg/report: shorten reports with kernelBuildSrc instead of kernelSrc

* pkg/report: Fix failing tests

* pkg/report: fix formating issues

* tools/syz-cover: Fix unintended redefinition

* make changes to fix failing ci build

* pkg/report: fix issues
  • Loading branch information...
R3x authored and dvyukov committed Jul 17, 2019
1 parent 0d10349 commit f613a7c41d0b3ea16eeaad515e44dec003688ffb
@@ -23,6 +23,7 @@ import (
type ReportGenerator struct {
vmlinux string
srcDir string
buildDir string
arch string
symbols []symbol
coverPCs []uint64
@@ -39,11 +40,12 @@ type coverage struct {
covered bool
}

func MakeReportGenerator(vmlinux, srcDir, arch string) (*ReportGenerator, error) {
func MakeReportGenerator(vmlinux, srcDir, buildDir, arch string) (*ReportGenerator, error) {
rg := &ReportGenerator{
vmlinux: vmlinux,
srcDir: srcDir,
arch: arch,
vmlinux: vmlinux,
srcDir: srcDir,
buildDir: buildDir,
arch: arch,
}
if err := rg.readSymbols(); err != nil {
return nil, err
@@ -61,31 +63,33 @@ func (rg *ReportGenerator) Do(w io.Writer, pcs []uint64) error {
for i, pc := range pcs {
pcs[i] = PreviousInstructionPC(rg.arch, pc)
}
covered, prefix, err := rg.symbolize(pcs)
covered, err := rg.symbolize(pcs)
if err != nil {
return err
}
if len(covered) == 0 {
return fmt.Errorf("'%s' does not have debug info (set CONFIG_DEBUG_INFO=y)", rg.vmlinux)
}
uncoveredPCs := rg.uncoveredPcsInFuncs(pcs)
uncovered, prefix2, err := rg.symbolize(uncoveredPCs)
uncovered, err := rg.symbolize(uncoveredPCs)
if err != nil {
return err
}
if len(uncoveredPCs) != 0 {
prefix = combinePrefix(prefix, prefix2)
}
return rg.generate(w, prefix, covered, uncovered)
return rg.generate(w, covered, uncovered)
}

func (rg *ReportGenerator) generate(w io.Writer, prefix string, covered, uncovered []symbolizer.Frame) error {
func (rg *ReportGenerator) generate(w io.Writer, covered, uncovered []symbolizer.Frame) error {
var d templateData
for f, covered := range fileSet(covered, uncovered) {
remain := filepath.Clean(strings.TrimPrefix(f, prefix))
if rg.srcDir != "" && !strings.HasPrefix(remain, rg.srcDir) {
f = filepath.Join(rg.srcDir, remain)
if !strings.HasPrefix(f, rg.buildDir) {
return fmt.Errorf("path '%s' doesn't match build dir '%s'", f, rg.buildDir)
}

// Trim the existing build dir
remain := filepath.Clean(strings.TrimPrefix(f, rg.buildDir))

// Add the current kernel source dir
f = filepath.Join(rg.srcDir, remain)
lines, err := parseFile(f)
if err != nil {
return err
@@ -219,39 +223,20 @@ func (rg *ReportGenerator) uncoveredPcsInFuncs(pcs []uint64) []uint64 {
return uncoveredPCs
}

func (rg *ReportGenerator) symbolize(pcs []uint64) ([]symbolizer.Frame, string, error) {
func (rg *ReportGenerator) symbolize(pcs []uint64) ([]symbolizer.Frame, error) {
symb := symbolizer.NewSymbolizer()
defer symb.Close()

frames, err := symb.SymbolizeArray(rg.vmlinux, pcs)
if err != nil {
return nil, "", err
return nil, err
}

prefix := ""
for i := range frames {
frame := &frames[i]
frame.PC--
if prefix == "" {
prefix = frame.File
} else {
prefix = combinePrefix(prefix, frame.File)
if prefix == "" {
break
}
}
}
return frames, prefix, nil
}

func combinePrefix(prefix, prefix2 string) string {
i := 0
for ; i < len(prefix) && i < len(prefix2); i++ {
if prefix[i] != prefix2[i] {
break
}
}
return prefix[:i]
return frames, nil
}

func parseFile(fn string) ([][]byte, error) {
@@ -24,6 +24,8 @@ type Config struct {
KernelObj string `json:"kernel_obj"`
// Kernel source directory (if not set defaults to KernelObj).
KernelSrc string `json:"kernel_src,omitempty"`
// Location of the driectory where the kernel was built (if not set defaults to KernelSrc)
KernelBuildSrc string `json:"kernel_build_src"`
// Arbitrary optional tag that is saved along with crash reports (e.g. branch/commit).
Tag string `json:"tag,omitempty"`
// Location of the disk image file.
@@ -111,6 +111,9 @@ func Complete(cfg *Config) error {
cfg.KernelSrc = cfg.KernelObj // assume in-tree build by default
}
cfg.KernelSrc = osutil.Abs(cfg.KernelSrc)
if cfg.KernelBuildSrc == "" {
cfg.KernelBuildSrc = cfg.KernelSrc
}
if cfg.HubClient != "" && (cfg.Name == "" || cfg.HubAddr == "" || cfg.HubKey == "") {
return fmt.Errorf("hub_client is set, but name/hub_addr/hub_key is empty")
}
@@ -21,7 +21,7 @@ type akaros struct {
objfile string
}

func ctorAkaros(target *targets.Target, kernelSrc, kernelObj string,
func ctorAkaros(target *targets.Target, kernelSrc, kernelBuildSrc, kernelObj string,
ignores []*regexp.Regexp) (Reporter, []string, error) {
ctx := &akaros{
ignores: ignores,
@@ -11,17 +11,17 @@ import (
)

type freebsd struct {
kernelSrc string
kernelObj string
ignores []*regexp.Regexp
kernelBuildSrc string
kernelObj string
ignores []*regexp.Regexp
}

func ctorFreebsd(target *targets.Target, kernelSrc, kernelObj string,
func ctorFreebsd(target *targets.Target, kernelSrc, kernelBuildSrc, kernelObj string,
ignores []*regexp.Regexp) (Reporter, []string, error) {
ctx := &freebsd{
kernelSrc: kernelSrc,
kernelObj: kernelObj,
ignores: ignores,
kernelBuildSrc: kernelBuildSrc,
kernelObj: kernelObj,
ignores: ignores,
}
return ctx, nil, nil
}
@@ -39,7 +39,7 @@ var (
}
)

func ctorFuchsia(target *targets.Target, kernelSrc, kernelObj string,
func ctorFuchsia(target *targets.Target, kernelSrc, kernelBuildSrc, kernelObj string,
ignores []*regexp.Regexp) (Reporter, []string, error) {
ctx := &fuchsia{
ignores: ignores,
@@ -14,7 +14,7 @@ type gvisor struct {
ignores []*regexp.Regexp
}

func ctorGvisor(target *targets.Target, kernelSrc, kernelObj string,
func ctorGvisor(target *targets.Target, kernelSrc, kernelBuildSrc, kernelObj string,
ignores []*regexp.Regexp) (Reporter, []string, error) {
ctx := &gvisor{
ignores: ignores,
@@ -21,6 +21,7 @@ import (

type linux struct {
kernelSrc string
kernelBuildSrc string
kernelObj string
vmlinux string
symbols map[string][]symbolizer.Symbol
@@ -35,7 +36,7 @@ type linux struct {
eoi []byte
}

func ctorLinux(target *targets.Target, kernelSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, []string, error) {
func ctorLinux(target *targets.Target, kernelSrc, kernelBuildSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, []string, error) {
var symbols map[string][]symbolizer.Symbol
vmlinux := ""
if kernelObj != "" {
@@ -47,11 +48,12 @@ func ctorLinux(target *targets.Target, kernelSrc, kernelObj string, ignores []*r
}
}
ctx := &linux{
kernelSrc: kernelSrc,
kernelObj: kernelObj,
vmlinux: vmlinux,
symbols: symbols,
ignores: ignores,
kernelSrc: kernelSrc,
kernelBuildSrc: kernelBuildSrc,
kernelObj: kernelObj,
vmlinux: vmlinux,
symbols: symbols,
ignores: ignores,
}
ctx.consoleOutputRe = regexp.MustCompile(`^(?:\*\* [0-9]+ printk messages dropped \*\* )?(?:.* login: )?(?:\<[0-9]+\>)?\[ *[0-9]+\.[0-9]+\](\[ *(?:C|T)[0-9]+\])? `)
ctx.questionableRes = []*regexp.Regexp{
@@ -335,14 +337,13 @@ func (ctx *linux) Symbolize(rep *Report) error {
func (ctx *linux) symbolize(rep *Report) error {
symb := symbolizer.NewSymbolizer()
defer symb.Close()
strip := ctx.stripPrefix(symb)
var symbolized []byte
s := bufio.NewScanner(bytes.NewReader(rep.Report))
prefix := rep.reportPrefixLen
for s.Scan() {
line := append([]byte{}, s.Bytes()...)
line = append(line, '\n')
newLine := symbolizeLine(symb.Symbolize, ctx.symbols, ctx.vmlinux, strip, line)
newLine := symbolizeLine(symb.Symbolize, ctx.symbols, ctx.vmlinux, ctx.kernelBuildSrc, line)
if prefix > len(symbolized) {
prefix += len(newLine) - len(line)
}
@@ -353,33 +354,6 @@ func (ctx *linux) symbolize(rep *Report) error {
return nil
}

func (ctx *linux) stripPrefix(symb *symbolizer.Symbolizer) string {
// Vmlinux may have been moved, so check if we can find debug info
// for some known functions and infer correct strip prefix from it.
knownSymbols := []struct {
symbol string
file string
}{
{"__sanitizer_cov_trace_pc", "kernel/kcov.c"},
{"__asan_load1", "mm/kasan/kasan.c"},
{"start_kernel", "init/main.c"},
}
for _, s := range knownSymbols {
for _, covSymb := range ctx.symbols[s.symbol] {
frames, _ := symb.Symbolize(ctx.vmlinux, covSymb.Addr)
if len(frames) > 0 {
file := frames[len(frames)-1].File
if idx := strings.Index(file, s.file); idx != -1 {
return file[:idx]
}
}
}
}
// Strip vmlinux location from all paths.
strip, _ := filepath.Abs(ctx.vmlinux)
return filepath.Dir(strip) + string(filepath.Separator)
}

func symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error),
symbols map[string][]symbolizer.Symbol, vmlinux, strip string, line []byte) []byte {
match := linuxSymbolizeRe.FindSubmatchIndex(line)
@@ -17,11 +17,12 @@ import (
)

type netbsd struct {
kernelSrc string
kernelObj string
kernelObject string
symbols map[string][]symbolizer.Symbol
ignores []*regexp.Regexp
kernelSrc string
kernelBuildSrc string
kernelObj string
kernelObject string
symbols map[string][]symbolizer.Symbol
ignores []*regexp.Regexp
}

var (
@@ -33,7 +34,7 @@ var (
}
)

func ctorNetbsd(target *targets.Target, kernelSrc, kernelObj string,
func ctorNetbsd(target *targets.Target, kernelSrc, kernelBuildSrc, kernelObj string,
ignores []*regexp.Regexp) (Reporter, []string, error) {
var symbols map[string][]symbolizer.Symbol
ignores = append(ignores, regexp.MustCompile("event_init: unable to initialize")) // postfix output
@@ -47,11 +48,12 @@ func ctorNetbsd(target *targets.Target, kernelSrc, kernelObj string,
}
}
ctx := &netbsd{
kernelSrc: kernelSrc,
kernelObj: kernelObj,
kernelObject: kernelObject,
symbols: symbols,
ignores: ignores,
kernelSrc: kernelSrc,
kernelBuildSrc: kernelBuildSrc,
kernelObj: kernelObj,
kernelObject: kernelObject,
symbols: symbols,
ignores: ignores,
}
return ctx, nil, nil
}
@@ -134,7 +136,7 @@ func (ctx *netbsd) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symboli
// and line numbers.
for _, frame := range frames {
file := frame.File
file = strings.TrimPrefix(file, ctx.kernelSrc)
file = strings.TrimPrefix(file, ctx.kernelBuildSrc)
file = strings.TrimPrefix(file, "/")
info := fmt.Sprintf(" %v:%v", file, frame.Line)
modified := append([]byte{}, line...)
@@ -82,10 +82,11 @@ func TestNetbsdSymbolizeLine(t *testing.T) {
}
}
nbsd := netbsd{
kernelSrc: "netbsd/src",
kernelObj: "/netbsd/src/obj/sys/arch/amd64/compile/GENERIC",
kernelObject: "netbsd.gdb",
symbols: symbols,
kernelSrc: "netbsd/src",
kernelBuildSrc: "netbsd/src",
kernelObj: "/netbsd/src/obj/sys/arch/amd64/compile/GENERIC",
kernelObject: "netbsd.gdb",
symbols: symbols,
}
for i, test := range tests {
t.Run(fmt.Sprint(i), func(t *testing.T) {
@@ -17,11 +17,12 @@ import (
)

type openbsd struct {
kernelSrc string
kernelObj string
kernelObject string
symbols map[string][]symbolizer.Symbol
ignores []*regexp.Regexp
kernelSrc string
kernelBuildSrc string
kernelObj string
kernelObject string
symbols map[string][]symbolizer.Symbol
ignores []*regexp.Regexp
}

var (
@@ -33,7 +34,7 @@ var (
}
)

func ctorOpenbsd(target *targets.Target, kernelSrc, kernelObj string,
func ctorOpenbsd(target *targets.Target, kernelSrc, kernelBuildSrc, kernelObj string,
ignores []*regexp.Regexp) (Reporter, []string, error) {
var symbols map[string][]symbolizer.Symbol
kernelObject := ""
@@ -46,11 +47,12 @@ func ctorOpenbsd(target *targets.Target, kernelSrc, kernelObj string,
}
}
ctx := &openbsd{
kernelSrc: kernelSrc,
kernelObj: kernelObj,
kernelObject: kernelObject,
symbols: symbols,
ignores: ignores,
kernelSrc: kernelSrc,
kernelBuildSrc: kernelBuildSrc,
kernelObj: kernelObj,
kernelObject: kernelObject,
symbols: symbols,
ignores: ignores,
}
return ctx, nil, nil
}
@@ -124,7 +126,7 @@ func (ctx *openbsd) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbol
var symbolized []byte
for _, frame := range frames {
file := frame.File
file = strings.TrimPrefix(file, ctx.kernelSrc)
file = strings.TrimPrefix(file, ctx.kernelBuildSrc)
file = strings.TrimPrefix(file, "/")
info := fmt.Sprintf(" %v:%v", file, frame.Line)
modified := append([]byte{}, line...)

0 comments on commit f613a7c

Please sign in to comment.
You can’t perform that action at this time.