Home | History | Annotate | Download | only in report
      1 // Copyright 2018 syzkaller project authors. All rights reserved.
      2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
      3 
      4 package report
      5 
      6 import (
      7 	"bufio"
      8 	"bytes"
      9 	"fmt"
     10 	"path/filepath"
     11 	"regexp"
     12 	"strconv"
     13 	"strings"
     14 
     15 	"github.com/google/syzkaller/pkg/symbolizer"
     16 )
     17 
     18 type akaros struct {
     19 	ignores []*regexp.Regexp
     20 	objfile string
     21 }
     22 
     23 func ctorAkaros(kernelSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, []string, error) {
     24 	ctx := &akaros{
     25 		ignores: ignores,
     26 		objfile: filepath.Join(kernelObj, "akaros-kernel-64b"),
     27 	}
     28 	return ctx, nil, nil
     29 }
     30 
     31 func (ctx *akaros) ContainsCrash(output []byte) bool {
     32 	return containsCrash(output, akarosOopses, ctx.ignores)
     33 }
     34 
     35 func (ctx *akaros) Parse(output []byte) *Report {
     36 	rep := simpleLineParser(output, akarosOopses, akarosStackParams, ctx.ignores)
     37 	if rep == nil {
     38 		return nil
     39 	}
     40 	rep.Report = ctx.minimizeReport(rep.Report)
     41 	return rep
     42 }
     43 
     44 func (ctx *akaros) Symbolize(rep *Report) error {
     45 	symb := symbolizer.NewSymbolizer()
     46 	defer symb.Close()
     47 	var symbolized []byte
     48 	s := bufio.NewScanner(bytes.NewReader(rep.Report))
     49 	for s.Scan() {
     50 		line := bytes.Trim(s.Bytes(), "\r")
     51 		line = ctx.symbolizeLine(symb.Symbolize, ctx.objfile, line)
     52 		symbolized = append(symbolized, line...)
     53 		symbolized = append(symbolized, '\n')
     54 	}
     55 	rep.Report = symbolized
     56 	return nil
     57 }
     58 
     59 func (ctx *akaros) symbolizeLine(symbFunc func(bin string, pc uint64) ([]symbolizer.Frame, error),
     60 	objfile string, line []byte) []byte {
     61 	match := akarosSymbolizeRe.FindSubmatchIndex(line)
     62 	if match == nil {
     63 		return line
     64 	}
     65 	addr, err := strconv.ParseUint(string(line[match[2]:match[3]]), 0, 64)
     66 	if err != nil {
     67 		return line
     68 	}
     69 	frames, err := symbFunc(objfile, addr-1)
     70 	if err != nil || len(frames) == 0 {
     71 		return line
     72 	}
     73 	var symbolized []byte
     74 	for i, frame := range frames {
     75 		if i != 0 {
     76 			symbolized = append(symbolized, '\n')
     77 		}
     78 		file := frame.File
     79 		if pos := strings.LastIndex(file, "/kern/"); pos != -1 {
     80 			file = file[pos+6:]
     81 		}
     82 		modified := append([]byte{}, line...)
     83 		modified = append(modified, fmt.Sprintf(" at %v:%v", file, frame.Line)...)
     84 		if frame.Inline {
     85 			modified = replace(modified, match[4], match[5], []byte(frame.Func))
     86 			modified = replace(modified, match[2], match[3], []byte("     [inline]     "))
     87 		}
     88 		symbolized = append(symbolized, modified...)
     89 	}
     90 	return symbolized
     91 }
     92 
     93 func (ctx *akaros) minimizeReport(report []byte) []byte {
     94 	out := new(bytes.Buffer)
     95 	for s := bufio.NewScanner(bytes.NewReader(report)); s.Scan(); {
     96 		line := bytes.Trim(s.Bytes(), "\r")
     97 		if len(line) == 0 ||
     98 			bytes.Contains(line, []byte("Entering Nanwan's Dungeon")) ||
     99 			bytes.Contains(line, []byte("Type 'help' for a list of commands")) {
    100 			continue
    101 		}
    102 		out.Write(line)
    103 		out.WriteByte('\n')
    104 	}
    105 	return out.Bytes()
    106 }
    107 
    108 var (
    109 	akarosSymbolizeRe = compile(`^#[0-9]+ \[\<(0x[0-9a-f]+)\>\] in ([a-zA-Z0-9_]+)`)
    110 	akarosBacktraceRe = compile(`(?:Stack Backtrace|Backtrace of kernel context) on Core [0-9]+:`)
    111 )
    112 
    113 var akarosStackParams = &stackParams{
    114 	stackStartRes: []*regexp.Regexp{
    115 		akarosBacktraceRe,
    116 	},
    117 	frameRes: []*regexp.Regexp{
    118 		compile(`^#[0-9]+ {{PC}} in ([a-zA-Z0-9_]+)`),
    119 	},
    120 	skipPatterns: []string{
    121 		"backtrace",
    122 		"mon_backtrace",
    123 		"monitor",
    124 		"_panic",
    125 		"_warn",
    126 	},
    127 }
    128 
    129 var akarosOopses = []*oops{
    130 	{
    131 		[]byte("kernel panic"),
    132 		[]oopsFormat{
    133 			{
    134 				title: compile("kernel panic at {{SRC}}, from core [0-9]+: assertion failed: (.*)"),
    135 				fmt:   "assertion failed: %[2]v",
    136 				stack: &stackFmt{
    137 					parts: []*regexp.Regexp{
    138 						akarosBacktraceRe,
    139 						parseStackTrace,
    140 					},
    141 				},
    142 			},
    143 			{
    144 				title: compile("kernel panic at {{SRC}}, from core [0-9]+: (.*)"),
    145 				fmt:   "kernel panic: %[2]v",
    146 				stack: &stackFmt{
    147 					parts: []*regexp.Regexp{
    148 						akarosBacktraceRe,
    149 						parseStackTrace,
    150 					},
    151 				},
    152 			},
    153 			{
    154 				title:        compile("kernel panic"),
    155 				fmt:          "kernel panic",
    156 				noStackTrace: true,
    157 				corrupted:    true,
    158 			},
    159 		},
    160 		[]*regexp.Regexp{},
    161 	},
    162 	{
    163 		[]byte("kernel warning"),
    164 		[]oopsFormat{
    165 			{
    166 				title: compile("kernel warning at {{SRC}}, from core [0-9]+"),
    167 				fmt:   "kernel warning in %[2]v",
    168 				stack: &stackFmt{
    169 					parts: []*regexp.Regexp{
    170 						akarosBacktraceRe,
    171 						parseStackTrace,
    172 					},
    173 				},
    174 			},
    175 			{
    176 				title:        compile("kernel warning"),
    177 				fmt:          "kernel warning",
    178 				noStackTrace: true,
    179 				corrupted:    true,
    180 			},
    181 		},
    182 		[]*regexp.Regexp{},
    183 	},
    184 }
    185