From e66542d78f1cf0c783877440cd239a11fb73fb15 Mon Sep 17 00:00:00 2001 From: Alexander Potapenko Date: Mon, 12 Feb 2024 10:53:25 +0100 Subject: pkg/cover, syz-manager: introduce the /cover?debug=1 parameter Debugging coverage point validation warnings may require looking at specific addresses, which are not printed anywhere. Add a URL parameter that can be passed to prepareFileMap() to print a more meaningful error message. Also factor out the error message code from prepareFileMap() to reduce its cyclomatic complexity. --- pkg/cover/html.go | 38 ++++++++++++++++++++++---------------- pkg/cover/report.go | 19 +++++++++++++++---- pkg/cover/report_test.go | 11 +++++++---- 3 files changed, 44 insertions(+), 24 deletions(-) (limited to 'pkg') diff --git a/pkg/cover/html.go b/pkg/cover/html.go index bbfc11536..8cb9e7511 100644 --- a/pkg/cover/html.go +++ b/pkg/cover/html.go @@ -24,9 +24,15 @@ import ( "github.com/google/syzkaller/pkg/mgrconfig" ) -func (rg *ReportGenerator) DoHTML(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error { - progs = fixUpPCs(rg.target.Arch, progs, coverFilter) - files, err := rg.prepareFileMap(progs) +type CoverHandlerParams struct { + Progs []Prog + CoverFilter map[uint32]uint32 + Debug bool +} + +func (rg *ReportGenerator) DoHTML(w io.Writer, params CoverHandlerParams) error { + var progs = fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) + files, err := rg.prepareFileMap(progs, params.Debug) if err != nil { return err } @@ -127,9 +133,9 @@ type lineCoverExport struct { Both []int `json:",omitempty"` } -func (rg *ReportGenerator) DoLineJSON(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error { - progs = fixUpPCs(rg.target.Arch, progs, coverFilter) - files, err := rg.prepareFileMap(progs) +func (rg *ReportGenerator) DoLineJSON(w io.Writer, params CoverHandlerParams) error { + var progs = fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) + files, err := rg.prepareFileMap(progs, params.Debug) if err != nil { return err } @@ -291,7 +297,7 @@ var csvFilesHeader = []string{ } func (rg *ReportGenerator) convertToStats(progs []Prog) ([]fileStats, error) { - files, err := rg.prepareFileMap(progs) + files, err := rg.prepareFileMap(progs, false) if err != nil { return nil, err } @@ -341,8 +347,8 @@ func (rg *ReportGenerator) convertToStats(progs []Prog) ([]fileStats, error) { return data, nil } -func (rg *ReportGenerator) DoCSVFiles(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error { - progs = fixUpPCs(rg.target.Arch, progs, coverFilter) +func (rg *ReportGenerator) DoCSVFiles(w io.Writer, params CoverHandlerParams) error { + var progs = fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) data, err := rg.convertToStats(progs) if err != nil { return err @@ -441,8 +447,8 @@ func groupCoverByFilePrefixes(datas []fileStats, subsystems []mgrconfig.Subsyste return d } -func (rg *ReportGenerator) DoHTMLTable(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error { - progs = fixUpPCs(rg.target.Arch, progs, coverFilter) +func (rg *ReportGenerator) DoHTMLTable(w io.Writer, params CoverHandlerParams) error { + var progs = fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) data, err := rg.convertToStats(progs) if err != nil { return err @@ -517,8 +523,8 @@ func groupCoverByModule(datas []fileStats) map[string]map[string]string { return d } -func (rg *ReportGenerator) DoModuleCover(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error { - progs = fixUpPCs(rg.target.Arch, progs, coverFilter) +func (rg *ReportGenerator) DoModuleCover(w io.Writer, params CoverHandlerParams) error { + var progs = fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) data, err := rg.convertToStats(progs) if err != nil { return err @@ -537,9 +543,9 @@ var csvHeader = []string{ "Total PCs", } -func (rg *ReportGenerator) DoCSV(w io.Writer, progs []Prog, coverFilter map[uint32]uint32) error { - progs = fixUpPCs(rg.target.Arch, progs, coverFilter) - files, err := rg.prepareFileMap(progs) +func (rg *ReportGenerator) DoCSV(w io.Writer, params CoverHandlerParams) error { + var progs = fixUpPCs(rg.target.Arch, params.Progs, params.CoverFilter) + files, err := rg.prepareFileMap(progs, params.Debug) if err != nil { return err } diff --git a/pkg/cover/report.go b/pkg/cover/report.go index 6bf7e0a6f..9d03811ad 100644 --- a/pkg/cover/report.go +++ b/pkg/cover/report.go @@ -74,7 +74,20 @@ type line struct { progIndex int // example program index that covers this line } -func (rg *ReportGenerator) prepareFileMap(progs []Prog) (map[string]*file, error) { +func coverageCallbackMismatch(debug bool, numPCs int, unmatchedProgPCs map[uint64]bool) error { + debugStr := "" + if debug { + debugStr += "\n\nUnmatched PCs:\n" + for pc := range unmatchedProgPCs { + debugStr += fmt.Sprintf("%x\n", pc) + } + } + // nolint: lll + return fmt.Errorf("%d out of %d PCs returned by kcov do not have matching coverage callbacks. Check the discoverModules() code.%s", + len(unmatchedProgPCs), numPCs, debugStr) +} + +func (rg *ReportGenerator) prepareFileMap(progs []Prog, debug bool) (map[string]*file, error) { if err := rg.lazySymbolize(progs); err != nil { return nil, err } @@ -131,9 +144,7 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog) (map[string]*file, error // If the backend provided coverage callback locations for the binaries, use them to // verify data returned by kcov. if verifyCoverPoints && (len(unmatchedProgPCs) > 0) { - return nil, fmt.Errorf("%d out of %d PCs returned by kcov do not have matching "+ - "coverage callbacks. Check the discoverModules() code", - len(unmatchedProgPCs), len(progPCs)) + return nil, coverageCallbackMismatch(debug, len(progPCs), unmatchedProgPCs) } for _, unit := range rg.Units { f := files[unit.Name] diff --git a/pkg/cover/report_test.go b/pkg/cover/report_test.go index c6c9d28f1..3d31841cc 100644 --- a/pkg/cover/report_test.go +++ b/pkg/cover/report_test.go @@ -365,20 +365,23 @@ func generateReport(t *testing.T, target *targets.Target, test *Test) ([]byte, [ progs = append(progs, Prog{Data: "main", PCs: pcs}) } html := new(bytes.Buffer) - if err := rg.DoHTML(html, progs, nil); err != nil { + params := CoverHandlerParams{ + Progs: progs, + } + if err := rg.DoHTML(html, params); err != nil { return nil, nil, err } htmlTable := new(bytes.Buffer) - if err := rg.DoHTMLTable(htmlTable, progs, nil); err != nil { + if err := rg.DoHTMLTable(htmlTable, params); err != nil { return nil, nil, err } _ = htmlTable csv := new(bytes.Buffer) - if err := rg.DoCSV(csv, progs, nil); err != nil { + if err := rg.DoCSV(csv, params); err != nil { return nil, nil, err } csvFiles := new(bytes.Buffer) - if err := rg.DoCSVFiles(csvFiles, progs, nil); err != nil { + if err := rg.DoCSVFiles(csvFiles, params); err != nil { return nil, nil, err } _ = csvFiles -- cgit mrf-deployment