diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2025-11-17 07:50:28 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2025-11-17 08:54:02 +0000 |
| commit | a41f43a1ab652ec0629a63d0812a30bfec0e0faf (patch) | |
| tree | 8e9cbf006b8801400fbdb2b538b1f9755141230f /pkg/clangtool | |
| parent | cbc18b106abc7ee5cbca73a11b24265328d29516 (diff) | |
pkg/clangtool: make more generic
Make it possible to use pkg/clangtool with other types than declextract.Output.
Diffstat (limited to 'pkg/clangtool')
| -rw-r--r-- | pkg/clangtool/clangtool.go | 66 |
1 files changed, 44 insertions, 22 deletions
diff --git a/pkg/clangtool/clangtool.go b/pkg/clangtool/clangtool.go index bed29eb7b..8ebc40dc2 100644 --- a/pkg/clangtool/clangtool.go +++ b/pkg/clangtool/clangtool.go @@ -5,6 +5,7 @@ package clangtool import ( "bytes" + "crypto/sha256" "encoding/json" "errors" "fmt" @@ -18,7 +19,6 @@ import ( "strings" "time" - "github.com/google/syzkaller/pkg/declextract" "github.com/google/syzkaller/pkg/osutil" ) @@ -30,14 +30,21 @@ type Config struct { DebugTrace io.Writer } +type OutputDataPtr[T any] interface { + *T + Merge(*T) + SetSourceFile(string, func(filename string) string) + SortAndDedup() +} + // Run runs the clang tool on all files in the compilation database // in the kernel build dir and returns combined output for all files. // It always caches results, and optionally reuses previously cached results. -func Run(cfg *Config) (*declextract.Output, error) { +func Run[Output any, OutputPtr OutputDataPtr[Output]](cfg *Config) (OutputPtr, error) { if cfg.CacheFile != "" { data, err := os.ReadFile(cfg.CacheFile) if err == nil { - out, err := unmarshal(data) + out, err := unmarshal[Output, OutputPtr](data) if err == nil { return out, nil } @@ -51,7 +58,7 @@ func Run(cfg *Config) (*declextract.Output, error) { } type result struct { - out *declextract.Output + out OutputPtr err error } results := make(chan *result, 10) @@ -59,7 +66,7 @@ func Run(cfg *Config) (*declextract.Output, error) { for w := 0; w < runtime.NumCPU(); w++ { go func() { for file := range files { - out, err := runTool(cfg, dbFile, file) + out, err := runTool[Output, OutputPtr](cfg, dbFile, file) results <- &result{out, err} } }() @@ -69,7 +76,7 @@ func Run(cfg *Config) (*declextract.Output, error) { } close(files) - out := new(declextract.Output) + out := OutputPtr(new(Output)) for range cmds { res := <-results if res.err != nil { @@ -91,7 +98,7 @@ func Run(cfg *Config) (*declextract.Output, error) { return out, nil } -func runTool(cfg *Config, dbFile, file string) (*declextract.Output, error) { +func runTool[Output any, OutputPtr OutputDataPtr[Output]](cfg *Config, dbFile, file string) (OutputPtr, error) { relFile := strings.TrimPrefix(strings.TrimPrefix(strings.TrimPrefix(filepath.Clean(file), cfg.KernelSrc), cfg.KernelObj), "/") // Suppress warning since we may build the tool on a different clang @@ -104,35 +111,32 @@ func runTool(cfg *Config, dbFile, file string) (*declextract.Output, error) { } return nil, err } - out, err := unmarshal(data) + out, err := unmarshal[Output, OutputPtr](data) if err != nil { return nil, err } - fixupFileNames(cfg, out, relFile) + // All includes in the tool output are relative to the build dir. + // Make them relative to the source dir. + out.SetSourceFile(relFile, func(filename string) string { + rel, err := filepath.Rel(cfg.KernelSrc, filepath.Join(cfg.KernelObj, filename)) + if err == nil && filename != "" { + return rel + } + return filename + }) return out, nil } -func unmarshal(data []byte) (*declextract.Output, error) { +func unmarshal[Output any, OutputPtr OutputDataPtr[Output]](data []byte) (OutputPtr, error) { dec := json.NewDecoder(bytes.NewReader(data)) dec.DisallowUnknownFields() - out := new(declextract.Output) + out := OutputPtr(new(Output)) if err := dec.Decode(out); err != nil { return nil, fmt.Errorf("failed to unmarshal clang tool output: %w\n%s", err, data) } return out, nil } -func fixupFileNames(cfg *Config, out *declextract.Output, file string) { - // All includes in the tool output are relative to the build dir. - // Make them relative to the source dir. - out.SetSourceFile(file, func(filename string) string { - if res, err := filepath.Rel(cfg.KernelSrc, filepath.Join(cfg.KernelObj, filename)); err == nil { - return res - } - return filename - }) -} - type compileCommand struct { Command string Directory string @@ -170,3 +174,21 @@ func loadCompileCommands(dbFile string) ([]compileCommand, error) { } return cmds, nil } + +func SortAndDedupSlice[Slice ~[]E, E comparable](s Slice) Slice { + dedup := make(map[[sha256.Size]byte]E) + text := make(map[E][]byte) + for _, e := range s { + t, _ := json.Marshal(e) + dedup[sha256.Sum256(t)] = e + text[e] = t + } + s = make([]E, 0, len(dedup)) + for _, e := range dedup { + s = append(s, e) + } + slices.SortFunc(s, func(a, b E) int { + return bytes.Compare(text[a], text[b]) + }) + return s +} |
