diff options
| author | Alexander Potapenko <glider@google.com> | 2024-01-10 16:17:08 +0100 |
|---|---|---|
| committer | Aleksandr Nogikh <nogikh@google.com> | 2024-01-29 09:09:17 +0000 |
| commit | 991a98f41ea59aba246c9165c8d9539d780a2544 (patch) | |
| tree | c10a0763b334f6b0beb52b6a663785768f2e96d7 /pkg/cover/report.go | |
| parent | e9cba3e0b8c082d74feee5139584c29866f4df60 (diff) | |
pkg/cover: ensure that all PCs returned by kcov have matching callbacks
In the case some modules' addresses are off, certain kernel addresses
returned by kcov may not have corresponding coverage callbacks in the
.ko files. Keep an additional map in the backend to verify those
addresses and report an error if that is the case.
Because GCC < 14 may tail-call coverage callbacks, the described check
is not performed for binaries which mention GCC in their .comment
section.
Also adjust text expectations in pkg/cover/report_test.go, so that
non-GCC targets check for PCs matching the callbacks.
See https://github.com/google/syzkaller/issues/4447 for more details.
Diffstat (limited to 'pkg/cover/report.go')
| -rw-r--r-- | pkg/cover/report.go | 12 |
1 files changed, 12 insertions, 0 deletions
diff --git a/pkg/cover/report.go b/pkg/cover/report.go index 2d1b8bd2e..a886eb014 100644 --- a/pkg/cover/report.go +++ b/pkg/cover/report.go @@ -88,12 +88,17 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog) (map[string]*file, error } } progPCs := make(map[uint64]map[int]bool) + unmatchedProgPCs := make(map[uint64]bool) + verifyCoverPoints := (len(rg.CoverPoints) > 0) for i, prog := range progs { for _, pc := range prog.PCs { if progPCs[pc] == nil { progPCs[pc] = make(map[int]bool) } progPCs[pc][i] = true + if verifyCoverPoints && !rg.CoverPoints[pc] { + unmatchedProgPCs[pc] = true + } } } matchedPC := false @@ -123,6 +128,13 @@ func (rg *ReportGenerator) prepareFileMap(progs []Prog) (map[string]*file, error if !matchedPC { return nil, fmt.Errorf("coverage doesn't match any coverage callbacks") } + // 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)) + } for _, unit := range rg.Units { f := files[unit.Name] for _, pc := range unit.PCs { |
