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