github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/tools/syz-query-subsystems/generator.go (about) 1 // Copyright 2023 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 package main 5 6 import ( 7 "bytes" 8 "fmt" 9 "go/format" 10 "regexp" 11 "sort" 12 "strings" 13 "text/template" 14 "unicode" 15 16 "github.com/google/syzkaller/pkg/serializer" 17 "github.com/google/syzkaller/pkg/subsystem" 18 "github.com/google/syzkaller/pkg/vcs" 19 ) 20 21 func generateSubsystemsFile(name string, list []*subsystem.Subsystem, commit *vcs.Commit) ([]byte, error) { 22 // Set names first -- we'll need them for filling in the Parents array. 23 objToName := map[*subsystem.Subsystem]string{} 24 for _, entry := range list { 25 varName := getVarName(entry) 26 if varName == "" { 27 return nil, fmt.Errorf("failed to get a var name for %#v", entry.Name) 28 } 29 objToName[entry] = varName 30 } 31 32 // Prepare the template data. 33 vars := &templateVars{ 34 Name: name, 35 CommitInfo: fmt.Sprintf(`Commit %s, "%.32s"`, commit.Hash, commit.Title), 36 Version: commit.Date.Year()*10000 + int(commit.Date.Month())*100 + commit.Date.Day(), 37 Hierarchy: hierarchyList(list), 38 } 39 for _, entry := range list { 40 varName := objToName[entry] 41 // The serializer does not understand parent references and just prints all the 42 // nested structures. 43 // Therefore we call it separately for the fields it can understand. 44 parents := []string{} 45 for _, p := range entry.Parents { 46 parents = append(parents, objToName[p]) 47 } 48 sort.Strings(parents) 49 subsystem := &templateSubsystem{ 50 VarName: varName, 51 Name: serializer.WriteString(entry.Name), 52 PathRules: serializer.WriteString(entry.PathRules), 53 Parents: parents, 54 NoReminders: entry.NoReminders, 55 NoIndirectCc: entry.NoIndirectCc, 56 } 57 // Some of the records are mostly empty. 58 if len(entry.Maintainers) > 0 { 59 sort.Strings(entry.Maintainers) 60 subsystem.Maintainers = serializer.WriteString(entry.Maintainers) 61 } 62 if len(entry.Syscalls) > 0 { 63 subsystem.Syscalls = serializer.WriteString(entry.Syscalls) 64 } 65 if len(entry.Lists) > 0 { 66 subsystem.Lists = serializer.WriteString(entry.Lists) 67 } 68 vars.List = append(vars.List, subsystem) 69 } 70 tmpl, err := template.New("source").Parse(fileTemplate) 71 if err != nil { 72 return nil, err 73 } 74 var b bytes.Buffer 75 if err = tmpl.Execute(&b, vars); err != nil { 76 return nil, err 77 } 78 return format.Source(b.Bytes()) 79 } 80 81 func getVarName(entry *subsystem.Subsystem) string { 82 varName := makeVarRegexp.ReplaceAllString(strings.ToLower(entry.Name), "") 83 if varName == "" { 84 return "" 85 } 86 if unicode.IsDigit(rune(varName[0])) { 87 return "_" + varName 88 } 89 return varName 90 } 91 92 func hierarchyList(list []*subsystem.Subsystem) []string { 93 children := map[*subsystem.Subsystem][]*subsystem.Subsystem{} 94 for _, entry := range list { 95 for _, p := range entry.Parents { 96 children[p] = append(children[p], entry) 97 } 98 } 99 ret := []string{} 100 var dfs func(*subsystem.Subsystem, string) 101 dfs = func(entry *subsystem.Subsystem, prefix string) { 102 ret = append(ret, fmt.Sprintf("%s- %s", prefix, entry.Name)) 103 for _, child := range children[entry] { 104 dfs(child, prefix+" ") 105 } 106 } 107 for _, entity := range list { 108 if len(entity.Parents) == 0 { 109 dfs(entity, "") 110 } 111 } 112 return ret 113 } 114 115 var makeVarRegexp = regexp.MustCompile(`[^\w]|^([^a-z0-9]+)`) 116 117 type templateSubsystem struct { 118 VarName string 119 Name string 120 Syscalls string 121 PathRules string 122 Lists string 123 Maintainers string 124 Parents []string 125 NoReminders bool 126 NoIndirectCc bool 127 } 128 129 type templateVars struct { 130 Name string 131 Version int 132 CommitInfo string 133 List []*templateSubsystem 134 Hierarchy []string 135 } 136 137 const fileTemplate = `// Code generated by the syz-query-subsystems tool. DO NOT EDIT. 138 {{- if .CommitInfo}} 139 // {{.CommitInfo}} 140 {{- end}} 141 142 package lists 143 144 import . "github.com/google/syzkaller/pkg/subsystem" 145 146 func init() { 147 RegisterList("{{.Name}}", subsystems_{{.Name}}(), {{.Version}}) 148 } 149 150 // The subsystem list: 151 {{- range .Hierarchy}} 152 // {{.}} 153 {{- end}} 154 155 func subsystems_{{.Name}}() []*Subsystem{ 156 var {{range $i, $item := .List}} 157 {{- if gt $i 0}}, {{end}} 158 {{- .VarName}} 159 {{- end}} Subsystem 160 161 {{range .List}} 162 {{.VarName}} = Subsystem{ 163 Name: {{.Name}}, 164 {{- if .Syscalls}} 165 Syscalls: {{.Syscalls}}, 166 {{- end}} 167 {{- if .Lists}} 168 Lists: {{.Lists}}, 169 {{- end}} 170 {{- if .Maintainers}} 171 Maintainers: {{.Maintainers}}, 172 {{- end}} 173 {{- if .Parents}} 174 Parents: []*Subsystem{ {{range .Parents}} &{{.}}, {{end}} }, 175 {{- end}} 176 PathRules: {{.PathRules}}, 177 {{- if .NoReminders}} 178 NoReminders: true, 179 {{- end}} 180 {{- if .NoIndirectCc}} 181 NoIndirectCc: true, 182 {{- end}} 183 } 184 {{end}} 185 186 return []*Subsystem{ 187 {{range .List}} &{{.VarName}}, {{- end}} 188 } 189 190 } 191 `