github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/tools/syz-cover/syz-cover.go (about) 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 // syz-cover generates coverage HTML report from raw coverage files. 5 // Raw coverage files are text files with one PC in hex form per line, e.g.: 6 // 7 // 0xffffffff8398658d 8 // 0xffffffff839862fc 9 // 0xffffffff8398633f 10 // 11 // Raw coverage files can be obtained either from /rawcover manager HTTP handler, 12 // or from syz-execprog with -coverfile flag. 13 // 14 // Usage: 15 // 16 // syz-cover -config config_file rawcover.file* 17 // 18 // or use all pcs in rg.Symbols 19 // 20 // syz-cover -config config_file 21 package main 22 23 import ( 24 "bufio" 25 "bytes" 26 "encoding/json" 27 "flag" 28 "os" 29 "os/exec" 30 "strconv" 31 "strings" 32 33 "github.com/google/syzkaller/pkg/cover" 34 "github.com/google/syzkaller/pkg/mgrconfig" 35 "github.com/google/syzkaller/pkg/osutil" 36 "github.com/google/syzkaller/pkg/tool" 37 ) 38 39 func main() { 40 var ( 41 flagConfig = flag.String("config", "", "configuration file") 42 flagModules = flag.String("modules", "", 43 "modules JSON info obtained from /modules (optional)") 44 flagExportCSV = flag.String("csv", "", "export coverage data in csv format (optional)") 45 flagExportLineJSON = flag.String("json", "", "export coverage data with source line info in json format (optional)") 46 flagExportJSONL = flag.String("jsonl", "", "export jsonl coverage data (optional)") 47 flagExportHTML = flag.String("html", "", "save coverage HTML report to file (optional)") 48 ) 49 defer tool.Init()() 50 51 cfg, err := mgrconfig.LoadFile(*flagConfig) 52 if err != nil { 53 tool.Fail(err) 54 } 55 var modules []cover.KernelModule 56 if *flagModules != "" { 57 m, err := loadModules(*flagModules) 58 if err != nil { 59 tool.Fail(err) 60 } 61 modules = m 62 } 63 rg, err := cover.MakeReportGenerator(cfg, cfg.KernelSubsystem, modules, false) 64 if err != nil { 65 tool.Fail(err) 66 } 67 var pcs []uint64 68 if len(flag.Args()) == 0 { 69 for _, s := range rg.Symbols { 70 pcs = append(pcs, s.PCs...) 71 } 72 } else { 73 pcs, err = readPCs(flag.Args()) 74 if err != nil { 75 tool.Fail(err) 76 } 77 } 78 progs := []cover.Prog{{PCs: pcs}} 79 buf := new(bytes.Buffer) 80 params := cover.CoverHandlerParams{ 81 Progs: progs, 82 CoverFilter: nil, 83 Debug: false, 84 Force: false, 85 } 86 if *flagExportCSV != "" { 87 if err := rg.DoCSV(buf, params); err != nil { 88 tool.Fail(err) 89 } 90 if err := osutil.WriteFile(*flagExportCSV, buf.Bytes()); err != nil { 91 tool.Fail(err) 92 } 93 return 94 } 95 if *flagExportLineJSON != "" { 96 if err := rg.DoLineJSON(buf, params); err != nil { 97 tool.Fail(err) 98 } 99 if err := osutil.WriteFile(*flagExportLineJSON, buf.Bytes()); err != nil { 100 tool.Fail(err) 101 } 102 return 103 } 104 if *flagExportJSONL != "" { 105 if err := rg.DoCoverJSONL(buf, params); err != nil { 106 tool.Fail(err) 107 } 108 if err := osutil.WriteFile(*flagExportJSONL, buf.Bytes()); err != nil { 109 tool.Fail(err) 110 } 111 return 112 } 113 if err := rg.DoHTML(buf, params); err != nil { 114 tool.Fail(err) 115 } 116 if *flagExportHTML != "" { 117 if err := osutil.WriteFile(*flagExportHTML, buf.Bytes()); err != nil { 118 tool.Fail(err) 119 } 120 return 121 } 122 fn, err := osutil.TempFile("syz-cover") 123 if err != nil { 124 tool.Fail(err) 125 } 126 fn += ".html" 127 if err := osutil.WriteFile(fn, buf.Bytes()); err != nil { 128 tool.Fail(err) 129 } 130 if err := exec.Command("xdg-open", fn).Start(); err != nil { 131 tool.Failf("failed to start browser: %v", err) 132 } 133 } 134 135 func readPCs(files []string) ([]uint64, error) { 136 var pcs []uint64 137 for _, file := range files { 138 data, err := os.ReadFile(file) 139 if err != nil { 140 return nil, err 141 } 142 for s := bufio.NewScanner(bytes.NewReader(data)); s.Scan(); { 143 line := strings.TrimSpace(s.Text()) 144 if line == "" { 145 continue 146 } 147 pc, err := strconv.ParseUint(line, 0, 64) 148 if err != nil { 149 return nil, err 150 } 151 pcs = append(pcs, pc) 152 } 153 } 154 return pcs, nil 155 } 156 157 func loadModules(fname string) ([]cover.KernelModule, error) { 158 data, err := os.ReadFile(fname) 159 if err != nil { 160 return nil, err 161 } 162 var modules []cover.KernelModule 163 err = json.Unmarshal(data, &modules) 164 if err != nil { 165 return nil, err 166 } 167 return modules, nil 168 }