diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-12-15 11:25:19 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-12-17 11:39:14 +0100 |
| commit | 431d3c90b1a4a31a6156ad1cd5fc692af3b1a314 (patch) | |
| tree | fbea978cb14e1daac37e8c9625a18ea18d6c2355 /pkg/csource | |
| parent | 9004acd9cc20a77e5227326a1ad4a0bcbc03316d (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.go | 86 | ||||
| -rw-r--r-- | pkg/csource/common.go | 123 | ||||
| -rw-r--r-- | pkg/csource/csource.go | 181 | ||||
| -rw-r--r-- | pkg/csource/gen.go | 19 |
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) + } +} |
