mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-28 05:40:26 +00:00
174 lines
4.8 KiB
Go
174 lines
4.8 KiB
Go
// Copyright 2017 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 report
|
|
|
|
import (
|
|
"bufio"
|
|
"bytes"
|
|
"fmt"
|
|
"path/filepath"
|
|
"regexp"
|
|
"strconv"
|
|
"strings"
|
|
|
|
"github.com/google/syzkaller/pkg/symbolizer"
|
|
"github.com/ianlancetaylor/demangle"
|
|
)
|
|
|
|
type fuchsia struct {
|
|
obj string
|
|
ignores []*regexp.Regexp
|
|
}
|
|
|
|
var (
|
|
zirconPanic = []byte("ZIRCON KERNEL PANIC")
|
|
zirconPanicShort = []byte("KERNEL PANIC")
|
|
zirconKernelHang = []byte("stopping other cpus")
|
|
zirconRIP = regexp.MustCompile(` RIP: (0x[0-9a-f]+) `)
|
|
zirconBT = regexp.MustCompile(`^bt#[0-9]+: (0x[0-9a-f]+)`)
|
|
zirconReportEnd = []byte("Halted")
|
|
zirconUnrelated = []*regexp.Regexp{
|
|
regexp.MustCompile(`^\[\d+\.\d+\] \d+\.\d+`),
|
|
regexp.MustCompile(`stopping other cpus`),
|
|
regexp.MustCompile(`^halting cpu`),
|
|
regexp.MustCompile(`^dso: `),
|
|
regexp.MustCompile(`^UPTIME: `),
|
|
regexp.MustCompile(`^BUILDID `),
|
|
regexp.MustCompile(`^Halting\.\.\.`),
|
|
}
|
|
zirconSkip = []*regexp.Regexp{
|
|
regexp.MustCompile("^platform_halt$"),
|
|
regexp.MustCompile("^exception_die$"),
|
|
regexp.MustCompile("^_panic$"),
|
|
}
|
|
)
|
|
|
|
func ctorFuchsia(kernelSrc, kernelObj string, ignores []*regexp.Regexp) (Reporter, []string, error) {
|
|
ctx := &fuchsia{
|
|
obj: filepath.Join(kernelObj, "zircon.elf"),
|
|
ignores: ignores,
|
|
}
|
|
suppressions := []string{
|
|
"fatal exception: process /tmp/syz-fuzzer", // OOM presumably
|
|
}
|
|
return ctx, suppressions, nil
|
|
}
|
|
|
|
func (ctx *fuchsia) ContainsCrash(output []byte) bool {
|
|
return bytes.Contains(output, zirconPanic) ||
|
|
bytes.Contains(output, zirconKernelHang)
|
|
}
|
|
|
|
func (ctx *fuchsia) Parse(output []byte) *Report {
|
|
rep := &Report{
|
|
Output: output,
|
|
EndPos: len(output),
|
|
}
|
|
wantLocation := true
|
|
if pos := bytes.Index(output, zirconPanic); pos != -1 {
|
|
rep.Title = string(zirconPanicShort)
|
|
rep.StartPos = pos
|
|
} else if pos := bytes.Index(output, zirconKernelHang); pos != -1 {
|
|
rep.Title = string(zirconKernelHang)
|
|
rep.StartPos = pos
|
|
wantLocation = false // these tend to produce random locations
|
|
} else {
|
|
return nil
|
|
}
|
|
symb := symbolizer.NewSymbolizer()
|
|
defer symb.Close()
|
|
where := ""
|
|
for s := bufio.NewScanner(bytes.NewReader(output[rep.StartPos:])); s.Scan(); {
|
|
line := s.Bytes()
|
|
if len(line) == 0 || matchesAny(line, zirconUnrelated) {
|
|
continue
|
|
}
|
|
if bytes.Equal(line, zirconReportEnd) {
|
|
break
|
|
}
|
|
if bytes.Contains(line, []byte("DEBUG ASSERT FAILED")) {
|
|
rep.Title = "ASSERT FAILED"
|
|
}
|
|
if bytes.Contains(line, []byte("Supervisor Page Fault exception")) {
|
|
rep.Title = "Supervisor fault"
|
|
}
|
|
if bytes.Contains(line, []byte("recursion in interrupt handler")) {
|
|
rep.Title = "recursion in interrupt handler"
|
|
}
|
|
if match := zirconRIP.FindSubmatchIndex(line); match != nil {
|
|
ctx.processPC(rep, symb, line, match, false, &where)
|
|
} else if match := zirconBT.FindSubmatchIndex(line); match != nil {
|
|
if ctx.processPC(rep, symb, line, match, true, &where) {
|
|
continue
|
|
}
|
|
}
|
|
rep.Report = append(rep.Report, line...)
|
|
rep.Report = append(rep.Report, '\n')
|
|
}
|
|
if wantLocation && where != "" {
|
|
rep.Title = fmt.Sprintf("%v in %v", rep.Title, where)
|
|
}
|
|
return rep
|
|
}
|
|
|
|
func (ctx *fuchsia) processPC(rep *Report, symb *symbolizer.Symbolizer,
|
|
line []byte, match []int, call bool, where *string) bool {
|
|
prefix := line[match[0]:match[1]]
|
|
pcStart := match[2] - match[0]
|
|
pcEnd := match[3] - match[0]
|
|
pcStr := prefix[pcStart:pcEnd]
|
|
pc, err := strconv.ParseUint(string(pcStr), 0, 64)
|
|
if err != nil {
|
|
return false
|
|
}
|
|
shortPC := pc & 0xfffffff
|
|
pc = 0xffffffff80000000 | shortPC
|
|
if call {
|
|
pc--
|
|
}
|
|
frames, err := symb.Symbolize(ctx.obj, pc)
|
|
if err != nil || len(frames) == 0 {
|
|
return false
|
|
}
|
|
for _, frame := range frames {
|
|
file := ctx.trimFile(frame.File)
|
|
name := demangle.Filter(frame.Func, demangle.NoParams, demangle.NoTemplateParams)
|
|
if wrap := "do_syscall<wrapper_"; strings.HasPrefix(name, wrap) {
|
|
// Work around clang bug which results in demangled name into debug info.
|
|
if brace := strings.IndexByte(name, '('); brace != -1 {
|
|
name = name[len(wrap):brace]
|
|
}
|
|
}
|
|
if *where == "" && !matchesAny([]byte(name), zirconSkip) {
|
|
*where = name
|
|
}
|
|
id := "[ inline ]"
|
|
if !frame.Inline {
|
|
id = fmt.Sprintf("0x%08x", shortPC)
|
|
}
|
|
start := replace(append([]byte{}, prefix...), pcStart, pcEnd, []byte(id))
|
|
frameLine := fmt.Sprintf("%s %v %v:%v\n", start, name, file, frame.Line)
|
|
rep.Report = append(rep.Report, frameLine...)
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (ctx *fuchsia) trimFile(file string) string {
|
|
const (
|
|
prefix1 = "zircon/kernel/"
|
|
prefix2 = "zircon/"
|
|
)
|
|
if pos := strings.LastIndex(file, prefix1); pos != -1 {
|
|
return file[pos+len(prefix1):]
|
|
}
|
|
if pos := strings.LastIndex(file, prefix2); pos != -1 {
|
|
return file[pos+len(prefix2):]
|
|
}
|
|
return file
|
|
}
|
|
|
|
func (ctx *fuchsia) Symbolize(rep *Report) error {
|
|
return nil
|
|
}
|