github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/tools/syz-declextract/declextract_test.go (about) 1 // Copyright 2024 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 "os" 8 "path/filepath" 9 "testing" 10 11 "github.com/google/syzkaller/pkg/ast" 12 "github.com/google/syzkaller/pkg/clangtool" 13 "github.com/google/syzkaller/pkg/clangtool/tooltest" 14 "github.com/google/syzkaller/pkg/compiler" 15 "github.com/google/syzkaller/pkg/declextract" 16 "github.com/google/syzkaller/pkg/ifaceprobe" 17 "github.com/google/syzkaller/pkg/osutil" 18 ) 19 20 func TestClangTool(t *testing.T) { 21 tooltest.TestClangTool[declextract.Output](t) 22 } 23 24 func TestDeclextract(t *testing.T) { 25 tooltest.ForEachTestFile(t, func(t *testing.T, cfg *clangtool.Config, file string) { 26 // Created cache file to avoid running the clang tool. 27 goldenFile := file + ".json" 28 cacheFile := filepath.Join(cfg.KernelObj, filepath.Base(goldenFile)) 29 if err := os.Symlink(goldenFile, cacheFile); err != nil { 30 t.Fatal(err) 31 } 32 if err := os.Symlink(filepath.Join(cfg.KernelSrc, "manual.txt"), 33 filepath.Join(cfg.KernelObj, "manual.txt")); err != nil { 34 t.Fatal(err) 35 } 36 cfg.ToolBin = "this-is-not-supposed-to-run" 37 probeInfo := new(ifaceprobe.Info) 38 probeFile := filepath.Join(cfg.KernelSrc, filepath.Base(file)+".probe") 39 if osutil.IsExist(probeFile) { 40 var err error 41 probeInfo, err = readProbeResult(probeFile) 42 if err != nil { 43 t.Fatal(err) 44 } 45 } 46 coverFile := filepath.Join(cfg.KernelSrc, filepath.Base(file)+".cover") 47 if !osutil.IsExist(coverFile) { 48 coverFile = "" 49 } 50 autoFile := filepath.Join(cfg.KernelObj, filepath.Base(file)+".txt") 51 runcfg := &config{ 52 autoFile: autoFile, 53 coverFile: coverFile, 54 loadProbeInfo: func() (*ifaceprobe.Info, error) { 55 return probeInfo, nil 56 }, 57 Config: cfg, 58 } 59 res, err := run(runcfg) 60 if err != nil { 61 if *tooltest.FlagUpdate { 62 osutil.CopyFile(autoFile, file+".txt") 63 osutil.CopyFile(autoFile+".info", file+".info") 64 } 65 t.Fatal(err) 66 } 67 68 // Check that descriptions compile. 69 eh, errors := errorHandler() 70 full := ast.ParseGlob(filepath.Join(cfg.KernelObj, "*.txt"), eh) 71 if full == nil { 72 t.Fatalf("failed to parse full descriptions:\n%s", errors) 73 } 74 constInfo := compiler.ExtractConsts(full, target, eh) 75 if constInfo == nil { 76 t.Fatalf("failed to compile full descriptions:\n%s", errors) 77 } 78 // Fabricate consts. 79 consts := make(map[string]uint64) 80 for _, info := range constInfo { 81 for i, c := range info.Consts { 82 consts[c.Name] = uint64(i + 1) 83 } 84 } 85 desc := compiler.Compile(full, consts, target, eh) 86 if desc == nil { 87 t.Fatalf("failed to compile full descriptions:\n%s", errors) 88 } 89 90 // Check that generated structs have the same size/align as they had in C. 91 // We assume size/align do not depend on const values (which we fabricated). 92 for _, typ := range desc.Types { 93 info := res.StructInfo[typ.Name()] 94 if info == nil { 95 continue 96 } 97 if typ.Size() != uint64(info.Size) || typ.Alignment() != uint64(info.Align) { 98 t.Errorf("incorrect generated type %v: size %v/%v align %v/%v", 99 typ.Name(), typ.Size(), info.Size, typ.Alignment(), info.Align) 100 } 101 } 102 103 // TODO: Ensure that none of the syscalls will be disabled by TransitivelyEnabledCalls. 104 105 tooltest.CompareGoldenFile(t, file+".txt", autoFile) 106 tooltest.CompareGoldenFile(t, file+".info", autoFile+".info") 107 }) 108 }