aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/cover/report.go
diff options
context:
space:
mode:
authorAlexander Potapenko <glider@google.com>2024-01-10 16:17:08 +0100
committerAleksandr Nogikh <nogikh@google.com>2024-01-29 09:09:17 +0000
commit991a98f41ea59aba246c9165c8d9539d780a2544 (patch)
treec10a0763b334f6b0beb52b6a663785768f2e96d7 /pkg/cover/report.go
parente9cba3e0b8c082d74feee5139584c29866f4df60 (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.go12
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 {