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