| // Copyright 2017 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 targets |
| |
| import ( |
| "fmt" |
| "os" |
| "os/exec" |
| "runtime" |
| "strings" |
| "sync" |
| ) |
| |
| type Target struct { |
| init sync.Once |
| osCommon |
| OS string |
| Arch string |
| VMArch string // e.g. amd64 for 386, or arm64 for arm |
| PtrSize uint64 |
| PageSize uint64 |
| NumPages uint64 |
| DataOffset uint64 |
| CFlags []string |
| CrossCFlags []string |
| CCompilerPrefix string |
| CCompiler string |
| KernelArch string |
| KernelHeaderArch string |
| // NeedSyscallDefine is used by csource package to decide when to emit __NR_* defines. |
| NeedSyscallDefine func(nr uint64) bool |
| } |
| |
| type osCommon struct { |
| // What OS can build native binaries for this OS. |
| // If not set, defaults to itself (i.e. native build). |
| // Later we can extend this to be a list, but so far we don't have more than one OS. |
| BuildOS string |
| // Does the OS use syscall numbers (e.g. Linux) or has interface based on functions (e.g. fuchsia). |
| SyscallNumbers bool |
| // E.g. "__NR_" or "SYS_". |
| SyscallPrefix string |
| // ipc<->executor communication tuning. |
| // If ExecutorUsesShmem, programs and coverage are passed through shmem, otherwise via pipes. |
| ExecutorUsesShmem bool |
| // If ExecutorUsesForkServer, executor uses extended protocol with handshake. |
| ExecutorUsesForkServer bool |
| // Extension of executable files (notably, .exe for windows). |
| ExeExtension string |
| // Name of the kernel object file. |
| KernelObject string |
| // Name of cpp(1) executable. |
| CPP string |
| } |
| |
| func Get(OS, arch string) *Target { |
| target := List[OS][arch] |
| if target == nil { |
| return nil |
| } |
| target.init.Do(func() { |
| checkOptionalFlags(target) |
| }) |
| return target |
| } |
| |
| // nolint: lll |
| var List = map[string]map[string]*Target{ |
| "test": { |
| "64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| CFlags: []string{"-m64"}, |
| CrossCFlags: []string{"-m64", "-static"}, |
| osCommon: osCommon{ |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: false, |
| ExecutorUsesForkServer: false, |
| }, |
| }, |
| "64_fork": { |
| PtrSize: 8, |
| PageSize: 8 << 10, |
| CFlags: []string{"-m64"}, |
| CrossCFlags: []string{"-m64", "-static"}, |
| osCommon: osCommon{ |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: false, |
| ExecutorUsesForkServer: true, |
| }, |
| }, |
| "32_shmem": { |
| PtrSize: 4, |
| PageSize: 8 << 10, |
| CFlags: []string{"-m32"}, |
| CrossCFlags: []string{"-m32", "-static"}, |
| osCommon: osCommon{ |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: true, |
| ExecutorUsesForkServer: false, |
| }, |
| }, |
| "32_fork_shmem": { |
| PtrSize: 4, |
| PageSize: 4 << 10, |
| CFlags: []string{"-m32"}, |
| CrossCFlags: []string{"-m32", "-static"}, |
| osCommon: osCommon{ |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: true, |
| ExecutorUsesForkServer: true, |
| }, |
| }, |
| }, |
| "linux": { |
| "amd64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| CFlags: []string{"-m64"}, |
| CrossCFlags: []string{"-m64", "-static"}, |
| CCompilerPrefix: "x86_64-linux-gnu-", |
| KernelArch: "x86_64", |
| KernelHeaderArch: "x86", |
| NeedSyscallDefine: func(nr uint64) bool { |
| // Only generate defines for new syscalls |
| // (added after commit 8a1ab3155c2ac on 2012-10-04). |
| return nr >= 313 |
| }, |
| }, |
| "386": { |
| VMArch: "amd64", |
| PtrSize: 4, |
| PageSize: 4 << 10, |
| CFlags: []string{"-m32"}, |
| CrossCFlags: []string{"-m32", "-static"}, |
| CCompilerPrefix: "x86_64-linux-gnu-", |
| KernelArch: "i386", |
| KernelHeaderArch: "x86", |
| }, |
| "arm64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| CrossCFlags: []string{"-static"}, |
| CCompilerPrefix: "aarch64-linux-gnu-", |
| KernelArch: "arm64", |
| KernelHeaderArch: "arm64", |
| }, |
| "arm": { |
| VMArch: "arm64", |
| PtrSize: 4, |
| PageSize: 4 << 10, |
| CFlags: []string{"-D__LINUX_ARM_ARCH__=6", "-m32", "-D__ARM_EABI__"}, |
| CrossCFlags: []string{"-D__LINUX_ARM_ARCH__=6", "-march=armv6", "-static"}, |
| CCompilerPrefix: "arm-linux-gnueabihf-", |
| KernelArch: "arm", |
| KernelHeaderArch: "arm", |
| }, |
| "ppc64le": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| CFlags: []string{"-D__powerpc64__"}, |
| CrossCFlags: []string{"-D__powerpc64__", "-static"}, |
| CCompilerPrefix: "powerpc64le-linux-gnu-", |
| KernelArch: "powerpc", |
| KernelHeaderArch: "powerpc", |
| }, |
| }, |
| "freebsd": { |
| "amd64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| CFlags: []string{"-m64"}, |
| CrossCFlags: []string{"-m64", "-static"}, |
| NeedSyscallDefine: dontNeedSyscallDefine, |
| }, |
| }, |
| "netbsd": { |
| "amd64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| CFlags: []string{"-m64"}, |
| CrossCFlags: []string{"-m64", "-static", |
| "--sysroot", os.ExpandEnv("${SOURCEDIR}/../dest/"), |
| }, |
| CCompiler: os.ExpandEnv("${SOURCEDIR}/../tools/bin/x86_64--netbsd-g++"), |
| }, |
| }, |
| "openbsd": { |
| "amd64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| CFlags: []string{"-m64"}, |
| CCompiler: "c++", |
| CrossCFlags: []string{"-m64", "-static", "-lutil"}, |
| NeedSyscallDefine: func(nr uint64) bool { |
| switch nr { |
| case 8: // SYS___tfork |
| return true |
| case 94: // SYS___thrsleep |
| return true |
| case 198: // SYS___syscall |
| return true |
| case 295: // SYS___semctl |
| return true |
| case 301: // SYS___thrwakeup |
| return true |
| case 302: // SYS___threxit |
| return true |
| case 303: // SYS___thrsigdivert |
| return true |
| case 304: // SYS___getcwd |
| return true |
| case 329: // SYS___set_tcb |
| return true |
| case 330: // SYS___get_tcb |
| return true |
| } |
| return false |
| }, |
| }, |
| }, |
| "fuchsia": { |
| "amd64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| KernelHeaderArch: "x64", |
| CCompiler: os.ExpandEnv("${SOURCEDIR}/buildtools/linux-x64/clang/bin/clang++"), |
| CrossCFlags: []string{ |
| "-Wno-deprecated", |
| "--target=x86_64-fuchsia", |
| "-lfdio", |
| "-lzircon", |
| "-ldriver", |
| "--sysroot", os.ExpandEnv("${SOURCEDIR}/out/x64/sdk/exported/zircon_sysroot/arch/x64/sysroot"), |
| "-I", os.ExpandEnv("${SOURCEDIR}/zircon/system/ulib/fdio/include"), |
| "-I", os.ExpandEnv("${SOURCEDIR}/zircon/system/ulib/ddk/include"), |
| "-L", os.ExpandEnv("${SOURCEDIR}/out/x64/x64-shared"), |
| }, |
| }, |
| "arm64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| KernelHeaderArch: "arm64", |
| CCompiler: os.ExpandEnv("${SOURCEDIR}/buildtools/linux-x64/clang/bin/clang++"), |
| CrossCFlags: []string{ |
| "-Wno-deprecated", |
| "--target=aarch64-fuchsia", |
| "-lfdio", |
| "-lzircon", |
| "-ldriver", |
| "--sysroot", os.ExpandEnv("${SOURCEDIR}/out/arm64/sdk/exported/zircon_sysroot/arch/arm64/sysroot"), |
| "-L", os.ExpandEnv("${SOURCEDIR}/out/arm64/arm64-shared"), |
| "-I", os.ExpandEnv("${SOURCEDIR}/zircon/system/ulib/fdio/include"), |
| "-I", os.ExpandEnv("${SOURCEDIR}/zircon/system/ulib/ddk/include"), |
| }, |
| }, |
| }, |
| "windows": { |
| "amd64": { |
| PtrSize: 8, |
| // TODO(dvyukov): what should we do about 4k vs 64k? |
| PageSize: 4 << 10, |
| }, |
| }, |
| "akaros": { |
| "amd64": { |
| PtrSize: 8, |
| PageSize: 4 << 10, |
| KernelHeaderArch: "x86", |
| NeedSyscallDefine: dontNeedSyscallDefine, |
| CCompiler: os.ExpandEnv("${SOURCEDIR}/toolchain/x86_64-ucb-akaros-gcc/bin/x86_64-ucb-akaros-g++"), |
| CrossCFlags: []string{ |
| "-static", |
| }, |
| }, |
| }, |
| "trusty": { |
| "arm": { |
| PtrSize: 4, |
| PageSize: 4 << 10, |
| NeedSyscallDefine: dontNeedSyscallDefine, |
| }, |
| }, |
| } |
| |
| var oses = map[string]osCommon{ |
| "linux": { |
| SyscallNumbers: true, |
| SyscallPrefix: "__NR_", |
| ExecutorUsesShmem: true, |
| ExecutorUsesForkServer: true, |
| KernelObject: "vmlinux", |
| CPP: "cpp", |
| }, |
| "freebsd": { |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: true, |
| ExecutorUsesForkServer: true, |
| KernelObject: "kernel.full", |
| CPP: "g++", |
| }, |
| "netbsd": { |
| BuildOS: "linux", |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: true, |
| ExecutorUsesForkServer: true, |
| KernelObject: "netbsd.gdb", |
| CPP: "cpp", |
| }, |
| "openbsd": { |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: true, |
| ExecutorUsesForkServer: true, |
| KernelObject: "bsd.gdb", |
| CPP: "ecpp", |
| }, |
| "fuchsia": { |
| BuildOS: "linux", |
| SyscallNumbers: false, |
| ExecutorUsesShmem: false, |
| ExecutorUsesForkServer: false, |
| KernelObject: "zircon.elf", |
| CPP: "cpp", |
| }, |
| "windows": { |
| SyscallNumbers: false, |
| ExecutorUsesShmem: false, |
| ExecutorUsesForkServer: false, |
| ExeExtension: ".exe", |
| KernelObject: "vmlinux", |
| CPP: "cpp", |
| }, |
| "akaros": { |
| BuildOS: "linux", |
| SyscallNumbers: true, |
| SyscallPrefix: "SYS_", |
| ExecutorUsesShmem: false, |
| ExecutorUsesForkServer: true, |
| KernelObject: "akaros-kernel-64b", |
| CPP: "cpp", |
| }, |
| "trusty": { |
| SyscallNumbers: true, |
| SyscallPrefix: "__NR_", |
| CPP: "cpp", |
| }, |
| } |
| |
| var ( |
| commonCFlags = []string{ |
| "-O2", |
| "-pthread", |
| "-Wall", |
| "-Werror", |
| "-Wparentheses", |
| "-Wunused-const-variable", |
| "-Wframe-larger-than=8192", |
| } |
| optionalCFlags = map[string]bool{ |
| "-static": true, // some distributions don't have static libraries |
| "-Wunused-const-variable": true, // gcc 5 does not support this flag |
| } |
| ) |
| |
| func init() { |
| for OS, archs := range List { |
| for arch, target := range archs { |
| initTarget(target, OS, arch) |
| } |
| } |
| goos := runtime.GOOS |
| if goos == "android" { |
| goos = "linux" |
| } |
| for _, target := range List["test"] { |
| target.CCompiler = List[goos][runtime.GOARCH].CCompiler |
| target.CPP = List[goos][runtime.GOARCH].CPP |
| target.BuildOS = goos |
| if runtime.GOOS == "freebsd" && runtime.GOARCH == "amd64" && target.PtrSize == 4 { |
| // -m32 alone does not work on freebsd with gcc. |
| // TODO(dvyukov): consider switching to clang on freebsd instead. |
| target.CFlags = append(target.CFlags, "-B/usr/lib32") |
| target.CrossCFlags = append(target.CrossCFlags, "-B/usr/lib32") |
| } |
| } |
| } |
| |
| func initTarget(target *Target, OS, arch string) { |
| if common, ok := oses[OS]; ok { |
| target.osCommon = common |
| } |
| target.OS = OS |
| target.Arch = arch |
| if target.NeedSyscallDefine == nil { |
| target.NeedSyscallDefine = needSyscallDefine |
| } |
| target.DataOffset = 512 << 20 |
| target.NumPages = (16 << 20) / target.PageSize |
| if OS == "linux" && arch == runtime.GOARCH { |
| // Don't use cross-compiler for native compilation, there are cases when this does not work: |
| // https://github.com/google/syzkaller/pull/619 |
| // https://github.com/google/syzkaller/issues/387 |
| // https://github.com/google/syzkaller/commit/06db3cec94c54e1cf720cdd5db72761514569d56 |
| target.CCompilerPrefix = "" |
| } |
| if target.CCompiler == "" { |
| target.CCompiler = target.CCompilerPrefix + "gcc" |
| } |
| if target.BuildOS == "" { |
| target.BuildOS = OS |
| } |
| if runtime.GOOS != target.BuildOS { |
| // Spoil native binaries if they are not usable, so that nobody tries to use them later. |
| target.CCompiler = fmt.Sprintf("cant-build-%v-on-%v", target.OS, runtime.GOOS) |
| target.CPP = target.CCompiler |
| } |
| target.CrossCFlags = append(append([]string{}, commonCFlags...), target.CrossCFlags...) |
| } |
| |
| func checkOptionalFlags(target *Target) { |
| flags := make(map[string]*bool) |
| var wg sync.WaitGroup |
| for _, flag := range target.CrossCFlags { |
| if !optionalCFlags[flag] { |
| continue |
| } |
| res := new(bool) |
| flags[flag] = res |
| wg.Add(1) |
| go func(flag string) { |
| defer wg.Done() |
| *res = checkFlagSupported(target, flag) |
| }(flag) |
| } |
| wg.Wait() |
| for i := 0; i < len(target.CrossCFlags); i++ { |
| if res := flags[target.CrossCFlags[i]]; res != nil && !*res { |
| copy(target.CrossCFlags[i:], target.CrossCFlags[i+1:]) |
| target.CrossCFlags = target.CrossCFlags[:len(target.CrossCFlags)-1] |
| i-- |
| } |
| } |
| } |
| |
| func checkFlagSupported(target *Target, flag string) bool { |
| cmd := exec.Command(target.CCompiler, "-x", "c", "-", "-o", "/dev/null", flag) |
| cmd.Stdin = strings.NewReader("int main(){}") |
| return cmd.Run() == nil |
| } |
| |
| func needSyscallDefine(nr uint64) bool { |
| return true |
| } |
| func dontNeedSyscallDefine(nr uint64) bool { |
| return false |
| } |