aboutsummaryrefslogtreecommitdiffstats
path: root/sysgen/fetch.go
blob: 941c6d587e9eaddee1b9d8143af3a3b62442ea04 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// Copyright 2015 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 main

import (
	"fmt"
	"io/ioutil"
	"os"
	"os/exec"
	"strconv"
	"strings"
)

// 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(arch string, vals []string, includes []string, defines map[string]string) []string {
	logf(1, "Use C compiler to fetch constant values for arch=%v", arch)
	includeText := ""
	for _, inc := range includes {
		includeText += fmt.Sprintf("#include <%v>\n", inc)
	}
	definesText := ""
	for k, v := range defines {
		definesText += fmt.Sprintf("#ifndef %v\n#define %v %v\n#endif\n", k, k, v)
	}
	src := strings.Replace(fetchSrc, "[[INCLUDES]]", includeText, 1)
	src = strings.Replace(src, "[[DEFAULTS]]", definesText, 1)
	src = strings.Replace(src, "[[VALS]]", strings.Join(vals, ","), 1)
	bin, err := ioutil.TempFile("", "")
	if err != nil {
		failf("failed to create temp file: %v", err)
	}
	bin.Close()
	defer os.Remove(bin.Name())
	logf(2, "  Build C program into temp file %v", bin.Name())

	args := []string{"-x", "c", "-", "-o", bin.Name()}
	args = append(args, []string{
		// This would be useful to ensure that we don't include any host headers,
		// but kernel includes at least <stdarg.h>
		// "-nostdinc",
		"-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",
	}...)

	logf(4, "  Source code:\n%v", src)
	logf(2, "  Execute gcc with: %v", args)
	cmd := exec.Command("gcc", args...)
	cmd.Stdin = strings.NewReader(src)
	out, err := cmd.CombinedOutput()
	if err != nil {
		failf("failed to run gcc: %v\n%v", err, string(out))
	}

	out, err = exec.Command(bin.Name()).CombinedOutput()
	if err != nil {
		failf("failed to flags binary: %v\n%v", err, string(out))
	}

	flagVals := strings.Split(string(out), " ")
	if len(flagVals) != len(vals) {
		failf("fetched wrong number of values")
	}
	for _, v := range flagVals {
		_, err := strconv.ParseUint(v, 10, 64)
		if err != nil {
			failf("failed to parse value: %v (%v)", err, v)
		}
	}
	return flagVals
}

var fetchSrc = `
[[INCLUDES]]
[[DEFAULTS]]
int printf(const char *format, ...);
unsigned long phys_base;
#ifndef __phys_addr
unsigned long __phys_addr(unsigned long addr) { return 0; }
#endif
int main() {
	int i;
	unsigned long vals[] = {[[VALS]]};
	for (i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {
		if (i != 0)
			printf(" ");
		printf("%lu", vals[i]);
	}
	return 0;
}
`