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
|
// Copyright 2023 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 linux
import (
"io/fs"
"regexp"
"runtime"
"sort"
"sync"
"github.com/google/syzkaller/pkg/subsystem"
)
func BuildCoincidenceMatrix(root fs.FS, list []*subsystem.Subsystem,
excludeRe *regexp.Regexp) (*CoincidenceMatrix, *matrixDebugInfo, error) {
// Create a matcher.
matcher := subsystem.MakePathMatcher(list)
chPaths, chResult := extractSubsystems(matcher)
// The final consumer goroutine.
cm := MakeCoincidenceMatrix()
ready := make(chan struct{})
debug := &matrixDebugInfo{files: map[*subsystem.Subsystem][]string{}}
go func() {
for item := range chResult {
cm.Record(item.list...)
for _, entity := range item.list {
debug.files[entity] = append(debug.files[entity], item.path)
}
}
ready <- struct{}{}
}()
// Source of data.
err := fs.WalkDir(root, ".", func(path string, info fs.DirEntry, err error) error {
if err != nil || info.IsDir() {
return err
}
if !includePathRe.MatchString(path) ||
(excludeRe != nil && excludeRe.MatchString(path)) {
return nil
}
chPaths <- path
return nil
})
close(chPaths)
<-ready
for _, list := range debug.files {
sort.Strings(list)
}
return cm, debug, err
}
type matrixDebugInfo struct {
files map[*subsystem.Subsystem][]string
}
var (
includePathRe = regexp.MustCompile(`(?:/|\.(?:c|h|S))$`)
)
type extracted struct {
path string
list []*subsystem.Subsystem
}
func extractSubsystems(matcher *subsystem.PathMatcher) (chan<- string, <-chan extracted) {
procs := runtime.NumCPU()
paths, output := make(chan string, procs), make(chan extracted, procs)
var wg sync.WaitGroup
for i := 0; i < procs; i++ {
wg.Add(1)
go func() {
defer wg.Done()
for path := range paths {
output <- extracted{
path: path,
list: matcher.Match(path),
}
}
}()
}
go func() {
wg.Wait()
close(output)
}()
return paths, output
}
|