// 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 (
"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 {
// 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
}
func Get(OS, arch string) *Target {
target := List[OS][arch]
if target == nil {
return nil
}
target.init.Do(func() {
checkStaticBuild(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=armv6t2", "-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"},
},
},
"netbsd": {
"amd64": {
PtrSize: 8,
PageSize: 4 << 10,
CFlags: []string{"-m64"},
CrossCFlags: []string{"-m64", "-static"},
},
},
"fuchsia": {
"amd64": {
PtrSize: 8,
PageSize: 4 << 10,
KernelHeaderArch: "x64",
CCompiler: os.ExpandEnv("${SOURCEDIR}/buildtools/linux-x64/clang/bin/clang++"),
CrossCFlags: []string{
"-Wno-deprecated",
"-Wno-error",
"--target=x86_64-fuchsia",
"-lfdio",
"-lzircon",
"-ldriver",
"--sysroot", os.ExpandEnv("${SOURCEDIR}/out/build-zircon/build-x64/sysroot"),
"-L", os.ExpandEnv("${SOURCEDIR}/out/x64/x64-shared"),
"-L", os.ExpandEnv("${SOURCEDIR}/out/x64/sdks/zircon_sysroot/arch/x64/sysroot/lib"),
"-L", os.ExpandEnv("${SOURCEDIR}/out/build-zircon/build-x64/system/ulib/driver"),
},
},
"arm64": {
PtrSize: 8,
PageSize: 4 << 10,
KernelHeaderArch: "arm64",
CCompiler: os.ExpandEnv("${SOURCEDIR}/buildtools/linux-x64/clang/bin/clang++"),
CrossCFlags: []string{
"-Wno-deprecated",
"-Wno-error",
"--target=aarch64-fuchsia",
"-lfdio",
"-lzircon",
"-ldriver",
"--sysroot", os.ExpandEnv("${SOURCEDIR}/out/build-zircon/build-arm64/sysroot"),
"-L", os.ExpandEnv("${SOURCEDIR}/out/arm64/arm64-shared"),
"-L", os.ExpandEnv("${SOURCEDIR}/out/arm64/sdks/zircon_sysroot/arch/arm64/sysroot/lib"),
"-L", os.ExpandEnv("${SOURCEDIR}/out/build-zircon/build-arm64/system/ulib/driver"),
},
},
},
"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",
},
},
},
}
var oses = map[string]osCommon{
"linux": {
SyscallNumbers: true,
SyscallPrefix: "__NR_",
ExecutorUsesShmem: true,
ExecutorUsesForkServer: true,
},
"freebsd": {
SyscallNumbers: true,
SyscallPrefix: "SYS_",
ExecutorUsesShmem: true,
ExecutorUsesForkServer: true,
},
"netbsd": {
SyscallNumbers: true,
SyscallPrefix: "SYS_",
ExecutorUsesShmem: true,
ExecutorUsesForkServer: true,
},
"fuchsia": {
SyscallNumbers: false,
ExecutorUsesShmem: false,
ExecutorUsesForkServer: false,
},
"windows": {
SyscallNumbers: false,
ExecutorUsesShmem: false,
ExecutorUsesForkServer: false,
ExeExtension: ".exe",
},
"akaros": {
SyscallNumbers: true,
SyscallPrefix: "SYS_",
ExecutorUsesShmem: false,
ExecutorUsesForkServer: true,
},
}
func init() {
for OS, archs := range List {
for arch, target := range archs {
initTarget(target, OS, arch)
}
}
}
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 == runtime.GOOS && 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"
}
}
func checkStaticBuild(target *Target) {
for i, flag := range target.CrossCFlags {
if flag == "-static" {
// Some distributions don't have static libraries.
if !supportsStatic(target) {
copy(target.CrossCFlags[i:], target.CrossCFlags[i+1:])
target.CrossCFlags = target.CrossCFlags[:len(target.CrossCFlags)-1]
}
break
}
}
}
func supportsStatic(target *Target) bool {
cmd := exec.Command(target.CCompiler, "-x", "c", "-", "-o", "/dev/null", "-static")
cmd.Stdin = strings.NewReader("int main(){}")
return cmd.Run() == nil
}
func needSyscallDefine(nr uint64) bool {
return true
}
func dontNeedSyscallDefine(nr uint64) bool {
return false
}