aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/csource
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-12-15 11:25:19 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-12-17 11:39:14 +0100
commit431d3c90b1a4a31a6156ad1cd5fc692af3b1a314 (patch)
treefbea978cb14e1daac37e8c9625a18ea18d6c2355 /pkg/csource
parent9004acd9cc20a77e5227326a1ad4a0bcbc03316d (diff)
pkg/csource: refactor
csource.go is too large and messy. Move Build/Format into buid.go. Move generation of common header into common.go. Split generation of common header into smaller managable functions.
Diffstat (limited to 'pkg/csource')
-rw-r--r--pkg/csource/build.go86
-rw-r--r--pkg/csource/common.go123
-rw-r--r--pkg/csource/csource.go181
-rw-r--r--pkg/csource/gen.go19
4 files changed, 230 insertions, 179 deletions
diff --git a/pkg/csource/build.go b/pkg/csource/build.go
new file mode 100644
index 000000000..a059dcaf8
--- /dev/null
+++ b/pkg/csource/build.go
@@ -0,0 +1,86 @@
+// 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 csource
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/prog"
+ "github.com/google/syzkaller/sys/targets"
+)
+
+// Build builds a C/C++ program from source src and returns name of the resulting binary.
+// lang can be "c" or "c++".
+func Build(target *prog.Target, lang, src string) (string, error) {
+ bin, err := ioutil.TempFile("", "syzkaller")
+ if err != nil {
+ return "", fmt.Errorf("failed to create temp file: %v", err)
+ }
+ bin.Close()
+ sysTarget := targets.List[target.OS][target.Arch]
+ compiler := sysTarget.CCompilerPrefix + "gcc"
+ if _, err := exec.LookPath(compiler); err != nil {
+ return "", NoCompilerErr
+ }
+ flags := []string{
+ "-x", lang, "-Wall", "-Werror", "-O1", "-g", "-o", bin.Name(),
+ src, "-pthread",
+ }
+ flags = append(flags, sysTarget.CrossCFlags...)
+ if sysTarget.PtrSize == 4 {
+ // We do generate uint64's for syscall arguments that overflow longs on 32-bit archs.
+ flags = append(flags, "-Wno-overflow")
+ }
+ out, err := osutil.Command(compiler, append(flags, "-static")...).CombinedOutput()
+ if err != nil {
+ // Some distributions don't have static libraries.
+ out, err = osutil.Command(compiler, flags...).CombinedOutput()
+ }
+ if err != nil {
+ os.Remove(bin.Name())
+ data, _ := ioutil.ReadFile(src)
+ return "", fmt.Errorf("failed to build program:\n%s\n%s\ncompiler invocation: %v %v\n",
+ data, out, compiler, flags)
+ }
+ return bin.Name(), nil
+}
+
+var NoCompilerErr = errors.New("no target compiler")
+
+// Format reformats C source using clang-format.
+func Format(src []byte) ([]byte, error) {
+ stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
+ cmd := osutil.Command("clang-format", "-assume-filename=/src.c", "-style", style)
+ cmd.Stdin = bytes.NewReader(src)
+ cmd.Stdout = stdout
+ cmd.Stderr = stderr
+ if err := cmd.Run(); err != nil {
+ return src, fmt.Errorf("failed to format source: %v\n%v", err, stderr.String())
+ }
+ return stdout.Bytes(), nil
+}
+
+// Something acceptable for kernel developers and email-friendly.
+var style = `{
+BasedOnStyle: LLVM,
+IndentWidth: 2,
+UseTab: Never,
+BreakBeforeBraces: Linux,
+IndentCaseLabels: false,
+DerivePointerAlignment: false,
+PointerAlignment: Left,
+AlignTrailingComments: true,
+AllowShortBlocksOnASingleLine: false,
+AllowShortCaseLabelsOnASingleLine: false,
+AllowShortFunctionsOnASingleLine: false,
+AllowShortIfStatementsOnASingleLine: false,
+AllowShortLoopsOnASingleLine: false,
+ColumnLimit: 72,
+}`
diff --git a/pkg/csource/common.go b/pkg/csource/common.go
new file mode 100644
index 000000000..6e46135e1
--- /dev/null
+++ b/pkg/csource/common.go
@@ -0,0 +1,123 @@
+// 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 csource
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+
+ "github.com/google/syzkaller/pkg/osutil"
+ "github.com/google/syzkaller/prog"
+ "github.com/google/syzkaller/sys/targets"
+)
+
+func createCommonHeader(p *prog.Prog, opts Options) ([]byte, error) {
+ commonHeader, err := getCommonHeader(p.Target.OS)
+ if err != nil {
+ return nil, err
+ }
+ defines, err := defineList(p, opts)
+ if err != nil {
+ return nil, err
+ }
+
+ cmd := osutil.Command("cpp", "-nostdinc", "-undef", "-fdirectives-only", "-dDI", "-E", "-P", "-")
+ for _, def := range defines {
+ cmd.Args = append(cmd.Args, "-D"+def)
+ }
+ cmd.Stdin = strings.NewReader(commonHeader)
+ stderr := new(bytes.Buffer)
+ stdout := new(bytes.Buffer)
+ cmd.Stderr = stderr
+ cmd.Stdout = stdout
+ if err := cmd.Run(); len(stdout.Bytes()) == 0 {
+ return nil, fmt.Errorf("cpp failed: %v\n%v\n%v\n", err, stdout.String(), stderr.String())
+ }
+
+ src, err := removeSystemDefines(stdout.Bytes(), defines)
+ if err != nil {
+ return nil, err
+ }
+ return src, nil
+}
+
+func defineList(p *prog.Prog, opts Options) ([]string, error) {
+ var defines []string
+ if prog.RequiresBitmasks(p) {
+ defines = append(defines, "SYZ_USE_BITMASKS")
+ }
+ if prog.RequiresChecksums(p) {
+ defines = append(defines, "SYZ_USE_CHECKSUMS")
+ }
+ switch opts.Sandbox {
+ case "":
+ // No sandbox, do nothing.
+ case "none":
+ defines = append(defines, "SYZ_SANDBOX_NONE")
+ case "setuid":
+ defines = append(defines, "SYZ_SANDBOX_SETUID")
+ case "namespace":
+ defines = append(defines, "SYZ_SANDBOX_NAMESPACE")
+ default:
+ return nil, fmt.Errorf("unknown sandbox mode: %v", opts.Sandbox)
+ }
+ if opts.Threaded {
+ defines = append(defines, "SYZ_THREADED")
+ }
+ if opts.Collide {
+ defines = append(defines, "SYZ_COLLIDE")
+ }
+ if opts.Repeat {
+ defines = append(defines, "SYZ_REPEAT")
+ }
+ if opts.Fault {
+ defines = append(defines, "SYZ_FAULT_INJECTION")
+ }
+ if opts.EnableTun {
+ defines = append(defines, "SYZ_TUN_ENABLE")
+ }
+ if opts.UseTmpDir {
+ defines = append(defines, "SYZ_USE_TMP_DIR")
+ }
+ if opts.HandleSegv {
+ defines = append(defines, "SYZ_HANDLE_SEGV")
+ }
+ if opts.WaitRepeat {
+ defines = append(defines, "SYZ_WAIT_REPEAT")
+ }
+ if opts.Debug {
+ defines = append(defines, "SYZ_DEBUG")
+ }
+ for _, c := range p.Calls {
+ defines = append(defines, "__NR_"+c.Meta.CallName)
+ }
+ defines = append(defines, targets.List[p.Target.OS][p.Target.Arch].CArch...)
+ return defines, nil
+}
+
+func removeSystemDefines(src []byte, defines []string) ([]byte, error) {
+ remove := append(defines, []string{
+ "__STDC__",
+ "__STDC_HOSTED__",
+ "__STDC_UTF_16__",
+ "__STDC_UTF_32__",
+ }...)
+ for _, def := range remove {
+ src = bytes.Replace(src, []byte("#define "+def+" 1\n"), nil, -1)
+ }
+ // strip: #define __STDC_VERSION__ 201112L
+ for _, def := range []string{"__STDC_VERSION__"} {
+ pos := bytes.Index(src, []byte("#define "+def))
+ if pos == -1 {
+ continue
+ }
+ end := bytes.IndexByte(src[pos:], '\n')
+ if end == -1 {
+ continue
+ }
+ src = bytes.Replace(src, src[pos:end+1], nil, -1)
+ }
+ return src, nil
+}
diff --git a/pkg/csource/csource.go b/pkg/csource/csource.go
index d8a4a5a01..d99a0168d 100644
--- a/pkg/csource/csource.go
+++ b/pkg/csource/csource.go
@@ -6,16 +6,11 @@ package csource
import (
"bytes"
- "errors"
"fmt"
- "io/ioutil"
- "os"
- "os/exec"
"regexp"
"strings"
"unsafe"
- "github.com/google/syzkaller/pkg/osutil"
"github.com/google/syzkaller/prog"
"github.com/google/syzkaller/sys/targets"
)
@@ -24,19 +19,6 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
if err := opts.Check(); err != nil {
return nil, fmt.Errorf("csource: invalid opts: %v", err)
}
- commonHeader := ""
- switch p.Target.OS {
- case "linux":
- commonHeader = commonHeaderLinux
- case "akaros":
- commonHeader = commonHeaderAkaros
- case "freebsd":
- commonHeader = commonHeaderFreebsd
- case "netbsd":
- commonHeader = commonHeaderNetbsd
- default:
- return nil, fmt.Errorf("unsupported OS: %v", p.Target.OS)
- }
ctx := &context{
p: p,
opts: opts,
@@ -51,11 +33,11 @@ func Write(p *prog.Prog, opts Options) ([]byte, error) {
ctx.print("// autogenerated by syzkaller (http://github.com/google/syzkaller)\n\n")
- hdr, err := ctx.preprocessCommonHeader(commonHeader)
+ hdr, err := createCommonHeader(p, opts)
if err != nil {
return nil, err
}
- ctx.print(hdr)
+ ctx.w.Write(hdr)
ctx.print("\n")
ctx.generateSyscallDefines()
@@ -424,162 +406,3 @@ loop:
newCall()
return calls, n
}
-
-func (ctx *context) preprocessCommonHeader(commonHeader string) (string, error) {
- var defines []string
- if prog.RequiresBitmasks(ctx.p) {
- defines = append(defines, "SYZ_USE_BITMASKS")
- }
- if prog.RequiresChecksums(ctx.p) {
- defines = append(defines, "SYZ_USE_CHECKSUMS")
- }
- opts := ctx.opts
- switch opts.Sandbox {
- case "":
- // No sandbox, do nothing.
- case "none":
- defines = append(defines, "SYZ_SANDBOX_NONE")
- case "setuid":
- defines = append(defines, "SYZ_SANDBOX_SETUID")
- case "namespace":
- defines = append(defines, "SYZ_SANDBOX_NAMESPACE")
- default:
- return "", fmt.Errorf("unknown sandbox mode: %v", opts.Sandbox)
- }
- if opts.Threaded {
- defines = append(defines, "SYZ_THREADED")
- }
- if opts.Collide {
- defines = append(defines, "SYZ_COLLIDE")
- }
- if opts.Repeat {
- defines = append(defines, "SYZ_REPEAT")
- }
- if opts.Fault {
- defines = append(defines, "SYZ_FAULT_INJECTION")
- }
- if opts.EnableTun {
- defines = append(defines, "SYZ_TUN_ENABLE")
- }
- if opts.UseTmpDir {
- defines = append(defines, "SYZ_USE_TMP_DIR")
- }
- if opts.HandleSegv {
- defines = append(defines, "SYZ_HANDLE_SEGV")
- }
- if opts.WaitRepeat {
- defines = append(defines, "SYZ_WAIT_REPEAT")
- }
- if opts.Debug {
- defines = append(defines, "SYZ_DEBUG")
- }
- for name, _ := range ctx.calls {
- defines = append(defines, "__NR_"+name)
- }
- defines = append(defines, ctx.sysTarget.CArch...)
-
- cmd := osutil.Command("cpp", "-nostdinc", "-undef", "-fdirectives-only", "-dDI", "-E", "-P", "-")
- for _, def := range defines {
- cmd.Args = append(cmd.Args, "-D"+def)
- }
- cmd.Stdin = strings.NewReader(commonHeader)
- stderr := new(bytes.Buffer)
- stdout := new(bytes.Buffer)
- cmd.Stderr = stderr
- cmd.Stdout = stdout
- if err := cmd.Run(); len(stdout.Bytes()) == 0 {
- return "", fmt.Errorf("cpp failed: %v\n%v\n%v\n", err, stdout.String(), stderr.String())
- }
- remove := append(defines, []string{
- "__STDC__",
- "__STDC_HOSTED__",
- "__STDC_UTF_16__",
- "__STDC_UTF_32__",
- }...)
- out := stdout.String()
- for _, def := range remove {
- out = strings.Replace(out, "#define "+def+" 1\n", "", -1)
- }
- // strip: #define __STDC_VERSION__ 201112L
- for _, def := range []string{"__STDC_VERSION__"} {
- pos := strings.Index(out, "#define "+def)
- if pos == -1 {
- continue
- }
- end := strings.IndexByte(out[pos:], '\n')
- if end == -1 {
- continue
- }
- out = strings.Replace(out, out[pos:end+1], "", -1)
- }
- return out, nil
-}
-
-// Build builds a C/C++ program from source src and returns name of the resulting binary.
-// lang can be "c" or "c++".
-func Build(target *prog.Target, lang, src string) (string, error) {
- bin, err := ioutil.TempFile("", "syzkaller")
- if err != nil {
- return "", fmt.Errorf("failed to create temp file: %v", err)
- }
- bin.Close()
- sysTarget := targets.List[target.OS][target.Arch]
- compiler := sysTarget.CCompilerPrefix + "gcc"
- if _, err := exec.LookPath(compiler); err != nil {
- return "", NoCompilerErr
- }
- flags := []string{
- "-x", lang, "-Wall", "-Werror", "-O1", "-g", "-o", bin.Name(),
- src, "-pthread",
- }
- flags = append(flags, sysTarget.CrossCFlags...)
- if sysTarget.PtrSize == 4 {
- // We do generate uint64's for syscall arguments that overflow longs on 32-bit archs.
- flags = append(flags, "-Wno-overflow")
- }
- out, err := osutil.Command(compiler, append(flags, "-static")...).CombinedOutput()
- if err != nil {
- // Some distributions don't have static libraries.
- out, err = osutil.Command(compiler, flags...).CombinedOutput()
- }
- if err != nil {
- os.Remove(bin.Name())
- data, _ := ioutil.ReadFile(src)
- return "", fmt.Errorf("failed to build program:\n%s\n%s\ncompiler invocation: %v %v\n",
- data, out, compiler, flags)
- }
- return bin.Name(), nil
-}
-
-var NoCompilerErr = errors.New("no target compiler")
-
-// Format reformats C source using clang-format.
-func Format(src []byte) ([]byte, error) {
- stdout, stderr := new(bytes.Buffer), new(bytes.Buffer)
- cmd := osutil.Command("clang-format", "-assume-filename=/src.c", "-style", style)
- cmd.Stdin = bytes.NewReader(src)
- cmd.Stdout = stdout
- cmd.Stderr = stderr
- if err := cmd.Run(); err != nil {
- return src, fmt.Errorf("failed to format source: %v\n%v", err, stderr.String())
- }
- return stdout.Bytes(), nil
-}
-
-// Something acceptable for kernel developers and email-friendly.
-var style = `{
-BasedOnStyle: LLVM,
-IndentWidth: 2,
-UseTab: Never,
-BreakBeforeBraces: Linux,
-IndentCaseLabels: false,
-DerivePointerAlignment: false,
-PointerAlignment: Left,
-AlignTrailingComments: true,
-AllowShortBlocksOnASingleLine: false,
-AllowShortCaseLabelsOnASingleLine: false,
-AllowShortFunctionsOnASingleLine: false,
-AllowShortIfStatementsOnASingleLine: false,
-AllowShortLoopsOnASingleLine: false,
-ColumnLimit: 72,
-}`
diff --git a/pkg/csource/gen.go b/pkg/csource/gen.go
index f100b0e52..1cd5c969d 100644
--- a/pkg/csource/gen.go
+++ b/pkg/csource/gen.go
@@ -16,3 +16,22 @@
//go:generate go fmt netbsd_common.go
package csource
+
+import (
+ "fmt"
+)
+
+func getCommonHeader(os string) (string, error) {
+ switch os {
+ case "linux":
+ return commonHeaderLinux, nil
+ case "akaros":
+ return commonHeaderAkaros, nil
+ case "freebsd":
+ return commonHeaderFreebsd, nil
+ case "netbsd":
+ return commonHeaderNetbsd, nil
+ default:
+ return "", fmt.Errorf("unsupported OS: %v", os)
+ }
+}