mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-27 21:30:33 +00:00
sys/syz-extract: generate build files out of tree
This does not pollute user kernel dir (we do make mrproper, though) and enables parallel generation.
This commit is contained in:
parent
7296cf374d
commit
4503776d2b
@ -26,16 +26,31 @@ var (
|
||||
flagLinux = flag.String("linux", "", "path to linux kernel source checkout")
|
||||
flagLinuxBld = flag.String("linuxbld", "", "path to linux kernel build directory")
|
||||
flagArch = flag.String("arch", "", "comma-separated list of arches to generate (all by default)")
|
||||
flagBuild = flag.Bool("build", false, "generate arch-specific files in the linux dir")
|
||||
flagBuild = flag.Bool("build", false, "regenerate arch-specific kernel headers")
|
||||
)
|
||||
|
||||
type Arch struct {
|
||||
target *sys.Target
|
||||
kernelDir string
|
||||
buildDir string
|
||||
build bool
|
||||
files []*File
|
||||
err error
|
||||
}
|
||||
|
||||
type File struct {
|
||||
arch *Arch
|
||||
name string
|
||||
undeclared map[string]bool
|
||||
err error
|
||||
}
|
||||
|
||||
func main() {
|
||||
failf := func(msg string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
const OS = "linux"
|
||||
flag.Parse()
|
||||
if *flagLinux == "" {
|
||||
@ -48,49 +63,105 @@ func main() {
|
||||
if n == 0 {
|
||||
failf("usage: syz-extract -linux=/linux/checkout -arch=arch input_file.txt...")
|
||||
}
|
||||
var arches []string
|
||||
|
||||
var archArray []string
|
||||
if *flagArch != "" {
|
||||
arches = strings.Split(*flagArch, ",")
|
||||
archArray = strings.Split(*flagArch, ",")
|
||||
} else {
|
||||
for arch := range sys.Targets[OS] {
|
||||
arches = append(arches, arch)
|
||||
archArray = append(archArray, arch)
|
||||
}
|
||||
sort.Strings(arches)
|
||||
sort.Strings(archArray)
|
||||
}
|
||||
for _, arch := range arches {
|
||||
fmt.Printf("generating %v/%v...\n", OS, arch)
|
||||
target := sys.Targets[OS][arch]
|
||||
if target == nil {
|
||||
failf("unknown arch %v", arch)
|
||||
|
||||
if *flagBuild {
|
||||
// Otherwise out-of-tree build fails.
|
||||
fmt.Printf("make mrproper\n")
|
||||
out, err := osutil.RunCmd(time.Hour, *flagLinux, "make", "mrproper")
|
||||
if err != nil {
|
||||
failf("make mrproper failed: %v\n%s\n", err, out)
|
||||
}
|
||||
} else {
|
||||
if len(archArray) > 1 {
|
||||
failf("more than 1 arch is invalid without -build")
|
||||
}
|
||||
}
|
||||
|
||||
jobC := make(chan interface{}, len(archArray)*len(flag.Args()))
|
||||
var wg sync.WaitGroup
|
||||
|
||||
var arches []*Arch
|
||||
for _, archStr := range archArray {
|
||||
buildDir := ""
|
||||
if *flagBuild {
|
||||
buildKernel(target, *flagLinux)
|
||||
*flagLinuxBld = *flagLinux
|
||||
} else if *flagLinuxBld == "" {
|
||||
*flagLinuxBld = *flagLinux
|
||||
dir, err := ioutil.TempDir("", "syzkaller-kernel-build")
|
||||
if err != nil {
|
||||
failf("failed to create temp dir: %v", err)
|
||||
}
|
||||
buildDir = dir
|
||||
} else if *flagLinuxBld != "" {
|
||||
buildDir = *flagLinuxBld
|
||||
} else {
|
||||
buildDir = *flagLinux
|
||||
}
|
||||
|
||||
files := make([]File, n)
|
||||
inc := make(chan *File, n)
|
||||
for i, f := range flag.Args() {
|
||||
files[i].name = f
|
||||
inc <- &files[i]
|
||||
target := sys.Targets[OS][archStr]
|
||||
if target == nil {
|
||||
failf("unknown arch: %v", archStr)
|
||||
}
|
||||
close(inc)
|
||||
|
||||
procs := runtime.GOMAXPROCS(0)
|
||||
var wg sync.WaitGroup
|
||||
wg.Add(procs)
|
||||
for p := 0; p < procs; p++ {
|
||||
go func() {
|
||||
defer wg.Done()
|
||||
for f := range inc {
|
||||
f.undeclared, f.err = processFile(target, f.name)
|
||||
arch := &Arch{
|
||||
target: target,
|
||||
kernelDir: *flagLinux,
|
||||
buildDir: buildDir,
|
||||
build: *flagBuild,
|
||||
}
|
||||
for _, f := range flag.Args() {
|
||||
arch.files = append(arch.files, &File{
|
||||
arch: arch,
|
||||
name: f,
|
||||
})
|
||||
}
|
||||
arches = append(arches, arch)
|
||||
jobC <- arch
|
||||
wg.Add(1)
|
||||
}
|
||||
|
||||
for p := 0; p < runtime.GOMAXPROCS(0); p++ {
|
||||
go func() {
|
||||
for job := range jobC {
|
||||
switch j := job.(type) {
|
||||
case *Arch:
|
||||
if j.build {
|
||||
j.err = buildKernel(j)
|
||||
}
|
||||
if j.err == nil {
|
||||
for _, f := range j.files {
|
||||
wg.Add(1)
|
||||
jobC <- f
|
||||
}
|
||||
}
|
||||
case *File:
|
||||
j.undeclared, j.err = processFile(j.arch, j.name)
|
||||
}
|
||||
}()
|
||||
wg.Done()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
|
||||
for _, arch := range arches {
|
||||
if arch.build {
|
||||
os.RemoveAll(arch.buildDir)
|
||||
}
|
||||
wg.Wait()
|
||||
for _, f := range files {
|
||||
}
|
||||
|
||||
for _, arch := range arches {
|
||||
fmt.Printf("generating %v/%v...\n", arch.target.OS, arch.target.Arch)
|
||||
if arch.err != nil {
|
||||
failf("%v", arch.err)
|
||||
}
|
||||
for _, f := range arch.files {
|
||||
fmt.Printf("extracting from %v\n", f.name)
|
||||
if f.err != nil {
|
||||
failf("%v", f.err)
|
||||
@ -103,8 +174,8 @@ func main() {
|
||||
}
|
||||
}
|
||||
|
||||
func processFile(target *sys.Target, inname string) (map[string]bool, error) {
|
||||
outname := strings.TrimSuffix(inname, ".txt") + "_" + target.Arch + ".const"
|
||||
func processFile(arch *Arch, inname string) (map[string]bool, error) {
|
||||
outname := strings.TrimSuffix(inname, ".txt") + "_" + arch.target.Arch + ".const"
|
||||
indata, err := ioutil.ReadFile(inname)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to read input file: %v", err)
|
||||
@ -125,7 +196,7 @@ func processFile(target *sys.Target, inname string) (map[string]bool, error) {
|
||||
return nil, nil
|
||||
}
|
||||
includes := append(info.Includes, "asm/unistd.h")
|
||||
consts, undeclared, err := fetchValues(target, info.Consts, includes, info.Incdirs, info.Defines)
|
||||
consts, undeclared, err := fetchValues(arch.target, arch.kernelDir, arch.buildDir, info.Consts, includes, info.Incdirs, info.Defines)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -136,36 +207,33 @@ func processFile(target *sys.Target, inname string) (map[string]bool, error) {
|
||||
return undeclared, nil
|
||||
}
|
||||
|
||||
func buildKernel(target *sys.Target, dir string) {
|
||||
// TODO(dvyukov): use separate temp build dir.
|
||||
// This will allow to do build for all archs in parallel and
|
||||
// won't destroy user's build state.
|
||||
func buildKernel(arch *Arch) error {
|
||||
target := arch.target
|
||||
kernelDir := arch.kernelDir
|
||||
buildDir := arch.buildDir
|
||||
makeArgs := []string{
|
||||
"ARCH=" + target.KernelArch,
|
||||
"CROSS_COMPILE=" + target.CCompilerPrefix,
|
||||
"CFLAGS=" + strings.Join(target.CrossCFlags, " "),
|
||||
"O=" + buildDir,
|
||||
}
|
||||
out, err := osutil.RunCmd(time.Hour, dir, "make", append(makeArgs, "defconfig")...)
|
||||
out, err := osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "defconfig")...)
|
||||
if err != nil {
|
||||
failf("make defconfig failed: %v\n%s\n", err, out)
|
||||
return fmt.Errorf("make defconfig failed: %v\n%s\n", err, out)
|
||||
}
|
||||
// Without CONFIG_NETFILTER kernel does not build.
|
||||
out, err = osutil.RunCmd(time.Minute, dir, "sed", "-i",
|
||||
out, err = osutil.RunCmd(time.Minute, buildDir, "sed", "-i",
|
||||
"s@# CONFIG_NETFILTER is not set@CONFIG_NETFILTER=y@g", ".config")
|
||||
if err != nil {
|
||||
failf("sed .config failed: %v\n%s\n", err, out)
|
||||
return fmt.Errorf("sed .config failed: %v\n%s\n", err, out)
|
||||
}
|
||||
out, err = osutil.RunCmd(time.Hour, dir, "make", append(makeArgs, "olddefconfig")...)
|
||||
out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "olddefconfig")...)
|
||||
if err != nil {
|
||||
failf("make olddefconfig failed: %v\n%s\n", err, out)
|
||||
return fmt.Errorf("make olddefconfig failed: %v\n%s\n", err, out)
|
||||
}
|
||||
out, err = osutil.RunCmd(time.Hour, dir, "make", append(makeArgs, "init/main.o")...)
|
||||
out, err = osutil.RunCmd(time.Hour, kernelDir, "make", append(makeArgs, "init/main.o")...)
|
||||
if err != nil {
|
||||
failf("make failed: %v\n%s\n", err, out)
|
||||
return fmt.Errorf("make failed: %v\n%s\n", err, out)
|
||||
}
|
||||
}
|
||||
|
||||
func failf(msg string, args ...interface{}) {
|
||||
fmt.Fprintf(os.Stderr, msg+"\n", args...)
|
||||
os.Exit(1)
|
||||
return nil
|
||||
}
|
||||
|
@ -18,9 +18,10 @@ import (
|
||||
// fetchValues converts literal constants (e.g. O_APPEND) or any other C expressions
|
||||
// into their respective numeric values. It does so by builting and executing a C program
|
||||
// that prints values of the provided expressions.
|
||||
func fetchValues(target *sys.Target, vals, includes, incdirs []string,
|
||||
defines map[string]string) (map[string]uint64, map[string]bool, error) {
|
||||
bin, out, err := runCompiler(target, nil, includes, incdirs, nil, nil)
|
||||
func fetchValues(target *sys.Target, kernelDir, buildDir string,
|
||||
vals, includes, incdirs []string, defines map[string]string) (
|
||||
map[string]uint64, map[string]bool, error) {
|
||||
bin, out, err := runCompiler(target, kernelDir, buildDir, nil, includes, incdirs, nil, nil)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to run gcc: %v\n%v", err, string(out))
|
||||
}
|
||||
@ -32,7 +33,7 @@ func fetchValues(target *sys.Target, vals, includes, incdirs []string,
|
||||
}
|
||||
|
||||
undeclared := make(map[string]bool)
|
||||
bin, out, err = runCompiler(target, vals, includes, incdirs, defines, undeclared)
|
||||
bin, out, err = runCompiler(target, kernelDir, buildDir, vals, includes, incdirs, defines, undeclared)
|
||||
if err != nil {
|
||||
for _, errMsg := range []string{
|
||||
"error: ‘([a-zA-Z0-9_]+)’ undeclared",
|
||||
@ -47,7 +48,7 @@ func fetchValues(target *sys.Target, vals, includes, incdirs []string,
|
||||
}
|
||||
}
|
||||
}
|
||||
bin, out, err = runCompiler(target, vals, includes, incdirs, defines, undeclared)
|
||||
bin, out, err = runCompiler(target, kernelDir, buildDir, vals, includes, incdirs, defines, undeclared)
|
||||
if err != nil {
|
||||
return nil, nil, fmt.Errorf("failed to run gcc: %v\n%v", err, string(out))
|
||||
}
|
||||
@ -86,7 +87,7 @@ func fetchValues(target *sys.Target, vals, includes, incdirs []string,
|
||||
return res, undeclared, nil
|
||||
}
|
||||
|
||||
func runCompiler(target *sys.Target, vals, includes, incdirs []string, defines map[string]string, undeclared map[string]bool) (bin string, out []byte, err error) {
|
||||
func runCompiler(target *sys.Target, kernelDir, buildDir string, vals, includes, incdirs []string, defines map[string]string, undeclared map[string]bool) (bin string, out []byte, err error) {
|
||||
includeText := ""
|
||||
for _, inc := range includes {
|
||||
includeText += fmt.Sprintf("#include <%v>\n", inc)
|
||||
@ -126,20 +127,20 @@ func runCompiler(target *sys.Target, vals, includes, incdirs []string, defines m
|
||||
"-I.",
|
||||
"-D__KERNEL__",
|
||||
"-DKBUILD_MODNAME=\"-\"",
|
||||
"-I" + *flagLinux + "/arch/" + arch + "/include",
|
||||
"-I" + *flagLinuxBld + "/arch/" + arch + "/include/generated/uapi",
|
||||
"-I" + *flagLinuxBld + "/arch/" + arch + "/include/generated",
|
||||
"-I" + *flagLinuxBld + "/include",
|
||||
"-I" + *flagLinux + "/include",
|
||||
"-I" + *flagLinux + "/arch/" + arch + "/include/uapi",
|
||||
"-I" + *flagLinuxBld + "/arch/" + arch + "/include/generated/uapi",
|
||||
"-I" + *flagLinux + "/include/uapi",
|
||||
"-I" + *flagLinuxBld + "/include/generated/uapi",
|
||||
"-I" + *flagLinux,
|
||||
"-include", *flagLinux + "/include/linux/kconfig.h",
|
||||
"-I" + kernelDir + "/arch/" + arch + "/include",
|
||||
"-I" + buildDir + "/arch/" + arch + "/include/generated/uapi",
|
||||
"-I" + buildDir + "/arch/" + arch + "/include/generated",
|
||||
"-I" + buildDir + "/include",
|
||||
"-I" + kernelDir + "/include",
|
||||
"-I" + kernelDir + "/arch/" + arch + "/include/uapi",
|
||||
"-I" + buildDir + "/arch/" + arch + "/include/generated/uapi",
|
||||
"-I" + kernelDir + "/include/uapi",
|
||||
"-I" + buildDir + "/include/generated/uapi",
|
||||
"-I" + kernelDir,
|
||||
"-include", kernelDir + "/include/linux/kconfig.h",
|
||||
}...)
|
||||
for _, incdir := range incdirs {
|
||||
args = append(args, "-I"+*flagLinux+"/"+incdir)
|
||||
args = append(args, "-I"+kernelDir+"/"+incdir)
|
||||
}
|
||||
cmd := exec.Command("gcc", args...)
|
||||
cmd.Stdin = strings.NewReader(src)
|
||||
|
Loading…
Reference in New Issue
Block a user