@@ -5,6 +5,7 @@ package clangtool
55
66import (
77 "bytes"
8+ "crypto/sha256"
89 "encoding/json"
910 "errors"
1011 "fmt"
@@ -18,7 +19,6 @@ import (
1819 "strings"
1920 "time"
2021
21- "github.com/google/syzkaller/pkg/declextract"
2222 "github.com/google/syzkaller/pkg/osutil"
2323)
2424
@@ -30,17 +30,21 @@ type Config struct {
3030 DebugTrace io.Writer
3131}
3232
33+ type OutputDataPtr [T any ] interface {
34+ * T
35+ Merge (* T )
36+ SetSourceFile (string , func (filename string ) string )
37+ SortAndDedup ()
38+ }
39+
3340// Run runs the clang tool on all files in the compilation database
3441// in the kernel build dir and returns combined output for all files.
3542// It always caches results, and optionally reuses previously cached results.
36- func Run (cfg * Config ) (* declextract. Output , error ) {
43+ func Run [ Output any , OutputPtr OutputDataPtr [ Output ]] (cfg * Config ) (OutputPtr , error ) {
3744 if cfg .CacheFile != "" {
38- data , err := os . ReadFile (cfg .CacheFile )
45+ out , err := osutil. ReadJSON [ OutputPtr ] (cfg .CacheFile )
3946 if err == nil {
40- out , err := unmarshal (data )
41- if err == nil {
42- return out , nil
43- }
47+ return out , nil
4448 }
4549 }
4650
@@ -51,15 +55,15 @@ func Run(cfg *Config) (*declextract.Output, error) {
5155 }
5256
5357 type result struct {
54- out * declextract. Output
58+ out OutputPtr
5559 err error
5660 }
5761 results := make (chan * result , 10 )
5862 files := make (chan string , len (cmds ))
5963 for w := 0 ; w < runtime .NumCPU (); w ++ {
6064 go func () {
6165 for file := range files {
62- out , err := runTool (cfg , dbFile , file )
66+ out , err := runTool [ Output , OutputPtr ] (cfg , dbFile , file )
6367 results <- & result {out , err }
6468 }
6569 }()
@@ -69,7 +73,7 @@ func Run(cfg *Config) (*declextract.Output, error) {
6973 }
7074 close (files )
7175
72- out := new (declextract. Output )
76+ out := OutputPtr ( new (Output ) )
7377 for range cmds {
7478 res := <- results
7579 if res .err != nil {
@@ -91,7 +95,7 @@ func Run(cfg *Config) (*declextract.Output, error) {
9195 return out , nil
9296}
9397
94- func runTool (cfg * Config , dbFile , file string ) (* declextract. Output , error ) {
98+ func runTool [ Output any , OutputPtr OutputDataPtr [ Output ]] (cfg * Config , dbFile , file string ) (OutputPtr , error ) {
9599 relFile := strings .TrimPrefix (strings .TrimPrefix (strings .TrimPrefix (filepath .Clean (file ),
96100 cfg .KernelSrc ), cfg .KernelObj ), "/" )
97101 // Suppress warning since we may build the tool on a different clang
@@ -104,33 +108,20 @@ func runTool(cfg *Config, dbFile, file string) (*declextract.Output, error) {
104108 }
105109 return nil , err
106110 }
107- out , err := unmarshal (data )
111+ out , err := osutil. ParseJSON [ OutputPtr ] (data )
108112 if err != nil {
109113 return nil , err
110114 }
111- fixupFileNames (cfg , out , relFile )
112- return out , nil
113- }
114-
115- func unmarshal (data []byte ) (* declextract.Output , error ) {
116- dec := json .NewDecoder (bytes .NewReader (data ))
117- dec .DisallowUnknownFields ()
118- out := new (declextract.Output )
119- if err := dec .Decode (out ); err != nil {
120- return nil , fmt .Errorf ("failed to unmarshal clang tool output: %w\n %s" , err , data )
121- }
122- return out , nil
123- }
124-
125- func fixupFileNames (cfg * Config , out * declextract.Output , file string ) {
126115 // All includes in the tool output are relative to the build dir.
127116 // Make them relative to the source dir.
128- out .SetSourceFile (file , func (filename string ) string {
129- if res , err := filepath .Rel (cfg .KernelSrc , filepath .Join (cfg .KernelObj , filename )); err == nil {
130- return res
117+ out .SetSourceFile (relFile , func (filename string ) string {
118+ rel , err := filepath .Rel (cfg .KernelSrc , filepath .Join (cfg .KernelObj , filename ))
119+ if err == nil && filename != "" {
120+ return rel
131121 }
132122 return filename
133123 })
124+ return out , nil
134125}
135126
136127type compileCommand struct {
@@ -170,3 +161,21 @@ func loadCompileCommands(dbFile string) ([]compileCommand, error) {
170161 }
171162 return cmds , nil
172163}
164+
165+ func SortAndDedupSlice [Slice ~ []E , E comparable ](s Slice ) Slice {
166+ dedup := make (map [[sha256 .Size ]byte ]E )
167+ text := make (map [E ][]byte )
168+ for _ , e := range s {
169+ t , _ := json .Marshal (e )
170+ dedup [sha256 .Sum256 (t )] = e
171+ text [e ] = t
172+ }
173+ s = make ([]E , 0 , len (dedup ))
174+ for _ , e := range dedup {
175+ s = append (s , e )
176+ }
177+ slices .SortFunc (s , func (a , b E ) int {
178+ return bytes .Compare (text [a ], text [b ])
179+ })
180+ return s
181+ }
0 commit comments