aboutsummaryrefslogtreecommitdiffstats
path: root/tools/syz-symbolize/symbolize.go
blob: 0a884119b86ecd62087c1c438848fd50c50a2500 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright 2016 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 (
	"flag"
	"fmt"
	"os"
	"path/filepath"
	"runtime"

	"github.com/google/syzkaller/pkg/hash"
	"github.com/google/syzkaller/pkg/mgrconfig"
	"github.com/google/syzkaller/pkg/osutil"
	"github.com/google/syzkaller/pkg/report"
	"github.com/google/syzkaller/pkg/tool"
	"github.com/google/syzkaller/pkg/vcs"
)

var (
	flagOS        = flag.String("os", runtime.GOOS, "target os")
	flagArch      = flag.String("arch", runtime.GOARCH, "target arch")
	flagKernelObj = flag.String("kernel_obj", ".", "path to kernel build/obj dir")
	flagKernelSrc = flag.String("kernel_src", "", "path to kernel sources (defaults to kernel_obj)")
	flagOutDir    = flag.String("outdir", "", "output directory")
	flagConfig    = flag.String("config", "", "optional configuration file")
)

func main() {
	flag.Parse()
	if len(flag.Args()) != 1 {
		fmt.Fprintf(os.Stderr, "usage: syz-symbolize [flags] kernel_log_file\n")
		flag.PrintDefaults()
		os.Exit(1)
	}
	var err error
	cfg := &mgrconfig.Config{}
	if *flagConfig != "" {
		cfg, err = mgrconfig.LoadPartialFile(*flagConfig)
	} else {
		cfg, err = mgrconfig.LoadPartialData([]byte(`{
			"kernel_obj": "` + *flagKernelObj + `",
			"kernel_src": "` + *flagKernelSrc + `",
			"target": "` + *flagOS + "/" + *flagArch + `"
		}`))
	}
	if err != nil {
		tool.Fail(err)
	}
	cfg.CompleteKernelDirs()
	reporter, err := report.NewReporter(cfg)
	if err != nil {
		tool.Failf("failed to create reporter: %v", err)
	}
	text, err := os.ReadFile(flag.Args()[0])
	if err != nil {
		tool.Failf("failed to open input file: %v", err)
	}
	reps := report.ParseAll(reporter, text)
	if len(reps) == 0 {
		rep := &report.Report{Report: text}
		if err := reporter.Symbolize(rep); err != nil {
			tool.Failf("failed to symbolize report: %v", err)
		}
		os.Stdout.Write(rep.Report)
		return
	}
	for _, rep := range reps {
		if *flagOutDir != "" {
			saveCrash(rep, *flagOutDir)
		}
		if err := reporter.Symbolize(rep); err != nil {
			fmt.Fprintf(os.Stderr, "failed to symbolize report: %v\n", err)
		}
		fmt.Printf("TITLE: %v\n", rep.Title)
		fmt.Printf("CORRUPTED: %v (%v)\n", rep.Corrupted, rep.CorruptedReason)
		fmt.Printf("SUPPRESSED: %v\n", rep.Suppressed)
		fmt.Printf("MAINTAINERS (TO): %v\n", rep.Recipients.GetEmails(vcs.To))
		fmt.Printf("MAINTAINERS (CC): %v\n", rep.Recipients.GetEmails(vcs.Cc))
		fmt.Printf("\n")
		os.Stdout.Write(rep.Report)
		fmt.Printf("\n\n")
	}
}

func saveCrash(rep *report.Report, path string) {
	sig := hash.Hash([]byte(rep.Title))
	id := sig.String()
	dir := filepath.Join(path, id)
	osutil.MkdirAll(dir)
	if err := osutil.WriteFile(filepath.Join(dir, "description"), []byte(rep.Title+"\n")); err != nil {
		tool.Failf("failed to write description: %v", err)
	}

	if err := osutil.WriteFile(filepath.Join(dir, "log"), rep.Output); err != nil {
		tool.Failf("failed to write log: %v", err)
	}

	if len(rep.Report) > 0 {
		if err := osutil.WriteFile(filepath.Join(dir, "report"), rep.Report); err != nil {
			tool.Failf("failed to write report: %v", err)
		}
	}
}