github.com/alexis81/domosgo@v0.0.0-20191016125037-5aee90a434af/Domos/src/golang.org/x/sys/unix/linux/mkall.go (about)

     1  // Copyright 2017 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // linux/mkall.go - Generates all Linux zsysnum, zsyscall, zerror, and ztype
     6  // files for all 11 linux architectures supported by the go compiler. See
     7  // README.md for more information about the build system.
     8  
     9  // To run it you must have a git checkout of the Linux kernel and glibc. Once
    10  // the appropriate sources are ready, the program is run as:
    11  //     go run linux/mkall.go <linux_dir> <glibc_dir>
    12  
    13  // +build ignore
    14  
    15  package main
    16  
    17  import (
    18  	"bufio"
    19  	"bytes"
    20  	"fmt"
    21  	"io"
    22  	"io/ioutil"
    23  	"os"
    24  	"os/exec"
    25  	"path/filepath"
    26  	"runtime"
    27  	"strings"
    28  	"unicode"
    29  )
    30  
    31  // These will be paths to the appropriate source directories.
    32  var LinuxDir string
    33  var GlibcDir string
    34  
    35  const TempDir = "/tmp"
    36  const IncludeDir = TempDir + "/include" // To hold our C headers
    37  const BuildDir = TempDir + "/build"     // To hold intermediate build files
    38  
    39  const GOOS = "linux"       // Only for Linux targets
    40  const BuildArch = "amd64"  // Must be built on this architecture
    41  const MinKernel = "2.6.23" // https://golang.org/doc/install#requirements
    42  
    43  type target struct {
    44  	GoArch     string // Architecture name according to Go
    45  	LinuxArch  string // Architecture name according to the Linux Kernel
    46  	GNUArch    string // Architecture name according to GNU tools (https://wiki.debian.org/Multiarch/Tuples)
    47  	BigEndian  bool   // Default Little Endian
    48  	SignedChar bool   // Is -fsigned-char needed (default no)
    49  	Bits       int
    50  }
    51  
    52  // List of the 11 Linux targets supported by the go compiler. sparc64 is not
    53  // currently supported, though a port is in progress.
    54  var targets = []target{
    55  	{
    56  		GoArch:    "386",
    57  		LinuxArch: "x86",
    58  		GNUArch:   "i686-linux-gnu", // Note "i686" not "i386"
    59  		Bits:      32,
    60  	},
    61  	{
    62  		GoArch:    "amd64",
    63  		LinuxArch: "x86",
    64  		GNUArch:   "x86_64-linux-gnu",
    65  		Bits:      64,
    66  	},
    67  	{
    68  		GoArch:     "arm64",
    69  		LinuxArch:  "arm64",
    70  		GNUArch:    "aarch64-linux-gnu",
    71  		SignedChar: true,
    72  		Bits:       64,
    73  	},
    74  	{
    75  		GoArch:    "arm",
    76  		LinuxArch: "arm",
    77  		GNUArch:   "arm-linux-gnueabi",
    78  		Bits:      32,
    79  	},
    80  	{
    81  		GoArch:    "mips",
    82  		LinuxArch: "mips",
    83  		GNUArch:   "mips-linux-gnu",
    84  		BigEndian: true,
    85  		Bits:      32,
    86  	},
    87  	{
    88  		GoArch:    "mipsle",
    89  		LinuxArch: "mips",
    90  		GNUArch:   "mipsel-linux-gnu",
    91  		Bits:      32,
    92  	},
    93  	{
    94  		GoArch:    "mips64",
    95  		LinuxArch: "mips",
    96  		GNUArch:   "mips64-linux-gnuabi64",
    97  		BigEndian: true,
    98  		Bits:      64,
    99  	},
   100  	{
   101  		GoArch:    "mips64le",
   102  		LinuxArch: "mips",
   103  		GNUArch:   "mips64el-linux-gnuabi64",
   104  		Bits:      64,
   105  	},
   106  	{
   107  		GoArch:    "ppc64",
   108  		LinuxArch: "powerpc",
   109  		GNUArch:   "powerpc64-linux-gnu",
   110  		BigEndian: true,
   111  		Bits:      64,
   112  	},
   113  	{
   114  		GoArch:    "ppc64le",
   115  		LinuxArch: "powerpc",
   116  		GNUArch:   "powerpc64le-linux-gnu",
   117  		Bits:      64,
   118  	},
   119  	{
   120  		GoArch:     "s390x",
   121  		LinuxArch:  "s390",
   122  		GNUArch:    "s390x-linux-gnu",
   123  		BigEndian:  true,
   124  		SignedChar: true,
   125  		Bits:       64,
   126  	},
   127  	// {
   128  	// 	GoArch:    "sparc64",
   129  	// 	LinuxArch: "sparc",
   130  	// 	GNUArch:   "sparc64-linux-gnu",
   131  	// 	BigEndian: true,
   132  	// 	Bits:      64,
   133  	// },
   134  }
   135  
   136  // ptracePairs is a list of pairs of targets that can, in some cases,
   137  // run each other's binaries.
   138  var ptracePairs = []struct{ a1, a2 string }{
   139  	{"386", "amd64"},
   140  	{"arm", "arm64"},
   141  	{"mips", "mips64"},
   142  	{"mipsle", "mips64le"},
   143  }
   144  
   145  func main() {
   146  	if runtime.GOOS != GOOS || runtime.GOARCH != BuildArch {
   147  		fmt.Printf("Build system has GOOS_GOARCH = %s_%s, need %s_%s\n",
   148  			runtime.GOOS, runtime.GOARCH, GOOS, BuildArch)
   149  		return
   150  	}
   151  
   152  	// Check that we are using the new build system if we should
   153  	if os.Getenv("GOLANG_SYS_BUILD") != "docker" {
   154  		fmt.Println("In the new build system, mkall.go should not be called directly.")
   155  		fmt.Println("See README.md")
   156  		return
   157  	}
   158  
   159  	// Parse the command line options
   160  	if len(os.Args) != 3 {
   161  		fmt.Println("USAGE: go run linux/mkall.go <linux_dir> <glibc_dir>")
   162  		return
   163  	}
   164  	LinuxDir = os.Args[1]
   165  	GlibcDir = os.Args[2]
   166  
   167  	for _, t := range targets {
   168  		fmt.Printf("----- GENERATING: %s -----\n", t.GoArch)
   169  		if err := t.generateFiles(); err != nil {
   170  			fmt.Printf("%v\n***** FAILURE:    %s *****\n\n", err, t.GoArch)
   171  		} else {
   172  			fmt.Printf("----- SUCCESS:    %s -----\n\n", t.GoArch)
   173  		}
   174  	}
   175  
   176  	fmt.Printf("----- GENERATING ptrace pairs -----\n")
   177  	ok := true
   178  	for _, p := range ptracePairs {
   179  		if err := generatePtracePair(p.a1, p.a2); err != nil {
   180  			fmt.Printf("%v\n***** FAILURE: %s/%s *****\n\n", err, p.a1, p.a2)
   181  			ok = false
   182  		}
   183  	}
   184  	if ok {
   185  		fmt.Printf("----- SUCCESS ptrace pairs    -----\n\n")
   186  	}
   187  }
   188  
   189  // Makes an exec.Cmd with Stderr attached to os.Stderr
   190  func makeCommand(name string, args ...string) *exec.Cmd {
   191  	cmd := exec.Command(name, args...)
   192  	cmd.Stderr = os.Stderr
   193  	return cmd
   194  }
   195  
   196  // Runs the command, pipes output to a formatter, pipes that to an output file.
   197  func (t *target) commandFormatOutput(formatter string, outputFile string,
   198  	name string, args ...string) (err error) {
   199  	mainCmd := makeCommand(name, args...)
   200  
   201  	fmtCmd := makeCommand(formatter)
   202  	if formatter == "mkpost" {
   203  		fmtCmd = makeCommand("go", "run", "mkpost.go")
   204  		// Set GOARCH_TARGET so mkpost knows what GOARCH is..
   205  		fmtCmd.Env = append(os.Environ(), "GOARCH_TARGET="+t.GoArch)
   206  		// Set GOARCH to host arch for mkpost, so it can run natively.
   207  		for i, s := range fmtCmd.Env {
   208  			if strings.HasPrefix(s, "GOARCH=") {
   209  				fmtCmd.Env[i] = "GOARCH=" + BuildArch
   210  			}
   211  		}
   212  	}
   213  
   214  	// mainCmd | fmtCmd > outputFile
   215  	if fmtCmd.Stdin, err = mainCmd.StdoutPipe(); err != nil {
   216  		return
   217  	}
   218  	if fmtCmd.Stdout, err = os.Create(outputFile); err != nil {
   219  		return
   220  	}
   221  
   222  	// Make sure the formatter eventually closes
   223  	if err = fmtCmd.Start(); err != nil {
   224  		return
   225  	}
   226  	defer func() {
   227  		fmtErr := fmtCmd.Wait()
   228  		if err == nil {
   229  			err = fmtErr
   230  		}
   231  	}()
   232  
   233  	return mainCmd.Run()
   234  }
   235  
   236  // Generates all the files for a Linux target
   237  func (t *target) generateFiles() error {
   238  	// Setup environment variables
   239  	os.Setenv("GOOS", GOOS)
   240  	os.Setenv("GOARCH", t.GoArch)
   241  
   242  	// Get appropriate compiler and emulator (unless on x86)
   243  	if t.LinuxArch != "x86" {
   244  		// Check/Setup cross compiler
   245  		compiler := t.GNUArch + "-gcc"
   246  		if _, err := exec.LookPath(compiler); err != nil {
   247  			return err
   248  		}
   249  		os.Setenv("CC", compiler)
   250  
   251  		// Check/Setup emulator (usually first component of GNUArch)
   252  		qemuArchName := t.GNUArch[:strings.Index(t.GNUArch, "-")]
   253  		if t.LinuxArch == "powerpc" {
   254  			qemuArchName = t.GoArch
   255  		}
   256  		os.Setenv("GORUN", "qemu-"+qemuArchName)
   257  	} else {
   258  		os.Setenv("CC", "gcc")
   259  	}
   260  
   261  	// Make the include directory and fill it with headers
   262  	if err := os.MkdirAll(IncludeDir, os.ModePerm); err != nil {
   263  		return err
   264  	}
   265  	defer os.RemoveAll(IncludeDir)
   266  	if err := t.makeHeaders(); err != nil {
   267  		return fmt.Errorf("could not make header files: %v", err)
   268  	}
   269  	fmt.Println("header files generated")
   270  
   271  	// Make each of the four files
   272  	if err := t.makeZSysnumFile(); err != nil {
   273  		return fmt.Errorf("could not make zsysnum file: %v", err)
   274  	}
   275  	fmt.Println("zsysnum file generated")
   276  
   277  	if err := t.makeZSyscallFile(); err != nil {
   278  		return fmt.Errorf("could not make zsyscall file: %v", err)
   279  	}
   280  	fmt.Println("zsyscall file generated")
   281  
   282  	if err := t.makeZTypesFile(); err != nil {
   283  		return fmt.Errorf("could not make ztypes file: %v", err)
   284  	}
   285  	fmt.Println("ztypes file generated")
   286  
   287  	if err := t.makeZErrorsFile(); err != nil {
   288  		return fmt.Errorf("could not make zerrors file: %v", err)
   289  	}
   290  	fmt.Println("zerrors file generated")
   291  
   292  	return nil
   293  }
   294  
   295  // Create the Linux and glibc headers in the include directory.
   296  func (t *target) makeHeaders() error {
   297  	// Make the Linux headers we need for this architecture
   298  	linuxMake := makeCommand("make", "headers_install", "ARCH="+t.LinuxArch, "INSTALL_HDR_PATH="+TempDir)
   299  	linuxMake.Dir = LinuxDir
   300  	if err := linuxMake.Run(); err != nil {
   301  		return err
   302  	}
   303  
   304  	// A Temporary build directory for glibc
   305  	if err := os.MkdirAll(BuildDir, os.ModePerm); err != nil {
   306  		return err
   307  	}
   308  	defer os.RemoveAll(BuildDir)
   309  
   310  	// Make the glibc headers we need for this architecture
   311  	confScript := filepath.Join(GlibcDir, "configure")
   312  	glibcConf := makeCommand(confScript, "--prefix="+TempDir, "--host="+t.GNUArch, "--enable-kernel="+MinKernel)
   313  	glibcConf.Dir = BuildDir
   314  	if err := glibcConf.Run(); err != nil {
   315  		return err
   316  	}
   317  	glibcMake := makeCommand("make", "install-headers")
   318  	glibcMake.Dir = BuildDir
   319  	if err := glibcMake.Run(); err != nil {
   320  		return err
   321  	}
   322  	// We only need an empty stubs file
   323  	stubsFile := filepath.Join(IncludeDir, "gnu/stubs.h")
   324  	if file, err := os.Create(stubsFile); err != nil {
   325  		return err
   326  	} else {
   327  		file.Close()
   328  	}
   329  
   330  	return nil
   331  }
   332  
   333  // makes the zsysnum_linux_$GOARCH.go file
   334  func (t *target) makeZSysnumFile() error {
   335  	zsysnumFile := fmt.Sprintf("zsysnum_linux_%s.go", t.GoArch)
   336  	unistdFile := filepath.Join(IncludeDir, "asm/unistd.h")
   337  
   338  	args := append(t.cFlags(), unistdFile)
   339  	return t.commandFormatOutput("gofmt", zsysnumFile, "linux/mksysnum.pl", args...)
   340  }
   341  
   342  // makes the zsyscall_linux_$GOARCH.go file
   343  func (t *target) makeZSyscallFile() error {
   344  	zsyscallFile := fmt.Sprintf("zsyscall_linux_%s.go", t.GoArch)
   345  	// Find the correct architecture syscall file (might end with x.go)
   346  	archSyscallFile := fmt.Sprintf("syscall_linux_%s.go", t.GoArch)
   347  	if _, err := os.Stat(archSyscallFile); os.IsNotExist(err) {
   348  		shortArch := strings.TrimSuffix(t.GoArch, "le")
   349  		archSyscallFile = fmt.Sprintf("syscall_linux_%sx.go", shortArch)
   350  	}
   351  
   352  	args := append(t.mksyscallFlags(), "-tags", "linux,"+t.GoArch,
   353  		"syscall_linux.go", archSyscallFile)
   354  	return t.commandFormatOutput("gofmt", zsyscallFile, "./mksyscall.pl", args...)
   355  }
   356  
   357  // makes the zerrors_linux_$GOARCH.go file
   358  func (t *target) makeZErrorsFile() error {
   359  	zerrorsFile := fmt.Sprintf("zerrors_linux_%s.go", t.GoArch)
   360  
   361  	return t.commandFormatOutput("gofmt", zerrorsFile, "./mkerrors.sh", t.cFlags()...)
   362  }
   363  
   364  // makes the ztypes_linux_$GOARCH.go file
   365  func (t *target) makeZTypesFile() error {
   366  	ztypesFile := fmt.Sprintf("ztypes_linux_%s.go", t.GoArch)
   367  
   368  	args := []string{"tool", "cgo", "-godefs", "--"}
   369  	args = append(args, t.cFlags()...)
   370  	args = append(args, "linux/types.go")
   371  	return t.commandFormatOutput("mkpost", ztypesFile, "go", args...)
   372  }
   373  
   374  // Flags that should be given to gcc and cgo for this target
   375  func (t *target) cFlags() []string {
   376  	// Compile statically to avoid cross-architecture dynamic linking.
   377  	flags := []string{"-Wall", "-Werror", "-static", "-I" + IncludeDir}
   378  
   379  	// Architecture-specific flags
   380  	if t.SignedChar {
   381  		flags = append(flags, "-fsigned-char")
   382  	}
   383  	if t.LinuxArch == "x86" {
   384  		flags = append(flags, fmt.Sprintf("-m%d", t.Bits))
   385  	}
   386  
   387  	return flags
   388  }
   389  
   390  // Flags that should be given to mksyscall for this target
   391  func (t *target) mksyscallFlags() (flags []string) {
   392  	if t.Bits == 32 {
   393  		if t.BigEndian {
   394  			flags = append(flags, "-b32")
   395  		} else {
   396  			flags = append(flags, "-l32")
   397  		}
   398  	}
   399  
   400  	// This flag menas a 64-bit value should use (even, odd)-pair.
   401  	if t.GoArch == "arm" || (t.LinuxArch == "mips" && t.Bits == 32) {
   402  		flags = append(flags, "-arm")
   403  	}
   404  	return
   405  }
   406  
   407  // generatePtracePair takes a pair of GOARCH values that can run each
   408  // other's binaries, such as 386 and amd64. It extracts the PtraceRegs
   409  // type for each one. It writes a new file defining the types
   410  // PtraceRegsArch1 and PtraceRegsArch2 and the corresponding functions
   411  // Ptrace{Get,Set}Regs{arch1,arch2}. This permits debugging the other
   412  // binary on a native system.
   413  func generatePtracePair(arch1, arch2 string) error {
   414  	def1, err := ptraceDef(arch1)
   415  	if err != nil {
   416  		return err
   417  	}
   418  	def2, err := ptraceDef(arch2)
   419  	if err != nil {
   420  		return err
   421  	}
   422  	f, err := os.Create(fmt.Sprintf("zptrace%s_linux.go", arch1))
   423  	if err != nil {
   424  		return err
   425  	}
   426  	buf := bufio.NewWriter(f)
   427  	fmt.Fprintf(buf, "// Code generated by linux/mkall.go generatePtracePair(%s, %s). DO NOT EDIT.\n", arch1, arch2)
   428  	fmt.Fprintf(buf, "\n")
   429  	fmt.Fprintf(buf, "// +build linux\n")
   430  	fmt.Fprintf(buf, "// +build %s %s\n", arch1, arch2)
   431  	fmt.Fprintf(buf, "\n")
   432  	fmt.Fprintf(buf, "package unix\n")
   433  	fmt.Fprintf(buf, "\n")
   434  	fmt.Fprintf(buf, "%s\n", `import "unsafe"`)
   435  	fmt.Fprintf(buf, "\n")
   436  	writeOnePtrace(buf, arch1, def1)
   437  	fmt.Fprintf(buf, "\n")
   438  	writeOnePtrace(buf, arch2, def2)
   439  	if err := buf.Flush(); err != nil {
   440  		return err
   441  	}
   442  	if err := f.Close(); err != nil {
   443  		return err
   444  	}
   445  	return nil
   446  }
   447  
   448  // ptraceDef returns the definition of PtraceRegs for arch.
   449  func ptraceDef(arch string) (string, error) {
   450  	filename := fmt.Sprintf("ztypes_linux_%s.go", arch)
   451  	data, err := ioutil.ReadFile(filename)
   452  	if err != nil {
   453  		return "", fmt.Errorf("reading %s: %v", filename, err)
   454  	}
   455  	start := bytes.Index(data, []byte("type PtraceRegs struct"))
   456  	if start < 0 {
   457  		return "", fmt.Errorf("%s: no definition of PtraceRegs", filename)
   458  	}
   459  	data = data[start:]
   460  	end := bytes.Index(data, []byte("\n}\n"))
   461  	if end < 0 {
   462  		return "", fmt.Errorf("%s: can't find end of PtraceRegs definition", filename)
   463  	}
   464  	return string(data[:end+2]), nil
   465  }
   466  
   467  // writeOnePtrace writes out the ptrace definitions for arch.
   468  func writeOnePtrace(w io.Writer, arch, def string) {
   469  	uarch := string(unicode.ToUpper(rune(arch[0]))) + arch[1:]
   470  	fmt.Fprintf(w, "// PtraceRegs%s is the registers used by %s binaries.\n", uarch, arch)
   471  	fmt.Fprintf(w, "%s\n", strings.Replace(def, "PtraceRegs", "PtraceRegs"+uarch, 1))
   472  	fmt.Fprintf(w, "\n")
   473  	fmt.Fprintf(w, "// PtraceGetRegs%s fetches the registers used by %s binaries.\n", uarch, arch)
   474  	fmt.Fprintf(w, "func PtraceGetRegs%s(pid int, regsout *PtraceRegs%s) error {\n", uarch, uarch)
   475  	fmt.Fprintf(w, "\treturn ptrace(PTRACE_GETREGS, pid, 0, uintptr(unsafe.Pointer(regsout)))\n")
   476  	fmt.Fprintf(w, "}\n")
   477  	fmt.Fprintf(w, "\n")
   478  	fmt.Fprintf(w, "// PtraceSetRegs%s sets the registers used by %s binaries.\n", uarch, arch)
   479  	fmt.Fprintf(w, "func PtraceSetRegs%s(pid int, regs *PtraceRegs%s) error {\n", uarch, uarch)
   480  	fmt.Fprintf(w, "\treturn ptrace(PTRACE_SETREGS, pid, 0, uintptr(unsafe.Pointer(regs)))\n")
   481  	fmt.Fprintf(w, "}\n")
   482  }